xref: /aoo41x/main/oox/source/xls/drawingmanager.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include "oox/xls/drawingmanager.hxx"
29 
30 #include <com/sun/star/awt/Rectangle.hpp>
31 #include <com/sun/star/drawing/CircleKind.hpp>
32 #include <com/sun/star/drawing/PointSequenceSequence.hpp>
33 #include <com/sun/star/drawing/PolygonKind.hpp>
34 #include <com/sun/star/drawing/XShapes.hpp>
35 #include "oox/core/filterbase.hxx"
36 #include "oox/drawingml/fillproperties.hxx"
37 #include "oox/drawingml/lineproperties.hxx"
38 #include "oox/drawingml/shapepropertymap.hxx"
39 #include "oox/helper/containerhelper.hxx"
40 #include "oox/token/tokens.hxx"
41 #include "oox/xls/biffinputstream.hxx"
42 #include "oox/xls/unitconverter.hxx"
43 
44 namespace oox {
45 namespace xls {
46 
47 // ============================================================================
48 
49 using namespace ::com::sun::star::awt;
50 using namespace ::com::sun::star::drawing;
51 using namespace ::com::sun::star::lang;
52 using namespace ::com::sun::star::uno;
53 using namespace ::oox::drawingml;
54 
55 using ::rtl::OUString;
56 
57 // ============================================================================
58 
59 namespace {
60 
61 // OBJ record -----------------------------------------------------------------
62 
63 const sal_uInt16 BIFF_OBJTYPE_GROUP         = 0;
64 const sal_uInt16 BIFF_OBJTYPE_LINE          = 1;
65 const sal_uInt16 BIFF_OBJTYPE_RECTANGLE     = 2;
66 const sal_uInt16 BIFF_OBJTYPE_OVAL          = 3;
67 const sal_uInt16 BIFF_OBJTYPE_ARC           = 4;
68 const sal_uInt16 BIFF_OBJTYPE_CHART         = 5;
69 const sal_uInt16 BIFF_OBJTYPE_TEXT          = 6;
70 const sal_uInt16 BIFF_OBJTYPE_BUTTON        = 7;
71 const sal_uInt16 BIFF_OBJTYPE_PICTURE       = 8;
72 const sal_uInt16 BIFF_OBJTYPE_POLYGON       = 9;        // new in BIFF4
73 const sal_uInt16 BIFF_OBJTYPE_CHECKBOX      = 11;       // new in BIFF5
74 const sal_uInt16 BIFF_OBJTYPE_OPTIONBUTTON  = 12;
75 const sal_uInt16 BIFF_OBJTYPE_EDIT          = 13;
76 const sal_uInt16 BIFF_OBJTYPE_LABEL         = 14;
77 const sal_uInt16 BIFF_OBJTYPE_DIALOG        = 15;
78 const sal_uInt16 BIFF_OBJTYPE_SPIN          = 16;
79 const sal_uInt16 BIFF_OBJTYPE_SCROLLBAR     = 17;
80 const sal_uInt16 BIFF_OBJTYPE_LISTBOX       = 18;
81 const sal_uInt16 BIFF_OBJTYPE_GROUPBOX      = 19;
82 const sal_uInt16 BIFF_OBJTYPE_DROPDOWN      = 20;
83 const sal_uInt16 BIFF_OBJTYPE_NOTE          = 25;       // new in BIFF8
84 const sal_uInt16 BIFF_OBJTYPE_DRAWING       = 30;
85 const sal_uInt16 BIFF_OBJTYPE_UNKNOWN       = 0xFFFF;   // for internal use only
86 
87 const sal_uInt16 BIFF_OBJ_HIDDEN            = 0x0100;
88 const sal_uInt16 BIFF_OBJ_VISIBLE           = 0x0200;
89 const sal_uInt16 BIFF_OBJ_PRINTABLE         = 0x0400;
90 
91 // line formatting ------------------------------------------------------------
92 
93 const sal_uInt8 BIFF_OBJ_LINE_AUTOCOLOR     = 64;
94 
95 const sal_uInt8 BIFF_OBJ_LINE_SOLID         = 0;
96 const sal_uInt8 BIFF_OBJ_LINE_DASH          = 1;
97 const sal_uInt8 BIFF_OBJ_LINE_DOT           = 2;
98 const sal_uInt8 BIFF_OBJ_LINE_DASHDOT       = 3;
99 const sal_uInt8 BIFF_OBJ_LINE_DASHDOTDOT    = 4;
100 const sal_uInt8 BIFF_OBJ_LINE_MEDTRANS      = 5;
101 const sal_uInt8 BIFF_OBJ_LINE_DARKTRANS     = 6;
102 const sal_uInt8 BIFF_OBJ_LINE_LIGHTTRANS    = 7;
103 const sal_uInt8 BIFF_OBJ_LINE_NONE          = 255;
104 
105 const sal_uInt8 BIFF_OBJ_LINE_HAIR          = 0;
106 const sal_uInt8 BIFF_OBJ_LINE_THIN          = 1;
107 const sal_uInt8 BIFF_OBJ_LINE_MEDIUM        = 2;
108 const sal_uInt8 BIFF_OBJ_LINE_THICK         = 3;
109 
110 const sal_uInt8 BIFF_OBJ_LINE_AUTO          = 0x01;
111 
112 const sal_uInt8 BIFF_OBJ_ARROW_NONE         = 0;
113 const sal_uInt8 BIFF_OBJ_ARROW_OPEN         = 1;
114 const sal_uInt8 BIFF_OBJ_ARROW_FILLED       = 2;
115 const sal_uInt8 BIFF_OBJ_ARROW_OPENBOTH     = 3;
116 const sal_uInt8 BIFF_OBJ_ARROW_FILLEDBOTH   = 4;
117 
118 const sal_uInt8 BIFF_OBJ_ARROW_NARROW       = 0;
119 const sal_uInt8 BIFF_OBJ_ARROW_MEDIUM       = 1;
120 const sal_uInt8 BIFF_OBJ_ARROW_WIDE         = 2;
121 
122 const sal_uInt8 BIFF_OBJ_LINE_TL            = 0;
123 const sal_uInt8 BIFF_OBJ_LINE_TR            = 1;
124 const sal_uInt8 BIFF_OBJ_LINE_BR            = 2;
125 const sal_uInt8 BIFF_OBJ_LINE_BL            = 3;
126 
127 const sal_uInt8 BIFF_OBJ_ARC_TR             = 0;
128 const sal_uInt8 BIFF_OBJ_ARC_TL             = 1;
129 const sal_uInt8 BIFF_OBJ_ARC_BL             = 2;
130 const sal_uInt8 BIFF_OBJ_ARC_BR             = 3;
131 
132 const sal_uInt16 BIFF_OBJ_POLY_CLOSED       = 0x0100;
133 
134 // fill formatting ------------------------------------------------------------
135 
136 const sal_uInt8 BIFF_OBJ_FILL_AUTOCOLOR     = 65;
137 
138 const sal_uInt8 BIFF_OBJ_PATT_NONE          = 0;
139 const sal_uInt8 BIFF_OBJ_PATT_SOLID         = 1;
140 
141 const sal_uInt8 BIFF_OBJ_FILL_AUTO          = 0x01;
142 
143 // text formatting ------------------------------------------------------------
144 
145 const sal_uInt8 BIFF_OBJ_HOR_LEFT           = 1;
146 const sal_uInt8 BIFF_OBJ_HOR_CENTER         = 2;
147 const sal_uInt8 BIFF_OBJ_HOR_RIGHT          = 3;
148 const sal_uInt8 BIFF_OBJ_HOR_JUSTIFY        = 4;
149 
150 const sal_uInt8 BIFF_OBJ_VER_TOP            = 1;
151 const sal_uInt8 BIFF_OBJ_VER_CENTER         = 2;
152 const sal_uInt8 BIFF_OBJ_VER_BOTTOM         = 3;
153 const sal_uInt8 BIFF_OBJ_VER_JUSTIFY        = 4;
154 
155 const sal_uInt16 BIFF_OBJ_ORIENT_NONE       = 0;
156 const sal_uInt16 BIFF_OBJ_ORIENT_STACKED    = 1;        /// Stacked top to bottom.
157 const sal_uInt16 BIFF_OBJ_ORIENT_90CCW      = 2;        /// 90 degr. counterclockwise.
158 const sal_uInt16 BIFF_OBJ_ORIENT_90CW       = 3;        /// 90 degr. clockwise.
159 
160 const sal_uInt16 BIFF_OBJ_TEXT_AUTOSIZE     = 0x0080;
161 const sal_uInt16 BIFF_OBJ_TEXT_LOCKED       = 0x0200;
162 
163 const sal_Int32 BIFF_OBJ_TEXT_MARGIN        = 20000;    /// Automatic text margin (EMUs).
164 
165 // BIFF8 OBJ sub records ------------------------------------------------------
166 
167 const sal_uInt16 BIFF_OBJCMO_PRINTABLE      = 0x0010;   /// Object printable.
168 const sal_uInt16 BIFF_OBJCMO_AUTOLINE       = 0x2000;   /// Automatic line formatting.
169 const sal_uInt16 BIFF_OBJCMO_AUTOFILL       = 0x4000;   /// Automatic fill formatting.
170 
171 // ----------------------------------------------------------------------------
172 
173 inline BiffInputStream& operator>>( BiffInputStream& rStrm, ShapeAnchor& rAnchor )
174 {
175     rAnchor.importBiffAnchor( rStrm );
176     return rStrm;
177 }
178 
179 } // namespace
180 
181 // ============================================================================
182 // Model structures for BIFF OBJ record data
183 // ============================================================================
184 
185 BiffObjLineModel::BiffObjLineModel() :
186     mnColorIdx( BIFF_OBJ_LINE_AUTOCOLOR ),
187     mnStyle( BIFF_OBJ_LINE_SOLID ),
188     mnWidth( BIFF_OBJ_LINE_HAIR ),
189     mbAuto( true )
190 {
191 }
192 
193 bool BiffObjLineModel::isVisible() const
194 {
195     return mbAuto || (mnStyle != BIFF_OBJ_LINE_NONE);
196 }
197 
198 BiffInputStream& operator>>( BiffInputStream& rStrm, BiffObjLineModel& rModel )
199 {
200     sal_uInt8 nFlags;
201     rStrm >> rModel.mnColorIdx >> rModel.mnStyle >> rModel.mnWidth >> nFlags;
202     rModel.mbAuto = getFlag( nFlags, BIFF_OBJ_LINE_AUTO );
203     return rStrm;
204 }
205 
206 // ============================================================================
207 
208 BiffObjFillModel::BiffObjFillModel() :
209     mnBackColorIdx( BIFF_OBJ_LINE_AUTOCOLOR ),
210     mnPattColorIdx( BIFF_OBJ_FILL_AUTOCOLOR ),
211     mnPattern( BIFF_OBJ_PATT_SOLID ),
212     mbAuto( true )
213 {
214 }
215 
216 bool BiffObjFillModel::isFilled() const
217 {
218     return mbAuto || (mnPattern != BIFF_OBJ_PATT_NONE);
219 }
220 
221 BiffInputStream& operator>>( BiffInputStream& rStrm, BiffObjFillModel& rModel )
222 {
223     sal_uInt8 nFlags;
224     rStrm >> rModel.mnBackColorIdx >> rModel.mnPattColorIdx >> rModel.mnPattern >> nFlags;
225     rModel.mbAuto = getFlag( nFlags, BIFF_OBJ_FILL_AUTO );
226     return rStrm;
227 }
228 
229 // ============================================================================
230 
231 BiffObjTextModel::BiffObjTextModel() :
232     mnTextLen( 0 ),
233     mnFormatSize( 0 ),
234     mnLinkSize( 0 ),
235     mnDefFontId( 0 ),
236     mnFlags( 0 ),
237     mnOrientation( BIFF_OBJ_ORIENT_NONE ),
238     mnButtonFlags( 0 ),
239     mnShortcut( 0 ),
240     mnShortcutEA( 0 )
241 {
242 }
243 
244 void BiffObjTextModel::readObj3( BiffInputStream& rStrm )
245 {
246     rStrm >> mnTextLen;
247     rStrm.skip( 2 );
248     rStrm >> mnFormatSize >> mnDefFontId;
249     rStrm.skip( 2 );
250     rStrm >> mnFlags >> mnOrientation;
251     rStrm.skip( 8 );
252 }
253 
254 void BiffObjTextModel::readObj5( BiffInputStream& rStrm )
255 {
256     rStrm >> mnTextLen;
257     rStrm.skip( 2 );
258     rStrm >> mnFormatSize >> mnDefFontId;
259     rStrm.skip( 2 );
260     rStrm >> mnFlags >> mnOrientation;
261     rStrm.skip( 2 );
262     rStrm >> mnLinkSize;
263     rStrm.skip( 2 );
264     rStrm >> mnButtonFlags >> mnShortcut >> mnShortcutEA;
265 }
266 
267 void BiffObjTextModel::readTxo8( BiffInputStream& rStrm )
268 {
269     rStrm >> mnFlags >> mnOrientation >> mnButtonFlags >> mnShortcut >> mnShortcutEA >> mnTextLen >> mnFormatSize;
270 }
271 
272 sal_uInt8 BiffObjTextModel::getHorAlign() const
273 {
274     return extractValue< sal_uInt8 >( mnFlags, 1, 3 );
275 }
276 
277 sal_uInt8 BiffObjTextModel::getVerAlign() const
278 {
279     return extractValue< sal_uInt8 >( mnFlags, 4, 3 );
280 }
281 
282 // ============================================================================
283 // BIFF drawing objects
284 // ============================================================================
285 
286 BiffDrawingObjectContainer::BiffDrawingObjectContainer()
287 {
288 }
289 
290 void BiffDrawingObjectContainer::append( const BiffDrawingObjectRef& rxDrawingObj )
291 {
292     maObjects.push_back( rxDrawingObj );
293 }
294 
295 void BiffDrawingObjectContainer::insertGrouped( const BiffDrawingObjectRef& rxDrawingObj )
296 {
297     if( !maObjects.empty() )
298         if( BiffGroupObject* pGroupObj = dynamic_cast< BiffGroupObject* >( maObjects.back().get() ) )
299             if( pGroupObj->tryInsert( rxDrawingObj ) )
300                 return;
301     maObjects.push_back( rxDrawingObj );
302 }
303 
304 void BiffDrawingObjectContainer::convertAndInsert( BiffDrawingBase& rDrawing, const Reference< XShapes >& rxShapes, const Rectangle* pParentRect ) const
305 {
306     maObjects.forEachMem( &BiffDrawingObjectBase::convertAndInsert, ::boost::ref( rDrawing ), ::boost::cref( rxShapes ), pParentRect );
307 }
308 
309 // ============================================================================
310 
311 BiffDrawingObjectBase::BiffDrawingObjectBase( const WorksheetHelper& rHelper ) :
312     WorksheetHelper( rHelper ),
313     maAnchor( rHelper ),
314     mnDffShapeId( 0 ),
315     mnDffFlags( 0 ),
316     mnObjId( BIFF_OBJ_INVALID_ID ),
317     mnObjType( BIFF_OBJTYPE_UNKNOWN ),
318     mbHasAnchor( false ),
319     mbHidden( false ),
320     mbVisible( true ),
321     mbPrintable( true ),
322     mbAreaObj( false ),
323     mbAutoMargin( true ),
324     mbSimpleMacro( true ),
325     mbProcessShape( true ),
326     mbInsertShape( true ),
327     mbCustomDff( false )
328 {
329 }
330 
331 BiffDrawingObjectBase::~BiffDrawingObjectBase()
332 {
333 }
334 
335 /*static*/ BiffDrawingObjectRef BiffDrawingObjectBase::importObjBiff3( const WorksheetHelper& rHelper, BiffInputStream& rStrm )
336 {
337     BiffDrawingObjectRef xDrawingObj;
338 
339     if( rStrm.getRemaining() >= 30 )
340     {
341         sal_uInt16 nObjType;
342         rStrm.skip( 4 );
343         rStrm >> nObjType;
344         switch( nObjType )
345         {
346             case BIFF_OBJTYPE_GROUP:        xDrawingObj.reset( new BiffGroupObject( rHelper ) );    break;
347             case BIFF_OBJTYPE_LINE:         xDrawingObj.reset( new BiffLineObject( rHelper ) );     break;
348             case BIFF_OBJTYPE_RECTANGLE:    xDrawingObj.reset( new BiffRectObject( rHelper ) );     break;
349             case BIFF_OBJTYPE_OVAL:         xDrawingObj.reset( new BiffOvalObject( rHelper ) );     break;
350             case BIFF_OBJTYPE_ARC:          xDrawingObj.reset( new BiffArcObject( rHelper ) );      break;
351 #if 0
352             case BIFF_OBJTYPE_CHART:        xDrawingObj.reset( new XclImpChartObj( rHelper ) );     break;
353             case BIFF_OBJTYPE_TEXT:         xDrawingObj.reset( new XclImpTextObj( rHelper ) );      break;
354             case BIFF_OBJTYPE_BUTTON:       xDrawingObj.reset( new XclImpButtonObj( rHelper ) );    break;
355             case BIFF_OBJTYPE_PICTURE:      xDrawingObj.reset( new XclImpPictureObj( rHelper ) );   break;
356 #endif
357             default:
358 #if 0
359                 OSL_ENSURE( false, "BiffDrawingObjectBase::importObjBiff3 - unknown object type" );
360 #endif
361                 xDrawingObj.reset( new BiffPlaceholderObject( rHelper ) );
362         }
363     }
364 
365     xDrawingObj->importObjBiff3( rStrm );
366     return xDrawingObj;
367 }
368 
369 /*static*/ BiffDrawingObjectRef BiffDrawingObjectBase::importObjBiff4( const WorksheetHelper& rHelper, BiffInputStream& rStrm )
370 {
371     BiffDrawingObjectRef xDrawingObj;
372 
373     if( rStrm.getRemaining() >= 30 )
374     {
375         sal_uInt16 nObjType;
376         rStrm.skip( 4 );
377         rStrm >> nObjType;
378         switch( nObjType )
379         {
380             case BIFF_OBJTYPE_GROUP:        xDrawingObj.reset( new BiffGroupObject( rHelper ) );    break;
381             case BIFF_OBJTYPE_LINE:         xDrawingObj.reset( new BiffLineObject( rHelper ) );     break;
382             case BIFF_OBJTYPE_RECTANGLE:    xDrawingObj.reset( new BiffRectObject( rHelper ) );     break;
383             case BIFF_OBJTYPE_OVAL:         xDrawingObj.reset( new BiffOvalObject( rHelper ) );     break;
384             case BIFF_OBJTYPE_ARC:          xDrawingObj.reset( new BiffArcObject( rHelper ) );      break;
385             case BIFF_OBJTYPE_POLYGON:      xDrawingObj.reset( new BiffPolygonObject( rHelper ) );  break;
386 #if 0
387             case BIFF_OBJTYPE_CHART:        xDrawingObj.reset( new XclImpChartObj( rHelper ) );     break;
388             case BIFF_OBJTYPE_TEXT:         xDrawingObj.reset( new XclImpTextObj( rHelper ) );      break;
389             case BIFF_OBJTYPE_BUTTON:       xDrawingObj.reset( new XclImpButtonObj( rHelper ) );    break;
390             case BIFF_OBJTYPE_PICTURE:      xDrawingObj.reset( new XclImpPictureObj( rHelper ) );   break;
391 #endif
392             default:
393 #if 0
394                 OSL_ENSURE( false, "BiffDrawingObjectBase::importObjBiff4 - unknown object type" );
395 #endif
396                 xDrawingObj.reset( new BiffPlaceholderObject( rHelper ) );
397         }
398     }
399 
400     xDrawingObj->importObjBiff4( rStrm );
401     return xDrawingObj;
402 }
403 
404 /*static*/ BiffDrawingObjectRef BiffDrawingObjectBase::importObjBiff5( const WorksheetHelper& rHelper, BiffInputStream& rStrm )
405 {
406     BiffDrawingObjectRef xDrawingObj;
407 
408     if( rStrm.getRemaining() >= 34 )
409     {
410         sal_uInt16 nObjType;
411         rStrm.skip( 4 );
412         rStrm >> nObjType;
413         switch( nObjType )
414         {
415             case BIFF_OBJTYPE_GROUP:        xDrawingObj.reset( new BiffGroupObject( rHelper ) );        break;
416             case BIFF_OBJTYPE_LINE:         xDrawingObj.reset( new BiffLineObject( rHelper ) );         break;
417             case BIFF_OBJTYPE_RECTANGLE:    xDrawingObj.reset( new BiffRectObject( rHelper ) );         break;
418             case BIFF_OBJTYPE_OVAL:         xDrawingObj.reset( new BiffOvalObject( rHelper ) );         break;
419             case BIFF_OBJTYPE_ARC:          xDrawingObj.reset( new BiffArcObject( rHelper ) );           break;
420             case BIFF_OBJTYPE_POLYGON:      xDrawingObj.reset( new BiffPolygonObject( rHelper ) );      break;
421 #if 0
422             case BIFF_OBJTYPE_CHART:        xDrawingObj.reset( new XclImpChartObj( rHelper ) );         break;
423             case BIFF_OBJTYPE_TEXT:         xDrawingObj.reset( new XclImpTextObj( rHelper ) );          break;
424             case BIFF_OBJTYPE_BUTTON:       xDrawingObj.reset( new XclImpButtonObj( rHelper ) );        break;
425             case BIFF_OBJTYPE_PICTURE:      xDrawingObj.reset( new XclImpPictureObj( rHelper ) );       break;
426             case BIFF_OBJTYPE_CHECKBOX:     xDrawingObj.reset( new XclImpCheckBoxObj( rHelper ) );      break;
427             case BIFF_OBJTYPE_OPTIONBUTTON: xDrawingObj.reset( new XclImpOptionButtonObj( rHelper ) );  break;
428             case BIFF_OBJTYPE_EDIT:         xDrawingObj.reset( new XclImpEditObj( rHelper ) );          break;
429             case BIFF_OBJTYPE_LABEL:        xDrawingObj.reset( new XclImpLabelObj( rHelper ) );         break;
430             case BIFF_OBJTYPE_DIALOG:       xDrawingObj.reset( new XclImpDialogObj( rHelper ) );        break;
431             case BIFF_OBJTYPE_SPIN:         xDrawingObj.reset( new XclImpSpinButtonObj( rHelper ) );    break;
432             case BIFF_OBJTYPE_SCROLLBAR:    xDrawingObj.reset( new XclImpScrollBarObj( rHelper ) );     break;
433             case BIFF_OBJTYPE_LISTBOX:      xDrawingObj.reset( new XclImpListBoxObj( rHelper ) );       break;
434             case BIFF_OBJTYPE_GROUPBOX:     xDrawingObj.reset( new XclImpGroupBoxObj( rHelper ) );      break;
435             case BIFF_OBJTYPE_DROPDOWN:     xDrawingObj.reset( new XclImpDropDownObj( rHelper ) );      break;
436 #endif
437             default:
438 #if 0
439                 OSL_ENSURE( false, "BiffDrawingObjectBase::importObjBiff5 - unknown object type" );
440 #endif
441                 xDrawingObj.reset( new BiffPlaceholderObject( rHelper ) );
442         }
443     }
444 
445     xDrawingObj->importObjBiff5( rStrm );
446     return xDrawingObj;
447 }
448 
449 /*static*/ BiffDrawingObjectRef BiffDrawingObjectBase::importObjBiff8( const WorksheetHelper& rHelper, BiffInputStream& rStrm )
450 {
451     BiffDrawingObjectRef xDrawingObj;
452 
453     if( rStrm.getRemaining() >= 10 )
454     {
455         sal_uInt16 nSubRecId, nSubRecSize, nObjType;
456         rStrm >> nSubRecId >> nSubRecSize >> nObjType;
457         OSL_ENSURE( nSubRecId == BIFF_ID_OBJCMO, "BiffDrawingObjectBase::importObjBiff8 - OBJCMO subrecord expected" );
458         if( (nSubRecId == BIFF_ID_OBJCMO) && (nSubRecSize >= 6) )
459         {
460             switch( nObjType )
461             {
462 #if 0
463                 // in BIFF8, all simple objects support text
464                 case BIFF_OBJTYPE_LINE:
465                 case BIFF_OBJTYPE_ARC:
466                     xDrawingObj.reset( new XclImpTextObj( rHelper ) );
467                     // lines and arcs may be 2-dimensional
468                     xDrawingObj->setAreaObj( false );
469                 break;
470 
471                 // in BIFF8, all simple objects support text
472                 case BIFF_OBJTYPE_RECTANGLE:
473                 case BIFF_OBJTYPE_OVAL:
474                 case BIFF_OBJTYPE_POLYGON:
475                 case BIFF_OBJTYPE_DRAWING:
476                 case BIFF_OBJTYPE_TEXT:
477                     xDrawingObj.reset( new XclImpTextObj( rHelper ) );
478                 break;
479 #endif
480 
481                 case BIFF_OBJTYPE_GROUP:        xDrawingObj.reset( new BiffGroupObject( rHelper ) );        break;
482 #if 0
483                 case BIFF_OBJTYPE_CHART:        xDrawingObj.reset( new XclImpChartObj( rHelper ) );         break;
484                 case BIFF_OBJTYPE_BUTTON:       xDrawingObj.reset( new XclImpButtonObj( rHelper ) );        break;
485                 case BIFF_OBJTYPE_PICTURE:      xDrawingObj.reset( new XclImpPictureObj( rHelper ) );       break;
486                 case BIFF_OBJTYPE_CHECKBOX:     xDrawingObj.reset( new XclImpCheckBoxObj( rHelper ) );      break;
487                 case BIFF_OBJTYPE_OPTIONBUTTON: xDrawingObj.reset( new XclImpOptionButtonObj( rHelper ) );  break;
488                 case BIFF_OBJTYPE_EDIT:         xDrawingObj.reset( new XclImpEditObj( rHelper ) );          break;
489                 case BIFF_OBJTYPE_LABEL:        xDrawingObj.reset( new XclImpLabelObj( rHelper ) );         break;
490                 case BIFF_OBJTYPE_DIALOG:       xDrawingObj.reset( new XclImpDialogObj( rHelper ) );        break;
491                 case BIFF_OBJTYPE_SPIN:         xDrawingObj.reset( new XclImpSpinButtonObj( rHelper ) );    break;
492                 case BIFF_OBJTYPE_SCROLLBAR:    xDrawingObj.reset( new XclImpScrollBarObj( rHelper ) );     break;
493                 case BIFF_OBJTYPE_LISTBOX:      xDrawingObj.reset( new XclImpListBoxObj( rHelper ) );       break;
494                 case BIFF_OBJTYPE_GROUPBOX:     xDrawingObj.reset( new XclImpGroupBoxObj( rHelper ) );      break;
495                 case BIFF_OBJTYPE_DROPDOWN:     xDrawingObj.reset( new XclImpDropDownObj( rHelper ) );      break;
496                 case BIFF_OBJTYPE_NOTE:         xDrawingObj.reset( new XclImpNoteObj( rHelper ) );          break;
497 #endif
498 
499                 default:
500 #if 0
501                     OSL_ENSURE( false, "BiffDrawingObjectBase::importObjBiff8 - unknown object type" );
502 #endif
503                     xDrawingObj.reset( new BiffPlaceholderObject( rHelper ) );
504             }
505         }
506     }
507 
508     xDrawingObj->importObjBiff8( rStrm );
509     return xDrawingObj;
510 }
511 
512 Reference< XShape > BiffDrawingObjectBase::convertAndInsert( BiffDrawingBase& rDrawing,
513         const Reference< XShapes >& rxShapes, const Rectangle* pParentRect ) const
514 {
515     Reference< XShape > xShape;
516     if( rxShapes.is() && mbProcessShape && !mbHidden )  // TODO: support for hidden objects?
517     {
518         // base class 'ShapeAnchor' calculates the shape rectangle in 1/100 mm
519         // in BIFF3-BIFF5, all shapes have absolute anchor (also children of group shapes)
520         Rectangle aShapeRect = maAnchor.calcAnchorRectHmm( getDrawPageSize() );
521 
522         // convert the shape, if the calculated rectangle is not empty
523         bool bHasWidth = aShapeRect.Width > 0;
524         bool bHasHeight = aShapeRect.Height > 0;
525         if( mbAreaObj ? (bHasWidth && bHasHeight) : (bHasWidth || bHasHeight) )
526         {
527             xShape = implConvertAndInsert( rDrawing, rxShapes, aShapeRect );
528             /*  Notify the drawing that a new shape has been inserted (but not
529                 for children of group shapes). For convenience, pass the
530                 rectangle that contains position and size of the shape. */
531             if( !pParentRect && xShape.is() )
532                 rDrawing.notifyShapeInserted( xShape, aShapeRect );
533         }
534     }
535     return xShape;
536 }
537 
538 // protected ------------------------------------------------------------------
539 
540 void BiffDrawingObjectBase::readNameBiff5( BiffInputStream& rStrm, sal_uInt16 nNameLen )
541 {
542     maObjName = OUString();
543     if( nNameLen > 0 )
544     {
545         // name length field is repeated before the name
546         maObjName = rStrm.readByteStringUC( false, getTextEncoding() );
547         // skip padding byte for word boundaries
548         rStrm.alignToBlock( 2 );
549     }
550 }
551 
552 void BiffDrawingObjectBase::readMacroBiff3( BiffInputStream& rStrm, sal_uInt16 nMacroSize )
553 {
554     maMacroName = OUString();
555     rStrm.skip( nMacroSize );
556     // skip padding byte for word boundaries, not contained in nMacroSize
557     rStrm.alignToBlock( 2 );
558 }
559 
560 void BiffDrawingObjectBase::readMacroBiff4( BiffInputStream& rStrm, sal_uInt16 nMacroSize )
561 {
562     maMacroName = OUString();
563     rStrm.skip( nMacroSize );
564 }
565 
566 void BiffDrawingObjectBase::readMacroBiff5( BiffInputStream& rStrm, sal_uInt16 nMacroSize )
567 {
568     maMacroName = OUString();
569     rStrm.skip( nMacroSize );
570 }
571 
572 void BiffDrawingObjectBase::readMacroBiff8( BiffInputStream& rStrm )
573 {
574     maMacroName = OUString();
575     if( rStrm.getRemaining() > 6 )
576     {
577         // macro is stored in a tNameXR token containing a link to a defined name
578         sal_uInt16 nFmlaSize;
579         rStrm >> nFmlaSize;
580         rStrm.skip( 4 );
581         OSL_ENSURE( nFmlaSize == 7, "BiffDrawingObjectBase::readMacroBiff8 - unexpected formula size" );
582         if( nFmlaSize == 7 )
583         {
584             sal_uInt8 nTokenId;
585             sal_uInt16 nExtLinkId, nExtNameId;
586             rStrm >> nTokenId >> nExtLinkId >> nExtNameId;
587 #if 0
588             OSL_ENSURE( nTokenId == XclTokenArrayHelper::GetTokenId( EXC_TOKID_NAMEX, EXC_TOKCLASS_REF ),
589                 "BiffDrawingObjectBase::readMacroBiff8 - tNameXR token expected" );
590             if( nTokenId == XclTokenArrayHelper::GetTokenId( EXC_TOKID_NAMEX, EXC_TOKCLASS_REF ) )
591                 maMacroName = GetLinkManager().GetMacroName( nExtLinkId, nExtNameId );
592 #endif
593         }
594     }
595 }
596 
597 void BiffDrawingObjectBase::convertLineProperties( ShapePropertyMap& rPropMap, const BiffObjLineModel& rLineModel, sal_uInt16 nArrows ) const
598 {
599     if( rLineModel.mbAuto )
600     {
601         BiffObjLineModel aAutoModel;
602         aAutoModel.mbAuto = false;
603         convertLineProperties( rPropMap, aAutoModel, nArrows );
604         return;
605     }
606 
607     /*  Convert line formatting to DrawingML line formatting and let the
608         DrawingML code do the hard work. */
609     LineProperties aLineProps;
610 
611     if( rLineModel.mnStyle == BIFF_OBJ_LINE_NONE )
612     {
613         aLineProps.maLineFill.moFillType = XML_noFill;
614     }
615     else
616     {
617         aLineProps.maLineFill.moFillType = XML_solidFill;
618         aLineProps.maLineFill.maFillColor.setPaletteClr( rLineModel.mnColorIdx );
619         aLineProps.moLineCompound = XML_sng;
620         aLineProps.moLineCap = XML_flat;
621         aLineProps.moLineJoint = XML_round;
622 
623         // line width: use 0.35 mm per BIFF line width step
624         sal_Int32 nLineWidth = 0;
625         switch( rLineModel.mnWidth )
626         {
627             default:
628             case BIFF_OBJ_LINE_HAIR:    nLineWidth = 0;     break;
629             case BIFF_OBJ_LINE_THIN:    nLineWidth = 20;    break;
630             case BIFF_OBJ_LINE_MEDIUM:  nLineWidth = 40;    break;
631             case BIFF_OBJ_LINE_THICK:   nLineWidth = 60;    break;
632         }
633         aLineProps.moLineWidth = getLimitedValue< sal_Int32, sal_Int64 >( convertHmmToEmu( nLineWidth ), 0, SAL_MAX_INT32 );
634 
635         // dash style and transparency
636         switch( rLineModel.mnStyle )
637         {
638             default:
639             case BIFF_OBJ_LINE_SOLID:
640                 aLineProps.moPresetDash = XML_solid;
641             break;
642             case BIFF_OBJ_LINE_DASH:
643                 aLineProps.moPresetDash = XML_lgDash;
644             break;
645             case BIFF_OBJ_LINE_DOT:
646                 aLineProps.moPresetDash = XML_dot;
647             break;
648             case BIFF_OBJ_LINE_DASHDOT:
649                 aLineProps.moPresetDash = XML_lgDashDot;
650             break;
651             case BIFF_OBJ_LINE_DASHDOTDOT:
652                 aLineProps.moPresetDash = XML_lgDashDotDot;
653             break;
654             case BIFF_OBJ_LINE_MEDTRANS:
655                 aLineProps.moPresetDash = XML_solid;
656                 aLineProps.maLineFill.maFillColor.addTransformation( XML_alpha, 50 * PER_PERCENT );
657             break;
658             case BIFF_OBJ_LINE_DARKTRANS:
659                 aLineProps.moPresetDash = XML_solid;
660                 aLineProps.maLineFill.maFillColor.addTransformation( XML_alpha, 75 * PER_PERCENT );
661             break;
662             case BIFF_OBJ_LINE_LIGHTTRANS:
663                 aLineProps.moPresetDash = XML_solid;
664                 aLineProps.maLineFill.maFillColor.addTransformation( XML_alpha, 25 * PER_PERCENT );
665             break;
666         }
667 
668         // line ends
669         bool bLineStart = false;
670         bool bLineEnd = false;
671         bool bFilled = false;
672         switch( extractValue< sal_uInt8 >( nArrows, 0, 4 ) )
673         {
674             case BIFF_OBJ_ARROW_OPEN:       bLineStart = false; bLineEnd = true;  bFilled = false;  break;
675             case BIFF_OBJ_ARROW_OPENBOTH:   bLineStart = true;  bLineEnd = true;  bFilled = false;  break;
676             case BIFF_OBJ_ARROW_FILLED:     bLineStart = false; bLineEnd = true;  bFilled = true;   break;
677             case BIFF_OBJ_ARROW_FILLEDBOTH: bLineStart = true;  bLineEnd = true;  bFilled = true;   break;
678         }
679         if( bLineStart || bLineEnd )
680         {
681             // arrow type (open or closed)
682             sal_Int32 nArrowType = bFilled ? XML_triangle : XML_arrow;
683             aLineProps.maStartArrow.moArrowType = bLineStart ? nArrowType : XML_none;
684             aLineProps.maEndArrow.moArrowType   = bLineEnd   ? nArrowType : XML_none;
685 
686             // arrow width
687             sal_Int32 nArrowWidth = XML_med;
688             switch( extractValue< sal_uInt8 >( nArrows, 4, 4 ) )
689             {
690                 case BIFF_OBJ_ARROW_NARROW: nArrowWidth = XML_sm;   break;
691                 case BIFF_OBJ_ARROW_MEDIUM: nArrowWidth = XML_med;  break;
692                 case BIFF_OBJ_ARROW_WIDE:   nArrowWidth = XML_lg;   break;
693             }
694             aLineProps.maStartArrow.moArrowWidth = aLineProps.maEndArrow.moArrowWidth = nArrowWidth;
695 
696             // arrow length
697             sal_Int32 nArrowLength = XML_med;
698             switch( extractValue< sal_uInt8 >( nArrows, 8, 4 ) )
699             {
700                 case BIFF_OBJ_ARROW_NARROW: nArrowLength = XML_sm;  break;
701                 case BIFF_OBJ_ARROW_MEDIUM: nArrowLength = XML_med; break;
702                 case BIFF_OBJ_ARROW_WIDE:   nArrowLength = XML_lg;  break;
703             }
704             aLineProps.maStartArrow.moArrowLength = aLineProps.maEndArrow.moArrowLength = nArrowLength;
705         }
706     }
707 
708     aLineProps.pushToPropMap( rPropMap, getBaseFilter().getGraphicHelper() );
709 }
710 
711 void BiffDrawingObjectBase::convertFillProperties( ShapePropertyMap& rPropMap, const BiffObjFillModel& rFillModel ) const
712 {
713     if( rFillModel.mbAuto )
714     {
715         BiffObjFillModel aAutoModel;
716         aAutoModel.mbAuto = false;
717         convertFillProperties( rPropMap, aAutoModel );
718         return;
719     }
720 
721     /*  Convert fill formatting to DrawingML fill formatting and let the
722         DrawingML code do the hard work. */
723     FillProperties aFillProps;
724 
725     if( rFillModel.mnPattern == BIFF_OBJ_PATT_NONE )
726     {
727         aFillProps.moFillType = XML_noFill;
728     }
729     else
730     {
731         const sal_Int32 spnPatternPresets[] = {
732             XML_TOKEN_INVALID, XML_TOKEN_INVALID, XML_pct50, XML_pct50, XML_pct25,
733             XML_dkHorz, XML_dkVert, XML_dkDnDiag, XML_dkUpDiag, XML_smCheck, XML_trellis,
734             XML_ltHorz, XML_ltVert, XML_ltDnDiag, XML_ltUpDiag, XML_smGrid, XML_diagCross,
735             XML_pct20, XML_pct10 };
736         sal_Int32 nPatternPreset = STATIC_ARRAY_SELECT( spnPatternPresets, rFillModel.mnPattern, XML_TOKEN_INVALID );
737         if( nPatternPreset == XML_TOKEN_INVALID )
738         {
739             aFillProps.moFillType = XML_solidFill;
740             aFillProps.maFillColor.setPaletteClr( rFillModel.mnPattColorIdx );
741         }
742         else
743         {
744             aFillProps.moFillType = XML_pattFill;
745             aFillProps.maPatternProps.maPattFgColor.setPaletteClr( rFillModel.mnPattColorIdx );
746             aFillProps.maPatternProps.maPattBgColor.setPaletteClr( rFillModel.mnBackColorIdx );
747             aFillProps.maPatternProps.moPattPreset = nPatternPreset;
748         }
749 #if 0
750         static const sal_uInt8 sppnPatterns[][ 8 ] =
751         {
752             { 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55 },
753             { 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD },
754             { 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22 },
755             { 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00 },
756             { 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC },
757             { 0x33, 0x66, 0xCC, 0x99, 0x33, 0x66, 0xCC, 0x99 },
758             { 0xCC, 0x66, 0x33, 0x99, 0xCC, 0x66, 0x33, 0x99 },
759             { 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33 },
760             { 0xCC, 0xFF, 0x33, 0xFF, 0xCC, 0xFF, 0x33, 0xFF },
761             { 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00 },
762             { 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88 },
763             { 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88 },
764             { 0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11 },
765             { 0xFF, 0x11, 0x11, 0x11, 0xFF, 0x11, 0x11, 0x11 },
766             { 0xAA, 0x44, 0xAA, 0x11, 0xAA, 0x44, 0xAA, 0x11 },
767             { 0x88, 0x00, 0x22, 0x00, 0x88, 0x00, 0x22, 0x00 },
768             { 0x80, 0x00, 0x08, 0x00, 0x80, 0x00, 0x08, 0x00 }
769         };
770         const sal_uInt8* const pnPattern = sppnPatterns[ ::std::min< size_t >( rFillData.mnPattern - 2, STATIC_ARRAY_SIZE( sppnPatterns ) ) ];
771         // create 2-colored 8x8 DIB
772         SvMemoryStream aMemStrm;
773 //      { 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x01, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00 }
774         aMemStrm << sal_uInt32( 12 ) << sal_Int16( 8 ) << sal_Int16( 8 ) << sal_uInt16( 1 ) << sal_uInt16( 1 );
775         aMemStrm << sal_uInt8( 0xFF ) << sal_uInt8( 0xFF ) << sal_uInt8( 0xFF );
776         aMemStrm << sal_uInt8( 0x00 ) << sal_uInt8( 0x00 ) << sal_uInt8( 0x00 );
777         for( size_t nIdx = 0; nIdx < 8; ++nIdx )
778             aMemStrm << sal_uInt32( pnPattern[ nIdx ] ); // 32-bit little-endian
779         aMemStrm.Seek( STREAM_SEEK_TO_BEGIN );
780         Bitmap aBitmap;
781         aBitmap.Read( aMemStrm, FALSE );
782         XOBitmap aXOBitmap( aBitmap );
783         aXOBitmap.Bitmap2Array();
784         aXOBitmap.SetBitmapType( XBITMAP_8X8 );
785         if( aXOBitmap.GetBackgroundColor().GetColor() == COL_BLACK )
786             ::std::swap( aPattColor, aBackColor );
787         aXOBitmap.SetPixelColor( aPattColor );
788         aXOBitmap.SetBackgroundColor( aBackColor );
789         rSdrObj.SetMergedItem( XFillStyleItem( XFILL_BITMAP ) );
790         rSdrObj.SetMergedItem( XFillBitmapItem( EMPTY_STRING, aXOBitmap ) );
791 #endif
792     }
793 
794     aFillProps.pushToPropMap( rPropMap, getBaseFilter().getGraphicHelper() );
795 }
796 
797 void BiffDrawingObjectBase::convertFrameProperties( ShapePropertyMap& /*rPropMap*/, sal_uInt16 /*nFrameFlags*/ ) const
798 {
799 }
800 
801 void BiffDrawingObjectBase::implReadObjBiff3( BiffInputStream& /*rStrm*/, sal_uInt16 /*nMacroSize*/ )
802 {
803 }
804 
805 void BiffDrawingObjectBase::implReadObjBiff4( BiffInputStream& /*rStrm*/, sal_uInt16 /*nMacroSize*/ )
806 {
807 }
808 
809 void BiffDrawingObjectBase::implReadObjBiff5( BiffInputStream& /*rStrm*/, sal_uInt16 /*nNameLen*/, sal_uInt16 /*nMacroSize*/ )
810 {
811 }
812 
813 void BiffDrawingObjectBase::implReadObjBiff8SubRec( BiffInputStream& /*rStrm*/, sal_uInt16 /*nSubRecId*/, sal_uInt16 /*nSubRecSize*/ )
814 {
815 }
816 
817 // private --------------------------------------------------------------------
818 
819 void BiffDrawingObjectBase::importObjBiff3( BiffInputStream& rStrm )
820 {
821     // back to offset 4 (ignore object count field)
822     rStrm.seek( 4 );
823 
824     sal_uInt16 nObjFlags, nMacroSize;
825     rStrm >> mnObjType >> mnObjId >> nObjFlags >> maAnchor >> nMacroSize;
826     rStrm.skip( 2 );
827 
828     mbHasAnchor = true;
829     mbHidden = getFlag( nObjFlags, BIFF_OBJ_HIDDEN );
830     mbVisible = getFlag( nObjFlags, BIFF_OBJ_VISIBLE );
831     implReadObjBiff3( rStrm, nMacroSize );
832 }
833 
834 void BiffDrawingObjectBase::importObjBiff4( BiffInputStream& rStrm )
835 {
836     // back to offset 4 (ignore object count field)
837     rStrm.seek( 4 );
838 
839     sal_uInt16 nObjFlags, nMacroSize;
840     rStrm >> mnObjType >> mnObjId >> nObjFlags >> maAnchor >> nMacroSize;
841     rStrm.skip( 2 );
842 
843     mbHasAnchor = true;
844     mbHidden = getFlag( nObjFlags, BIFF_OBJ_HIDDEN );
845     mbVisible = getFlag( nObjFlags, BIFF_OBJ_VISIBLE );
846     mbPrintable = getFlag( nObjFlags, BIFF_OBJ_PRINTABLE );
847     implReadObjBiff4( rStrm, nMacroSize );
848 }
849 
850 void BiffDrawingObjectBase::importObjBiff5( BiffInputStream& rStrm )
851 {
852     // back to offset 4 (ignore object count field)
853     rStrm.seek( 4 );
854 
855     sal_uInt16 nObjFlags, nMacroSize, nNameLen;
856     rStrm >> mnObjType >> mnObjId >> nObjFlags >> maAnchor >> nMacroSize;
857     rStrm.skip( 2 );
858     rStrm >> nNameLen;
859     rStrm.skip( 2 );
860 
861     mbHasAnchor = true;
862     mbHidden = getFlag( nObjFlags, BIFF_OBJ_HIDDEN );
863     mbVisible = getFlag( nObjFlags, BIFF_OBJ_VISIBLE );
864     mbPrintable = getFlag( nObjFlags, BIFF_OBJ_PRINTABLE );
865     implReadObjBiff5( rStrm, nNameLen, nMacroSize );
866 }
867 
868 void BiffDrawingObjectBase::importObjBiff8( BiffInputStream& rStrm )
869 {
870     // back to beginning
871     rStrm.seekToStart();
872 
873     bool bLoop = true;
874     while( bLoop && (rStrm.getRemaining() >= 4) )
875     {
876         sal_uInt16 nSubRecId, nSubRecSize;
877         rStrm >> nSubRecId >> nSubRecSize;
878         sal_Int64 nStrmPos = rStrm.tell();
879         // sometimes the last subrecord has an invalid length (OBJLBSDATA) -> min()
880         nSubRecSize = static_cast< sal_uInt16 >( ::std::min< sal_Int64 >( nSubRecSize, rStrm.getRemaining() ) );
881 
882         switch( nSubRecId )
883         {
884             case BIFF_ID_OBJCMO:
885                 OSL_ENSURE( rStrm.tell() == 4, "BiffDrawingObjectBase::importObjBiff8 - unexpected OBJCMO subrecord" );
886                 if( (rStrm.tell() == 4) && (nSubRecSize >= 6) )
887                 {
888                     sal_uInt16 nObjFlags;
889                     rStrm >> mnObjType >> mnObjId >> nObjFlags;
890                     mbPrintable = getFlag( nObjFlags, BIFF_OBJCMO_PRINTABLE );
891                 }
892             break;
893             case BIFF_ID_OBJMACRO:
894                 readMacroBiff8( rStrm );
895             break;
896             case BIFF_ID_OBJEND:
897                 bLoop = false;
898             break;
899             default:
900                 implReadObjBiff8SubRec( rStrm, nSubRecId, nSubRecSize );
901         }
902 
903         // seek to end of subrecord
904         rStrm.seek( nStrmPos + nSubRecSize );
905     }
906 
907     /*  Call doReadObj8SubRec() with BIFF_ID_OBJEND for further stream
908         processing (e.g. charts), even if the OBJEND subrecord is missing. */
909     implReadObjBiff8SubRec( rStrm, BIFF_ID_OBJEND, 0 );
910 
911     /*  Pictures that Excel reads from BIFF5 and writes to BIFF8 still have the
912         IMGDATA record following the OBJ record (but they use the image data
913         stored in DFF). The IMGDATA record may be continued by several CONTINUE
914         records. But the last CONTINUE record may be in fact an MSODRAWING
915         record that contains the DFF data of the next drawing object! So we
916         have to skip just enough CONTINUE records to look at the next
917         MSODRAWING/CONTINUE record. */
918     if( (rStrm.getNextRecId() == BIFF3_ID_IMGDATA) && rStrm.startNextRecord() )
919     {
920         rStrm.skip( 4 );
921         sal_Int64 nDataSize = rStrm.readuInt32();
922         nDataSize -= rStrm.getRemaining();
923         // skip following CONTINUE records until IMGDATA ends
924         while( (nDataSize > 0) && (rStrm.getNextRecId() == BIFF_ID_CONT) && rStrm.startNextRecord() )
925         {
926             OSL_ENSURE( nDataSize >= rStrm.getRemaining(), "BiffDrawingObjectBase::importObjBiff8 - CONTINUE too long" );
927             nDataSize -= ::std::min( rStrm.getRemaining(), nDataSize );
928         }
929         OSL_ENSURE( nDataSize == 0, "BiffDrawingObjectBase::importObjBiff8 - missing CONTINUE records" );
930         // next record may be MSODRAWING or CONTINUE or anything else
931     }
932 }
933 
934 // ============================================================================
935 
936 BiffPlaceholderObject::BiffPlaceholderObject( const WorksheetHelper& rHelper ) :
937     BiffDrawingObjectBase( rHelper )
938 {
939     setProcessShape( false );
940 }
941 
942 Reference< XShape > BiffPlaceholderObject::implConvertAndInsert( BiffDrawingBase& /*rDrawing*/,
943         const Reference< XShapes >& /*rxShapes*/, const Rectangle& /*rShapeRect*/ ) const
944 {
945     return Reference< XShape >();
946 }
947 
948 // ============================================================================
949 
950 BiffGroupObject::BiffGroupObject( const WorksheetHelper& rHelper ) :
951     BiffDrawingObjectBase( rHelper ),
952     mnFirstUngrouped( BIFF_OBJ_INVALID_ID )
953 {
954 }
955 
956 bool BiffGroupObject::tryInsert( const BiffDrawingObjectRef& rxDrawingObj )
957 {
958     if( rxDrawingObj->getObjId() == mnFirstUngrouped )
959         return false;
960     // insert into own list or into nested group
961     maChildren.insertGrouped( rxDrawingObj );
962     return true;
963 }
964 
965 void BiffGroupObject::implReadObjBiff3( BiffInputStream& rStrm, sal_uInt16 nMacroSize )
966 {
967     rStrm.skip( 4 );
968     rStrm >> mnFirstUngrouped;
969     rStrm.skip( 16 );
970     readMacroBiff3( rStrm, nMacroSize );
971 }
972 
973 void BiffGroupObject::implReadObjBiff4( BiffInputStream& rStrm, sal_uInt16 nMacroSize )
974 {
975     rStrm.skip( 4 );
976     rStrm >> mnFirstUngrouped;
977     rStrm.skip( 16 );
978     readMacroBiff4( rStrm, nMacroSize );
979 }
980 
981 void BiffGroupObject::implReadObjBiff5( BiffInputStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 nMacroSize )
982 {
983     rStrm.skip( 4 );
984     rStrm >> mnFirstUngrouped;
985     rStrm.skip( 16 );
986     readNameBiff5( rStrm, nNameLen );
987     readMacroBiff5( rStrm, nMacroSize );
988 }
989 
990 Reference< XShape > BiffGroupObject::implConvertAndInsert( BiffDrawingBase& rDrawing,
991         const Reference< XShapes >& rxShapes, const Rectangle& rShapeRect ) const
992 {
993     Reference< XShape > xGroupShape;
994     if( !maChildren.empty() ) try
995     {
996         xGroupShape = rDrawing.createAndInsertXShape( CREATE_OUSTRING( "com.sun.star.drawing.GroupShape" ), rxShapes, rShapeRect );
997         Reference< XShapes > xChildShapes( xGroupShape, UNO_QUERY_THROW );
998         maChildren.convertAndInsert( rDrawing, xChildShapes, &rShapeRect );
999         // no child shape has been created - delete the group shape
1000         if( !xChildShapes->hasElements() )
1001         {
1002             rxShapes->remove( xGroupShape );
1003             xGroupShape.clear();
1004         }
1005     }
1006     catch( Exception& )
1007     {
1008     }
1009     return xGroupShape;
1010 }
1011 
1012 // ============================================================================
1013 
1014 BiffLineObject::BiffLineObject( const WorksheetHelper& rHelper ) :
1015     BiffDrawingObjectBase( rHelper ),
1016     mnArrows( 0 ),
1017     mnStartPoint( BIFF_OBJ_LINE_TL )
1018 {
1019     setAreaObj( false );
1020 }
1021 
1022 void BiffLineObject::implReadObjBiff3( BiffInputStream& rStrm, sal_uInt16 nMacroSize )
1023 {
1024     rStrm >> maLineModel >> mnArrows >> mnStartPoint;
1025     rStrm.skip( 1 );
1026     readMacroBiff3( rStrm, nMacroSize );
1027 }
1028 
1029 void BiffLineObject::implReadObjBiff4( BiffInputStream& rStrm, sal_uInt16 nMacroSize )
1030 {
1031     rStrm >> maLineModel >> mnArrows >> mnStartPoint;
1032     rStrm.skip( 1 );
1033     readMacroBiff4( rStrm, nMacroSize );
1034 }
1035 
1036 void BiffLineObject::implReadObjBiff5( BiffInputStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 nMacroSize )
1037 {
1038     rStrm >> maLineModel >> mnArrows >> mnStartPoint;
1039     rStrm.skip( 1 );
1040     readNameBiff5( rStrm, nNameLen );
1041     readMacroBiff5( rStrm, nMacroSize );
1042 }
1043 
1044 Reference< XShape > BiffLineObject::implConvertAndInsert( BiffDrawingBase& rDrawing,
1045         const Reference< XShapes >& rxShapes, const Rectangle& rShapeRect ) const
1046 {
1047     ShapePropertyMap aPropMap( getBaseFilter().getModelObjectHelper() );
1048     convertLineProperties( aPropMap, maLineModel, mnArrows );
1049 
1050     // create the line polygon
1051     PointSequenceSequence aPoints( 1 );
1052     aPoints[ 0 ].realloc( 2 );
1053     Point& rBeg = aPoints[ 0 ][ 0 ];
1054     Point& rEnd = aPoints[ 0 ][ 1 ];
1055     sal_Int32 nL = rShapeRect.X;
1056     sal_Int32 nT = rShapeRect.Y;
1057     sal_Int32 nR = rShapeRect.X + ::std::max< sal_Int32 >( rShapeRect.Width - 1, 0 );
1058     sal_Int32 nB = rShapeRect.Y + ::std::max< sal_Int32 >( rShapeRect.Height - 1, 0 );
1059     switch( mnStartPoint )
1060     {
1061         default:
1062         case BIFF_OBJ_LINE_TL: rBeg.X = nL; rBeg.Y = nT; rEnd.X = nR; rEnd.Y = nB; break;
1063         case BIFF_OBJ_LINE_TR: rBeg.X = nR; rBeg.Y = nT; rEnd.X = nL; rEnd.Y = nB; break;
1064         case BIFF_OBJ_LINE_BR: rBeg.X = nR; rBeg.Y = nB; rEnd.X = nL; rEnd.Y = nT; break;
1065         case BIFF_OBJ_LINE_BL: rBeg.X = nL; rBeg.Y = nB; rEnd.X = nR; rEnd.Y = nT; break;
1066     }
1067     aPropMap.setProperty( PROP_PolyPolygon, aPoints );
1068     aPropMap.setProperty( PROP_PolygonKind, PolygonKind_LINE );
1069 
1070     // create the shape
1071     Reference< XShape > xShape = rDrawing.createAndInsertXShape( CREATE_OUSTRING( "com.sun.star.drawing.LineShape" ), rxShapes, rShapeRect );
1072     PropertySet( xShape ).setProperties( aPropMap );
1073     return xShape;
1074 }
1075 
1076 // ============================================================================
1077 
1078 BiffRectObject::BiffRectObject( const WorksheetHelper& rHelper ) :
1079     BiffDrawingObjectBase( rHelper ),
1080     mnFrameFlags( 0 )
1081 {
1082     setAreaObj( true );
1083 }
1084 
1085 void BiffRectObject::readFrameData( BiffInputStream& rStrm )
1086 {
1087     rStrm >> maFillModel >> maLineModel >> mnFrameFlags;
1088 }
1089 
1090 void BiffRectObject::convertRectProperties( ShapePropertyMap& rPropMap ) const
1091 {
1092     convertLineProperties( rPropMap, maLineModel );
1093     convertFillProperties( rPropMap, maFillModel );
1094     convertFrameProperties( rPropMap, mnFrameFlags );
1095 }
1096 
1097 void BiffRectObject::implReadObjBiff3( BiffInputStream& rStrm, sal_uInt16 nMacroSize )
1098 {
1099     readFrameData( rStrm );
1100     readMacroBiff3( rStrm, nMacroSize );
1101 }
1102 
1103 void BiffRectObject::implReadObjBiff4( BiffInputStream& rStrm, sal_uInt16 nMacroSize )
1104 {
1105     readFrameData( rStrm );
1106     readMacroBiff4( rStrm, nMacroSize );
1107 }
1108 
1109 void BiffRectObject::implReadObjBiff5( BiffInputStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 nMacroSize )
1110 {
1111     readFrameData( rStrm );
1112     readNameBiff5( rStrm, nNameLen );
1113     readMacroBiff5( rStrm, nMacroSize );
1114 }
1115 
1116 Reference< XShape > BiffRectObject::implConvertAndInsert( BiffDrawingBase& rDrawing,
1117         const Reference< XShapes >& rxShapes, const Rectangle& rShapeRect ) const
1118 {
1119     ShapePropertyMap aPropMap( getBaseFilter().getModelObjectHelper() );
1120     convertRectProperties( aPropMap );
1121 
1122     Reference< XShape > xShape = rDrawing.createAndInsertXShape( CREATE_OUSTRING( "com.sun.star.drawing.RectangleShape" ), rxShapes, rShapeRect );
1123     PropertySet( xShape ).setProperties( aPropMap );
1124     return xShape;
1125 }
1126 
1127 // ============================================================================
1128 
1129 BiffOvalObject::BiffOvalObject( const WorksheetHelper& rHelper ) :
1130     BiffRectObject( rHelper )
1131 {
1132 }
1133 
1134 Reference< XShape > BiffOvalObject::implConvertAndInsert( BiffDrawingBase& rDrawing,
1135         const Reference< XShapes >& rxShapes, const Rectangle& rShapeRect ) const
1136 {
1137     ShapePropertyMap aPropMap( getBaseFilter().getModelObjectHelper() );
1138     convertRectProperties( aPropMap );
1139 
1140     Reference< XShape > xShape = rDrawing.createAndInsertXShape( CREATE_OUSTRING( "com.sun.star.drawing.EllipseShape" ), rxShapes, rShapeRect );
1141     PropertySet( xShape ).setProperties( aPropMap );
1142     return xShape;
1143 }
1144 
1145 // ============================================================================
1146 
1147 BiffArcObject::BiffArcObject( const WorksheetHelper& rHelper ) :
1148     BiffDrawingObjectBase( rHelper ),
1149     mnQuadrant( BIFF_OBJ_ARC_TR )
1150 {
1151     setAreaObj( false );    // arc may be 2-dimensional
1152 }
1153 
1154 void BiffArcObject::implReadObjBiff3( BiffInputStream& rStrm, sal_uInt16 nMacroSize )
1155 {
1156     rStrm >> maFillModel >> maLineModel >> mnQuadrant;
1157     rStrm.skip( 1 );
1158     readMacroBiff3( rStrm, nMacroSize );
1159 }
1160 
1161 void BiffArcObject::implReadObjBiff4( BiffInputStream& rStrm, sal_uInt16 nMacroSize )
1162 {
1163     rStrm >> maFillModel >> maLineModel >> mnQuadrant;
1164     rStrm.skip( 1 );
1165     readMacroBiff4( rStrm, nMacroSize );
1166 }
1167 
1168 void BiffArcObject::implReadObjBiff5( BiffInputStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 nMacroSize )
1169 {
1170     rStrm >> maFillModel >> maLineModel >> mnQuadrant;
1171     rStrm.skip( 1 );
1172     readNameBiff5( rStrm, nNameLen );
1173     readMacroBiff5( rStrm, nMacroSize );
1174 }
1175 
1176 Reference< XShape > BiffArcObject::implConvertAndInsert( BiffDrawingBase& rDrawing,
1177         const Reference< XShapes >& rxShapes, const Rectangle& rShapeRect ) const
1178 {
1179     ShapePropertyMap aPropMap( getBaseFilter().getModelObjectHelper() );
1180     convertLineProperties( aPropMap, maLineModel );
1181     convertFillProperties( aPropMap, maFillModel );
1182 
1183     /*  Simulate arc objects with ellipse sections. While the original arc
1184         object uses the entire object rectangle, only one quarter of the
1185         ellipse shape will be visible. Thus, the size of the ellipse shape
1186         needs to be extended and its position adjusted according to the visible
1187         quadrant. */
1188     Rectangle aNewRect( rShapeRect.X, rShapeRect.Y, rShapeRect.Width * 2, rShapeRect.Height * 2 );
1189     long nStartAngle = 0;
1190     switch( mnQuadrant )
1191     {
1192         default:
1193         case BIFF_OBJ_ARC_TR: nStartAngle =     0; aNewRect.X -= rShapeRect.Width;                                  break;
1194         case BIFF_OBJ_ARC_TL: nStartAngle =  9000;                                                                  break;
1195         case BIFF_OBJ_ARC_BL: nStartAngle = 18000;                                 aNewRect.Y -= rShapeRect.Height; break;
1196         case BIFF_OBJ_ARC_BR: nStartAngle = 27000; aNewRect.X -= rShapeRect.Width; aNewRect.Y -= rShapeRect.Height; break;
1197     }
1198     long nEndAngle = (nStartAngle + 9000) % 36000;
1199     aPropMap.setProperty( PROP_CircleKind, maFillModel.isFilled() ? CircleKind_SECTION : CircleKind_ARC );
1200     aPropMap.setProperty( PROP_CircleStartAngle, nStartAngle );
1201     aPropMap.setProperty( PROP_CircleEndAngle, nEndAngle );
1202 
1203     // create the shape
1204     Reference< XShape > xShape = rDrawing.createAndInsertXShape( CREATE_OUSTRING( "com.sun.star.drawing.EllipseShape" ), rxShapes, aNewRect );
1205     PropertySet( xShape ).setProperties( aPropMap );
1206     return xShape;
1207 }
1208 
1209 // ============================================================================
1210 
1211 BiffPolygonObject::BiffPolygonObject( const WorksheetHelper& rHelper ) :
1212     BiffRectObject( rHelper ),
1213     mnPolyFlags( 0 ),
1214     mnPointCount( 0 )
1215 {
1216     setAreaObj( false );    // polygon may be 2-dimensional
1217 }
1218 
1219 void BiffPolygonObject::implReadObjBiff4( BiffInputStream& rStrm, sal_uInt16 nMacroSize )
1220 {
1221     readFrameData( rStrm );
1222     rStrm >> mnPolyFlags;
1223     rStrm.skip( 10 );
1224     rStrm >> mnPointCount;
1225     rStrm.skip( 8 );
1226     readMacroBiff4( rStrm, nMacroSize );
1227     importCoordList( rStrm );
1228 }
1229 
1230 void BiffPolygonObject::implReadObjBiff5( BiffInputStream& rStrm, sal_uInt16 nNameLen, sal_uInt16 nMacroSize )
1231 {
1232     readFrameData( rStrm );
1233     rStrm >> mnPolyFlags;
1234     rStrm.skip( 10 );
1235     rStrm >> mnPointCount;
1236     rStrm.skip( 8 );
1237     readNameBiff5( rStrm, nNameLen );
1238     readMacroBiff5( rStrm, nMacroSize );
1239     importCoordList( rStrm );
1240 }
1241 
1242 namespace {
1243 
1244 Point lclGetPolyPoint( const Rectangle& rAnchorRect, const Point& rPoint )
1245 {
1246     // polygon coordinates are given in 1/16384 of shape size
1247     return Point(
1248         rAnchorRect.X + static_cast< sal_Int32 >( rAnchorRect.Width * getLimitedValue< double >( static_cast< double >( rPoint.X ) / 16384.0, 0.0, 1.0 ) + 0.5 ),
1249         rAnchorRect.Y + static_cast< sal_Int32 >( rAnchorRect.Height * getLimitedValue< double >( static_cast< double >( rPoint.Y ) / 16384.0, 0.0, 1.0 ) + 0.5 ) );
1250 }
1251 
1252 } // namespace
1253 
1254 Reference< XShape > BiffPolygonObject::implConvertAndInsert( BiffDrawingBase& rDrawing,
1255         const Reference< XShapes >& rxShapes, const Rectangle& rShapeRect ) const
1256 {
1257     Reference< XShape > xShape;
1258     if( maCoords.size() >= 2 )
1259     {
1260         ShapePropertyMap aPropMap( getBaseFilter().getModelObjectHelper() );
1261         convertRectProperties( aPropMap );
1262 
1263         // create the polygon
1264         PointVector aPolygon;
1265         for( PointVector::const_iterator aIt = maCoords.begin(), aEnd = maCoords.end(); aIt != aEnd; ++aIt )
1266             aPolygon.push_back( lclGetPolyPoint( rShapeRect, *aIt ) );
1267         // close polygon if specified
1268         if( getFlag( mnPolyFlags, BIFF_OBJ_POLY_CLOSED ) && ((maCoords.front().X != maCoords.back().X) || (maCoords.front().Y != maCoords.back().Y)) )
1269             aPolygon.push_back( aPolygon.front() );
1270         PointSequenceSequence aPoints( 1 );
1271         aPoints[ 0 ] = ContainerHelper::vectorToSequence( aPolygon );
1272         aPropMap.setProperty( PROP_PolyPolygon, aPoints );
1273 
1274         // create the shape
1275         OUString aService = maFillModel.isFilled() ?
1276             CREATE_OUSTRING( "com.sun.star.drawing.PolyPolygonShape" ) :
1277             CREATE_OUSTRING( "com.sun.star.drawing.PolyLineShape" );
1278         xShape = rDrawing.createAndInsertXShape( aService, rxShapes, rShapeRect );
1279         PropertySet( xShape ).setProperties( aPropMap );
1280     }
1281     return xShape;
1282 }
1283 
1284 void BiffPolygonObject::importCoordList( BiffInputStream& rStrm )
1285 {
1286     if( (rStrm.getNextRecId() == BIFF_ID_COORDLIST) && rStrm.startNextRecord() )
1287     {
1288         OSL_ENSURE( rStrm.getRemaining() / 4 == mnPointCount, "BiffPolygonObject::importCoordList - wrong polygon point count" );
1289         while( rStrm.getRemaining() >= 4 )
1290         {
1291             sal_uInt16 nX, nY;
1292             rStrm >> nX >> nY;
1293             maCoords.push_back( Point( nX, nY ) );
1294         }
1295     }
1296 }
1297 
1298 // ============================================================================
1299 // BIFF drawing page
1300 // ============================================================================
1301 
1302 BiffDrawingBase::BiffDrawingBase( const WorksheetHelper& rHelper, const Reference< XDrawPage >& rxDrawPage ) :
1303     WorksheetHelper( rHelper ),
1304     mxDrawPage( rxDrawPage )
1305 {
1306 }
1307 
1308 void BiffDrawingBase::importObj( BiffInputStream& rStrm )
1309 {
1310     BiffDrawingObjectRef xDrawingObj;
1311 
1312 #if 0
1313     /*  #i61786# In BIFF8 streams, OBJ records may occur without MSODRAWING
1314         records. In this case, the OBJ records are in BIFF5 format. Do a sanity
1315         check here that there is no DFF data loaded before. */
1316     DBG_ASSERT( maDffStrm.Tell() == 0, "BiffDrawingBase::importObj - unexpected DFF stream data, OBJ will be ignored" );
1317     if( maDffStrm.Tell() == 0 ) switch( GetBiff() )
1318 #else
1319     switch( getBiff() )
1320 #endif
1321     {
1322         case BIFF3:
1323             xDrawingObj = BiffDrawingObjectBase::importObjBiff3( *this, rStrm );
1324         break;
1325         case BIFF4:
1326             xDrawingObj = BiffDrawingObjectBase::importObjBiff4( *this, rStrm );
1327         break;
1328         case BIFF5:
1329 // TODO: add BIFF8 when DFF is supported
1330 //        case BIFF8:
1331             xDrawingObj = BiffDrawingObjectBase::importObjBiff5( *this, rStrm );
1332         break;
1333         default:;
1334     }
1335 
1336     if( xDrawingObj.get() )
1337     {
1338         // insert into maRawObjs or into the last open group object
1339         maRawObjs.insertGrouped( xDrawingObj );
1340         // to be able to find objects by ID
1341         maObjMapId[ xDrawingObj->getObjId() ] = xDrawingObj;
1342     }
1343 }
1344 
1345 void BiffDrawingBase::setSkipObj( sal_uInt16 nObjId )
1346 {
1347     /*  Store identifiers of objects to be skipped in a separate list (the OBJ
1348         record may not be read yet). In the finalization phase, all objects
1349         registered here will be skipped. */
1350     maSkipObjs.push_back( nObjId );
1351 }
1352 
1353 void BiffDrawingBase::finalizeImport()
1354 {
1355     Reference< XShapes > xShapes( mxDrawPage, UNO_QUERY );
1356     OSL_ENSURE( xShapes.is(), "BiffDrawingBase::finalizeImport - no shapes container" );
1357     if( !xShapes.is() )
1358         return;
1359 
1360     // process list of objects to be skipped
1361     for( BiffObjIdVector::const_iterator aIt = maSkipObjs.begin(), aEnd = maSkipObjs.end(); aIt != aEnd; ++aIt )
1362         if( BiffDrawingObjectBase* pDrawingObj = maObjMapId.get( *aIt ).get() )
1363             pDrawingObj->setProcessShape( false );
1364 
1365     // process drawing objects without DFF data
1366     maRawObjs.convertAndInsert( *this, xShapes );
1367 }
1368 
1369 Reference< XShape > BiffDrawingBase::createAndInsertXShape( const OUString& rService,
1370         const Reference< XShapes >& rxShapes, const Rectangle& rShapeRect ) const
1371 {
1372     OSL_ENSURE( rService.getLength() > 0, "BiffDrawingBase::createAndInsertXShape - missing UNO shape service name" );
1373     OSL_ENSURE( rxShapes.is(), "BiffDrawingBase::createAndInsertXShape - missing XShapes container" );
1374     Reference< XShape > xShape;
1375     if( (rService.getLength() > 0) && rxShapes.is() ) try
1376     {
1377         xShape.set( getBaseFilter().getModelFactory()->createInstance( rService ), UNO_QUERY_THROW );
1378         // insert shape into passed shape collection (maybe drawpage or group shape)
1379         rxShapes->add( xShape );
1380         xShape->setPosition( Point( rShapeRect.X, rShapeRect.Y ) );
1381         xShape->setSize( Size( rShapeRect.Width, rShapeRect.Height ) );
1382     }
1383     catch( Exception& )
1384     {
1385     }
1386     OSL_ENSURE( xShape.is(), "BiffDrawingBase::createAndInsertXShape - cannot instanciate shape object" );
1387     return xShape;
1388 }
1389 
1390 // protected ------------------------------------------------------------------
1391 
1392 void BiffDrawingBase::appendRawObject( const BiffDrawingObjectRef& rxDrawingObj )
1393 {
1394     OSL_ENSURE( rxDrawingObj.get(), "BiffDrawingBase::appendRawObject - unexpected empty object reference" );
1395     maRawObjs.append( rxDrawingObj );
1396 }
1397 
1398 // ============================================================================
1399 
1400 BiffSheetDrawing::BiffSheetDrawing( const WorksheetHelper& rHelper ) :
1401     BiffDrawingBase( rHelper, rHelper.getDrawPage() )
1402 {
1403 }
1404 
1405 void BiffSheetDrawing::notifyShapeInserted( const Reference< XShape >& /*rxShape*/, const Rectangle& rShapeRect )
1406 {
1407     // collect all shape positions in the WorksheetHelper base class
1408     extendShapeBoundingBox( rShapeRect );
1409 }
1410 
1411 // ============================================================================
1412 
1413 } // namespace xls
1414 } // namespace oox
1415