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 #ifndef INCLUDED_HWPFILTER_SOURCE_DRAWING_H
21 #define INCLUDED_HWPFILTER_SOURCE_DRAWING_H
22 
23 #include "precompile.h"
24 
25 #include <list>
26 #include <math.h>
27 
28 #include <osl/diagnose.h>
29 
30 #include <comphelper/newarray.hxx>
31 
32 #include "hwplib.h"
33 #include "hwpfile.h"
34 #include "hiodev.h"
35 #include "hbox.h"
36 #include "drawdef.h"
37 
38 enum
39 {
40     OBJFUNC_LOAD,
41     OBJFUNC_FREE,
42     OBJFUNC_DISPLAY,
43     OBJFUNC_NITEM
44 };
45 
46 enum
47 {
48     BEGIN_GRADATION = 0, LINEAR, RADIAL, CONICAL, SQUARE,
49     END_GRADATION, BITMAP_PATTERN
50 };
51 
52 #define OBJRET_FILE_OK           0
53 #define OBJRET_FILE_ERROR       (-1)
54 #define OBJRET_FILE_NO_PRIVATE_BLOCK    (-2)
55 #define OBJRET_FILE_NO_PRIVATE_BLOCK_2  (-3)
56 
57 typedef int (*HWPDOFuncType) (int, HWPDrawingObject *, int, void *, int);
58 
59 #define HWPDOFunc(hdo, cmd, argp, argv) \
60     (HWPDOFuncTbl[(hdo)->type]((hdo)->type, (hdo), (cmd), (argp), (argv)))
61 
62 static int HWPDOLineFunc(int, HWPDrawingObject *, int, void *, int);
63 static int HWPDORectFunc(int, HWPDrawingObject *, int, void *, int);
64 static int HWPDOEllipseFunc(int, HWPDrawingObject *, int, void *, int);
65 static int HWPDOArcFunc(int, HWPDrawingObject *, int, void *, int);
66 static int HWPDOFreeFormFunc(int, HWPDrawingObject *, int, void *, int);
67 static int HWPDOTextBoxFunc(int, HWPDrawingObject *, int, void *, int);
68 static int HWPDOEllipse2Func(int, HWPDrawingObject *, int, void *, int);
69 static int HWPDOArc2Func(int, HWPDrawingObject *, int, void *, int);
70 static int HWPDOContainerFunc(int, HWPDrawingObject *, int, void *, int);
71 static HWPPara *LoadParaList();
72 
73 HWPDOFuncType HWPDOFuncTbl[] =
74 {
75     HWPDOContainerFunc,
76     HWPDOLineFunc,
77     HWPDORectFunc,
78     HWPDOEllipseFunc,
79     HWPDOArcFunc,
80     HWPDOFreeFormFunc,
81     HWPDOTextBoxFunc,
82     HWPDOFreeFormFunc,
83     HWPDOEllipse2Func,
84     HWPDOArc2Func,
85     HWPDOFreeFormFunc,
86 };
87 
88 static HIODev *hmem = nullptr;
89 
90 static int count = 0;
91 
SetHdoParallRgn(HWPDrawingObject * hdo,int width,int height)92 static void SetHdoParallRgn(HWPDrawingObject * hdo, int width, int height)
93 {
94     hdo->property.parall.pt[0].x = 0;
95     hdo->property.parall.pt[0].y = 0;
96     hdo->property.parall.pt[1].x = width;
97     hdo->property.parall.pt[1].y = 0;
98     hdo->property.parall.pt[2].x = width;
99     hdo->property.parall.pt[2].y = height;
100 }
101 
SkipPrivateBlock(int type)102 static bool SkipPrivateBlock(int type)
103 {
104     int n;
105 
106     if (type == OBJRET_FILE_NO_PRIVATE_BLOCK)
107     {
108         if (!hmem->read4b(n))
109             return false;
110         if (hmem->state() || hmem->skipBlock(n) != static_cast<size_t>(n))
111             return false;
112     }
113     if (!hmem->read4b(n))
114         return false;
115     if (hmem->state())
116         return false;
117     return hmem->skipBlock(n) == static_cast<size_t>(n);
118 }
119 
120 static int SizeExpected;
121 static int SizeRead;
122 
ReadSizeField(int size)123 static int ReadSizeField(int size)
124 {
125     SizeExpected = size;
126     if (!hmem->read4b(SizeRead))
127         return -1;
128     if (hmem->state())
129         return -1;
130     return SizeRead;
131 }
132 
SkipUnusedField(void)133 static bool SkipUnusedField(void)
134 {
135     return (SizeExpected >= SizeRead) &&
136         hmem->skipBlock(SizeRead - SizeExpected) != 0;
137 }
138 
139 
140 #define HDOFILE_HEADER_SIZE (2*4+16)              // 16=sizeof(ZZRect)
141 #define HDOFILE_COMMON_SIZE (7*4+16+44)
142 
143 #define HDOFILE_HAS_NEXT    0x01
144 #define HDOFILE_HAS_CHILD   0x02
145 
LoadCommonHeader(HWPDrawingObject * hdo,unsigned short * link_info)146 static bool LoadCommonHeader(HWPDrawingObject * hdo, unsigned short * link_info)
147 {
148     uint size, common_size;
149 
150     if (!hmem)
151         return false;
152     if (!hmem->read4b(size))
153         return false;
154     if (hmem->state())
155         return false;
156     if (size < HDOFILE_COMMON_SIZE)
157         return false;
158 
159     common_size = HDOFILE_COMMON_SIZE;
160     unsigned short tmp16;
161     if (!hmem->read2b(tmp16))
162         return false;
163     hdo->type = tmp16;
164     if (!hmem->read2b(tmp16))
165         return false;
166     *link_info = tmp16;
167     if (!hmem->read4b(hdo->offset.x))
168         return false;
169     if (!hmem->read4b(hdo->offset.y))
170         return false;
171     if (!hmem->read4b(hdo->extent.w))
172         return false;
173     if (!hmem->read4b(hdo->extent.h))
174         return false;
175     if (!hmem->read4b(hdo->offset2.x))
176         return false;
177     if (!hmem->read4b(hdo->offset2.y))
178         return false;
179 
180     if (hmem->state())
181         return false;
182 
183     if (!hmem->read4b(hdo->vrect.x))
184         return false;
185     if (!hmem->read4b(hdo->vrect.y))
186         return false;
187     if (!hmem->read4b(hdo->vrect.w))
188         return false;
189     if (!hmem->read4b(hdo->vrect.h))
190         return false;
191 
192 // read bare property 44 bytes
193     if (!hmem->read4b(hdo->property.line_pstyle))
194         return false;
195     if (!hmem->read4b(hdo->property.line_hstyle))
196         return false;
197     if (!hmem->read4b(hdo->property.line_tstyle))
198         return false;
199     if (!hmem->read4b(hdo->property.line_color))
200         return false;
201     unsigned int tmp32;
202     if (!hmem->read4b(tmp32))
203         return false;
204     hdo->property.line_width = static_cast<hunit>(tmp32);
205     if (!hmem->read4b(hdo->property.fill_color))
206         return false;
207     if (!hmem->read4b(hdo->property.pattern_type))
208         return false;
209     if (!hmem->read4b(hdo->property.pattern_color))
210         return false;
211     if (!hmem->read4b(tmp32))
212         return false;
213     hdo->property.hmargin = static_cast<hunit>(tmp32);
214     if (!hmem->read4b(tmp32))
215         return false;
216     hdo->property.vmargin = static_cast<hunit>(tmp32);
217     if (!hmem->read4b(hdo->property.flag))
218         return false;
219 // read rotation property 32 bytes
220     if ((size >= common_size + 32)
221         && (hdo->property.flag & HWPDO_FLAG_ROTATION))
222     {
223         if (!hmem->read4b(hdo->property.rot_originx))
224             return false;
225         if (!hmem->read4b(hdo->property.rot_originy))
226             return false;
227         for (int ii = 0; ii < 3; ++ii)
228         {
229             if (!hmem->read4b(hdo->property.parall.pt[ii].x))
230                 return false;
231             if (!hmem->read4b(hdo->property.parall.pt[ii].y))
232                 return false;
233         }
234         common_size += 32;
235     }
236     else
237         SetHdoParallRgn(hdo, hdo->extent.w, hdo->extent.h);
238 
239 // read gradient property 28 bytes
240     if ((size >= common_size + 28) &&
241         (hdo->property.flag & HWPDO_FLAG_GRADATION))
242     {
243         if (!hmem->read4b(hdo->property.fromcolor))
244             return false;
245         if (!hmem->read4b(hdo->property.tocolor))
246             return false;
247         if (!hmem->read4b(hdo->property.gstyle))
248             return false;
249         if (!hmem->read4b(hdo->property.angle))
250             return false;
251         if (!hmem->read4b(hdo->property.center_x))
252             return false;
253         if (!hmem->read4b(hdo->property.center_y))
254             return false;
255         if (!hmem->read4b(hdo->property.nstep))
256             return false;
257         common_size += 28;
258     }
259 
260 // read bitmap property 278 bytes
261     if ((size >= common_size + 278) && \
262         (hdo->property.flag & HWPDO_FLAG_BITMAP))
263     {
264         if (!hmem->read4b(hdo->property.offset1.x))
265             return false;
266         if (!hmem->read4b(hdo->property.offset1.y))
267             return false;
268         if (!hmem->read4b(hdo->property.offset2.x))
269             return false;
270         if (!hmem->read4b(hdo->property.offset2.y))
271             return false;
272         if (!hmem->readBlock(hdo->property.szPatternFile, 261))
273             return false;
274         if (!hmem->read1b(hdo->property.pictype))
275             return false;
276         common_size += 278;
277     }
278     if( ( size >= common_size + 3 ) && ( hdo->property.flag & HWPDO_FLAG_WATERMARK ) )
279      //if( ( size >= common_size ) && ( hdo->property.flag >> 20 & 0x01 ) )
280     {
281         if (size - common_size >= 5)
282             hmem->skipBlock(2);
283         unsigned char tmp8;
284         if (!hmem->read1b(tmp8))
285             return false;
286         hdo->property.luminance = tmp8;
287         if (!hmem->read1b(tmp8))
288             return false;
289         hdo->property.contrast = tmp8;
290         if (!hmem->read1b(tmp8))
291             return false;
292         hdo->property.greyscale = tmp8;
293 
294         common_size += 5;
295     }
296     else
297     {
298         hdo->property.luminance = 0;
299         hdo->property.contrast = 0;
300         hdo->property.greyscale = 0;
301     }
302     hdo->property.pPara = nullptr;
303 
304     if( ( size > common_size ) && (hdo->property.flag & HWPDO_FLAG_AS_TEXTBOX) )
305     {
306         hmem->skipBlock(8);
307         hdo->property.pPara = LoadParaList();
308         if( hdo->property.pPara )
309             return true;
310         else
311             return false;
312      }
313 
314     if (size <= common_size)
315           return true;
316     return hmem->skipBlock(size - common_size ) != 0;
317 }
318 
LoadDrawingObject(void)319 static std::unique_ptr<HWPDrawingObject> LoadDrawingObject(void)
320 {
321     HWPDrawingObject *prev = nullptr;
322     std::unique_ptr<HWPDrawingObject> hdo, head;
323 
324     unsigned short link_info;
325 
326     do
327     {
328         hdo.reset(new HWPDrawingObject);
329         if (!LoadCommonHeader(hdo.get(), &link_info))
330         {
331             goto error;
332         }
333         if (hdo->type < 0 || hdo->type >= HWPDO_NITEMS)
334         {
335             hdo->type = HWPDO_RECT;
336             if (!SkipPrivateBlock(OBJRET_FILE_NO_PRIVATE_BLOCK))
337             {
338                 goto error;
339             }
340         }
341         else
342         {
343             switch (int res = HWPDOFunc(hdo.get(), OBJFUNC_LOAD, nullptr, 0))
344             {
345                 case OBJRET_FILE_ERROR:
346                     goto error;
347                 case OBJRET_FILE_OK:
348                     break;
349                 case OBJRET_FILE_NO_PRIVATE_BLOCK:
350                 case OBJRET_FILE_NO_PRIVATE_BLOCK_2:
351                     if (!SkipPrivateBlock(res))
352                         goto error;
353                     break;
354             }
355         }
356         if (link_info & HDOFILE_HAS_CHILD)
357         {
358             hdo->child = LoadDrawingObject();
359             if (hdo->child == nullptr)
360             {
361                 goto error;
362             }
363         }
364         if (prev == nullptr)
365         {
366             head = std::move(hdo);
367             prev = head.get();
368         }
369         else
370         {
371             prev->next = std::move(hdo);
372             prev = prev->next.get();
373         }
374     }
375     while (link_info & HDOFILE_HAS_NEXT);
376 
377     return head;
378 
379 error:
380 // drawing object can be list.
381 // hdo = current item, head = list;
382 
383     if (hdo->type < 0 || hdo->type >= HWPDO_NITEMS)
384     {
385         hdo->type = HWPDO_RECT;
386     }
387     HWPDOFunc(hdo.get(), OBJFUNC_FREE, nullptr, 0);
388     hdo.reset();
389 
390     if( prev )
391     {
392         prev->next = nullptr;
393         return head;
394     }
395     else
396         return nullptr;
397 }
398 
399 
LoadDrawingObjectBlock(Picture * pic)400 static bool LoadDrawingObjectBlock(Picture * pic)
401 {
402     int size;
403     if (!hmem->read4b(size))
404         return false;
405 
406     if (hmem->state() || size < HDOFILE_HEADER_SIZE)
407         return false;
408 
409     if (!hmem->read4b(pic->picinfo.picdraw.zorder))
410         return false;
411     if (!hmem->read4b(pic->picinfo.picdraw.mbrcnt))
412         return false;
413     if (!hmem->read4b(pic->picinfo.picdraw.vrect.x))
414         return false;
415     if (!hmem->read4b(pic->picinfo.picdraw.vrect.y))
416         return false;
417     if (!hmem->read4b(pic->picinfo.picdraw.vrect.w))
418         return false;
419     if (!hmem->read4b(pic->picinfo.picdraw.vrect.h))
420         return false;
421 
422     if (size > HDOFILE_HEADER_SIZE &&
423         !hmem->skipBlock(size - HDOFILE_HEADER_SIZE))
424         return false;
425 
426     pic->picinfo.picdraw.hdo = LoadDrawingObject().release();
427     if (pic->picinfo.picdraw.hdo == nullptr)
428         return false;
429     return true;
430 }
431 
432 // object manipulation function
433 static int
HWPDODefaultFunc(int cmd)434 HWPDODefaultFunc(int cmd)
435 {
436     if (cmd == OBJFUNC_LOAD)
437         return OBJRET_FILE_NO_PRIVATE_BLOCK;
438     return OBJRET_FILE_OK;
439 }
440 
441 static int
HWPDOLineFunc(int,HWPDrawingObject * hdo,int cmd,void *,int)442 HWPDOLineFunc(int /*type*/, HWPDrawingObject * hdo, int cmd, void * /*argp*/, int /*argv*/)
443 {
444     int ret = OBJRET_FILE_OK;
445     switch (cmd)
446     {
447         case OBJFUNC_LOAD:
448             if (ReadSizeField(4) < 4)
449                 return OBJRET_FILE_ERROR;
450             if (!hmem->read4b(hdo->u.line_arc.flip))
451                 return OBJRET_FILE_ERROR;
452             if (hmem->state())
453                 return OBJRET_FILE_ERROR;
454             if (!SkipUnusedField())
455                 return OBJRET_FILE_ERROR;
456             ret = OBJRET_FILE_NO_PRIVATE_BLOCK_2;
457             break;
458         default:
459             ret = HWPDODefaultFunc(cmd);
460             break;
461     }
462     return ret;
463 }
464 
465 
466 // rectangle
467 
468 static int
HWPDORectFunc(int,HWPDrawingObject *,int cmd,void *,int)469 HWPDORectFunc(int /*type*/, HWPDrawingObject * /*hdo*/, int cmd, void * /*argp*/, int /*argv*/)
470 {
471     return HWPDODefaultFunc(cmd);
472 }
473 
474 
475 // ellipse
476 
477 static int
HWPDOEllipseFunc(int,HWPDrawingObject *,int cmd,void *,int)478 HWPDOEllipseFunc(int /*type*/, HWPDrawingObject * /*hdo*/,
479 int cmd, void * /*argp*/, int /*argv*/)
480 {
481     return HWPDODefaultFunc(cmd);
482 }
483 
484 #define WTMM(x)     ((double)(x) / 1800. * 25.4)
485 static int
HWPDOEllipse2Func(int,HWPDrawingObject * hdo,int cmd,void *,int)486 HWPDOEllipse2Func(int /*type*/, HWPDrawingObject * hdo,
487 int cmd, void * /*argp*/, int /*argv*/)
488 {
489     switch (cmd)
490     {
491         case OBJFUNC_LOAD:
492             if (ReadSizeField(16) < 16)
493                 return OBJRET_FILE_ERROR;
494             if (!hmem->read4b(hdo->u.arc.radial[0].x))
495                 return OBJRET_FILE_ERROR;
496             if (!hmem->read4b(hdo->u.arc.radial[0].y))
497                 return OBJRET_FILE_ERROR;
498             if (!hmem->read4b(hdo->u.arc.radial[1].x))
499                 return OBJRET_FILE_ERROR;
500             if (!hmem->read4b(hdo->u.arc.radial[1].y))
501                 return OBJRET_FILE_ERROR;
502             if (ReadSizeField(0) < 0)
503                 return OBJRET_FILE_ERROR;
504             break;
505         default:
506             return HWPDODefaultFunc(cmd);
507     }
508     return OBJRET_FILE_OK;
509 }
510 
511 
512 // arc
513 
514 static int
HWPDOArcFunc(int,HWPDrawingObject * hdo,int cmd,void *,int)515 HWPDOArcFunc(int /*type*/, HWPDrawingObject * hdo, int cmd, void * /*argp*/, int /*argv*/)
516 {
517     switch (cmd)
518     {
519         case OBJFUNC_LOAD:
520             if (ReadSizeField(4) < 4)
521                 return OBJRET_FILE_ERROR;
522             if (!hmem->read4b(hdo->u.line_arc.flip))
523                 return OBJRET_FILE_ERROR;
524             if (hmem->state())
525                 return OBJRET_FILE_ERROR;
526             if (!SkipUnusedField())
527                 return OBJRET_FILE_ERROR;
528             break;
529         default:
530             return HWPDODefaultFunc(cmd);
531     }
532     return OBJRET_FILE_OK;
533 }
534 
535 
536 static int
HWPDOArc2Func(int,HWPDrawingObject *,int cmd,void *,int)537 HWPDOArc2Func(int /*type*/, HWPDrawingObject * /*hdo*/, int cmd, void * /*argp*/, int /*argv*/)
538 {
539     int ret = OBJRET_FILE_OK;
540     switch (cmd)
541     {
542         case OBJFUNC_LOAD:
543             ret = OBJRET_FILE_NO_PRIVATE_BLOCK;
544             break;
545         default:
546             ret = HWPDODefaultFunc(cmd);
547             break;
548     }
549     return ret;
550 }
551 
552 
553 static int
HWPDOFreeFormFunc(int,HWPDrawingObject * hdo,int cmd,void *,int)554 HWPDOFreeFormFunc(int /*type*/, HWPDrawingObject * hdo,
555 int cmd, void * /*argp*/, int /*argv*/)
556 {
557     switch (cmd)
558     {
559         case OBJFUNC_LOAD:
560         {
561             hdo->u.freeform.pt = nullptr;
562             if (ReadSizeField(4) < 4)
563                 return OBJRET_FILE_ERROR;
564             if (!hmem->read4b(hdo->u.freeform.npt))
565                 return OBJRET_FILE_ERROR;
566             if (hmem->state())
567                 return OBJRET_FILE_ERROR;
568             if (!SkipUnusedField())
569                 return OBJRET_FILE_ERROR;
570 
571             int size = hdo->u.freeform.npt * sizeof(ZZPoint);
572 
573             if (ReadSizeField(size) < size)
574                 return OBJRET_FILE_ERROR;
575             if (hdo->u.freeform.npt)
576             {
577                 hdo->u.freeform.pt =
578                     ::comphelper::newArray_null<ZZPoint>(hdo->u.freeform.npt);
579                 if (hdo->u.freeform.pt == nullptr)
580                 {
581                     hdo->u.freeform.npt = 0;
582                     return OBJRET_FILE_ERROR;
583                 }
584                 for (int ii = 0; ii < hdo->u.freeform.npt; ++ii)
585                 {
586                     bool bFailure = false;
587                     if (!hmem->read4b(hdo->u.freeform.pt[ii].x))
588                         bFailure = true;
589                     if (!hmem->read4b(hdo->u.freeform.pt[ii].y))
590                         bFailure = true;
591                     if (hmem->state())
592                         bFailure = true;
593                     if (bFailure)
594                     {
595                         delete[]hdo->u.freeform.pt;
596                         hdo->u.freeform.npt = 0;
597                         return OBJRET_FILE_ERROR;
598                     }
599                 }
600             }
601             if (!SkipUnusedField())
602                 return OBJRET_FILE_ERROR;
603             return OBJRET_FILE_OK;
604         }
605         case OBJFUNC_FREE:
606             if (hdo->u.freeform.pt)
607                 delete[]hdo->u.freeform.pt;
608             break;
609         default:
610             return HWPDODefaultFunc(cmd);
611     }
612     return OBJRET_FILE_OK;
613 }
614 
615 
616 // text box
617 
FreeParaList(HWPPara * para)618 static void FreeParaList(HWPPara * para)
619 {
620     if (para->Next())
621         FreeParaList(para->Next());
622     delete para;
623 }
624 
625 
LoadParaList()626 static HWPPara *LoadParaList()
627 {
628     if (!hmem)
629         return nullptr;
630 
631     HWPFile *hwpf = GetCurrentDoc();
632     std::unique_ptr<HIODev> hio = hwpf->SetIODevice(std::unique_ptr<HIODev>(hmem));
633 
634     std::vector< HWPPara* > plist;
635 
636     hwpf->ReadParaList(plist);
637     std::unique_ptr<HIODev> orighmem = hwpf->SetIODevice(std::move(hio));
638     hmem = orighmem.release();
639 
640     return plist.size()? plist.front() : nullptr;
641 }
642 
643 
644 static int
HWPDOTextBoxFunc(int,HWPDrawingObject * hdo,int cmd,void *,int)645 HWPDOTextBoxFunc(int /*type*/, HWPDrawingObject * hdo,
646 int cmd, void * /*argp*/, int /*argv*/)
647 {
648     switch (cmd)
649     {
650         case OBJFUNC_LOAD:
651             if (ReadSizeField(0) < 0 || !SkipUnusedField())
652                 return OBJRET_FILE_ERROR;
653             if (ReadSizeField(0) < 0)
654                 return OBJRET_FILE_ERROR;
655             hdo->u.textbox.h = LoadParaList();
656             return hdo->u.textbox.h ? OBJRET_FILE_OK : OBJRET_FILE_ERROR;
657         case OBJFUNC_FREE:
658             if (hdo->u.textbox.h)
659             {
660                 FreeParaList(hdo->u.textbox.h);
661                 hdo->u.textbox.h = nullptr;
662             }
663             break;
664         default:
665             return HWPDODefaultFunc(cmd);
666     }
667     return OBJRET_FILE_OK;
668 }
669 
670 
671 
672 static int
HWPDOContainerFunc(int,HWPDrawingObject *,int cmd,void *,int)673 HWPDOContainerFunc(int /*type*/, HWPDrawingObject * /*hdo*/,
674 int cmd, void * /*argp*/, int /*argv*/)
675 {
676     return HWPDODefaultFunc(cmd);
677 }
678 
679 
HWPDrawingObject()680 HWPDrawingObject::HWPDrawingObject():
681     type(0), offset{0, 0}, offset2{0, 0}, extent{0, 0}, vrect{0, 0, 0, 0}
682 {
683     memset(&property, 0, sizeof property);
684     memset(&u, 0, sizeof u);
685     index = ++count;
686 }
687 
688 
~HWPDrawingObject()689 HWPDrawingObject::~HWPDrawingObject()
690 {
691     if (property.pPara)
692         FreeParaList(property.pPara);
693 
694     HWPDOFunc(this, OBJFUNC_FREE, nullptr, 0);
695 }
696 #endif
697 
698 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
699