LibreOffice Module vcl (master) 1
gdimetafiletools.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
21#include <vcl/metaact.hxx>
22#include <vcl/canvastools.hxx>
27#include <vcl/virdev.hxx>
28#include <vcl/svapp.hxx>
29#include <vcl/graphictools.hxx>
30#include <osl/diagnose.h>
31#include <tools/stream.hxx>
32
33// helpers
34
35namespace
36{
37 bool handleGeometricContent(
38 const basegfx::B2DPolyPolygon& rClip,
39 const basegfx::B2DPolyPolygon& rSource,
40 GDIMetaFile& rTarget,
41 bool bStroke)
42 {
43 if(rSource.count() && rClip.count())
44 {
45 const basegfx::B2DPolyPolygon aResult(
47 rSource,
48 rClip,
49 true, // inside
50 bStroke));
51
52 if(aResult.count())
53 {
54 if(aResult == rSource)
55 {
56 // not clipped, but inside. Add original
57 return false;
58 }
59 else
60 {
61 // add clipped geometry
62 if(bStroke)
63 {
64 for(auto const& rB2DPolygon : aResult)
65 {
66 rTarget.AddAction(
68 tools::Polygon(rB2DPolygon)));
69 }
70 }
71 else
72 {
73 rTarget.AddAction(
75 tools::PolyPolygon(aResult)));
76 }
77 }
78 }
79 }
80
81 return true;
82 }
83
84 bool handleGradientContent(
85 const basegfx::B2DPolyPolygon& rClip,
86 const basegfx::B2DPolyPolygon& rSource,
87 const Gradient& rGradient,
88 GDIMetaFile& rTarget)
89 {
90 if(rSource.count() && rClip.count())
91 {
92 const basegfx::B2DPolyPolygon aResult(
94 rSource,
95 rClip,
96 true, // inside
97 false)); // stroke
98
99 if(aResult.count())
100 {
101 if(aResult == rSource)
102 {
103 // not clipped, but inside. Add original
104 return false;
105 }
106 else
107 {
108 // add clipped geometry
109 rTarget.AddAction(
111 tools::PolyPolygon(aResult),
112 rGradient));
113 }
114 }
115 }
116
117 return true;
118 }
119
120 bool handleBitmapContent(
121 const basegfx::B2DPolyPolygon& rClip,
122 const Point& rPoint,
123 const Size& rSize,
124 const BitmapEx& rBitmapEx,
125 GDIMetaFile& rTarget)
126 {
127 if(!rSize.Width() || !rSize.Height() || rBitmapEx.IsEmpty())
128 {
129 // bitmap or size is empty
130 return true;
131 }
132
133 const basegfx::B2DRange aLogicBitmapRange(
134 rPoint.X(), rPoint.Y(),
135 rPoint.X() + rSize.Width(), rPoint.Y() + rSize.Height());
136 const basegfx::B2DPolyPolygon aClipOfBitmap(
138 rClip,
139 aLogicBitmapRange,
140 true,
141 false)); // stroke
142
143 if(!aClipOfBitmap.count())
144 {
145 // outside clip region
146 return true;
147 }
148
149 // inside or overlapping. Use area to find out if it is completely
150 // covering (inside) or overlapping
151 const double fClipArea(basegfx::utils::getArea(aClipOfBitmap));
152 const double fBitmapArea(
153 aLogicBitmapRange.getWidth() * aLogicBitmapRange.getWidth() +
154 aLogicBitmapRange.getHeight() * aLogicBitmapRange.getHeight());
155 const double fFactor(fClipArea / fBitmapArea);
156
157 if(basegfx::fTools::more(fFactor, 1.0 - 0.001))
158 {
159 // completely covering (with 0.1% tolerance)
160 return false;
161 }
162
163 // needs clipping (with 0.1% tolerance). Prepare VirtualDevice
164 // in pixel mode for alpha channel painting (black is transparent,
165 // white to paint 100% opacity)
166 const Size aSizePixel(rBitmapEx.GetSizePixel());
168
169 aVDev->SetOutputSizePixel(aSizePixel);
170 aVDev->EnableMapMode(false);
171 aVDev->SetFillColor( COL_WHITE);
172 aVDev->SetLineColor();
173
174 if(rBitmapEx.IsAlpha())
175 {
176 // use given alpha channel
177 aVDev->DrawBitmap(Point(0, 0), rBitmapEx.GetAlphaMask().GetBitmap());
178 }
179 else
180 {
181 // reset alpha channel
182 aVDev->SetBackground(Wallpaper(COL_BLACK));
183 aVDev->Erase();
184 }
185
186 // transform polygon from clipping to pixel coordinates
187 basegfx::B2DPolyPolygon aPixelPoly(aClipOfBitmap);
188 basegfx::B2DHomMatrix aTransform;
189
190 aTransform.translate(-aLogicBitmapRange.getMinX(), -aLogicBitmapRange.getMinY());
191 aTransform.scale(
192 static_cast< double >(aSizePixel.Width()) / aLogicBitmapRange.getWidth(),
193 static_cast< double >(aSizePixel.Height()) / aLogicBitmapRange.getHeight());
194 aPixelPoly.transform(aTransform);
195
196 // to fill the non-covered parts, use the Xor fill rule of
197 // tools::PolyPolygon painting. Start with an all-covering polygon and
198 // add the clip polygon one
199 basegfx::B2DPolyPolygon aInvertPixelPoly;
200
201 aInvertPixelPoly.append(
204 0.0, 0.0,
205 aSizePixel.Width(), aSizePixel.Height())));
206 aInvertPixelPoly.append(aPixelPoly);
207
208 // paint as alpha
209 aVDev->DrawPolyPolygon(aInvertPixelPoly);
210
211 // get created alpha mask and set defaults
212 AlphaMask aAlpha(
213 aVDev->GetBitmap(
214 Point(0, 0),
215 aSizePixel));
216
217 aAlpha.SetPrefSize(rBitmapEx.GetPrefSize());
218 aAlpha.SetPrefMapMode(rBitmapEx.GetPrefMapMode());
219
220 // add new action replacing the old one
221 rTarget.AddAction(
223 Point(
224 basegfx::fround(aLogicBitmapRange.getMinX()),
225 basegfx::fround(aLogicBitmapRange.getMinY())),
226 Size(
227 basegfx::fround(aLogicBitmapRange.getWidth()),
228 basegfx::fround(aLogicBitmapRange.getHeight())),
229 BitmapEx(rBitmapEx.GetBitmap(), aAlpha)));
230
231 return true;
232 }
233
234 void addSvtGraphicStroke(const SvtGraphicStroke& rStroke, GDIMetaFile& rTarget)
235 {
236 // write SvtGraphicFill
237 SvMemoryStream aMemStm;
238 WriteSvtGraphicStroke( aMemStm, rStroke );
239 rTarget.AddAction(
241 "XPATHSTROKE_SEQ_BEGIN",
242 0,
243 static_cast< const sal_uInt8* >(aMemStm.GetData()),
244 aMemStm.TellEnd()));
245 }
246
247 void addSvtGraphicFill(const SvtGraphicFill &rFilling, GDIMetaFile& rTarget)
248 {
249 // write SvtGraphicFill
250 SvMemoryStream aMemStm;
251 WriteSvtGraphicFill( aMemStm, rFilling );
252 rTarget.AddAction(
254 "XPATHFILL_SEQ_BEGIN",
255 0,
256 static_cast< const sal_uInt8* >(aMemStm.GetData()),
257 aMemStm.TellEnd()));
258 }
259} // end of anonymous namespace
260
261// #i121267# Tooling to internally clip geometry against internal clip regions
262
264{
265 const sal_uLong nObjCount(rSource.GetActionSize());
266
267 if(!nObjCount)
268 {
269 return;
270 }
271
272 // prepare target data container and push/pop stack data
273 GDIMetaFile aTarget;
274 bool bChanged(false);
275 std::vector< basegfx::B2DPolyPolygon > aClips;
276 std::vector< vcl::PushFlags > aPushFlags;
277 std::vector< MapMode > aMapModes;
278
279 // start with empty region
280 aClips.emplace_back();
281
282 // start with default MapMode (MapUnit::MapPixel)
283 aMapModes.emplace_back();
284
285 for(sal_uLong i(0); i < nObjCount; ++i)
286 {
287 const MetaAction* pAction(rSource.GetAction(i));
288 const MetaActionType nType(pAction->GetType());
289 bool bDone(false);
290
291 // basic operation takes care of clipregion actions (four) and push/pop of these
292 // to steer the currently set clip region. There *is* an active
293 // clip region when (aClips.size() && aClips.back().count()), see
294 // below
295 switch(nType)
296 {
298 {
299 const MetaClipRegionAction* pA = static_cast< const MetaClipRegionAction* >(pAction);
300
301 if(pA->IsClipping())
302 {
303 const vcl::Region& rRegion = pA->GetRegion();
304 const basegfx::B2DPolyPolygon aNewClip(rRegion.GetAsB2DPolyPolygon());
305
306 aClips.back() = aNewClip;
307 }
308 else
309 {
310 aClips.back() = basegfx::B2DPolyPolygon();
311 }
312
313 break;
314 }
315
317 {
318 const MetaISectRectClipRegionAction* pA = static_cast< const MetaISectRectClipRegionAction* >(pAction);
319 const tools::Rectangle& rRect = pA->GetRect();
320
321 if(!rRect.IsEmpty() && !aClips.empty() && aClips.back().count())
322 {
324
326 aClips.back(),
327 aClipRange,
328 true, // inside
329 false); // stroke
330 }
331 break;
332 }
333
335 {
336 const MetaISectRegionClipRegionAction* pA = static_cast< const MetaISectRegionClipRegionAction* >(pAction);
337 const vcl::Region& rRegion = pA->GetRegion();
338
339 if(!rRegion.IsEmpty() && !aClips.empty() && aClips.back().count())
340 {
341 const basegfx::B2DPolyPolygon aNewClip(rRegion.GetAsB2DPolyPolygon());
342
344 aClips.back(),
345 aNewClip,
346 true, // inside
347 false); // stroke
348 }
349 break;
350 }
351
353 {
354 const MetaMoveClipRegionAction* pA = static_cast< const MetaMoveClipRegionAction* >(pAction);
355 const tools::Long aHorMove(pA->GetHorzMove());
356 const tools::Long aVerMove(pA->GetVertMove());
357
358 if((aHorMove || aVerMove) && !aClips.empty() && aClips.back().count())
359 {
360 aClips.back().transform(
362 aHorMove,
363 aVerMove));
364 }
365 break;
366 }
367
369 {
370 const MetaPushAction* pA = static_cast< const MetaPushAction* >(pAction);
371 const vcl::PushFlags nFlags(pA->GetFlags());
372
373 aPushFlags.push_back(nFlags);
374
375 if(nFlags & vcl::PushFlags::CLIPREGION)
376 {
377 aClips.push_back(aClips.back());
378 }
379
380 if(nFlags & vcl::PushFlags::MAPMODE)
381 {
382 aMapModes.push_back(aMapModes.back());
383 }
384 break;
385 }
386
388 {
389
390 if(!aPushFlags.empty())
391 {
392 const vcl::PushFlags nFlags(aPushFlags.back());
393 aPushFlags.pop_back();
394
395 if(nFlags & vcl::PushFlags::CLIPREGION)
396 {
397 if(aClips.size() > 1)
398 {
399 aClips.pop_back();
400 }
401 else
402 {
403 OSL_ENSURE(false, "Wrong POP() in ClipRegions (!)");
404 }
405 }
406
407 if(nFlags & vcl::PushFlags::MAPMODE)
408 {
409 if(aMapModes.size() > 1)
410 {
411 aMapModes.pop_back();
412 }
413 else
414 {
415 OSL_ENSURE(false, "Wrong POP() in MapModes (!)");
416 }
417 }
418 }
419 else
420 {
421 OSL_ENSURE(false, "Invalid pop() without push() (!)");
422 }
423
424 break;
425 }
426
428 {
429 const MetaMapModeAction* pA = static_cast< const MetaMapModeAction* >(pAction);
430
431 aMapModes.back() = pA->GetMapMode();
432 break;
433 }
434
435 default:
436 {
437 break;
438 }
439 }
440
441 // this area contains all actions which could potentially be clipped. Since
442 // this tooling is only a fallback (see comments in header), only the needed
443 // actions will be implemented. Extend using the pattern for the already
444 // implemented actions.
445 if(!aClips.empty() && aClips.back().count())
446 {
447 switch(nType)
448 {
449
450 // pixel actions, just check on inside
451
453 {
454 const MetaPixelAction* pA = static_cast< const MetaPixelAction* >(pAction);
455 const Point& rPoint = pA->GetPoint();
456
458 aClips.back(),
459 basegfx::B2DPoint(rPoint.X(), rPoint.Y())))
460 {
461 // when not inside, do not add original
462 bDone = true;
463 }
464 break;
465 }
466
468 {
469 const MetaPointAction* pA = static_cast< const MetaPointAction* >(pAction);
470 const Point& rPoint = pA->GetPoint();
471
473 aClips.back(),
474 basegfx::B2DPoint(rPoint.X(), rPoint.Y())))
475 {
476 // when not inside, do not add original
477 bDone = true;
478 }
479 break;
480 }
481
482 // geometry actions
483
485 {
486 const MetaLineAction* pA = static_cast< const MetaLineAction* >(pAction);
487 const Point& rStart(pA->GetStartPoint());
488 const Point& rEnd(pA->GetEndPoint());
490
491 aLine.append(basegfx::B2DPoint(rStart.X(), rStart.Y()));
492 aLine.append(basegfx::B2DPoint(rEnd.X(), rEnd.Y()));
493
494 bDone = handleGeometricContent(
495 aClips.back(),
497 aTarget,
498 true); // stroke
499 break;
500 }
501
503 {
504 const MetaRectAction* pA = static_cast< const MetaRectAction* >(pAction);
505 const tools::Rectangle& rRect = pA->GetRect();
506
507 if(rRect.IsEmpty())
508 {
509 bDone = true;
510 }
511 else
512 {
513
514 bDone = handleGeometricContent(
515 aClips.back(),
519 aTarget,
520 false); // stroke
521 }
522 break;
523 }
524
526 {
527 const MetaRoundRectAction* pA = static_cast< const MetaRoundRectAction* >(pAction);
528 const tools::Rectangle& rRect = pA->GetRect();
529
530 if(rRect.IsEmpty())
531 {
532 bDone = true;
533 }
534 else
535 {
536 const sal_uInt32 nHor(pA->GetHorzRound());
537 const sal_uInt32 nVer(pA->GetVertRound());
539 basegfx::B2DPolygon aOutline;
540
541 if(nHor || nVer)
542 {
543 double fRadiusX((nHor * 2.0) / (aRange.getWidth() > 0.0 ? aRange.getWidth() : 1.0));
544 double fRadiusY((nVer * 2.0) / (aRange.getHeight() > 0.0 ? aRange.getHeight() : 1.0));
545 fRadiusX = std::clamp(fRadiusX, 0.0, 1.0);
546 fRadiusY = std::clamp(fRadiusY, 0.0, 1.0);
547
548 aOutline = basegfx::utils::createPolygonFromRect(aRange, fRadiusX, fRadiusY);
549 }
550 else
551 {
552 aOutline = basegfx::utils::createPolygonFromRect(aRange);
553 }
554
555 bDone = handleGeometricContent(
556 aClips.back(),
557 basegfx::B2DPolyPolygon(aOutline),
558 aTarget,
559 false); // stroke
560 }
561 break;
562 }
563
565 {
566 const MetaEllipseAction* pA = static_cast< const MetaEllipseAction* >(pAction);
567 const tools::Rectangle& rRect = pA->GetRect();
568
569 if(rRect.IsEmpty())
570 {
571 bDone = true;
572 }
573 else
574 {
576
577 bDone = handleGeometricContent(
578 aClips.back(),
581 aRange.getCenter(),
582 aRange.getWidth() * 0.5,
583 aRange.getHeight() * 0.5)),
584 aTarget,
585 false); // stroke
586 }
587 break;
588 }
589
591 {
592 const MetaArcAction* pA = static_cast< const MetaArcAction* >(pAction);
593 const tools::Rectangle& rRect = pA->GetRect();
594
595 if(rRect.IsEmpty())
596 {
597 bDone = true;
598 }
599 else
600 {
601 const tools::Polygon aToolsPoly(
602 rRect,
603 pA->GetStartPoint(),
604 pA->GetEndPoint(),
605 PolyStyle::Arc);
606
607 bDone = handleGeometricContent(
608 aClips.back(),
610 aTarget,
611 true); // stroke
612 }
613 break;
614 }
615
617 {
618 const MetaPieAction* pA = static_cast< const MetaPieAction* >(pAction);
619 const tools::Rectangle& rRect = pA->GetRect();
620
621 if(rRect.IsEmpty())
622 {
623 bDone = true;
624 }
625 else
626 {
627 const tools::Polygon aToolsPoly(
628 rRect,
629 pA->GetStartPoint(),
630 pA->GetEndPoint(),
631 PolyStyle::Pie);
632
633 bDone = handleGeometricContent(
634 aClips.back(),
636 aTarget,
637 false); // stroke
638 }
639 break;
640 }
641
643 {
644 const MetaChordAction* pA = static_cast< const MetaChordAction* >(pAction);
645 const tools::Rectangle& rRect = pA->GetRect();
646
647 if(rRect.IsEmpty())
648 {
649 bDone = true;
650 }
651 else
652 {
653 const tools::Polygon aToolsPoly(
654 rRect,
655 pA->GetStartPoint(),
656 pA->GetEndPoint(),
657 PolyStyle::Chord);
658
659 bDone = handleGeometricContent(
660 aClips.back(),
662 aTarget,
663 false); // stroke
664 }
665 break;
666 }
667
669 {
670 const MetaPolyLineAction* pA = static_cast< const MetaPolyLineAction* >(pAction);
671
672 bDone = handleGeometricContent(
673 aClips.back(),
675 aTarget,
676 true); // stroke
677 break;
678 }
679
681 {
682 const MetaPolygonAction* pA = static_cast< const MetaPolygonAction* >(pAction);
683
684 bDone = handleGeometricContent(
685 aClips.back(),
687 aTarget,
688 false); // stroke
689 break;
690 }
691
693 {
694 const MetaPolyPolygonAction* pA = static_cast< const MetaPolyPolygonAction* >(pAction);
695 const tools::PolyPolygon& rPoly = pA->GetPolyPolygon();
696
697 bDone = handleGeometricContent(
698 aClips.back(),
699 rPoly.getB2DPolyPolygon(),
700 aTarget,
701 false); // stroke
702 break;
703 }
704
705 // bitmap actions, create BitmapEx with alpha channel derived
706 // from clipping
707
709 {
710 const MetaBmpExAction* pA = static_cast< const MetaBmpExAction* >(pAction);
711 const BitmapEx& rBitmapEx = pA->GetBitmapEx();
712
713 // the logical size depends on the PrefSize of the given bitmap in
714 // combination with the current MapMode
715 Size aLogicalSize(rBitmapEx.GetPrefSize());
716
717 if(MapUnit::MapPixel == rBitmapEx.GetPrefMapMode().GetMapUnit())
718 {
719 aLogicalSize = Application::GetDefaultDevice()->PixelToLogic(aLogicalSize, aMapModes.back());
720 }
721 else
722 {
723 aLogicalSize = OutputDevice::LogicToLogic(aLogicalSize, rBitmapEx.GetPrefMapMode(), aMapModes.back());
724 }
725
726 bDone = handleBitmapContent(
727 aClips.back(),
728 pA->GetPoint(),
729 aLogicalSize,
730 rBitmapEx,
731 aTarget);
732 break;
733 }
734
736 {
737 const MetaBmpAction* pA = static_cast< const MetaBmpAction* >(pAction);
738 const Bitmap& rBitmap = pA->GetBitmap();
739
740 // the logical size depends on the PrefSize of the given bitmap in
741 // combination with the current MapMode
742 Size aLogicalSize(rBitmap.GetPrefSize());
743
744 if(MapUnit::MapPixel == rBitmap.GetPrefMapMode().GetMapUnit())
745 {
746 aLogicalSize = Application::GetDefaultDevice()->PixelToLogic(aLogicalSize, aMapModes.back());
747 }
748 else
749 {
750 aLogicalSize = OutputDevice::LogicToLogic(aLogicalSize, rBitmap.GetPrefMapMode(), aMapModes.back());
751 }
752
753 bDone = handleBitmapContent(
754 aClips.back(),
755 pA->GetPoint(),
756 aLogicalSize,
757 BitmapEx(rBitmap),
758 aTarget);
759 break;
760 }
761
763 {
764 const MetaBmpExScaleAction* pA = static_cast< const MetaBmpExScaleAction* >(pAction);
765
766 bDone = handleBitmapContent(
767 aClips.back(),
768 pA->GetPoint(),
769 pA->GetSize(),
770 pA->GetBitmapEx(),
771 aTarget);
772 break;
773 }
774
776 {
777 const MetaBmpScaleAction* pA = static_cast< const MetaBmpScaleAction* >(pAction);
778
779 bDone = handleBitmapContent(
780 aClips.back(),
781 pA->GetPoint(),
782 pA->GetSize(),
783 BitmapEx(pA->GetBitmap()),
784 aTarget);
785 break;
786 }
787
789 {
790 const MetaBmpExScalePartAction* pA = static_cast< const MetaBmpExScalePartAction* >(pAction);
791 const BitmapEx& rBitmapEx = pA->GetBitmapEx();
792
793 if(rBitmapEx.IsEmpty())
794 {
795 // empty content
796 bDone = true;
797 }
798 else
799 {
800 BitmapEx aCroppedBitmapEx(rBitmapEx);
801 const tools::Rectangle aCropRectangle(pA->GetSrcPoint(), pA->GetSrcSize());
802
803 if(aCropRectangle.IsEmpty())
804 {
805 // empty content
806 bDone = true;
807 }
808 else
809 {
810 aCroppedBitmapEx.Crop(aCropRectangle);
811 bDone = handleBitmapContent(
812 aClips.back(),
813 pA->GetDestPoint(),
814 pA->GetDestSize(),
815 aCroppedBitmapEx,
816 aTarget);
817 }
818 }
819 break;
820 }
821
823 {
824 const MetaBmpScalePartAction* pA = static_cast< const MetaBmpScalePartAction* >(pAction);
825 const Bitmap& rBitmap = pA->GetBitmap();
826
827 if(rBitmap.IsEmpty())
828 {
829 // empty content
830 bDone = true;
831 }
832 else
833 {
834 Bitmap aCroppedBitmap(rBitmap);
835 const tools::Rectangle aCropRectangle(pA->GetSrcPoint(), pA->GetSrcSize());
836
837 if(aCropRectangle.IsEmpty())
838 {
839 // empty content
840 bDone = true;
841 }
842 else
843 {
844 aCroppedBitmap.Crop(aCropRectangle);
845 bDone = handleBitmapContent(
846 aClips.back(),
847 pA->GetDestPoint(),
848 pA->GetDestSize(),
849 BitmapEx(aCroppedBitmap),
850 aTarget);
851 }
852 }
853 break;
854 }
855
856 // need to handle all those 'hacks' which hide data in comments
857
859 {
860 const MetaCommentAction* pA = static_cast< const MetaCommentAction* >(pAction);
861 const OString& rComment = pA->GetComment();
862
863 if(rComment.equalsIgnoreAsciiCase("XGRAD_SEQ_BEGIN"))
864 {
865 // nothing to do; this just means that between here and XGRAD_SEQ_END
866 // exists a MetaActionType::GRADIENTEX mixed with Xor-tricked painting
867 // commands. This comment is used to scan over these and filter for
868 // the gradient action. It is needed to support MetaActionType::GRADIENTEX
869 // in this processor to solve usages.
870 }
871 else if(rComment.equalsIgnoreAsciiCase("XPATHFILL_SEQ_BEGIN"))
872 {
873 SvtGraphicFill aFilling;
874 tools::PolyPolygon aPath;
875
876 { // read SvtGraphicFill
877 SvMemoryStream aMemStm(const_cast<sal_uInt8 *>(pA->GetData()), pA->GetDataSize(),StreamMode::READ);
878 ReadSvtGraphicFill( aMemStm, aFilling );
879 }
880
881 aFilling.getPath(aPath);
882
883 if(aPath.Count())
884 {
885 const basegfx::B2DPolyPolygon aSource(aPath.getB2DPolyPolygon());
886 const basegfx::B2DPolyPolygon aResult(
888 aSource,
889 aClips.back(),
890 true, // inside
891 false)); // stroke
892
893 if(aResult.count())
894 {
895 if(aResult != aSource)
896 {
897 // add clipped geometry
898 aFilling.setPath(tools::PolyPolygon(aResult));
899 addSvtGraphicFill(aFilling, aTarget);
900 bDone = true;
901 }
902 }
903 else
904 {
905 // exchange with empty polygon
906 aFilling.setPath(tools::PolyPolygon());
907 addSvtGraphicFill(aFilling, aTarget);
908 bDone = true;
909 }
910 }
911 }
912 else if(rComment.equalsIgnoreAsciiCase("XPATHSTROKE_SEQ_BEGIN"))
913 {
914 SvtGraphicStroke aStroke;
915 tools::Polygon aPath;
916
917 { // read SvtGraphicFill
918 SvMemoryStream aMemStm(const_cast<sal_uInt8 *>(pA->GetData()), pA->GetDataSize(),StreamMode::READ);
919 ReadSvtGraphicStroke( aMemStm, aStroke );
920 }
921
922 aStroke.getPath(aPath);
923
924 if(aPath.GetSize())
925 {
926 const basegfx::B2DPolygon aSource(aPath.getB2DPolygon());
927 const basegfx::B2DPolyPolygon aResult(
929 aSource,
930 aClips.back(),
931 true, // inside
932 true)); // stroke
933
934 if(aResult.count())
935 {
936 if(aResult.count() > 1 || aResult.getB2DPolygon(0) != aSource)
937 {
938 // add clipped geometry
939 for(auto const& rB2DPolygon : aResult)
940 {
941 aStroke.setPath(tools::Polygon(rB2DPolygon));
942 addSvtGraphicStroke(aStroke, aTarget);
943 }
944
945 bDone = true;
946 }
947 }
948 else
949 {
950 // exchange with empty polygon
951 aStroke.setPath(tools::Polygon());
952 addSvtGraphicStroke(aStroke, aTarget);
953 bDone = true;
954 }
955
956 }
957 }
958 break;
959 }
960
961 // need to handle gradient fills (hopefully only unrotated ones)
962
964 {
965 const MetaGradientAction* pA = static_cast< const MetaGradientAction* >(pAction);
966 const tools::Rectangle& rRect = pA->GetRect();
967
968 if(rRect.IsEmpty())
969 {
970 bDone = true;
971 }
972 else
973 {
974 bDone = handleGradientContent(
975 aClips.back(),
979 pA->GetGradient(),
980 aTarget);
981 }
982
983 break;
984 }
985
987 {
988 const MetaGradientExAction* pA = static_cast< const MetaGradientExAction* >(pAction);
989 const tools::PolyPolygon& rPolyPoly = pA->GetPolyPolygon();
990
991 bDone = handleGradientContent(
992 aClips.back(),
993 rPolyPoly.getB2DPolyPolygon(),
994 pA->GetGradient(),
995 aTarget);
996 break;
997 }
998
999 // not (yet) supported actions
1000
1001 // MetaActionType::NONE
1002 // MetaActionType::TEXT
1003 // MetaActionType::TEXTARRAY
1004 // MetaActionType::STRETCHTEXT
1005 // MetaActionType::TEXTRECT
1006 // MetaActionType::MASK
1007 // MetaActionType::MASKSCALE
1008 // MetaActionType::MASKSCALEPART
1009 // MetaActionType::HATCH
1010 // MetaActionType::WALLPAPER
1011 // MetaActionType::FILLCOLOR
1012 // MetaActionType::TEXTCOLOR
1013 // MetaActionType::TEXTFILLCOLOR
1014 // MetaActionType::TEXTALIGN
1015 // MetaActionType::MAPMODE
1016 // MetaActionType::FONT
1017 // MetaActionType::Transparent
1018 // MetaActionType::EPS
1019 // MetaActionType::REFPOINT
1020 // MetaActionType::TEXTLINECOLOR
1021 // MetaActionType::TEXTLINE
1022 // MetaActionType::FLOATTRANSPARENT
1023 // MetaActionType::LAYOUTMODE
1024 // MetaActionType::TEXTLANGUAGE
1025 // MetaActionType::OVERLINECOLOR
1026
1027 // if an action is not handled at all, it will simply get copied to the
1028 // target (see below). This is the default for all non-implemented actions
1029 default:
1030 {
1031 break;
1032 }
1033 }
1034 }
1035
1036 if(bDone)
1037 {
1038 bChanged = true;
1039 }
1040 else
1041 {
1042 aTarget.AddAction(const_cast< MetaAction* >(pAction));
1043 }
1044 }
1045
1046 if(bChanged)
1047 {
1048 // when changed, copy back and do not forget to set MapMode
1049 // and PrefSize
1050 aTarget.SetPrefMapMode(rSource.GetPrefMapMode());
1051 aTarget.SetPrefSize(rSource.GetPrefSize());
1052 rSource = aTarget;
1053 }
1054}
1055
1056bool usesClipActions(const GDIMetaFile& rSource)
1057{
1058 const sal_uLong nObjCount(rSource.GetActionSize());
1059
1060 for(sal_uLong i(0); i < nObjCount; ++i)
1061 {
1062 const MetaAction* pAction(rSource.GetAction(i));
1063 const MetaActionType nType(pAction->GetType());
1064
1065 switch(nType)
1066 {
1071 {
1072 return true;
1073 }
1074
1075 default: break;
1076 }
1077 }
1078
1079 return false;
1080}
1081
1082MetafileAccessor::~MetafileAccessor()
1083{
1084}
1085
1086/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Bitmap const & GetBitmap() const
Definition: alpha.cxx:77
static OutputDevice * GetDefaultDevice()
Get the default "device" (in this case the default window).
Definition: svapp.cxx:1043
const AlphaMask & GetAlphaMask() const
Definition: bitmapex.hxx:71
bool IsAlpha() const
Definition: BitmapEx.cxx:207
bool IsEmpty() const
Definition: BitmapEx.cxx:186
Bitmap GetBitmap(Color aTransparentReplaceColor) const
Definition: BitmapEx.cxx:217
const MapMode & GetPrefMapMode() const
Definition: bitmapex.hxx:79
bool Crop(const tools::Rectangle &rRectPixel)
Crop the bitmap.
Definition: BitmapEx.cxx:363
const Size & GetPrefSize() const
Definition: bitmapex.hxx:76
const Size & GetSizePixel() const
Definition: bitmapex.hxx:73
bool Crop(const tools::Rectangle &rRectPixel)
Crop the bitmap.
const MapMode & GetPrefMapMode() const
bool IsEmpty() const
const Size & GetPrefSize() const
size_t GetActionSize() const
Definition: gdimtf.cxx:181
const Size & GetPrefSize() const
Definition: gdimtf.hxx:176
MetaAction * GetAction(size_t nAction) const
Definition: gdimtf.cxx:186
void AddAction(const rtl::Reference< MetaAction > &pAction)
Definition: gdimtf.cxx:585
void SetPrefMapMode(const MapMode &rMapMode)
Definition: gdimtf.hxx:180
const MapMode & GetPrefMapMode() const
Definition: gdimtf.hxx:179
void SetPrefSize(const Size &rSize)
Definition: gdimtf.hxx:177
MapUnit GetMapUnit() const
Definition: mapmod.cxx:181
MetaActionType GetType() const
Definition: metaact.hxx:96
const Point & GetStartPoint() const
Definition: metaact.hxx:308
const tools::Rectangle & GetRect() const
Definition: metaact.hxx:307
const Point & GetEndPoint() const
Definition: metaact.hxx:309
const Bitmap & GetBitmap() const
Definition: metaact.hxx:693
const Point & GetPoint() const
Definition: metaact.hxx:694
const BitmapEx & GetBitmapEx() const
Definition: metaact.hxx:798
const Point & GetPoint() const
Definition: metaact.hxx:799
const Size & GetSize() const
Definition: metaact.hxx:833
const Point & GetPoint() const
Definition: metaact.hxx:832
const BitmapEx & GetBitmapEx() const
Definition: metaact.hxx:831
const Point & GetSrcPoint() const
Definition: metaact.hxx:872
const Size & GetDestSize() const
Definition: metaact.hxx:871
const Point & GetDestPoint() const
Definition: metaact.hxx:870
const Size & GetSrcSize() const
Definition: metaact.hxx:873
const BitmapEx & GetBitmapEx() const
Definition: metaact.hxx:869
const Point & GetPoint() const
Definition: metaact.hxx:726
const Size & GetSize() const
Definition: metaact.hxx:727
const Bitmap & GetBitmap() const
Definition: metaact.hxx:725
const Bitmap & GetBitmap() const
Definition: metaact.hxx:762
const Point & GetDestPoint() const
Definition: metaact.hxx:763
const Point & GetSrcPoint() const
Definition: metaact.hxx:765
const Size & GetSrcSize() const
Definition: metaact.hxx:766
const Size & GetDestSize() const
Definition: metaact.hxx:764
const tools::Rectangle & GetRect() const
Definition: metaact.hxx:375
const Point & GetStartPoint() const
Definition: metaact.hxx:376
const Point & GetEndPoint() const
Definition: metaact.hxx:377
const vcl::Region & GetRegion() const
Definition: metaact.hxx:1142
bool IsClipping() const
Definition: metaact.hxx:1143
const sal_uInt8 * GetData() const
Definition: metaact.hxx:1712
const OString & GetComment() const
Definition: metaact.hxx:1709
sal_uInt32 GetDataSize() const
Definition: metaact.hxx:1711
const tools::Rectangle & GetRect() const
Definition: metaact.hxx:277
const tools::Rectangle & GetRect() const
Definition: metaact.hxx:1022
const Gradient & GetGradient() const
Definition: metaact.hxx:1023
const tools::PolyPolygon & GetPolyPolygon() const
Definition: metaact.hxx:1052
const Gradient & GetGradient() const
Definition: metaact.hxx:1053
const tools::Rectangle & GetRect() const
Definition: metaact.hxx:1171
const vcl::Region & GetRegion() const
Definition: metaact.hxx:1198
const Point & GetEndPoint() const
Definition: metaact.hxx:186
const Point & GetStartPoint() const
Definition: metaact.hxx:185
const MapMode & GetMapMode() const
Definition: metaact.hxx:1438
tools::Long GetVertMove() const
Definition: metaact.hxx:1226
tools::Long GetHorzMove() const
Definition: metaact.hxx:1225
const Point & GetEndPoint() const
Definition: metaact.hxx:343
const Point & GetStartPoint() const
Definition: metaact.hxx:342
const tools::Rectangle & GetRect() const
Definition: metaact.hxx:341
const Point & GetPoint() const
Definition: metaact.hxx:126
const Point & GetPoint() const
Definition: metaact.hxx:154
const tools::Polygon & GetPolygon() const
Definition: metaact.hxx:408
const tools::PolyPolygon & GetPolyPolygon() const
Definition: metaact.hxx:464
const tools::Polygon & GetPolygon() const
Definition: metaact.hxx:437
vcl::PushFlags GetFlags() const
Definition: metaact.hxx:1497
const tools::Rectangle & GetRect() const
Definition: metaact.hxx:216
sal_uInt32 GetHorzRound() const
Definition: metaact.hxx:247
sal_uInt32 GetVertRound() const
Definition: metaact.hxx:248
const tools::Rectangle & GetRect() const
Definition: metaact.hxx:246
SAL_WARN_UNUSED_RESULT Point PixelToLogic(const Point &rDevicePt) const
Definition: map.cxx:1110
SAL_WARN_UNUSED_RESULT Point LogicToLogic(const Point &rPtSource, const MapMode *pMapModeSource, const MapMode *pMapModeDest) const
Definition: map.cxx:1580
constexpr tools::Long Y() const
constexpr tools::Long X() const
constexpr tools::Long Height() const
constexpr tools::Long Width() const
const void * GetData()
virtual sal_uInt64 TellEnd() override
Encapsulates geometry and associated attributes of a filled area.
void getPath(tools::PolyPolygon &) const
Query path to fill.
void setPath(const tools::PolyPolygon &rPath)
Set path to fill.
Encapsulates geometry and associated attributes of a graphical 'pen stroke'.
void getPath(tools::Polygon &) const
Query path to stroke.
void setPath(const tools::Polygon &)
Set path to stroke.
void translate(double fX, double fY)
void scale(double fX, double fY)
B2DPolygon const & getB2DPolygon(sal_uInt32 nIndex) const
void append(const B2DPolygon &rPolygon, sal_uInt32 nCount=1)
sal_uInt32 count() const
void append(const basegfx::B2DPoint &rPoint, sal_uInt32 nCount)
B2DPoint getCenter() const
TYPE getWidth() const
TYPE getHeight() const
sal_uInt16 Count() const
::basegfx::B2DPolyPolygon getB2DPolyPolygon() const
::basegfx::B2DPolygon getB2DPolygon() const
sal_uInt16 GetSize() const
constexpr bool IsEmpty() const
basegfx::B2DPolyPolygon GetAsB2DPolyPolygon() const
Definition: region.cxx:1294
bool IsEmpty() const
Definition: region.cxx:229
FilterGroup & rTarget
bool usesClipActions(const GDIMetaFile &rSource)
void clipMetafileContentAgainstOwnRegions(GDIMetaFile &rSource)
SvStream & WriteSvtGraphicFill(SvStream &rOStm, const SvtGraphicFill &rClass)
SvStream & ReadSvtGraphicStroke(SvStream &rIStm, SvtGraphicStroke &rClass)
SvStream & ReadSvtGraphicFill(SvStream &rIStm, SvtGraphicFill &rClass)
SvStream & WriteSvtGraphicStroke(SvStream &rOStm, const SvtGraphicStroke &rClass)
MetaActionType
bool more(const T &rfValA, const T &rfValB)
double getArea(const B2DPolygon &rCandidate)
B2DPolygon createPolygonFromRect(const B2DRectangle &rRect, double fRadiusX, double fRadiusY)
B2DPolyPolygon clipPolyPolygonOnRange(const B2DPolyPolygon &rCandidate, const B2DRange &rRange, bool bInside, bool bStroke)
bool isInside(const B2DPolygon &rCandidate, const B2DPoint &rPoint, bool bWithBorder)
B2DPolyPolygon clipPolyPolygonOnPolyPolygon(const B2DPolyPolygon &rCandidate, const B2DPolyPolygon &rClip, bool bInside, bool bStroke, size_t *pPointLimit)
B2DPolyPolygon clipPolygonOnPolyPolygon(const B2DPolygon &rCandidate, const B2DPolyPolygon &rClip, bool bInside, bool bStroke)
B2DHomMatrix createTranslateB2DHomMatrix(double fTranslateX, double fTranslateY)
B2DPolygon createPolygonFromEllipse(const B2DPoint &rCenter, double fRadiusX, double fRadiusY, sal_uInt32 nStartQuadrant=0)
B2IRange fround(const B2DRange &rRange)
int i
long Long
basegfx::B2DRange b2DRectangleFromRectangle(const ::tools::Rectangle &rRect)
PushFlags
Definition: State.hxx:40
QPRO_FUNC_TYPE nType
sal_uIntPtr sal_uLong
unsigned char sal_uInt8