Update git submodules
[LibreOffice.git] / filter / source / graphicfilter / icgm / actimpr.cxx
blob3d51d8e4470a885f535ea2b77735ef20f2af2be3
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
21 #include <sal/log.hxx>
23 #include <o3tl/any.hxx>
24 #include <o3tl/safeint.hxx>
25 #include <vcl/bitmapex.hxx>
26 #include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
27 #include <com/sun/star/drawing/LineStyle.hpp>
28 #include <com/sun/star/drawing/LineDash.hpp>
29 #include <com/sun/star/drawing/FillStyle.hpp>
30 #include <com/sun/star/drawing/Hatch.hpp>
31 #include <com/sun/star/awt/FontDescriptor.hpp>
32 #include <com/sun/star/awt/FontWeight.hpp>
33 #include <com/sun/star/awt/FontUnderline.hpp>
34 #include <com/sun/star/drawing/XShapeGrouper.hpp>
35 #include <com/sun/star/drawing/CircleKind.hpp>
36 #include <com/sun/star/awt/XBitmap.hpp>
37 #include <com/sun/star/drawing/PointSequenceSequence.hpp>
38 #include <com/sun/star/drawing/PointSequence.hpp>
39 #include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
40 #include <com/sun/star/drawing/FlagSequence.hpp>
41 #include <com/sun/star/drawing/ShapeCollection.hpp>
42 #include <com/sun/star/drawing/TextAdjust.hpp>
43 #include <com/sun/star/text/XText.hpp>
44 #include <com/sun/star/text/XTextRange.hpp>
45 #include <com/sun/star/style/HorizontalAlignment.hpp>
47 #include <comphelper/processfactory.hxx>
48 #include <toolkit/helper/vclunohelper.hxx>
49 #include <tools/helpers.hxx>
50 #include <comphelper/configuration.hxx>
52 #include "bitmap.hxx"
53 #include "elements.hxx"
54 #include "outact.hxx"
56 #define MAX_PAGES_FOR_FUZZING 2048
58 using namespace ::com::sun::star;
60 CGMImpressOutAct::CGMImpressOutAct(CGM& rCGM, const uno::Reference< frame::XModel > & rModel)
61 : mnCurrentPage(0)
62 , mnGroupActCount(0)
63 , mnGroupLevel(0)
64 , maGroupLevel()
65 , mpCGM(&rCGM)
66 , nFinalTextCount(0)
68 if ( !mpCGM->mbStatus )
69 return;
71 bool bStatRet = false;
73 uno::Reference< drawing::XDrawPagesSupplier > aDrawPageSup( rModel, uno::UNO_QUERY );
74 if( aDrawPageSup.is() )
76 maXDrawPages = aDrawPageSup->getDrawPages();
77 if ( maXDrawPages.is() )
79 maXMultiServiceFactory.set( rModel, uno::UNO_QUERY);
80 if( maXMultiServiceFactory.is() )
82 maXDrawPage = *o3tl::doAccess<uno::Reference<drawing::XDrawPage>>(maXDrawPages->getByIndex( 0 ));
83 if ( ImplInitPage() )
84 bStatRet = true;
88 mpCGM->mbStatus = bStatRet;
91 CGMImpressOutAct::~CGMImpressOutAct()
93 for (auto &a : maLockedNewXShapes)
94 a->removeActionLock();
97 bool CGMImpressOutAct::ImplInitPage()
99 bool bStatRet = false;
100 if( maXDrawPage.is() )
102 maXShapes = maXDrawPage;
103 if ( maXShapes.is() )
105 bStatRet = true;
108 return bStatRet;
111 bool CGMImpressOutAct::ImplCreateShape( const OUString& rType )
113 if (comphelper::IsFuzzing())
114 return false;
115 uno::Reference< uno::XInterface > xNewShape( maXMultiServiceFactory->createInstance( rType ) );
116 maXShape.set( xNewShape, uno::UNO_QUERY );
117 maXPropSet.set( xNewShape, uno::UNO_QUERY );
118 if ( maXShape.is() && maXPropSet.is() )
120 maXShapes->add( maXShape );
121 uno::Reference<document::XActionLockable> xLockable(maXShape, uno::UNO_QUERY);
122 if (xLockable)
124 xLockable->addActionLock();
125 maLockedNewXShapes.push_back(xLockable);
127 return true;
129 return false;
132 void CGMImpressOutAct::ImplSetOrientation( FloatPoint const & rRefPoint, double rOrientation )
134 maXPropSet->setPropertyValue( u"RotationPointX"_ustr, uno::Any(static_cast<sal_Int32>(rRefPoint.X)) );
135 maXPropSet->setPropertyValue( u"RotationPointY"_ustr, uno::Any(static_cast<sal_Int32>(rRefPoint.Y)) );
136 maXPropSet->setPropertyValue( u"RotateAngle"_ustr, uno::Any(static_cast<sal_Int32>( rOrientation * 100.0 )) );
140 void CGMImpressOutAct::ImplSetLineBundle()
142 drawing::LineStyle eLS;
144 sal_uInt32 nLineColor;
145 LineType eLineType;
146 double fLineWidth;
148 if ( mpCGM->pElement->nAspectSourceFlags & ASF_LINECOLOR )
149 nLineColor = mpCGM->pElement->pLineBundle->GetColor();
150 else
151 nLineColor = mpCGM->pElement->aLineBundle.GetColor();
152 if ( mpCGM->pElement->nAspectSourceFlags & ASF_LINETYPE )
153 eLineType = mpCGM->pElement->pLineBundle->eLineType;
154 else
155 eLineType = mpCGM->pElement->aLineBundle.eLineType;
156 if ( mpCGM->pElement->nAspectSourceFlags & ASF_LINEWIDTH )
157 fLineWidth = mpCGM->pElement->pLineBundle->nLineWidth;
158 else
159 fLineWidth = mpCGM->pElement->aLineBundle.nLineWidth;
161 maXPropSet->setPropertyValue( u"LineColor"_ustr, uno::Any(static_cast<sal_Int32>(nLineColor)) );
163 maXPropSet->setPropertyValue( u"LineWidth"_ustr, uno::Any(static_cast<sal_Int32>(fLineWidth)) );
165 switch( eLineType )
167 case LT_NONE :
168 eLS = drawing::LineStyle_NONE;
169 break;
170 case LT_DASH :
171 case LT_DOT :
172 case LT_DASHDOT :
173 case LT_DOTDOTSPACE :
174 case LT_LONGDASH :
175 case LT_DASHDASHDOT :
176 eLS = drawing::LineStyle_DASH;
177 break;
178 case LT_SOLID :
179 default:
180 eLS = drawing::LineStyle_SOLID;
181 break;
183 maXPropSet->setPropertyValue( u"LineStyle"_ustr, uno::Any(eLS) );
184 if ( eLS == drawing::LineStyle_DASH )
186 drawing::LineDash aLineDash( drawing::DashStyle_RECTRELATIVE, 1, 50, 3, 33, 100 );
187 maXPropSet->setPropertyValue( u"LineDash"_ustr, uno::Any(aLineDash) );
191 void CGMImpressOutAct::ImplSetFillBundle()
193 drawing::LineStyle eLS;
194 drawing::FillStyle eFS;
196 sal_uInt32 nEdgeColor = 0;
197 EdgeType eEdgeType;
198 double fEdgeWidth = 0;
200 sal_uInt32 nFillColor;
201 FillInteriorStyle eFillStyle;
202 sal_uInt32 nHatchIndex;
204 if ( mpCGM->pElement->eEdgeVisibility == EV_ON )
206 if ( mpCGM->pElement->nAspectSourceFlags & ASF_EDGETYPE )
207 eEdgeType = mpCGM->pElement->pEdgeBundle->eEdgeType;
208 else
209 eEdgeType = mpCGM->pElement->aEdgeBundle.eEdgeType;
210 if ( mpCGM->pElement->nAspectSourceFlags & ASF_EDGEWIDTH )
211 fEdgeWidth = mpCGM->pElement->pEdgeBundle->nEdgeWidth;
212 else
213 fEdgeWidth = mpCGM->pElement->aEdgeBundle.nEdgeWidth;
214 if ( mpCGM->pElement->nAspectSourceFlags & ASF_EDGECOLOR )
215 nEdgeColor = mpCGM->pElement->pEdgeBundle->GetColor();
216 else
217 nEdgeColor = mpCGM->pElement->aEdgeBundle.GetColor();
219 else
220 eEdgeType = ET_NONE;
222 if ( mpCGM->pElement->nAspectSourceFlags & ASF_FILLINTERIORSTYLE )
223 eFillStyle = mpCGM->pElement->pFillBundle->eFillInteriorStyle;
224 else
225 eFillStyle = mpCGM->pElement->aFillBundle.eFillInteriorStyle;
226 if ( mpCGM->pElement->nAspectSourceFlags & ASF_FILLCOLOR )
227 nFillColor = mpCGM->pElement->pFillBundle->GetColor();
228 else
229 nFillColor = mpCGM->pElement->aFillBundle.GetColor();
230 if ( mpCGM->pElement->nAspectSourceFlags & ASF_HATCHINDEX )
231 nHatchIndex = static_cast<sal_uInt32>(mpCGM->pElement->pFillBundle->nFillHatchIndex);
232 else
233 nHatchIndex = static_cast<sal_uInt32>(mpCGM->pElement->aFillBundle.nFillHatchIndex);
235 maXPropSet->setPropertyValue( u"FillColor"_ustr, uno::Any(static_cast<sal_Int32>(nFillColor)) );
237 switch ( eFillStyle )
239 case FIS_HATCH :
241 if ( nHatchIndex == 0 )
242 eFS = drawing::FillStyle_NONE;
243 else
244 eFS = drawing::FillStyle_HATCH;
246 break;
247 case FIS_PATTERN :
248 case FIS_SOLID :
250 eFS = drawing::FillStyle_SOLID;
252 break;
254 case FIS_GEOPATTERN :
256 if ( mpCGM->pElement->eTransparency == T_ON )
257 nFillColor = mpCGM->pElement->nAuxiliaryColor;
258 eFS = drawing::FillStyle_NONE;
260 break;
262 case FIS_INTERPOLATED :
263 case FIS_GRADIENT :
265 eFS = drawing::FillStyle_GRADIENT;
267 break;
269 case FIS_HOLLOW :
270 case FIS_EMPTY :
271 default:
273 eFS = drawing::FillStyle_NONE;
277 if ( mpCGM->mnAct4PostReset & ACT4_GRADIENT_ACTION )
278 eFS = drawing::FillStyle_GRADIENT;
280 if ( eFS == drawing::FillStyle_GRADIENT )
282 maXPropSet->setPropertyValue( u"FillGradient"_ustr, uno::Any(*mpGradient) );
284 maXPropSet->setPropertyValue( u"FillStyle"_ustr, uno::Any(eFS) );
286 eLS = drawing::LineStyle_NONE;
287 if ( eFillStyle == FIS_HOLLOW )
289 eLS = drawing::LineStyle_SOLID;
290 maXPropSet->setPropertyValue( u"LineColor"_ustr, uno::Any(static_cast<sal_Int32>(nFillColor)) );
291 maXPropSet->setPropertyValue( u"LineWidth"_ustr, uno::Any(sal_Int32(0)) );
293 else if ( eEdgeType != ET_NONE )
295 maXPropSet->setPropertyValue( u"LineColor"_ustr, uno::Any(static_cast<sal_Int32>(nEdgeColor)) );
297 maXPropSet->setPropertyValue( u"LineWidth"_ustr, uno::Any(static_cast<sal_Int32>(fEdgeWidth)) );
299 switch( eEdgeType )
301 case ET_DASH :
302 case ET_DOT :
303 case ET_DASHDOT :
304 case ET_DASHDOTDOT :
305 case ET_DOTDOTSPACE :
306 case ET_LONGDASH :
307 case ET_DASHDASHDOT :
308 default: // case ET_SOLID :
310 eLS = drawing::LineStyle_SOLID;
312 break;
316 maXPropSet->setPropertyValue( u"LineStyle"_ustr, uno::Any(eLS) );
318 if ( eFS != drawing::FillStyle_HATCH )
319 return;
321 drawing::Hatch aHatch;
323 aHatch.Color = nFillColor;
324 if ( mpCGM->pElement->maHatchMap.contains( nHatchIndex ) )
326 HatchEntry& rHatchEntry = mpCGM->pElement->maHatchMap[ nHatchIndex ];
327 switch ( rHatchEntry.HatchStyle )
329 case 0 : aHatch.Style = drawing::HatchStyle_SINGLE; break;
330 case 1 : aHatch.Style = drawing::HatchStyle_DOUBLE; break;
331 case 2 : aHatch.Style = drawing::HatchStyle_TRIPLE; break;
333 aHatch.Distance = rHatchEntry.HatchDistance;
334 aHatch.Angle = rHatchEntry.HatchAngle;
336 else
338 aHatch.Style = drawing::HatchStyle_TRIPLE;
339 aHatch.Distance = 10 * ( nHatchIndex & 0x1f ) | 100;
340 aHatch.Angle = 15 * ( ( nHatchIndex & 0x1f ) - 5 );
342 maXPropSet->setPropertyValue( u"FillHatch"_ustr, uno::Any(aHatch) );
345 void CGMImpressOutAct::ImplSetTextBundle( const uno::Reference< beans::XPropertySet > & rProperty )
347 sal_uInt32 nTextFontIndex;
348 sal_uInt32 nTextColor;
350 if ( mpCGM->pElement->nAspectSourceFlags & ASF_TEXTFONTINDEX )
351 nTextFontIndex = mpCGM->pElement->pTextBundle->nTextFontIndex;
352 else
353 nTextFontIndex = mpCGM->pElement->aTextBundle.nTextFontIndex;
354 if ( mpCGM->pElement->nAspectSourceFlags & ASF_TEXTCOLOR )
355 nTextColor = mpCGM->pElement->pTextBundle->GetColor();
356 else
357 nTextColor = mpCGM->pElement->aTextBundle.GetColor();
359 rProperty->setPropertyValue( u"CharColor"_ustr, uno::Any(static_cast<sal_Int32>(nTextColor)) );
361 sal_uInt32 nFontType = 0;
362 awt::FontDescriptor aFontDescriptor;
363 FontEntry* pFontEntry = mpCGM->pElement->aFontList.GetFontEntry( nTextFontIndex );
364 if ( pFontEntry )
366 nFontType = pFontEntry->nFontType;
367 aFontDescriptor.Name = OUString(reinterpret_cast<char*>(pFontEntry->aFontName.data()),
368 pFontEntry->aFontName.size(),
369 RTL_TEXTENCODING_ASCII_US);
371 aFontDescriptor.Height = sal_Int16( mpCGM->pElement->nCharacterHeight * 1.50 );
372 if ( nFontType & 1 )
373 aFontDescriptor.Slant = awt::FontSlant_ITALIC;
374 if ( nFontType & 2 )
375 aFontDescriptor.Weight = awt::FontWeight::BOLD;
376 else
377 aFontDescriptor.Weight = awt::FontWeight::NORMAL;
379 if ( mpCGM->pElement->eUnderlineMode != UM_OFF )
381 aFontDescriptor.Underline = awt::FontUnderline::SINGLE;
383 rProperty->setPropertyValue( u"FontDescriptor"_ustr, uno::Any(aFontDescriptor) );
386 void CGMImpressOutAct::InsertPage()
388 if ( mnCurrentPage ) // one side is always existing, therefore the first side will be left out
390 maXDrawPage = maXDrawPages->insertNewByIndex(0xffff);
391 if ( !ImplInitPage() )
392 mpCGM->mbStatus = false;
393 if (mnCurrentPage > MAX_PAGES_FOR_FUZZING && comphelper::IsFuzzing())
395 // ofz#21753 that's enough pages for fuzzing, we're not doing anything productive now
396 mpCGM->mbStatus = false;
399 mnCurrentPage++;
402 void CGMImpressOutAct::BeginGroup()
404 if ( mnGroupLevel < CGM_OUTACT_MAX_GROUP_LEVEL )
406 maGroupLevel[mnGroupLevel] = maXShapes->getCount();
408 ++mnGroupLevel;
409 mnGroupActCount = mpCGM->mnActCount;
412 void CGMImpressOutAct::EndGroup()
414 if (!mnGroupLevel)
415 return;
416 --mnGroupLevel;
417 if ( mnGroupLevel >= CGM_OUTACT_MAX_GROUP_LEVEL )
418 return;
420 sal_uInt32 nFirstIndex = maGroupLevel[mnGroupLevel];
421 if ( nFirstIndex == 0xffffffff )
422 nFirstIndex = 0;
423 sal_uInt32 nCurrentCount = maXShapes->getCount();
424 if ( ( nCurrentCount - nFirstIndex ) <= 1 )
425 return;
427 uno::Reference< drawing::XShapeGrouper > aXShapeGrouper;
428 aXShapeGrouper.set( maXDrawPage, uno::UNO_QUERY );
429 if( !aXShapeGrouper.is() )
430 return;
432 uno::Reference< drawing::XShapes > aXShapes = drawing::ShapeCollection::create(comphelper::getProcessComponentContext());
433 for ( sal_uInt32 i = nFirstIndex; i < nCurrentCount; i++ )
435 uno::Reference< drawing::XShape > aXShape = *o3tl::doAccess<uno::Reference<drawing::XShape>>(maXShapes->getByIndex( i ));
436 if (aXShape.is() )
438 aXShapes->add( aXShape );
441 aXShapeGrouper->group( aXShapes );
444 void CGMImpressOutAct::EndGrouping()
446 while ( mnGroupLevel )
448 EndGroup();
452 void CGMImpressOutAct::DrawRectangle( FloatRect const & rFloatRect )
454 if (mnGroupActCount == (mpCGM->mnActCount - 1)) // POWERPOINT HACK !!!
455 return;
456 if (useless(rFloatRect.Left))
458 SAL_WARN("filter.icgm", "bad left: " << rFloatRect.Left);
459 return;
461 if (useless(rFloatRect.Top))
463 SAL_WARN("filter.icgm", "bad top: " << rFloatRect.Top);
464 return;
466 double fWidth = rFloatRect.Right - rFloatRect.Left;
467 if (useless(fWidth))
469 SAL_WARN("filter.icgm", "bad width: " << fWidth);
470 return;
472 double fHeight = rFloatRect.Bottom - rFloatRect.Top;
473 if (useless(fHeight))
475 SAL_WARN("filter.icgm", "bad height: " << fHeight);
476 return;
478 if (!ImplCreateShape( u"com.sun.star.drawing.RectangleShape"_ustr))
479 return;
480 maXShape->setSize(awt::Size(fWidth, fHeight));
481 maXShape->setPosition(awt::Point(rFloatRect.Left, rFloatRect.Top));
482 ImplSetFillBundle();
485 void CGMImpressOutAct::DrawEllipse( FloatPoint const & rCenter, FloatPoint const & rSize, double& rOrientation )
487 if ( !ImplCreateShape( u"com.sun.star.drawing.EllipseShape"_ustr ) )
488 return;
490 drawing::CircleKind eCircleKind = drawing::CircleKind_FULL;
491 uno::Any aAny( &eCircleKind, ::cppu::UnoType<drawing::CircleKind>::get() );
492 maXPropSet->setPropertyValue( u"CircleKind"_ustr, aAny );
494 tools::Long nXSize = static_cast<tools::Long>( rSize.X * 2.0 ); // strange behaviour with an awt::Size of 0
495 tools::Long nYSize = static_cast<tools::Long>( rSize.Y * 2.0 );
496 if ( nXSize < 1 )
497 nXSize = 1;
498 if ( nYSize < 1 )
499 nYSize = 1;
500 maXShape->setSize( awt::Size( nXSize, nYSize ) );
501 maXShape->setPosition( awt::Point( static_cast<tools::Long>( rCenter.X - rSize.X ), static_cast<tools::Long>( rCenter.Y - rSize.Y ) ) );
503 if ( rOrientation != 0 )
505 ImplSetOrientation( rCenter, rOrientation );
507 ImplSetFillBundle();
510 void CGMImpressOutAct::DrawEllipticalArc( FloatPoint const & rCenter, FloatPoint const & rSize, double& rOrientation,
511 sal_uInt32 nType, double& fStartAngle, double& fEndAngle )
513 if ( !ImplCreateShape( u"com.sun.star.drawing.EllipseShape"_ustr ) )
514 return;
516 uno::Any aAny;
517 drawing::CircleKind eCircleKind;
520 tools::Long nXSize = static_cast<tools::Long>( rSize.X * 2.0 ); // strange behaviour with an awt::Size of 0
521 tools::Long nYSize = static_cast<tools::Long>( rSize.Y * 2.0 );
522 if ( nXSize < 1 )
523 nXSize = 1;
524 if ( nYSize < 1 )
525 nYSize = 1;
527 maXShape->setSize( awt::Size ( nXSize, nYSize ) );
529 if ( rOrientation != 0 )
531 fStartAngle = NormAngle360(fStartAngle + rOrientation);
532 fEndAngle = NormAngle360(fEndAngle + rOrientation);
534 switch( nType )
536 case 0 : eCircleKind = drawing::CircleKind_SECTION; break;
537 case 1 : eCircleKind = drawing::CircleKind_CUT; break;
538 case 2 : eCircleKind = drawing::CircleKind_ARC; break;
539 default : eCircleKind = drawing::CircleKind_FULL; break;
541 if ( static_cast<tools::Long>(fStartAngle) == static_cast<tools::Long>(fEndAngle) )
543 eCircleKind = drawing::CircleKind_FULL;
544 maXPropSet->setPropertyValue( u"CircleKind"_ustr, uno::Any(eCircleKind) );
546 else
548 maXPropSet->setPropertyValue( u"CircleKind"_ustr, uno::Any(eCircleKind) );
549 maXPropSet->setPropertyValue( u"CircleStartAngle"_ustr, uno::Any(static_cast<sal_Int32>( fStartAngle * 100 )) );
550 maXPropSet->setPropertyValue( u"CircleEndAngle"_ustr, uno::Any(static_cast<sal_Int32>( fEndAngle * 100 )) );
552 maXShape->setPosition( awt::Point( static_cast<tools::Long>( rCenter.X - rSize.X ), static_cast<tools::Long>( rCenter.Y - rSize.Y ) ) );
553 if ( rOrientation != 0 )
555 ImplSetOrientation( rCenter, rOrientation );
557 if ( eCircleKind == drawing::CircleKind_ARC )
559 ImplSetLineBundle();
561 else
563 ImplSetFillBundle();
564 if ( nType == 2 )
566 ImplSetLineBundle();
567 aAny <<= drawing::FillStyle_NONE;
568 maXPropSet->setPropertyValue( u"FillStyle"_ustr, aAny );
573 void CGMImpressOutAct::DrawBitmap( CGMBitmapDescriptor* pBmpDesc )
575 if ( !pBmpDesc->mbStatus || pBmpDesc->mxBitmap.IsEmpty() )
576 return;
578 FloatPoint aOrigin = pBmpDesc->mnOrigin;
579 double fdx = pBmpDesc->mndx;
580 double fdy = pBmpDesc->mndy;
582 BmpMirrorFlags nMirr = BmpMirrorFlags::NONE;
583 if ( pBmpDesc->mbVMirror )
584 nMirr |= BmpMirrorFlags::Vertical;
585 if ( nMirr != BmpMirrorFlags::NONE )
586 pBmpDesc->mxBitmap.Mirror( nMirr );
588 mpCGM->ImplMapPoint( aOrigin );
589 mpCGM->ImplMapX( fdx );
590 mpCGM->ImplMapY( fdy );
592 if ( !ImplCreateShape( u"com.sun.star.drawing.GraphicObjectShape"_ustr ) )
593 return;
595 maXShape->setSize( awt::Size( static_cast<tools::Long>(fdx), static_cast<tools::Long>(fdy) ) );
596 maXShape->setPosition( awt::Point( static_cast<tools::Long>(aOrigin.X), static_cast<tools::Long>(aOrigin.Y) ) );
598 if ( pBmpDesc->mnOrientation != 0 )
600 ImplSetOrientation( aOrigin, pBmpDesc->mnOrientation );
603 uno::Reference< awt::XBitmap > xBitmap( VCLUnoHelper::CreateBitmap( pBmpDesc->mxBitmap ) );
604 maXPropSet->setPropertyValue( u"GraphicObjectFillBitmap"_ustr, uno::Any(xBitmap) );
607 void CGMImpressOutAct::DrawPolygon( tools::Polygon& rPoly )
609 sal_uInt16 nPoints = rPoly.GetSize();
611 if ( !(( nPoints > 1 ) && ImplCreateShape( u"com.sun.star.drawing.PolyPolygonShape"_ustr )) )
612 return;
614 drawing::PointSequenceSequence aRetval;
616 // prepare inside polygons
617 aRetval.realloc( 1 );
619 // get pointer to outside arrays
620 drawing::PointSequence* pOuterSequence = aRetval.getArray();
622 // make room in arrays
623 pOuterSequence->realloc(static_cast<sal_Int32>(nPoints));
625 // get pointer to arrays
626 awt::Point* pInnerSequence = pOuterSequence->getArray();
628 for( sal_uInt16 n = 0; n < nPoints; n++ )
629 *pInnerSequence++ = awt::Point( rPoly[ n ].X(), rPoly[n].Y() );
631 uno::Any aParam;
632 aParam <<= aRetval;
633 maXPropSet->setPropertyValue( u"PolyPolygon"_ustr, aParam );
634 ImplSetFillBundle();
637 void CGMImpressOutAct::DrawPolyLine( tools::Polygon& rPoly )
639 sal_uInt16 nPoints = rPoly.GetSize();
641 if ( !(( nPoints > 1 ) && ImplCreateShape( u"com.sun.star.drawing.PolyLineShape"_ustr )) )
642 return;
644 drawing::PointSequenceSequence aRetval;
646 // prepare inside polygons
647 aRetval.realloc( 1 );
649 // get pointer to outside arrays
650 drawing::PointSequence* pOuterSequence = aRetval.getArray();
652 // make room in arrays
653 pOuterSequence->realloc(static_cast<sal_Int32>(nPoints));
655 // get pointer to arrays
656 awt::Point* pInnerSequence = pOuterSequence->getArray();
658 for( sal_uInt16 n = 0; n < nPoints; n++ )
659 *pInnerSequence++ = awt::Point( rPoly[ n ].X(), rPoly[n].Y() );
661 uno::Any aParam;
662 aParam <<= aRetval;
663 maXPropSet->setPropertyValue( u"PolyPolygon"_ustr, aParam );
664 ImplSetLineBundle();
667 void CGMImpressOutAct::DrawPolybezier( tools::Polygon& rPolygon )
669 sal_uInt16 nPoints = rPolygon.GetSize();
670 if ( !(( nPoints > 1 ) && ImplCreateShape( u"com.sun.star.drawing.OpenBezierShape"_ustr )) )
671 return;
673 drawing::PolyPolygonBezierCoords aRetval;
675 aRetval.Coordinates.realloc( 1 );
676 aRetval.Flags.realloc( 1 );
678 // get pointer to outside arrays
679 drawing::PointSequence* pOuterSequence = aRetval.Coordinates.getArray();
680 drawing::FlagSequence* pOuterFlags = aRetval.Flags.getArray();
682 // make room in arrays
683 pOuterSequence->realloc( nPoints );
684 pOuterFlags->realloc( nPoints );
686 awt::Point* pInnerSequence = pOuterSequence->getArray();
687 drawing::PolygonFlags* pInnerFlags = pOuterFlags->getArray();
689 for( sal_uInt16 i = 0; i < nPoints; i++ )
691 *pInnerSequence++ = awt::Point( rPolygon[ i ].X(), rPolygon[ i ].Y() );
692 *pInnerFlags++ = static_cast<drawing::PolygonFlags>(rPolygon.GetFlags( i ));
694 uno::Any aParam;
695 aParam <<= aRetval;
696 maXPropSet->setPropertyValue( u"PolyPolygonBezier"_ustr, aParam );
697 ImplSetLineBundle();
700 void CGMImpressOutAct::DrawPolyPolygon( tools::PolyPolygon const & rPolyPolygon )
702 sal_uInt32 nNumPolys = rPolyPolygon.Count();
703 if ( !(nNumPolys && ImplCreateShape( u"com.sun.star.drawing.ClosedBezierShape"_ustr )) )
704 return;
706 drawing::PolyPolygonBezierCoords aRetval;
708 // prepare inside polygons
709 aRetval.Coordinates.realloc(static_cast<sal_Int32>(nNumPolys));
710 aRetval.Flags.realloc(static_cast<sal_Int32>(nNumPolys));
712 // get pointer to outside arrays
713 drawing::PointSequence* pOuterSequence = aRetval.Coordinates.getArray();
714 drawing::FlagSequence* pOuterFlags = aRetval.Flags.getArray();
716 for( sal_uInt32 a = 0; a < nNumPolys; a++ )
718 const tools::Polygon& aPolygon( rPolyPolygon.GetObject( a ) );
719 sal_uInt32 nNumPoints = aPolygon.GetSize();
721 // make room in arrays
722 pOuterSequence->realloc(static_cast<sal_Int32>(nNumPoints));
723 pOuterFlags->realloc(static_cast<sal_Int32>(nNumPoints));
725 // get pointer to arrays
726 awt::Point* pInnerSequence = pOuterSequence->getArray();
727 drawing::PolygonFlags* pInnerFlags = pOuterFlags->getArray();
729 for( sal_uInt32 b = 0; b < nNumPoints; b++ )
731 *pInnerSequence++ = awt::Point( aPolygon.GetPoint( b ).X(), aPolygon.GetPoint( b ).Y() ) ;
732 *pInnerFlags++ = static_cast<drawing::PolygonFlags>(aPolygon.GetFlags( b ));
734 pOuterSequence++;
735 pOuterFlags++;
737 uno::Any aParam;
738 aParam <<= aRetval;
739 maXPropSet->setPropertyValue( u"PolyPolygonBezier"_ustr, aParam);
740 ImplSetFillBundle();
743 void CGMImpressOutAct::DrawText(awt::Point const & rTextPos, awt::Size const & rTextSize, const OUString& rString, FinalFlag eFlag)
745 if ( !ImplCreateShape( u"com.sun.star.drawing.TextShape"_ustr ) )
746 return;
748 uno::Any aAny;
749 tools::Long nWidth = rTextSize.Width;
750 tools::Long nHeight = rTextSize.Height;
752 awt::Point aTextPos( rTextPos );
753 switch ( mpCGM->pElement->eTextAlignmentV )
755 case TAV_HALF :
757 aTextPos.Y = o3tl::saturating_add(aTextPos.X, static_cast<sal_Int32>((mpCGM->pElement->nCharacterHeight * -1.5) / 2));
759 break;
761 case TAV_BASE :
762 case TAV_BOTTOM :
763 case TAV_NORMAL :
764 aTextPos.Y = o3tl::saturating_add(aTextPos.Y, static_cast<sal_Int32>(mpCGM->pElement->nCharacterHeight * -1.5));
765 break;
766 case TAV_TOP :
767 break;
768 case TAV_CAP:
769 case TAV_CONT:
770 break; // -Wall these two were not here.
773 if ( nWidth < 0 )
775 nWidth = -nWidth;
777 else if ( nWidth == 0 )
779 nWidth = -1;
781 if ( nHeight < 0 )
783 nHeight = -nHeight;
785 else if ( nHeight == 0 )
787 nHeight = -1;
789 maXShape->setPosition( aTextPos );
790 maXShape->setSize( awt::Size( nWidth, nHeight ) );
791 double nX = mpCGM->pElement->nCharacterOrientation[ 2 ];
792 double nY = mpCGM->pElement->nCharacterOrientation[ 3 ];
793 double fSqrt = std::hypot(nX, nY);
794 double nOrientation = fSqrt != 0.0 ? basegfx::rad2deg(acos(nX / fSqrt)) : 0.0;
795 if ( nY < 0 )
796 nOrientation = 360 - nOrientation;
798 if ( nOrientation )
800 maXPropSet->setPropertyValue( u"RotationPointX"_ustr, uno::Any(aTextPos.X) );
801 maXPropSet->setPropertyValue( u"RotationPointY"_ustr, uno::Any(static_cast<sal_Int32>( aTextPos.Y + nHeight )) );
802 maXPropSet->setPropertyValue( u"RotateAngle"_ustr, uno::Any(static_cast<sal_Int32>( nOrientation * 100 )) );
804 if ( nWidth == -1 )
806 aAny <<= true;
807 maXPropSet->setPropertyValue( u"TextAutoGrowWidth"_ustr, aAny );
809 drawing::TextAdjust eTextAdjust;
810 switch ( mpCGM->pElement->eTextAlignmentH )
812 case TAH_RIGHT :
813 eTextAdjust = drawing::TextAdjust_RIGHT;
814 break;
815 case TAH_LEFT :
816 case TAH_CONT :
817 case TAH_NORMAL :
818 eTextAdjust = drawing::TextAdjust_LEFT;
819 break;
820 case TAH_CENTER :
821 eTextAdjust = drawing::TextAdjust_CENTER;
822 break;
824 maXPropSet->setPropertyValue( u"TextHorizontalAdjust"_ustr, uno::Any(eTextAdjust) );
826 if ( nHeight == -1 )
828 maXPropSet->setPropertyValue( u"TextAutoGrowHeight"_ustr, uno::Any(true) );
830 uno::Reference< text::XText > xText;
831 uno::Any aFirstQuery( maXShape->queryInterface( cppu::UnoType<text::XText>::get()));
832 if( aFirstQuery >>= xText )
834 uno::Reference< text::XTextCursor > aXTextCursor( xText->createTextCursor() );
836 aXTextCursor->gotoEnd( false );
837 uno::Reference< text::XTextRange > aCursorText;
838 uno::Any aSecondQuery( aXTextCursor->queryInterface( cppu::UnoType<text::XTextRange>::get()));
839 if ( aSecondQuery >>= aCursorText )
841 uno::Reference< beans::XPropertySet > aCursorPropSet;
843 uno::Any aQuery( aCursorText->queryInterface( cppu::UnoType<beans::XPropertySet>::get()));
844 if( aQuery >>= aCursorPropSet )
846 if ( nWidth != -1 ) // paragraph adjusting in a valid textbox ?
848 switch ( mpCGM->pElement->eTextAlignmentH )
850 case TAH_RIGHT :
851 aAny <<= sal_Int16(style::HorizontalAlignment_RIGHT);
852 break;
853 case TAH_LEFT :
854 case TAH_CONT :
855 case TAH_NORMAL :
856 aAny <<= sal_Int16(style::HorizontalAlignment_LEFT);
857 break;
858 case TAH_CENTER :
859 aAny <<= sal_Int16(style::HorizontalAlignment_CENTER);
860 break;
862 aCursorPropSet->setPropertyValue( u"ParaAdjust"_ustr, aAny );
864 if ( nWidth > 0 && nHeight > 0 ) // restricted text
866 aAny <<= true;
867 maXPropSet->setPropertyValue( u"TextFitToSize"_ustr, aAny );
869 aCursorText->setString(rString);
870 aXTextCursor->gotoEnd( true );
871 ImplSetTextBundle( aCursorPropSet );
876 if ( eFlag == FF_NOT_FINAL )
878 nFinalTextCount = maXShapes->getCount();
882 void CGMImpressOutAct::AppendText( const char* pString )
884 if ( !nFinalTextCount )
885 return;
887 uno::Reference< drawing::XShape > aShape = *o3tl::doAccess<uno::Reference<drawing::XShape>>(maXShapes->getByIndex( nFinalTextCount - 1 ));
888 if ( !aShape.is() )
889 return;
891 uno::Reference< text::XText > xText;
892 uno::Any aFirstQuery( aShape->queryInterface( cppu::UnoType<text::XText>::get()) );
893 if( !(aFirstQuery >>= xText) )
894 return;
896 OUString aStr(pString, strlen(pString), RTL_TEXTENCODING_ASCII_US);
898 uno::Reference< text::XTextCursor > aXTextCursor( xText->createTextCursor() );
899 if ( !aXTextCursor.is() )
900 return;
902 aXTextCursor->gotoEnd( false );
903 uno::Reference< text::XTextRange > aCursorText;
904 uno::Any aSecondQuery(aXTextCursor->queryInterface( cppu::UnoType<text::XTextRange>::get()));
905 if ( aSecondQuery >>= aCursorText )
907 uno::Reference< beans::XPropertySet > aPropSet;
908 uno::Any aQuery(aCursorText->queryInterface( cppu::UnoType<beans::XPropertySet>::get()));
909 if( aQuery >>= aPropSet )
911 aCursorText->setString( aStr );
912 aXTextCursor->gotoEnd( true );
913 ImplSetTextBundle( aPropSet );
919 void CGMImpressOutAct::BeginFigure()
921 if (!maPoints.empty())
922 EndFigure();
924 BeginGroup();
925 maPoints.clear();
926 maFlags.clear();
929 void CGMImpressOutAct::CloseRegion()
931 if (maPoints.size() > 2)
933 NewRegion();
934 DrawPolyPolygon( maPolyPolygon );
935 maPolyPolygon.Clear();
939 void CGMImpressOutAct::NewRegion()
941 if (maPoints.size() > 2)
943 tools::Polygon aPolygon(maPoints.size(), maPoints.data(), maFlags.data());
944 maPolyPolygon.Insert( aPolygon );
946 maPoints.clear();
947 maFlags.clear();
950 void CGMImpressOutAct::EndFigure()
952 NewRegion();
953 DrawPolyPolygon( maPolyPolygon );
954 maPolyPolygon.Clear();
955 EndGroup();
956 maPoints.clear();
957 maFlags.clear();
960 void CGMImpressOutAct::RegPolyLine( tools::Polygon const & rPolygon, bool bReverse )
962 sal_uInt16 nPoints = rPolygon.GetSize();
963 if ( !nPoints )
964 return;
966 if ( bReverse )
968 for ( sal_uInt16 i = 0; i < nPoints; i++ )
970 maPoints.push_back(rPolygon.GetPoint(nPoints - i - 1));
971 maFlags.push_back(rPolygon.GetFlags(nPoints - i - 1));
974 else
976 for ( sal_uInt16 i = 0; i < nPoints; i++ )
978 maPoints.push_back(rPolygon.GetPoint(i));
979 maFlags.push_back(rPolygon.GetFlags(i));
984 void CGMImpressOutAct::SetGradientOffset( tools::Long nHorzOfs, tools::Long nVertOfs )
986 if ( !mpGradient )
987 mpGradient.reset( new awt::Gradient );
988 mpGradient->XOffset = ( static_cast<sal_uInt16>(nHorzOfs) & 0x7f );
989 mpGradient->YOffset = ( static_cast<sal_uInt16>(nVertOfs) & 0x7f );
992 void CGMImpressOutAct::SetGradientAngle( tools::Long nAngle )
994 if ( !mpGradient )
995 mpGradient.reset( new awt::Gradient );
996 mpGradient->Angle = sal::static_int_cast< sal_Int16 >(nAngle);
999 void CGMImpressOutAct::SetGradientDescriptor( sal_uInt32 nColorFrom, sal_uInt32 nColorTo )
1001 if ( !mpGradient )
1002 mpGradient.reset( new awt::Gradient );
1003 mpGradient->StartColor = nColorFrom;
1004 mpGradient->EndColor = nColorTo;
1007 void CGMImpressOutAct::SetGradientStyle( sal_uInt32 nStyle )
1009 if ( !mpGradient )
1010 mpGradient.reset( new awt::Gradient );
1011 switch ( nStyle )
1013 case 0xff :
1015 mpGradient->Style = awt::GradientStyle_AXIAL;
1017 break;
1018 case 4 :
1020 mpGradient->Style = awt::GradientStyle_RADIAL; // CONICAL
1022 break;
1023 case 3 :
1025 mpGradient->Style = awt::GradientStyle_RECT;
1027 break;
1028 case 2 :
1030 mpGradient->Style = awt::GradientStyle_ELLIPTICAL;
1032 break;
1033 default :
1035 mpGradient->Style = awt::GradientStyle_LINEAR;
1040 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */