LibreOffice Module drawinglayer (master) 1
wmfemfhelper.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
20#include <wmfemfhelper.hxx>
22#include <vcl/lineinfo.hxx>
23#include <vcl/metaact.hxx>
35#include <vcl/BitmapPalette.hxx>
49#include <sal/log.hxx>
50#include <tools/fract.hxx>
51#include <tools/stream.hxx>
53#include <vcl/canvastools.hxx>
54#include <vcl/gradient.hxx>
55#include <vcl/hatch.hxx>
56#include <vcl/outdev.hxx>
58#include <emfplushelper.hxx>
59#include <numeric>
61
63{
64 namespace {
65
76 class NonOverlappingFillGradientPrimitive2D : public FillGradientPrimitive2D
77 {
78 protected:
80 virtual void create2DDecomposition(Primitive2DContainer& rContainer,
81 const geometry::ViewInformation2D& rViewInformation) const override;
82
83 public:
85 NonOverlappingFillGradientPrimitive2D(
86 const basegfx::B2DRange& rObjectRange,
87 const attribute::FillGradientAttribute& rFillGradient)
88 : FillGradientPrimitive2D(rObjectRange, rFillGradient)
89 {
90 }
91 };
92
93 }
94
95 void NonOverlappingFillGradientPrimitive2D::create2DDecomposition(
96 Primitive2DContainer& rContainer,
97 const geometry::ViewInformation2D& /*rViewInformation*/) const
98 {
99 if (!getFillGradient().isDefault())
100 {
101 createFill(rContainer, false);
102 }
103 }
104
105} // end of namespace
106
108{
116 : maMapUnit(MapUnit::Map100thMM),
117 maTextColor(sal_uInt32(COL_BLACK)),
118 maRasterOp(RasterOp::OverPaint),
119 mnLayoutMode(vcl::text::ComplexTextLayoutFlags::Default),
120 maLanguageType(0),
121 mnPushFlags(vcl::PushFlags::NONE),
122 mbLineColor(false),
123 mbFillColor(false),
124 mbTextColor(true),
125 mbTextFillColor(false),
126 mbTextLineColor(false),
127 mbOverlineColor(false),
128 mbClipPolyPolygonActive(false)
129 {
130 }
131}
132
133namespace wmfemfhelper
134{
145 {
146 maPropertyHolders.push_back(new PropertyHolder());
147 }
148
150 {
151 PropertyHolder* pNew = new PropertyHolder();
152 maPropertyHolders.push_back(pNew);
153 }
154
156 {
157 if (bool(nPushFlags))
158 {
159 OSL_ENSURE(maPropertyHolders.size(), "PropertyHolders: PUSH with no property holders (!)");
160 if (!maPropertyHolders.empty())
161 {
163 pNew->setPushFlags(nPushFlags);
164 maPropertyHolders.push_back(pNew);
165 }
166 }
167 }
168
170 {
171 OSL_ENSURE(maPropertyHolders.size(), "PropertyHolders: POP with no property holders (!)");
172 const sal_uInt32 nSize(maPropertyHolders.size());
173
174 if (!nSize)
175 return;
176
177 const PropertyHolder* pTip = maPropertyHolders.back();
178 const vcl::PushFlags nPushFlags(pTip->getPushFlags());
179
180 if (nPushFlags != vcl::PushFlags::NONE)
181 {
182 if (nSize > 1)
183 {
184 // copy back content for all non-set flags
185 PropertyHolder* pLast = maPropertyHolders[nSize - 2];
186
187 if (vcl::PushFlags::ALL != nPushFlags)
188 {
189 if (!(nPushFlags & vcl::PushFlags::LINECOLOR))
190 {
191 pLast->setLineColor(pTip->getLineColor());
193 }
194 if (!(nPushFlags & vcl::PushFlags::FILLCOLOR))
195 {
196 pLast->setFillColor(pTip->getFillColor());
198 }
199 if (!(nPushFlags & vcl::PushFlags::FONT))
200 {
201 pLast->setFont(pTip->getFont());
202 }
203 if (!(nPushFlags & vcl::PushFlags::TEXTCOLOR))
204 {
205 pLast->setTextColor(pTip->getTextColor());
207 }
208 if (!(nPushFlags & vcl::PushFlags::MAPMODE))
209 {
210 pLast->setTransformation(pTip->getTransformation());
211 pLast->setMapUnit(pTip->getMapUnit());
212 }
213 if (!(nPushFlags & vcl::PushFlags::CLIPREGION))
214 {
217 }
218 if (!(nPushFlags & vcl::PushFlags::RASTEROP))
219 {
220 pLast->setRasterOp(pTip->getRasterOp());
221 }
222 if (!(nPushFlags & vcl::PushFlags::TEXTFILLCOLOR))
223 {
224 pLast->setTextFillColor(pTip->getTextFillColor());
226 }
227 if (!(nPushFlags & vcl::PushFlags::TEXTALIGN))
228 {
229 if (pLast->getFont().GetAlignment() != pTip->getFont().GetAlignment())
230 {
231 vcl::Font aFont(pLast->getFont());
232 aFont.SetAlignment(pTip->getFont().GetAlignment());
233 pLast->setFont(aFont);
234 }
235 }
236 if (!(nPushFlags & vcl::PushFlags::REFPOINT))
237 {
238 // not supported
239 }
240 if (!(nPushFlags & vcl::PushFlags::TEXTLINECOLOR))
241 {
242 pLast->setTextLineColor(pTip->getTextLineColor());
244 }
245 if (!(nPushFlags & vcl::PushFlags::TEXTLAYOUTMODE))
246 {
247 pLast->setLayoutMode(pTip->getLayoutMode());
248 }
249 if (!(nPushFlags & vcl::PushFlags::TEXTLANGUAGE))
250 {
251 pLast->setLanguageType(pTip->getLanguageType());
252 }
253 if (!(nPushFlags & vcl::PushFlags::OVERLINECOLOR))
254 {
255 pLast->setOverlineColor(pTip->getOverlineColor());
257 }
258 }
259 }
260 }
261
262 // execute the pop
263 delete maPropertyHolders.back();
264 maPropertyHolders.pop_back();
265 }
266
268 {
269 static PropertyHolder aDummy;
270 OSL_ENSURE(maPropertyHolders.size(), "PropertyHolders: CURRENT with no property holders (!)");
271 return maPropertyHolders.empty() ? aDummy : *maPropertyHolders.back();
272 }
273
275 {
276 while (!maPropertyHolders.empty())
277 {
278 delete maPropertyHolders.back();
279 maPropertyHolders.pop_back();
280 }
281 }
282}
283
284namespace
285{
293 basegfx::B2DPolyPolygon getB2DPolyPolygonFromRegion(const vcl::Region& rRegion)
294 {
296
297 if (!rRegion.IsEmpty())
298 {
299 aRetval = rRegion.GetAsB2DPolyPolygon();
300 }
301
302 return aRetval;
303 }
304}
305
306namespace wmfemfhelper
307{
315 {
316 }
317
319 {
320 }
321
322 sal_uInt32 TargetHolder::size() const
323 {
324 return aTargets.size();
325 }
326
328 {
329 if (pCandidate)
330 {
331 aTargets.push_back(pCandidate);
332 }
333 }
334
336 {
338
339
340 if (!xRetval.empty() && rPropertyHolder.getClipPolyPolygonActive())
341 {
342 const basegfx::B2DPolyPolygon& rClipPolyPolygon = rPropertyHolder.getClipPolyPolygon();
343
344 if (rClipPolyPolygon.count())
345 {
348 rClipPolyPolygon,
349 std::move(xRetval)));
350
352 }
353 }
354
355 return xRetval;
356 }
357}
358
359namespace wmfemfhelper
360{
363 {
364 maTargetHolders.push_back(new TargetHolder());
365 }
366
367 sal_uInt32 TargetHolders::size() const
368 {
369 return maTargetHolders.size();
370 }
371
373 {
374 maTargetHolders.push_back(new TargetHolder());
375 }
376
378 {
379 OSL_ENSURE(maTargetHolders.size(), "TargetHolders: POP with no property holders (!)");
380 if (!maTargetHolders.empty())
381 {
382 delete maTargetHolders.back();
383 maTargetHolders.pop_back();
384 }
385 }
386
388 {
389 static TargetHolder aDummy;
390 OSL_ENSURE(maTargetHolders.size(), "TargetHolders: CURRENT with no property holders (!)");
391 return maTargetHolders.empty() ? aDummy : *maTargetHolders.back();
392 }
393
395 {
396 while (!maTargetHolders.empty())
397 {
398 delete maTargetHolders.back();
399 maTargetHolders.pop_back();
400 }
401 }
402}
403
404namespace
405{
407 basegfx::B2DHomMatrix getTransformFromMapMode(const MapMode& rMapMode)
408 {
409 basegfx::B2DHomMatrix aMapping;
410 const Fraction aNoScale(1, 1);
411 const Point& rOrigin(rMapMode.GetOrigin());
412
413 if(0 != rOrigin.X() || 0 != rOrigin.Y())
414 {
415 aMapping.translate(rOrigin.X(), rOrigin.Y());
416 }
417
418 if(rMapMode.GetScaleX() != aNoScale || rMapMode.GetScaleY() != aNoScale)
419 {
420 aMapping.scale(
421 double(rMapMode.GetScaleX()),
422 double(rMapMode.GetScaleY()));
423 }
424
425 return aMapping;
426 }
427}
428
429namespace wmfemfhelper
430{
433 std::vector< basegfx::B2DPoint >&& rPositions,
434 TargetHolder& rTarget,
435 PropertyHolder const & rProperties,
436 const basegfx::BColor& rBColor)
437 {
438 if(rPositions.empty())
439 return;
440
441 if(rProperties.getTransformation().isIdentity())
442 {
443 rTarget.append(
445 std::move(rPositions),
446 rBColor));
447 }
448 else
449 {
450 for(basegfx::B2DPoint & aPosition : rPositions)
451 {
452 aPosition = rProperties.getTransformation() * aPosition;
453 }
454
455 rTarget.append(
457 std::move(rPositions),
458 rBColor));
459 }
460 }
461
464 const basegfx::B2DPolygon& rLinePolygon,
465 TargetHolder& rTarget,
466 PropertyHolder const & rProperties)
467 {
468 if(rLinePolygon.count())
469 {
470 basegfx::B2DPolygon aLinePolygon(rLinePolygon);
471 aLinePolygon.transform(rProperties.getTransformation());
472 rTarget.append(
474 std::move(aLinePolygon),
475 rProperties.getLineColor()));
476 }
477 }
478
481 const basegfx::B2DPolyPolygon& rFillPolyPolygon,
482 TargetHolder& rTarget,
483 PropertyHolder const & rProperties)
484 {
485 if(rFillPolyPolygon.count())
486 {
487 basegfx::B2DPolyPolygon aFillPolyPolygon(rFillPolyPolygon);
488 aFillPolyPolygon.transform(rProperties.getTransformation());
489 rTarget.append(
491 std::move(aFillPolyPolygon),
492 rProperties.getFillColor()));
493 }
494 }
495
498 const basegfx::B2DPolygon& rLinePolygon,
499 const LineInfo& rLineInfo,
500 TargetHolder& rTarget,
501 PropertyHolder const & rProperties)
502 {
503 if(!rLinePolygon.count())
504 return;
505
506 const bool bDashDotUsed(LineStyle::Dash == rLineInfo.GetStyle());
507 const bool bWidthUsed(rLineInfo.GetWidth() > 1);
508
509 if(bDashDotUsed || bWidthUsed)
510 {
511 basegfx::B2DPolygon aLinePolygon(rLinePolygon);
512 aLinePolygon.transform(rProperties.getTransformation());
514 rProperties.getLineColor(),
515 bWidthUsed ? rLineInfo.GetWidth() : 0.0,
516 rLineInfo.GetLineJoin(),
517 rLineInfo.GetLineCap());
518
519 if(bDashDotUsed)
520 {
521 std::vector< double > fDotDashArray = rLineInfo.GetDotDashArray();
522 const double fAccumulated(std::accumulate(fDotDashArray.begin(), fDotDashArray.end(), 0.0));
524 std::move(fDotDashArray),
525 fAccumulated);
526
527 rTarget.append(
529 std::move(aLinePolygon),
530 std::move(aLineAttribute),
531 std::move(aStrokeAttribute)));
532 }
533 else
534 {
535 rTarget.append(
537 std::move(aLinePolygon),
538 aLineAttribute));
539 }
540 }
541 else
542 {
543 createHairlinePrimitive(rLinePolygon, rTarget, rProperties);
544 }
545 }
546
549 const basegfx::B2DPolygon& rPolygon,
550 TargetHolder& rTarget,
551 PropertyHolder const & rProperties)
552 {
553 if(rProperties.getFillColorActive())
554 {
555 createFillPrimitive(basegfx::B2DPolyPolygon(rPolygon), rTarget, rProperties);
556 }
557
558 if(rProperties.getLineColorActive())
559 {
560 createHairlinePrimitive(rPolygon, rTarget, rProperties);
561 }
562 }
563
566 const basegfx::B2DPolyPolygon& rPolyPolygon,
567 TargetHolder& rTarget,
568 PropertyHolder const & rProperties)
569 {
570 if(rProperties.getFillColorActive())
571 {
572 createFillPrimitive(rPolyPolygon, rTarget, rProperties);
573 }
574
575 if(rProperties.getLineColorActive())
576 {
577 for(sal_uInt32 a(0); a < rPolyPolygon.count(); a++)
578 {
579 createHairlinePrimitive(rPolyPolygon.getB2DPolygon(a), rTarget, rProperties);
580 }
581 }
582 }
583
591 const BitmapEx& rBitmapEx,
592 const Point& rPoint,
593 TargetHolder& rTarget,
594 PropertyHolder const & rProperties)
595 {
596 if(!rBitmapEx.IsEmpty())
597 {
598 basegfx::B2DPoint aPoint(rPoint.X(), rPoint.Y());
599 aPoint = rProperties.getTransformation() * aPoint;
600
601 rTarget.append(
603 rBitmapEx,
604 aPoint));
605 }
606 }
607
610 const BitmapEx& rBitmapEx,
611 const Point& rPoint,
612 const Size& rSize,
613 TargetHolder& rTarget,
614 PropertyHolder const & rProperties)
615 {
616 if(rBitmapEx.IsEmpty())
617 return;
618
619 basegfx::B2DHomMatrix aObjectTransform;
620
621 aObjectTransform.set(0, 0, rSize.Width());
622 aObjectTransform.set(1, 1, rSize.Height());
623 aObjectTransform.set(0, 2, rPoint.X());
624 aObjectTransform.set(1, 2, rPoint.Y());
625
626 aObjectTransform = rProperties.getTransformation() * aObjectTransform;
627
628 rTarget.append(
630 rBitmapEx,
631 aObjectTransform));
632 }
633
638 static BitmapEx createMaskBmpEx(const Bitmap& rBitmap, const Color& rMaskColor)
639 {
640 const Color aWhite(COL_WHITE);
641 BitmapPalette aBiLevelPalette {
642 aWhite, rMaskColor
643 };
644
645 Bitmap aMask(rBitmap.CreateMask(aWhite));
646 Bitmap aSolid(rBitmap.GetSizePixel(), vcl::PixelFormat::N8_BPP, &aBiLevelPalette);
647
648 aSolid.Erase(rMaskColor);
649
650 return BitmapEx(aSolid, aMask);
651 }
652
657 {
658 const Color aStartColor(rGradient.GetStartColor());
659 const sal_uInt16 nStartIntens(rGradient.GetStartIntensity());
660 basegfx::BColor aStart(aStartColor.getBColor());
661
662 if(nStartIntens != 100)
663 {
664 const basegfx::BColor aBlack;
665 aStart = interpolate(aBlack, aStart, static_cast<double>(nStartIntens) * 0.01);
666 }
667
668 const Color aEndColor(rGradient.GetEndColor());
669 const sal_uInt16 nEndIntens(rGradient.GetEndIntensity());
670 basegfx::BColor aEnd(aEndColor.getBColor());
671
672 if(nEndIntens != 100)
673 {
674 const basegfx::BColor aBlack;
675 aEnd = interpolate(aBlack, aEnd, static_cast<double>(nEndIntens) * 0.01);
676 }
677
679 rGradient.GetStyle(),
680 static_cast<double>(rGradient.GetBorder()) * 0.01,
681 static_cast<double>(rGradient.GetOfsX()) * 0.01,
682 static_cast<double>(rGradient.GetOfsY()) * 0.01,
683 toRadians(rGradient.GetAngle()),
684 basegfx::BColorStops(aStart, aEnd),
685 rGradient.GetSteps());
686 }
687
692 {
694
695 switch(rHatch.GetStyle())
696 {
697 default : // case HatchStyle::Single :
698 {
700 break;
701 }
702 case HatchStyle::Double :
703 {
705 break;
706 }
707 case HatchStyle::Triple :
708 {
710 break;
711 }
712 }
713
715 aHatchStyle,
716 static_cast<double>(rHatch.GetDistance()),
717 toRadians(rHatch.GetAngle()),
718 rHatch.GetColor().getBColor(),
719 3, // same default as VCL, a minimum of three discrete units (pixels) offset
720 false);
721 }
722
730 const basegfx::B2DPolyPolygon& rClipPolyPolygon,
731 TargetHolders& rTargetHolders,
732 PropertyHolders& rPropertyHolders)
733 {
734 const bool bNewActive(rClipPolyPolygon.count());
735
736 // #i108636# The handling of new ClipPolyPolygons was not done as good as possible
737 // in the first version of this interpreter; e.g. when a ClipPolyPolygon was set
738 // initially and then using a lot of push/pop actions, the pop always leads
739 // to setting a 'new' ClipPolyPolygon which indeed is the return to the ClipPolyPolygon
740 // of the properties next on the stack.
741
742 // This ClipPolyPolygon is identical to the current one, so there is no need to
743 // create a MaskPrimitive2D containing the up-to-now created primitives, but
744 // this was done before. While this does not lead to wrong primitive
745 // representations of the metafile data, it creates unnecessarily expensive
746 // representations. Just detecting when no really 'new' ClipPolyPolygon gets set
747 // solves the problem.
748
749 if(!rPropertyHolders.Current().getClipPolyPolygonActive() && !bNewActive)
750 {
751 // no active ClipPolyPolygon exchanged by no new one, done
752 return;
753 }
754
755 if(rPropertyHolders.Current().getClipPolyPolygonActive() && bNewActive)
756 {
757 // active ClipPolyPolygon and new active ClipPolyPolygon
758 if(rPropertyHolders.Current().getClipPolyPolygon() == rClipPolyPolygon)
759 {
760 // new is the same as old, done
761 return;
762 }
763 }
764
765 // Here the old and the new are definitively different, maybe
766 // old one and/or new one is not active.
767
768 // Handle deletion of old ClipPolyPolygon. The process evtl. created primitives which
769 // belong to this active ClipPolyPolygon. These need to be embedded to a
770 // MaskPrimitive2D accordingly.
771 if(rPropertyHolders.Current().getClipPolyPolygonActive() && rTargetHolders.size() > 1)
772 {
774
775 if(rPropertyHolders.Current().getClipPolyPolygon().count()
776 && rTargetHolders.Current().size())
777 {
778 aSubContent = rTargetHolders.Current().getPrimitive2DSequence(
779 rPropertyHolders.Current());
780 }
781
782 rTargetHolders.Pop();
783
784 if(!aSubContent.empty())
785 {
786 rTargetHolders.Current().append(
788 std::move(aSubContent)));
789 }
790 }
791
792 // apply new settings to current properties by setting
793 // the new region now
794 rPropertyHolders.Current().setClipPolyPolygonActive(bNewActive);
795
796 if(bNewActive)
797 {
798 rPropertyHolders.Current().setClipPolyPolygon(rClipPolyPolygon);
799
800 // prepare new content holder for new active region
801 rTargetHolders.Push();
802 }
803 }
804
811 static void HandleNewRasterOp(
812 RasterOp aRasterOp,
813 TargetHolders& rTargetHolders,
814 PropertyHolders& rPropertyHolders)
815 {
816 // check if currently active
817 if(rPropertyHolders.Current().isRasterOpActive() && rTargetHolders.size() > 1)
818 {
820
821 if(rTargetHolders.Current().size())
822 {
823 aSubContent = rTargetHolders.Current().getPrimitive2DSequence(rPropertyHolders.Current());
824 }
825
826 rTargetHolders.Pop();
827
828 if(!aSubContent.empty())
829 {
830 if(rPropertyHolders.Current().isRasterOpForceBlack())
831 {
832 // force content to black
833 rTargetHolders.Current().append(
835 std::move(aSubContent),
836 std::make_shared<basegfx::BColorModifier_replace>(
837 basegfx::BColor(0.0, 0.0, 0.0))));
838 }
839 else // if(rPropertyHolders.Current().isRasterOpInvert())
840 {
841 // invert content
842 rTargetHolders.Current().append(
844 std::move(aSubContent)));
845 }
846 }
847 }
848
849 // apply new settings
850 rPropertyHolders.Current().setRasterOp(aRasterOp);
851
852 // check if now active
853 if(rPropertyHolders.Current().isRasterOpActive())
854 {
855 // prepare new content holder for new invert
856 rTargetHolders.Push();
857 }
858 }
859
864 const basegfx::B2DRange& rRange,
865 const basegfx::BColor& rColor,
866 PropertyHolder const & rPropertyHolder)
867 {
869 aOutline.transform(rPropertyHolder.getTransformation());
870
872 basegfx::B2DPolyPolygon(aOutline),
873 rColor);
874 }
875
880 const basegfx::B2DRange& rRange,
881 const Gradient& rGradient,
882 PropertyHolder const & rPropertyHolder)
883 {
885 basegfx::BColor aSingleColor;
886
887 if (aAttribute.getColorStops().isSingleColor(aSingleColor))
888 {
889 // not really a gradient. Create filled rectangle
890 return CreateColorWallpaper(rRange, aSingleColor, rPropertyHolder);
891 }
892 else
893 {
894 // really a gradient
897 rRange,
898 std::move(aAttribute)));
899
900 if(!rPropertyHolder.getTransformation().isIdentity())
901 {
904
906 rPropertyHolder.getTransformation(),
907 std::move(xSeq));
908 }
909
910 return pRetval;
911 }
912 }
913
921 basegfx::B2DRange aWallpaperRange,
922 const Wallpaper& rWallpaper,
923 TargetHolder& rTarget,
924 PropertyHolder const & rProperty)
925 {
926 const BitmapEx aBitmapEx(rWallpaper.GetBitmap());
927 const WallpaperStyle eWallpaperStyle(rWallpaper.GetStyle());
928
929 // if bitmap visualisation is transparent, maybe background
930 // needs to be filled. Create background
931 if(aBitmapEx.IsAlpha()
932 || (WallpaperStyle::Tile != eWallpaperStyle && WallpaperStyle::Scale != eWallpaperStyle))
933 {
934 if(rWallpaper.IsGradient())
935 {
936 rTarget.append(
938 aWallpaperRange,
939 rWallpaper.GetGradient(),
940 rProperty));
941 }
942 else if(!rWallpaper.GetColor().IsTransparent())
943 {
944 rTarget.append(
946 aWallpaperRange,
947 rWallpaper.GetColor().getBColor(),
948 rProperty));
949 }
950 }
951
952 // use wallpaper rect if set
953 if(rWallpaper.IsRect() && !rWallpaper.GetRect().IsEmpty())
954 {
955 aWallpaperRange = vcl::unotools::b2DRectangleFromRectangle(rWallpaper.GetRect());
956 }
957
960 aWallpaperRange,
961 aBitmapEx,
962 eWallpaperStyle);
963
964 if(rProperty.getTransformation().isIdentity())
965 {
966 // add directly
967 rTarget.append(pBitmapWallpaperFill);
968 }
969 else
970 {
971 // when a transformation is set, embed to it
972 const drawinglayer::primitive2d::Primitive2DReference xPrim(pBitmapWallpaperFill);
973
974 rTarget.append(
976 rProperty.getTransformation(),
978 }
979 }
980
982 static bool isUnderlineAbove(const vcl::Font& rFont)
983 {
984 if(!rFont.IsVertical())
985 {
986 return false;
987 }
988
989 // the underline is right for Japanese only
990 return (LANGUAGE_JAPANESE == rFont.GetLanguage()) || (LANGUAGE_JAPANESE == rFont.GetCJKContextLanguage());
991 }
992
995 basegfx::B2DHomMatrix& rTextTransform,
996 basegfx::B2DVector& rAlignmentOffset,
997 PropertyHolder const & rProperty)
998 {
999 const vcl::Font& rFont = rProperty.getFont();
1000 basegfx::B2DVector aFontScaling;
1001
1003 aFontScaling,
1004 rFont,
1007
1008 // add FontScaling
1009 rTextTransform.scale(aFontScaling.getX(), aFontScaling.getY());
1010
1011 // take text align into account
1012 if(ALIGN_BASELINE != rFont.GetAlignment())
1013 {
1015 aTextLayouterDevice.setFont(rFont);
1016
1017 if(ALIGN_TOP == rFont.GetAlignment())
1018 {
1019 rAlignmentOffset.setY(aTextLayouterDevice.getFontAscent());
1020 }
1021 else // ALIGN_BOTTOM
1022 {
1023 rAlignmentOffset.setY(-aTextLayouterDevice.getFontDescent());
1024 }
1025
1026 rTextTransform.translate(rAlignmentOffset.getX(), rAlignmentOffset.getY());
1027 }
1028
1029 // add FontRotation (if used)
1030 if(rFont.GetOrientation())
1031 {
1032 rTextTransform.rotate(-toRadians(rFont.GetOrientation()));
1033 }
1034 }
1035
1040 const Point& rTextStartPosition,
1041 const OUString& rText,
1042 sal_uInt16 nTextStart,
1043 sal_uInt16 nTextLength,
1044 std::vector< double >&& rDXArray,
1045 std::vector< sal_Bool >&& rKashidaArray,
1046 TargetHolder& rTarget,
1047 PropertyHolder const & rProperty)
1048 {
1050 const vcl::Font& rFont = rProperty.getFont();
1051 basegfx::B2DVector aAlignmentOffset(0.0, 0.0);
1052
1053 if(nTextLength)
1054 {
1056 basegfx::B2DHomMatrix aTextTransform;
1057
1058 // fill parameters derived from current font
1060 aFontAttribute,
1061 aTextTransform,
1062 aAlignmentOffset,
1063 rProperty);
1064
1065 // add TextStartPosition
1066 aTextTransform.translate(rTextStartPosition.X(), rTextStartPosition.Y());
1067
1068 // prepare FontColor and Locale
1069 const basegfx::BColor aFontColor(rProperty.getTextColor());
1070 const Color aFillColor(rFont.GetFillColor());
1071 css::lang::Locale aLocale(LanguageTag(rProperty.getLanguageType()).getLocale());
1072 const bool bWordLineMode(rFont.IsWordLineMode());
1073
1074 const bool bDecoratedIsNeeded(
1075 LINESTYLE_NONE != rFont.GetOverline()
1076 || LINESTYLE_NONE != rFont.GetUnderline()
1077 || STRIKEOUT_NONE != rFont.GetStrikeout()
1078 || FontEmphasisMark::NONE != (rFont.GetEmphasisMark() & FontEmphasisMark::Style)
1079 || FontRelief::NONE != rFont.GetRelief()
1080 || rFont.IsShadow()
1081 || bWordLineMode);
1082
1083 if(bDecoratedIsNeeded)
1084 {
1085 // prepare overline, underline and strikeout data
1089
1090 // check UndelineAbove
1091 const bool bUnderlineAbove(drawinglayer::primitive2d::TEXT_LINE_NONE != eFontLineStyle && isUnderlineAbove(rFont));
1092
1093 // prepare emphasis mark data
1095
1096 switch(rFont.GetEmphasisMark() & FontEmphasisMark::Style)
1097 {
1098 case FontEmphasisMark::Dot : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_FONT_EMPHASIS_MARK_DOT; break;
1099 case FontEmphasisMark::Circle : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_FONT_EMPHASIS_MARK_CIRCLE; break;
1100 case FontEmphasisMark::Disc : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_FONT_EMPHASIS_MARK_DISC; break;
1101 case FontEmphasisMark::Accent : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_FONT_EMPHASIS_MARK_ACCENT; break;
1102 default: break;
1103 }
1104
1105 const bool bEmphasisMarkAbove(rFont.GetEmphasisMark() & FontEmphasisMark::PosAbove);
1106 const bool bEmphasisMarkBelow(rFont.GetEmphasisMark() & FontEmphasisMark::PosBelow);
1107
1108 // prepare font relief data
1110
1111 switch(rFont.GetRelief())
1112 {
1113 case FontRelief::Embossed : eTextRelief = drawinglayer::primitive2d::TEXT_RELIEF_EMBOSSED; break;
1114 case FontRelief::Engraved : eTextRelief = drawinglayer::primitive2d::TEXT_RELIEF_ENGRAVED; break;
1115 default : break; // RELIEF_NONE, FontRelief_FORCE_EQUAL_SIZE
1116 }
1117
1118 // prepare shadow/outline data
1119 const bool bShadow(rFont.IsShadow());
1120
1121 // TextDecoratedPortionPrimitive2D is needed, create one
1123
1124 // attributes for TextSimplePortionPrimitive2D
1125 aTextTransform,
1126 rText,
1127 nTextStart,
1128 nTextLength,
1129 std::move(rDXArray),
1130 std::move(rKashidaArray),
1131 aFontAttribute,
1132 aLocale,
1133 aFontColor,
1134 aFillColor,
1135
1136 // attributes for TextDecoratedPortionPrimitive2D
1137 rProperty.getOverlineColorActive() ? rProperty.getOverlineColor() : aFontColor,
1138 rProperty.getTextLineColorActive() ? rProperty.getTextLineColor() : aFontColor,
1139 eFontOverline,
1140 eFontLineStyle,
1141 bUnderlineAbove,
1142 eTextStrikeout,
1143 bWordLineMode,
1144 eTextEmphasisMark,
1145 bEmphasisMarkAbove,
1146 bEmphasisMarkBelow,
1147 eTextRelief,
1148 bShadow);
1149 }
1150 else
1151 {
1152 // TextSimplePortionPrimitive2D is enough
1154 aTextTransform,
1155 rText,
1156 nTextStart,
1157 nTextLength,
1158 std::vector(rDXArray),
1159 std::vector(rKashidaArray),
1160 std::move(aFontAttribute),
1161 std::move(aLocale),
1162 aFontColor);
1163 }
1164 }
1165
1166 if(pResult && rProperty.getTextFillColorActive())
1167 {
1168 // text background is requested, add and encapsulate both to new primitive
1170 aTextLayouterDevice.setFont(rFont);
1171
1172 // get text width
1173 double fTextWidth(0.0);
1174
1175 if(rDXArray.empty())
1176 {
1177 fTextWidth = aTextLayouterDevice.getTextWidth(rText, nTextStart, nTextLength);
1178 }
1179 else
1180 {
1181 fTextWidth = rDXArray.back();
1182 }
1183
1184 if(basegfx::fTools::more(fTextWidth, 0.0))
1185 {
1186 // build text range
1187 const basegfx::B2DRange aTextRange(
1188 0.0, -aTextLayouterDevice.getFontAscent(),
1189 fTextWidth, aTextLayouterDevice.getFontDescent());
1190
1191 // create Transform
1192 basegfx::B2DHomMatrix aTextTransform;
1193
1194 aTextTransform.translate(aAlignmentOffset.getX(), aAlignmentOffset.getY());
1195
1196 if(rFont.GetOrientation())
1197 {
1198 aTextTransform.rotate(-toRadians(rFont.GetOrientation()));
1199 }
1200
1201 aTextTransform.translate(rTextStartPosition.X(), rTextStartPosition.Y());
1202
1203 // prepare Primitive2DSequence, put text in foreground
1205 aSequence[1] = pResult;
1206
1207 // prepare filled polygon
1209 aOutline.transform(aTextTransform);
1210
1213 basegfx::B2DPolyPolygon(aOutline),
1214 rProperty.getTextFillColor()));
1215
1216 // set as group at pResult
1217 pResult = new drawinglayer::primitive2d::GroupPrimitive2D(std::move(aSequence));
1218 }
1219 }
1220
1221 if(!pResult)
1222 return;
1223
1224 // add created text primitive to target
1225 if(rProperty.getTransformation().isIdentity())
1226 {
1227 rTarget.append(pResult);
1228 }
1229 else
1230 {
1231 // when a transformation is set, embed to it
1232 const drawinglayer::primitive2d::Primitive2DReference aReference(pResult);
1233
1234 rTarget.append(
1236 rProperty.getTransformation(),
1238 }
1239 }
1240
1243 const MetaTextLineAction& rAction,
1244 TargetHolder& rTarget,
1245 PropertyHolder const & rProperty)
1246 {
1247 const double fLineWidth(fabs(static_cast<double>(rAction.GetWidth())));
1248
1249 if(fLineWidth <= 0.0)
1250 return;
1251
1255
1256 const bool bOverlineUsed(drawinglayer::primitive2d::TEXT_LINE_NONE != aOverlineMode);
1257 const bool bUnderlineUsed(drawinglayer::primitive2d::TEXT_LINE_NONE != aUnderlineMode);
1258 const bool bStrikeoutUsed(drawinglayer::primitive2d::TEXT_STRIKEOUT_NONE != aTextStrikeout);
1259
1260 if(!(bUnderlineUsed || bStrikeoutUsed || bOverlineUsed))
1261 return;
1262
1264 basegfx::B2DVector aAlignmentOffset(0.0, 0.0);
1266 basegfx::B2DHomMatrix aTextTransform;
1267
1268 // fill parameters derived from current font
1270 aFontAttribute,
1271 aTextTransform,
1272 aAlignmentOffset,
1273 rProperty);
1274
1275 // add TextStartPosition
1276 aTextTransform.translate(rAction.GetStartPoint().X(), rAction.GetStartPoint().Y());
1277
1278 // prepare TextLayouter (used in most cases)
1280 aTextLayouter.setFont(rProperty.getFont());
1281
1282 if(bOverlineUsed)
1283 {
1284 // create primitive geometry for overline
1285 aTargets.push_back(
1287 aTextTransform,
1288 fLineWidth,
1289 aTextLayouter.getOverlineOffset(),
1290 aTextLayouter.getOverlineHeight(),
1291 aOverlineMode,
1292 rProperty.getOverlineColor()));
1293 }
1294
1295 if(bUnderlineUsed)
1296 {
1297 // create primitive geometry for underline
1298 aTargets.push_back(
1300 aTextTransform,
1301 fLineWidth,
1302 aTextLayouter.getUnderlineOffset(),
1303 aTextLayouter.getUnderlineHeight(),
1304 aUnderlineMode,
1305 rProperty.getTextLineColor()));
1306 }
1307
1308 if(bStrikeoutUsed)
1309 {
1310 // create primitive geometry for strikeout
1313 {
1314 // strikeout with character
1315 const sal_Unicode aStrikeoutChar(
1316 drawinglayer::primitive2d::TEXT_STRIKEOUT_SLASH == aTextStrikeout ? '/' : 'X');
1317 css::lang::Locale aLocale(LanguageTag(
1318 rProperty.getLanguageType()).getLocale());
1319
1320 aTargets.push_back(
1322 aTextTransform,
1323 fLineWidth,
1324 rProperty.getTextColor(),
1325 aStrikeoutChar,
1326 std::move(aFontAttribute),
1327 std::move(aLocale)));
1328 }
1329 else
1330 {
1331 // strikeout with geometry
1332 aTargets.push_back(
1334 aTextTransform,
1335 fLineWidth,
1336 rProperty.getTextColor(),
1337 aTextLayouter.getUnderlineHeight(),
1338 aTextLayouter.getStrikeoutOffset(),
1339 aTextStrikeout));
1340 }
1341 }
1342
1343 if(aTargets.empty())
1344 return;
1345
1346 // add created text primitive to target
1347 if(rProperty.getTransformation().isIdentity())
1348 {
1349 rTarget.append(std::move(aTargets));
1350 }
1351 else
1352 {
1353 // when a transformation is set, embed to it
1354 rTarget.append(
1356 rProperty.getTransformation(),
1357 std::move(aTargets)));
1358 }
1359 }
1360
1398 const GDIMetaFile& rMetaFile,
1399 TargetHolders& rTargetHolders,
1400 PropertyHolders& rPropertyHolders,
1401 const drawinglayer::geometry::ViewInformation2D& rViewInformation)
1402 {
1403 const size_t nCount(rMetaFile.GetActionSize());
1404 std::unique_ptr<emfplushelper::EmfPlusHelper> aEMFPlus;
1405
1406 for(size_t nAction(0); nAction < nCount; nAction++)
1407 {
1408 MetaAction* pAction = rMetaFile.GetAction(nAction);
1409
1410 switch(pAction->GetType())
1411 {
1412 case MetaActionType::NONE :
1413 {
1415 break;
1416 }
1417 case MetaActionType::PIXEL :
1418 {
1420 std::vector< basegfx::B2DPoint > aPositions;
1421 Color aLastColor(COL_BLACK);
1422
1423 while(MetaActionType::PIXEL == pAction->GetType() && nAction < nCount)
1424 {
1425 const MetaPixelAction* pA = static_cast<const MetaPixelAction*>(pAction);
1426
1427 if(pA->GetColor() != aLastColor)
1428 {
1429 if(!aPositions.empty())
1430 {
1431 createPointArrayPrimitive(std::move(aPositions), rTargetHolders.Current(), rPropertyHolders.Current(), aLastColor.getBColor());
1432 aPositions.clear();
1433 }
1434
1435 aLastColor = pA->GetColor();
1436 }
1437
1438 const Point& rPoint = pA->GetPoint();
1439 aPositions.emplace_back(rPoint.X(), rPoint.Y());
1440 nAction++; if(nAction < nCount) pAction = rMetaFile.GetAction(nAction);
1441 }
1442
1443 nAction--;
1444
1445 if(!aPositions.empty())
1446 {
1447 createPointArrayPrimitive(std::move(aPositions), rTargetHolders.Current(), rPropertyHolders.Current(), aLastColor.getBColor());
1448 }
1449
1450 break;
1451 }
1452 case MetaActionType::POINT :
1453 {
1455 if(rPropertyHolders.Current().getLineColorActive())
1456 {
1457 std::vector< basegfx::B2DPoint > aPositions;
1458
1459 while(MetaActionType::POINT == pAction->GetType() && nAction < nCount)
1460 {
1461 const MetaPointAction* pA = static_cast<const MetaPointAction*>(pAction);
1462 const Point& rPoint = pA->GetPoint();
1463 aPositions.emplace_back(rPoint.X(), rPoint.Y());
1464 nAction++; if(nAction < nCount) pAction = rMetaFile.GetAction(nAction);
1465 }
1466
1467 nAction--;
1468
1469 if(!aPositions.empty())
1470 {
1471 createPointArrayPrimitive(std::move(aPositions), rTargetHolders.Current(), rPropertyHolders.Current(), rPropertyHolders.Current().getLineColor());
1472 }
1473 }
1474
1475 break;
1476 }
1477 case MetaActionType::LINE :
1478 {
1480 if(rPropertyHolders.Current().getLineColorActive())
1481 {
1482 basegfx::B2DPolygon aLinePolygon;
1483 LineInfo aLineInfo;
1484
1485 while(MetaActionType::LINE == pAction->GetType() && nAction < nCount)
1486 {
1487 const MetaLineAction* pA = static_cast<const MetaLineAction*>(pAction);
1488 const Point& rStartPoint = pA->GetStartPoint();
1489 const Point& rEndPoint = pA->GetEndPoint();
1490 const basegfx::B2DPoint aStart(rStartPoint.X(), rStartPoint.Y());
1491 const basegfx::B2DPoint aEnd(rEndPoint.X(), rEndPoint.Y());
1492
1493 if(aLinePolygon.count())
1494 {
1495 if(pA->GetLineInfo() == aLineInfo
1496 && aStart == aLinePolygon.getB2DPoint(aLinePolygon.count() - 1))
1497 {
1498 aLinePolygon.append(aEnd);
1499 }
1500 else
1501 {
1502 createLinePrimitive(aLinePolygon, aLineInfo, rTargetHolders.Current(), rPropertyHolders.Current());
1503 aLinePolygon.clear();
1504 aLineInfo = pA->GetLineInfo();
1505 aLinePolygon.append(aStart);
1506 aLinePolygon.append(aEnd);
1507 }
1508 }
1509 else
1510 {
1511 aLineInfo = pA->GetLineInfo();
1512 aLinePolygon.append(aStart);
1513 aLinePolygon.append(aEnd);
1514 }
1515
1516 nAction++;
1517 if (nAction < nCount)
1518 pAction = rMetaFile.GetAction(nAction);
1519 }
1520
1521 nAction--;
1522 if (aLinePolygon.count())
1523 createLinePrimitive(aLinePolygon, aLineInfo, rTargetHolders.Current(), rPropertyHolders.Current());
1524 }
1525
1526 break;
1527 }
1528 case MetaActionType::RECT :
1529 {
1531 if(rPropertyHolders.Current().getLineOrFillActive())
1532 {
1533 const MetaRectAction* pA = static_cast<const MetaRectAction*>(pAction);
1534 const tools::Rectangle& rRectangle = pA->GetRect();
1535
1536 if(!rRectangle.IsEmpty())
1537 {
1539
1540 if(!aRange.isEmpty())
1541 {
1543 createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
1544 }
1545 }
1546 }
1547
1548 break;
1549 }
1550 case MetaActionType::ROUNDRECT :
1551 {
1558 if(rPropertyHolders.Current().getLineOrFillActive())
1559 {
1560 const MetaRoundRectAction* pA = static_cast<const MetaRoundRectAction*>(pAction);
1561 const tools::Rectangle& rRectangle = pA->GetRect();
1562
1563 if(!rRectangle.IsEmpty())
1564 {
1566
1567 if(!aRange.isEmpty())
1568 {
1569 const sal_uInt32 nHor(pA->GetHorzRound());
1570 const sal_uInt32 nVer(pA->GetVertRound());
1571 basegfx::B2DPolygon aOutline;
1572
1573 if(nHor || nVer)
1574 {
1575 double fRadiusX((nHor * 2.0) / (aRange.getWidth() > 0.0 ? aRange.getWidth() : 1.0));
1576 double fRadiusY((nVer * 2.0) / (aRange.getHeight() > 0.0 ? aRange.getHeight() : 1.0));
1577 fRadiusX = std::clamp(fRadiusX, 0.0, 1.0);
1578 fRadiusY = std::clamp(fRadiusY, 0.0, 1.0);
1579
1580 aOutline = basegfx::utils::createPolygonFromRect(aRange, fRadiusX, fRadiusY);
1581 }
1582 else
1583 {
1584 aOutline = basegfx::utils::createPolygonFromRect(aRange);
1585 }
1586
1587 createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
1588 }
1589 }
1590 }
1591
1592 break;
1593 }
1594 case MetaActionType::ELLIPSE :
1595 {
1597 if(rPropertyHolders.Current().getLineOrFillActive())
1598 {
1599 const MetaEllipseAction* pA = static_cast<const MetaEllipseAction*>(pAction);
1600 const tools::Rectangle& rRectangle = pA->GetRect();
1601
1602 if(!rRectangle.IsEmpty())
1603 {
1605
1606 if(!aRange.isEmpty())
1607 {
1609 aRange.getCenter(), aRange.getWidth() * 0.5, aRange.getHeight() * 0.5));
1610
1611 createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
1612 }
1613 }
1614 }
1615
1616 break;
1617 }
1618 case MetaActionType::ARC :
1619 {
1621 if(rPropertyHolders.Current().getLineColorActive())
1622 {
1623 const MetaArcAction* pA = static_cast<const MetaArcAction*>(pAction);
1624 const tools::Polygon aToolsPoly(pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), PolyStyle::Arc);
1625 const basegfx::B2DPolygon aOutline(aToolsPoly.getB2DPolygon());
1626
1627 createHairlinePrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
1628 }
1629
1630 break;
1631 }
1632 case MetaActionType::PIE :
1633 {
1635 if(rPropertyHolders.Current().getLineOrFillActive())
1636 {
1637 const MetaPieAction* pA = static_cast<const MetaPieAction*>(pAction);
1638 const tools::Polygon aToolsPoly(pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), PolyStyle::Pie);
1639 const basegfx::B2DPolygon aOutline(aToolsPoly.getB2DPolygon());
1640
1641 createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
1642 }
1643
1644 break;
1645 }
1646 case MetaActionType::CHORD :
1647 {
1649 if(rPropertyHolders.Current().getLineOrFillActive())
1650 {
1651 const MetaChordAction* pA = static_cast<const MetaChordAction*>(pAction);
1652 const tools::Polygon aToolsPoly(pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), PolyStyle::Chord);
1653 const basegfx::B2DPolygon aOutline(aToolsPoly.getB2DPolygon());
1654
1655 createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
1656 }
1657
1658 break;
1659 }
1660 case MetaActionType::POLYLINE :
1661 {
1663 if(rPropertyHolders.Current().getLineColorActive())
1664 {
1665 const MetaPolyLineAction* pA = static_cast<const MetaPolyLineAction*>(pAction);
1666 createLinePrimitive(pA->GetPolygon().getB2DPolygon(), pA->GetLineInfo(), rTargetHolders.Current(), rPropertyHolders.Current());
1667 }
1668
1669 break;
1670 }
1671 case MetaActionType::POLYGON :
1672 {
1674 if(rPropertyHolders.Current().getLineOrFillActive())
1675 {
1676 const MetaPolygonAction* pA = static_cast<const MetaPolygonAction*>(pAction);
1678
1679 // the metafile play interprets the polygons from MetaPolygonAction
1680 // always as closed and always paints an edge from last to first point,
1681 // so force to closed here to emulate that
1682 if(aOutline.count() > 1 && !aOutline.isClosed())
1683 {
1684 aOutline.setClosed(true);
1685 }
1686
1687 createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
1688 }
1689
1690 break;
1691 }
1692 case MetaActionType::POLYPOLYGON :
1693 {
1695 if(rPropertyHolders.Current().getLineOrFillActive())
1696 {
1697 const MetaPolyPolygonAction* pA = static_cast<const MetaPolyPolygonAction*>(pAction);
1698 basegfx::B2DPolyPolygon aPolyPolygonOutline(pA->GetPolyPolygon().getB2DPolyPolygon());
1699
1700 // the metafile play interprets the single polygons from MetaPolyPolygonAction
1701 // always as closed and always paints an edge from last to first point,
1702 // so force to closed here to emulate that
1703 for(sal_uInt32 b(0); b < aPolyPolygonOutline.count(); b++)
1704 {
1705 basegfx::B2DPolygon aPolygonOutline(aPolyPolygonOutline.getB2DPolygon(b));
1706
1707 if(aPolygonOutline.count() > 1 && !aPolygonOutline.isClosed())
1708 {
1709 aPolygonOutline.setClosed(true);
1710 aPolyPolygonOutline.setB2DPolygon(b, aPolygonOutline);
1711 }
1712 }
1713
1714 createHairlineAndFillPrimitive(aPolyPolygonOutline, rTargetHolders.Current(), rPropertyHolders.Current());
1715 }
1716
1717 break;
1718 }
1719 case MetaActionType::TEXT :
1720 {
1722 const MetaTextAction* pA = static_cast<const MetaTextAction*>(pAction);
1723 sal_uInt32 nTextLength(pA->GetLen());
1724 const sal_uInt32 nTextIndex(pA->GetIndex());
1725 const sal_uInt32 nStringLength(pA->GetText().getLength());
1726
1727 if(nTextLength + nTextIndex > nStringLength)
1728 {
1729 nTextLength = nStringLength - nTextIndex;
1730 }
1731
1732 if(nTextLength && rPropertyHolders.Current().getTextColorActive())
1733 {
1734 std::vector< double > aDXArray{};
1736 pA->GetPoint(),
1737 pA->GetText(),
1738 nTextIndex,
1739 nTextLength,
1740 std::move(aDXArray),
1741 {},
1742 rTargetHolders.Current(),
1743 rPropertyHolders.Current());
1744 }
1745
1746 break;
1747 }
1748 case MetaActionType::TEXTARRAY :
1749 {
1751 const MetaTextArrayAction* pA = static_cast<const MetaTextArrayAction*>(pAction);
1752 sal_uInt32 nTextLength(pA->GetLen());
1753 const sal_uInt32 nTextIndex(pA->GetIndex());
1754 const sal_uInt32 nStringLength(pA->GetText().getLength());
1755
1756 if(nTextLength + nTextIndex > nStringLength)
1757 {
1758 nTextLength = nTextIndex > nStringLength ? 0 : nStringLength - nTextIndex;
1759 }
1760
1761 if(nTextLength && rPropertyHolders.Current().getTextColorActive())
1762 {
1763 // prepare DXArray (if used)
1764 std::vector< double > aDXArray;
1765 const KernArray& rDXArray = pA->GetDXArray();
1766 std::vector< sal_Bool > aKashidaArray = pA->GetKashidaArray();
1767
1768 if(!rDXArray.empty())
1769 {
1770 aDXArray.reserve(nTextLength);
1771
1772 for(sal_uInt32 a(0); a < nTextLength; a++)
1773 {
1774 aDXArray.push_back(static_cast<double>(rDXArray[a]));
1775 }
1776 }
1777
1779 pA->GetPoint(),
1780 pA->GetText(),
1781 nTextIndex,
1782 nTextLength,
1783 std::move(aDXArray),
1784 std::move(aKashidaArray),
1785 rTargetHolders.Current(),
1786 rPropertyHolders.Current());
1787 }
1788
1789 break;
1790 }
1791 case MetaActionType::STRETCHTEXT :
1792 {
1793 // #i108440# StarMath uses MetaStretchTextAction, thus support is needed.
1794 // It looks as if it pretty never really uses a width different from
1795 // the default text-layout width, but it's not possible to be sure.
1796 // Implemented getting the DXArray and checking for scale at all. If
1797 // scale is more than 3.5% different, scale the DXArray before usage.
1798 // New status:
1799
1801 const MetaStretchTextAction* pA = static_cast<const MetaStretchTextAction*>(pAction);
1802 sal_uInt32 nTextLength(pA->GetLen());
1803 const sal_uInt32 nTextIndex(pA->GetIndex());
1804 const sal_uInt32 nStringLength(pA->GetText().getLength());
1805
1806 if(nTextLength + nTextIndex > nStringLength)
1807 {
1808 nTextLength = nStringLength - nTextIndex;
1809 }
1810
1811 if(nTextLength && rPropertyHolders.Current().getTextColorActive())
1812 {
1814 aTextLayouterDevice.setFont(rPropertyHolders.Current().getFont());
1815
1816 std::vector< double > aTextArray(
1817 aTextLayouterDevice.getTextArray(
1818 pA->GetText(),
1819 nTextIndex,
1820 nTextLength));
1821
1822 if(!aTextArray.empty())
1823 {
1824 const double fTextLength(aTextArray.back());
1825
1826 if(0.0 != fTextLength && pA->GetWidth())
1827 {
1828 const double fRelative(pA->GetWidth() / fTextLength);
1829
1830 if(fabs(fRelative - 1.0) >= 0.035)
1831 {
1832 // when derivation is more than 3,5% from default text size,
1833 // scale the DXArray
1834 for(double & a : aTextArray)
1835 {
1836 a *= fRelative;
1837 }
1838 }
1839 }
1840 }
1841
1843 pA->GetPoint(),
1844 pA->GetText(),
1845 nTextIndex,
1846 nTextLength,
1847 std::move(aTextArray),
1848 {},
1849 rTargetHolders.Current(),
1850 rPropertyHolders.Current());
1851 }
1852
1853 break;
1854 }
1855 case MetaActionType::TEXTRECT :
1856 {
1858 // OSL_FAIL("MetaActionType::TEXTRECT requested (!)");
1859 const MetaTextRectAction* pA = static_cast<const MetaTextRectAction*>(pAction);
1860 const tools::Rectangle& rRectangle = pA->GetRect();
1861 const sal_uInt32 nStringLength(pA->GetText().getLength());
1862
1863 if(!rRectangle.IsEmpty() && 0 != nStringLength)
1864 {
1865 // The problem with this action is that it describes unlayouted text
1866 // and the layout capabilities are in EditEngine/Outliner in SVX. The
1867 // same problem is true for VCL which internally has implementations
1868 // to layout text in this case. There exists even a call
1869 // OutputDevice::AddTextRectActions(...) to create the needed actions
1870 // as 'sub-content' of a Metafile. Unfortunately i do not have an
1871 // OutputDevice here since this interpreter tries to work without
1872 // VCL AFAP.
1873 // Since AddTextRectActions is the only way as long as we do not have
1874 // a simple text layouter available, i will try to add it to the
1875 // TextLayouterDevice isolation.
1877 aTextLayouterDevice.setFont(rPropertyHolders.Current().getFont());
1878 GDIMetaFile aGDIMetaFile;
1879
1880 aTextLayouterDevice.addTextRectActions(
1881 rRectangle, pA->GetText(), pA->GetStyle(), aGDIMetaFile);
1882
1883 if(aGDIMetaFile.GetActionSize())
1884 {
1885 // create sub-content
1887 {
1888 rTargetHolders.Push();
1889
1890 // for sub-Mteafile contents, do start with new, default render state
1891 // #i124686# ...but copy font, this is already set accordingly
1892 vcl::Font aTargetFont = rPropertyHolders.Current().getFont();
1893 rPropertyHolders.PushDefault();
1894 rPropertyHolders.Current().setFont(aTargetFont);
1895
1896 implInterpretMetafile(aGDIMetaFile, rTargetHolders, rPropertyHolders, rViewInformation);
1897 xSubContent = rTargetHolders.Current().getPrimitive2DSequence(rPropertyHolders.Current());
1898 rPropertyHolders.Pop();
1899 rTargetHolders.Pop();
1900 }
1901
1902 if(!xSubContent.empty())
1903 {
1904 // add with transformation
1905 rTargetHolders.Current().append(
1907 rPropertyHolders.Current().getTransformation(),
1908 std::move(xSubContent)));
1909 }
1910 }
1911 }
1912
1913 break;
1914 }
1915 case MetaActionType::BMP :
1916 {
1918 const MetaBmpAction* pA = static_cast<const MetaBmpAction*>(pAction);
1919 const BitmapEx aBitmapEx(pA->GetBitmap());
1920
1921 createBitmapExPrimitive(aBitmapEx, pA->GetPoint(), rTargetHolders.Current(), rPropertyHolders.Current());
1922
1923 break;
1924 }
1925 case MetaActionType::BMPSCALE :
1926 {
1928 const MetaBmpScaleAction* pA = static_cast<const MetaBmpScaleAction*>(pAction);
1929 const BitmapEx aBitmapEx(pA->GetBitmap());
1930
1931 createBitmapExPrimitive(aBitmapEx, pA->GetPoint(), pA->GetSize(), rTargetHolders.Current(), rPropertyHolders.Current());
1932
1933 break;
1934 }
1935 case MetaActionType::BMPSCALEPART :
1936 {
1938 const MetaBmpScalePartAction* pA = static_cast<const MetaBmpScalePartAction*>(pAction);
1939 const Bitmap& rBitmap = pA->GetBitmap();
1940
1941 if(!rBitmap.IsEmpty())
1942 {
1943 Bitmap aCroppedBitmap(rBitmap);
1944 const tools::Rectangle aCropRectangle(pA->GetSrcPoint(), pA->GetSrcSize());
1945
1946 if(!aCropRectangle.IsEmpty())
1947 {
1948 aCroppedBitmap.Crop(aCropRectangle);
1949 }
1950
1951 const BitmapEx aCroppedBitmapEx(aCroppedBitmap);
1952 createBitmapExPrimitive(aCroppedBitmapEx, pA->GetDestPoint(), pA->GetDestSize(), rTargetHolders.Current(), rPropertyHolders.Current());
1953 }
1954
1955 break;
1956 }
1957 case MetaActionType::BMPEX :
1958 {
1960 const MetaBmpExAction* pA = static_cast<const MetaBmpExAction*>(pAction);
1961 const BitmapEx& rBitmapEx = pA->GetBitmapEx();
1962
1963 createBitmapExPrimitive(rBitmapEx, pA->GetPoint(), rTargetHolders.Current(), rPropertyHolders.Current());
1964
1965 break;
1966 }
1967 case MetaActionType::BMPEXSCALE :
1968 {
1970 const MetaBmpExScaleAction* pA = static_cast<const MetaBmpExScaleAction*>(pAction);
1971 const BitmapEx& rBitmapEx = pA->GetBitmapEx();
1972
1973 createBitmapExPrimitive(rBitmapEx, pA->GetPoint(), pA->GetSize(), rTargetHolders.Current(), rPropertyHolders.Current());
1974
1975 break;
1976 }
1977 case MetaActionType::BMPEXSCALEPART :
1978 {
1980 const MetaBmpExScalePartAction* pA = static_cast<const MetaBmpExScalePartAction*>(pAction);
1981 const BitmapEx& rBitmapEx = pA->GetBitmapEx();
1982
1983 if(!rBitmapEx.IsEmpty())
1984 {
1985 BitmapEx aCroppedBitmapEx(rBitmapEx);
1986 const tools::Rectangle aCropRectangle(pA->GetSrcPoint(), pA->GetSrcSize());
1987
1988 if(!aCropRectangle.IsEmpty())
1989 {
1990 aCroppedBitmapEx.Crop(aCropRectangle);
1991 }
1992
1993 createBitmapExPrimitive(aCroppedBitmapEx, pA->GetDestPoint(), pA->GetDestSize(), rTargetHolders.Current(), rPropertyHolders.Current());
1994 }
1995
1996 break;
1997 }
1998 case MetaActionType::MASK :
1999 {
2002 const MetaMaskAction* pA = static_cast<const MetaMaskAction*>(pAction);
2003 const BitmapEx aBitmapEx(createMaskBmpEx(pA->GetBitmap(), pA->GetColor()));
2004
2005 createBitmapExPrimitive(aBitmapEx, pA->GetPoint(), rTargetHolders.Current(), rPropertyHolders.Current());
2006
2007 break;
2008 }
2009 case MetaActionType::MASKSCALE :
2010 {
2012 const MetaMaskScaleAction* pA = static_cast<const MetaMaskScaleAction*>(pAction);
2013 const BitmapEx aBitmapEx(createMaskBmpEx(pA->GetBitmap(), pA->GetColor()));
2014
2015 createBitmapExPrimitive(aBitmapEx, pA->GetPoint(), pA->GetSize(), rTargetHolders.Current(), rPropertyHolders.Current());
2016
2017 break;
2018 }
2019 case MetaActionType::MASKSCALEPART :
2020 {
2022 const MetaMaskScalePartAction* pA = static_cast<const MetaMaskScalePartAction*>(pAction);
2023 const Bitmap& rBitmap = pA->GetBitmap();
2024
2025 if(!rBitmap.IsEmpty())
2026 {
2027 Bitmap aCroppedBitmap(rBitmap);
2028 const tools::Rectangle aCropRectangle(pA->GetSrcPoint(), pA->GetSrcSize());
2029
2030 if(!aCropRectangle.IsEmpty())
2031 {
2032 aCroppedBitmap.Crop(aCropRectangle);
2033 }
2034
2035 const BitmapEx aCroppedBitmapEx(createMaskBmpEx(aCroppedBitmap, pA->GetColor()));
2036 createBitmapExPrimitive(aCroppedBitmapEx, pA->GetDestPoint(), pA->GetDestSize(), rTargetHolders.Current(), rPropertyHolders.Current());
2037 }
2038
2039 break;
2040 }
2041 case MetaActionType::GRADIENT :
2042 {
2044 const MetaGradientAction* pA = static_cast<const MetaGradientAction*>(pAction);
2045 const tools::Rectangle& rRectangle = pA->GetRect();
2046
2047 if(!rRectangle.IsEmpty())
2048 {
2050
2051 if(!aRange.isEmpty())
2052 {
2053 const Gradient& rGradient = pA->GetGradient();
2056 basegfx::BColor aSingleColor;
2057
2058 if (aAttribute.getColorStops().isSingleColor(aSingleColor))
2059 {
2060 // not really a gradient. Create filled rectangle
2062 aOutline,
2063 rTargetHolders.Current(),
2064 rPropertyHolders.Current());
2065 }
2066 else
2067 {
2068 // really a gradient
2069 aRange.transform(rPropertyHolders.Current().getTransformation());
2071
2072 if(rPropertyHolders.Current().isRasterOpInvert())
2073 {
2074 // use a special version of FillGradientPrimitive2D which creates
2075 // non-overlapping geometry on decomposition to make the old XOR
2076 // paint 'trick' work.
2078 new drawinglayer::primitive2d::NonOverlappingFillGradientPrimitive2D(
2079 aRange,
2080 aAttribute));
2081 }
2082 else
2083 {
2086 aRange,
2087 std::move(aAttribute)));
2088 }
2089
2090 // #i112300# clip against polygon representing the rectangle from
2091 // the action. This is implicitly done using a temp Clipping in VCL
2092 // when a MetaGradientAction is executed
2093 aOutline.transform(rPropertyHolders.Current().getTransformation());
2094 rTargetHolders.Current().append(
2096 std::move(aOutline),
2097 std::move(xGradient)));
2098 }
2099 }
2100 }
2101
2102 break;
2103 }
2104 case MetaActionType::HATCH :
2105 {
2107 const MetaHatchAction* pA = static_cast<const MetaHatchAction*>(pAction);
2109
2110 if(aOutline.count())
2111 {
2112 const Hatch& rHatch = pA->GetHatch();
2114
2115 aOutline.transform(rPropertyHolders.Current().getTransformation());
2116
2117 const basegfx::B2DRange aObjectRange(aOutline.getB2DRange());
2120 aObjectRange,
2122 std::move(aAttribute)));
2123
2124 rTargetHolders.Current().append(
2126 std::move(aOutline),
2128 }
2129
2130 break;
2131 }
2132 case MetaActionType::WALLPAPER :
2133 {
2135 const MetaWallpaperAction* pA = static_cast<const MetaWallpaperAction*>(pAction);
2136 tools::Rectangle aWallpaperRectangle(pA->GetRect());
2137
2138 if(!aWallpaperRectangle.IsEmpty())
2139 {
2140 const Wallpaper& rWallpaper = pA->GetWallpaper();
2141 const WallpaperStyle eWallpaperStyle(rWallpaper.GetStyle());
2142 basegfx::B2DRange aWallpaperRange = vcl::unotools::b2DRectangleFromRectangle(aWallpaperRectangle);
2143
2144 if(WallpaperStyle::NONE != eWallpaperStyle)
2145 {
2146 if(rWallpaper.IsBitmap())
2147 {
2148 // create bitmap background. Caution: This
2149 // also will create gradient/color background(s)
2150 // when the bitmap is transparent or not tiled
2152 aWallpaperRange,
2153 rWallpaper,
2154 rTargetHolders.Current(),
2155 rPropertyHolders.Current());
2156 }
2157 else if(rWallpaper.IsGradient())
2158 {
2159 // create gradient background
2160 rTargetHolders.Current().append(
2162 aWallpaperRange,
2163 rWallpaper.GetGradient(),
2164 rPropertyHolders.Current()));
2165 }
2166 else if(!rWallpaper.GetColor().IsTransparent())
2167 {
2168 // create color background
2169 rTargetHolders.Current().append(
2171 aWallpaperRange,
2172 rWallpaper.GetColor().getBColor(),
2173 rPropertyHolders.Current()));
2174 }
2175 }
2176 }
2177
2178 break;
2179 }
2180 case MetaActionType::CLIPREGION :
2181 {
2183 const MetaClipRegionAction* pA = static_cast<const MetaClipRegionAction*>(pAction);
2184
2185 if(pA->IsClipping())
2186 {
2187 // new clipping. Get tools::PolyPolygon and transform with current transformation
2188 basegfx::B2DPolyPolygon aNewClipPolyPolygon(getB2DPolyPolygonFromRegion(pA->GetRegion()));
2189
2190 aNewClipPolyPolygon.transform(rPropertyHolders.Current().getTransformation());
2191 HandleNewClipRegion(aNewClipPolyPolygon, rTargetHolders, rPropertyHolders);
2192 }
2193 else
2194 {
2195 // end clipping
2196 const basegfx::B2DPolyPolygon aEmptyPolyPolygon;
2197
2198 HandleNewClipRegion(aEmptyPolyPolygon, rTargetHolders, rPropertyHolders);
2199 }
2200
2201 break;
2202 }
2203 case MetaActionType::ISECTRECTCLIPREGION :
2204 {
2206 const MetaISectRectClipRegionAction* pA = static_cast<const MetaISectRectClipRegionAction*>(pAction);
2207 const tools::Rectangle& rRectangle = pA->GetRect();
2208
2209 if(rRectangle.IsEmpty())
2210 {
2211 // intersect with empty rectangle will always give empty
2212 // ClipPolyPolygon; start new clipping with empty PolyPolygon
2213 const basegfx::B2DPolyPolygon aEmptyPolyPolygon;
2214
2215 HandleNewClipRegion(aEmptyPolyPolygon, rTargetHolders, rPropertyHolders);
2216 }
2217 else
2218 {
2219 // create transformed ClipRange
2221
2222 aClipRange.transform(rPropertyHolders.Current().getTransformation());
2223
2224 if(rPropertyHolders.Current().getClipPolyPolygonActive())
2225 {
2226 if(0 == rPropertyHolders.Current().getClipPolyPolygon().count())
2227 {
2228 // nothing to do, empty active clipPolyPolygon will stay
2229 // empty when intersecting
2230 }
2231 else
2232 {
2233 // AND existing region and new ClipRange
2234 const basegfx::B2DPolyPolygon aOriginalPolyPolygon(
2235 rPropertyHolders.Current().getClipPolyPolygon());
2236 basegfx::B2DPolyPolygon aClippedPolyPolygon;
2237
2238 if(aOriginalPolyPolygon.count())
2239 {
2240 aClippedPolyPolygon = basegfx::utils::clipPolyPolygonOnRange(
2241 aOriginalPolyPolygon,
2242 aClipRange,
2243 true,
2244 false);
2245 }
2246
2247 if(aClippedPolyPolygon != aOriginalPolyPolygon)
2248 {
2249 // start new clipping with intersected region
2251 aClippedPolyPolygon,
2252 rTargetHolders,
2253 rPropertyHolders);
2254 }
2255 }
2256 }
2257 else
2258 {
2259 // start new clipping with ClipRange
2260 const basegfx::B2DPolyPolygon aNewClipPolyPolygon(
2262
2263 HandleNewClipRegion(aNewClipPolyPolygon, rTargetHolders, rPropertyHolders);
2264 }
2265 }
2266
2267 break;
2268 }
2269 case MetaActionType::ISECTREGIONCLIPREGION :
2270 {
2272 const MetaISectRegionClipRegionAction* pA = static_cast<const MetaISectRegionClipRegionAction*>(pAction);
2273 const vcl::Region& rNewRegion = pA->GetRegion();
2274
2275 if(rNewRegion.IsEmpty())
2276 {
2277 // intersect with empty region will always give empty
2278 // region; start new clipping with empty PolyPolygon
2279 const basegfx::B2DPolyPolygon aEmptyPolyPolygon;
2280
2281 HandleNewClipRegion(aEmptyPolyPolygon, rTargetHolders, rPropertyHolders);
2282 }
2283 else
2284 {
2285 // get new ClipPolyPolygon, transform it with current transformation
2286 basegfx::B2DPolyPolygon aNewClipPolyPolygon(getB2DPolyPolygonFromRegion(rNewRegion));
2287 aNewClipPolyPolygon.transform(rPropertyHolders.Current().getTransformation());
2288
2289 if(rPropertyHolders.Current().getClipPolyPolygonActive())
2290 {
2291 if(0 == rPropertyHolders.Current().getClipPolyPolygon().count())
2292 {
2293 // nothing to do, empty active clipPolyPolygon will stay empty
2294 // when intersecting with any region
2295 }
2296 else
2297 {
2298 // AND existing and new region
2299 const basegfx::B2DPolyPolygon aOriginalPolyPolygon(
2300 rPropertyHolders.Current().getClipPolyPolygon());
2301 basegfx::B2DPolyPolygon aClippedPolyPolygon;
2302
2303 if(aOriginalPolyPolygon.count())
2304 {
2306 aOriginalPolyPolygon, aNewClipPolyPolygon, true, false);
2307 }
2308
2309 if(aClippedPolyPolygon != aOriginalPolyPolygon)
2310 {
2311 // start new clipping with intersected ClipPolyPolygon
2312 HandleNewClipRegion(aClippedPolyPolygon, rTargetHolders, rPropertyHolders);
2313 }
2314 }
2315 }
2316 else
2317 {
2318 // start new clipping with new ClipPolyPolygon
2319 HandleNewClipRegion(aNewClipPolyPolygon, rTargetHolders, rPropertyHolders);
2320 }
2321 }
2322
2323 break;
2324 }
2325 case MetaActionType::MOVECLIPREGION :
2326 {
2328 const MetaMoveClipRegionAction* pA = static_cast<const MetaMoveClipRegionAction*>(pAction);
2329
2330 if(rPropertyHolders.Current().getClipPolyPolygonActive())
2331 {
2332 if(0 == rPropertyHolders.Current().getClipPolyPolygon().count())
2333 {
2334 // nothing to do
2335 }
2336 else
2337 {
2338 const sal_Int32 nHor(pA->GetHorzMove());
2339 const sal_Int32 nVer(pA->GetVertMove());
2340
2341 if(0 != nHor || 0 != nVer)
2342 {
2343 // prepare translation, add current transformation
2344 basegfx::B2DVector aVector(pA->GetHorzMove(), pA->GetVertMove());
2345 aVector *= rPropertyHolders.Current().getTransformation();
2346 basegfx::B2DHomMatrix aTransform(
2348
2349 // transform existing region
2350 basegfx::B2DPolyPolygon aClipPolyPolygon(
2351 rPropertyHolders.Current().getClipPolyPolygon());
2352
2353 aClipPolyPolygon.transform(aTransform);
2354 HandleNewClipRegion(aClipPolyPolygon, rTargetHolders, rPropertyHolders);
2355 }
2356 }
2357 }
2358
2359 break;
2360 }
2361 case MetaActionType::LINECOLOR :
2362 {
2364 const MetaLineColorAction* pA = static_cast<const MetaLineColorAction*>(pAction);
2365 // tdf#89901 do as OutDev does: COL_TRANSPARENT deactivates line draw
2366 const bool bActive(pA->IsSetting() && COL_TRANSPARENT != pA->GetColor());
2367
2368 rPropertyHolders.Current().setLineColorActive(bActive);
2369 if(bActive)
2370 rPropertyHolders.Current().setLineColor(pA->GetColor().getBColor());
2371
2372 break;
2373 }
2374 case MetaActionType::FILLCOLOR :
2375 {
2377 const MetaFillColorAction* pA = static_cast<const MetaFillColorAction*>(pAction);
2378 // tdf#89901 do as OutDev does: COL_TRANSPARENT deactivates polygon fill
2379 const bool bActive(pA->IsSetting() && COL_TRANSPARENT != pA->GetColor());
2380
2381 rPropertyHolders.Current().setFillColorActive(bActive);
2382 if(bActive)
2383 rPropertyHolders.Current().setFillColor(pA->GetColor().getBColor());
2384
2385 break;
2386 }
2387 case MetaActionType::TEXTCOLOR :
2388 {
2390 const MetaTextColorAction* pA = static_cast<const MetaTextColorAction*>(pAction);
2391 const bool bActivate(COL_TRANSPARENT != pA->GetColor());
2392
2393 rPropertyHolders.Current().setTextColorActive(bActivate);
2394 rPropertyHolders.Current().setTextColor(pA->GetColor().getBColor());
2395
2396 break;
2397 }
2398 case MetaActionType::TEXTFILLCOLOR :
2399 {
2401 const MetaTextFillColorAction* pA = static_cast<const MetaTextFillColorAction*>(pAction);
2402 const bool bWithColorArgument(pA->IsSetting());
2403
2404 if(bWithColorArgument)
2405 {
2406 // emulate OutputDevice::SetTextFillColor(...) WITH argument
2407 const Color& rFontFillColor = pA->GetColor();
2408 rPropertyHolders.Current().setTextFillColor(rFontFillColor.getBColor());
2409 rPropertyHolders.Current().setTextFillColorActive(COL_TRANSPARENT != rFontFillColor);
2410 }
2411 else
2412 {
2413 // emulate SetFillColor() <- NO argument (!)
2414 rPropertyHolders.Current().setTextFillColorActive(false);
2415 }
2416
2417 break;
2418 }
2419 case MetaActionType::TEXTALIGN :
2420 {
2422 const MetaTextAlignAction* pA = static_cast<const MetaTextAlignAction*>(pAction);
2423 const TextAlign aNewTextAlign = pA->GetTextAlign();
2424
2425 // TextAlign is applied to the current font (as in
2426 // OutputDevice::SetTextAlign which would be used when
2427 // playing the Metafile)
2428 if(rPropertyHolders.Current().getFont().GetAlignment() != aNewTextAlign)
2429 {
2430 vcl::Font aNewFont(rPropertyHolders.Current().getFont());
2431 aNewFont.SetAlignment(aNewTextAlign);
2432 rPropertyHolders.Current().setFont(aNewFont);
2433 }
2434
2435 break;
2436 }
2437 case MetaActionType::MAPMODE :
2438 {
2440 // the most necessary MapMode to be interpreted is MapUnit::MapRelative,
2441 // but also the others may occur. Even not yet supported ones
2442 // may need to be added here later
2443 const MetaMapModeAction* pA = static_cast<const MetaMapModeAction*>(pAction);
2444 const MapMode& rMapMode = pA->GetMapMode();
2445 basegfx::B2DHomMatrix aMapping;
2446
2447 if(MapUnit::MapRelative == rMapMode.GetMapUnit())
2448 {
2449 aMapping = getTransformFromMapMode(rMapMode);
2450 }
2451 else
2452 {
2453 const auto eFrom = MapToO3tlLength(rPropertyHolders.Current().getMapUnit()),
2454 eTo = MapToO3tlLength(rMapMode.GetMapUnit());
2455 if (eFrom != o3tl::Length::invalid && eTo != o3tl::Length::invalid)
2456 {
2457 const double fConvert(o3tl::convert(1.0, eFrom, eTo));
2458 aMapping.scale(fConvert, fConvert);
2459 }
2460 else
2461 OSL_FAIL("implInterpretMetafile: MetaActionType::MAPMODE with unsupported MapUnit (!)");
2462
2463 aMapping = getTransformFromMapMode(rMapMode) * aMapping;
2464 rPropertyHolders.Current().setMapUnit(rMapMode.GetMapUnit());
2465 }
2466
2467 if(!aMapping.isIdentity())
2468 {
2469 aMapping = aMapping * rPropertyHolders.Current().getTransformation();
2470 rPropertyHolders.Current().setTransformation(aMapping);
2471 }
2472
2473 break;
2474 }
2475 case MetaActionType::FONT :
2476 {
2478 const MetaFontAction* pA = static_cast<const MetaFontAction*>(pAction);
2479 rPropertyHolders.Current().setFont(pA->GetFont());
2480 Size aFontSize(pA->GetFont().GetFontSize());
2481
2482 if(0 == aFontSize.Height())
2483 {
2484 // this should not happen but i got Metafiles where this was the
2485 // case. A height needs to be guessed (similar to OutputDevice::ImplNewFont())
2486 vcl::Font aCorrectedFont(pA->GetFont());
2487
2488 // guess 16 pixel (as in VCL)
2489 aFontSize = Size(0, 16);
2490
2491 // convert to target MapUnit if not pixels
2492 aFontSize = OutputDevice::LogicToLogic(
2493 aFontSize, MapMode(MapUnit::MapPixel), MapMode(rPropertyHolders.Current().getMapUnit()));
2494
2495 aCorrectedFont.SetFontSize(aFontSize);
2496 rPropertyHolders.Current().setFont(aCorrectedFont);
2497 }
2498
2499 // older Metafiles have no MetaActionType::TEXTCOLOR which defines
2500 // the FontColor now, so use the Font's color when not transparent
2501 const Color& rFontColor = pA->GetFont().GetColor();
2502 const bool bActivate(COL_TRANSPARENT != rFontColor);
2503
2504 if(bActivate)
2505 {
2506 rPropertyHolders.Current().setTextColor(rFontColor.getBColor());
2507 }
2508
2509 // caution: do NOT deactivate here on transparent, see
2510 // OutputDevice::SetFont(..) for more info
2511 // rPropertyHolders.Current().setTextColorActive(bActivate);
2512
2513 // for fill color emulate a MetaTextFillColorAction with !transparent as bool,
2514 // see OutputDevice::SetFont(..) the if(mpMetaFile) case
2515 if(bActivate)
2516 {
2517 const Color& rFontFillColor = pA->GetFont().GetFillColor();
2518 rPropertyHolders.Current().setTextFillColor(rFontFillColor.getBColor());
2519 rPropertyHolders.Current().setTextFillColorActive(COL_TRANSPARENT != rFontFillColor);
2520 }
2521 else
2522 {
2523 rPropertyHolders.Current().setTextFillColorActive(false);
2524 }
2525
2526 break;
2527 }
2528 case MetaActionType::PUSH :
2529 {
2531 const MetaPushAction* pA = static_cast<const MetaPushAction*>(pAction);
2532 rPropertyHolders.Push(pA->GetFlags());
2533
2534 break;
2535 }
2536 case MetaActionType::POP :
2537 {
2539 const bool bRegionMayChange(rPropertyHolders.Current().getPushFlags() & vcl::PushFlags::CLIPREGION);
2540 const bool bRasterOpMayChange(rPropertyHolders.Current().getPushFlags() & vcl::PushFlags::RASTEROP);
2541
2542 if(bRegionMayChange && rPropertyHolders.Current().getClipPolyPolygonActive())
2543 {
2544 // end evtl. clipping
2545 const basegfx::B2DPolyPolygon aEmptyPolyPolygon;
2546
2547 HandleNewClipRegion(aEmptyPolyPolygon, rTargetHolders, rPropertyHolders);
2548 }
2549
2550 if(bRasterOpMayChange && rPropertyHolders.Current().isRasterOpActive())
2551 {
2552 // end evtl. RasterOp
2553 HandleNewRasterOp(RasterOp::OverPaint, rTargetHolders, rPropertyHolders);
2554 }
2555
2556 rPropertyHolders.Pop();
2557
2558 if(bRasterOpMayChange && rPropertyHolders.Current().isRasterOpActive())
2559 {
2560 // start evtl. RasterOp
2561 HandleNewRasterOp(rPropertyHolders.Current().getRasterOp(), rTargetHolders, rPropertyHolders);
2562 }
2563
2564 if(bRegionMayChange && rPropertyHolders.Current().getClipPolyPolygonActive())
2565 {
2566 // start evtl. clipping
2568 rPropertyHolders.Current().getClipPolyPolygon(), rTargetHolders, rPropertyHolders);
2569 }
2570
2571 break;
2572 }
2573 case MetaActionType::RASTEROP :
2574 {
2576 const MetaRasterOpAction* pA = static_cast<const MetaRasterOpAction*>(pAction);
2577 const RasterOp aRasterOp = pA->GetRasterOp();
2578
2579 HandleNewRasterOp(aRasterOp, rTargetHolders, rPropertyHolders);
2580
2581 break;
2582 }
2583 case MetaActionType::Transparent :
2584 {
2586 const MetaTransparentAction* pA = static_cast<const MetaTransparentAction*>(pAction);
2588
2589 if(aOutline.count())
2590 {
2591 const sal_uInt16 nTransparence(pA->GetTransparence());
2592
2593 if(0 == nTransparence)
2594 {
2595 // not transparent
2596 createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
2597 }
2598 else if(nTransparence >= 100)
2599 {
2600 // fully or more than transparent
2601 }
2602 else
2603 {
2604 // transparent. Create new target
2605 rTargetHolders.Push();
2606
2607 // create primitives there and get them
2608 createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
2610 rTargetHolders.Current().getPrimitive2DSequence(rPropertyHolders.Current()));
2611
2612 // back to old target
2613 rTargetHolders.Pop();
2614
2615 if(!aSubContent.empty())
2616 {
2617 rTargetHolders.Current().append(
2619 std::move(aSubContent),
2620 nTransparence * 0.01));
2621 }
2622 }
2623 }
2624
2625 break;
2626 }
2627 case MetaActionType::EPS :
2628 {
2630 // To support this action, I have added a EpsPrimitive2D which will
2631 // by default decompose to the Metafile replacement data. To support
2632 // this EPS on screen, the renderer visualizing this has to support
2633 // that primitive and visualize the Eps file (e.g. printing)
2634 const MetaEPSAction* pA = static_cast<const MetaEPSAction*>(pAction);
2635 const tools::Rectangle aRectangle(pA->GetPoint(), pA->GetSize());
2636
2637 if(!aRectangle.IsEmpty())
2638 {
2639 // create object transform
2640 basegfx::B2DHomMatrix aObjectTransform;
2641
2642 aObjectTransform.set(0, 0, aRectangle.GetWidth());
2643 aObjectTransform.set(1, 1, aRectangle.GetHeight());
2644 aObjectTransform.set(0, 2, aRectangle.Left());
2645 aObjectTransform.set(1, 2, aRectangle.Top());
2646
2647 // add current transformation
2648 aObjectTransform = rPropertyHolders.Current().getTransformation() * aObjectTransform;
2649
2650 // embed using EpsPrimitive
2651 rTargetHolders.Current().append(
2653 aObjectTransform,
2654 pA->GetLink(),
2655 pA->GetSubstitute()));
2656 }
2657
2658 break;
2659 }
2660 case MetaActionType::REFPOINT :
2661 {
2663 // only used for hatch and line pattern offsets, pretty much no longer
2664 // supported today
2665 // const MetaRefPointAction* pA = (const MetaRefPointAction*)pAction;
2666 break;
2667 }
2668 case MetaActionType::TEXTLINECOLOR :
2669 {
2671 const MetaTextLineColorAction* pA = static_cast<const MetaTextLineColorAction*>(pAction);
2672 const bool bActive(pA->IsSetting());
2673
2674 rPropertyHolders.Current().setTextLineColorActive(bActive);
2675 if(bActive)
2676 rPropertyHolders.Current().setTextLineColor(pA->GetColor().getBColor());
2677
2678 break;
2679 }
2680 case MetaActionType::TEXTLINE :
2681 {
2683 // actually creates overline, underline and strikeouts, so
2684 // these should be isolated from TextDecoratedPortionPrimitive2D
2685 // to own primitives. Done, available now.
2686 //
2687 // This Metaaction seems not to be used (was not used in any
2688 // checked files). It's used in combination with the current
2689 // Font.
2690 const MetaTextLineAction* pA = static_cast<const MetaTextLineAction*>(pAction);
2691
2693 *pA,
2694 rTargetHolders.Current(),
2695 rPropertyHolders.Current());
2696
2697 break;
2698 }
2699 case MetaActionType::FLOATTRANSPARENT :
2700 {
2702 const MetaFloatTransparentAction* pA = static_cast<const MetaFloatTransparentAction*>(pAction);
2703 const basegfx::B2DRange aTargetRange(
2704 pA->GetPoint().X(),
2705 pA->GetPoint().Y(),
2706 pA->GetPoint().X() + pA->GetSize().Width(),
2707 pA->GetPoint().Y() + pA->GetSize().Height());
2708
2709 if(!aTargetRange.isEmpty())
2710 {
2711 const GDIMetaFile& rContent = pA->GetGDIMetaFile();
2712
2713 if(rContent.GetActionSize())
2714 {
2715 // create the sub-content with no embedding specific to the
2716 // sub-metafile, this seems not to be used.
2718 {
2719 rTargetHolders.Push();
2720 // #i# for sub-Mteafile contents, do start with new, default render state
2721 rPropertyHolders.PushDefault();
2722 implInterpretMetafile(rContent, rTargetHolders, rPropertyHolders, rViewInformation);
2723 xSubContent = rTargetHolders.Current().getPrimitive2DSequence(rPropertyHolders.Current());
2724 rPropertyHolders.Pop();
2725 rTargetHolders.Pop();
2726 }
2727
2728 if(!xSubContent.empty())
2729 {
2730 // prepare sub-content transform
2731 basegfx::B2DHomMatrix aSubTransform;
2732
2733 // create SourceRange
2734 const basegfx::B2DRange aSourceRange(
2735 rContent.GetPrefMapMode().GetOrigin().X(),
2736 rContent.GetPrefMapMode().GetOrigin().Y(),
2737 rContent.GetPrefMapMode().GetOrigin().X() + rContent.GetPrefSize().Width(),
2738 rContent.GetPrefMapMode().GetOrigin().Y() + rContent.GetPrefSize().Height());
2739
2740 // apply mapping if aTargetRange and aSourceRange are not equal
2741 if(!aSourceRange.equal(aTargetRange))
2742 {
2743 aSubTransform.translate(-aSourceRange.getMinX(), -aSourceRange.getMinY());
2744 aSubTransform.scale(
2745 aTargetRange.getWidth() / (basegfx::fTools::equalZero(aSourceRange.getWidth()) ? 1.0 : aSourceRange.getWidth()),
2746 aTargetRange.getHeight() / (basegfx::fTools::equalZero(aSourceRange.getHeight()) ? 1.0 : aSourceRange.getHeight()));
2747 aSubTransform.translate(aTargetRange.getMinX(), aTargetRange.getMinY());
2748 }
2749
2750 // apply general current transformation
2751 aSubTransform = rPropertyHolders.Current().getTransformation() * aSubTransform;
2752
2753 // evtl. embed sub-content to its transformation
2754 if(!aSubTransform.isIdentity())
2755 {
2756 const drawinglayer::primitive2d::Primitive2DReference aEmbeddedTransform(
2758 aSubTransform,
2759 std::move(xSubContent)));
2760
2761 xSubContent = drawinglayer::primitive2d::Primitive2DContainer { aEmbeddedTransform };
2762 }
2763
2764 // check if gradient is a real gradient
2765 const Gradient& rGradient = pA->GetGradient();
2767 basegfx::BColor aSingleColor;
2768
2769 if (aAttribute.getColorStops().isSingleColor(aSingleColor))
2770 {
2771 // not really a gradient; create UnifiedTransparencePrimitive2D
2772 rTargetHolders.Current().append(
2774 std::move(xSubContent),
2775 aSingleColor.luminance()));
2776 }
2777 else
2778 {
2779 // really a gradient. Create gradient sub-content (with correct scaling)
2780 basegfx::B2DRange aRange(aTargetRange);
2781 aRange.transform(rPropertyHolders.Current().getTransformation());
2782
2783 // prepare gradient for transparent content
2786 aRange,
2787 std::move(aAttribute)));
2788
2789 // create transparence primitive
2790 rTargetHolders.Current().append(
2792 std::move(xSubContent),
2794 }
2795 }
2796 }
2797 }
2798
2799 break;
2800 }
2801 case MetaActionType::GRADIENTEX :
2802 {
2804 // This is only a data holder which is interpreted inside comment actions,
2805 // see MetaActionType::COMMENT for more info
2806 // const MetaGradientExAction* pA = (const MetaGradientExAction*)pAction;
2807 break;
2808 }
2809 case MetaActionType::LAYOUTMODE :
2810 {
2812 const MetaLayoutModeAction* pA = static_cast<const MetaLayoutModeAction*>(pAction);
2813 rPropertyHolders.Current().setLayoutMode(pA->GetLayoutMode());
2814 break;
2815 }
2816 case MetaActionType::TEXTLANGUAGE :
2817 {
2819 const MetaTextLanguageAction* pA = static_cast<const MetaTextLanguageAction*>(pAction);
2820 rPropertyHolders.Current().setLanguageType(pA->GetTextLanguage());
2821 break;
2822 }
2823 case MetaActionType::OVERLINECOLOR :
2824 {
2826 const MetaOverlineColorAction* pA = static_cast<const MetaOverlineColorAction*>(pAction);
2827 const bool bActive(pA->IsSetting());
2828
2829 rPropertyHolders.Current().setOverlineColorActive(bActive);
2830 if(bActive)
2831 rPropertyHolders.Current().setOverlineColor(pA->GetColor().getBColor());
2832
2833 break;
2834 }
2835 case MetaActionType::COMMENT :
2836 {
2838 // I already implemented
2839 // XPATHFILL_SEQ_BEGIN, XPATHFILL_SEQ_END
2840 // XPATHSTROKE_SEQ_BEGIN, XPATHSTROKE_SEQ_END,
2841 // but opted to remove these again; it works well without them
2842 // and makes the code less dependent from those Metafile Add-Ons
2843 const MetaCommentAction* pA = static_cast<const MetaCommentAction*>(pAction);
2844
2845 if (pA->GetComment().equalsIgnoreAsciiCase("XGRAD_SEQ_BEGIN"))
2846 {
2847 // XGRAD_SEQ_BEGIN, XGRAD_SEQ_END should be supported since the
2848 // pure recorded paint of the gradients uses the XOR paint functionality
2849 // ('trick'). This is (and will be) problematic with AntiAliasing, so it's
2850 // better to use this info
2851 const MetaGradientExAction* pMetaGradientExAction = nullptr;
2852 bool bDone(false);
2853 size_t b(nAction + 1);
2854
2855 for(; !bDone && b < nCount; b++)
2856 {
2857 pAction = rMetaFile.GetAction(b);
2858
2859 if(MetaActionType::GRADIENTEX == pAction->GetType())
2860 {
2861 pMetaGradientExAction = static_cast<const MetaGradientExAction*>(pAction);
2862 }
2863 else if(MetaActionType::COMMENT == pAction->GetType())
2864 {
2865 if (static_cast<const MetaCommentAction*>(pAction)->GetComment().equalsIgnoreAsciiCase("XGRAD_SEQ_END"))
2866 {
2867 bDone = true;
2868 }
2869 }
2870 }
2871
2872 if(bDone && pMetaGradientExAction)
2873 {
2874 // consume actions and skip forward
2875 nAction = b - 1;
2876
2877 // get geometry data
2878 basegfx::B2DPolyPolygon aPolyPolygon(pMetaGradientExAction->GetPolyPolygon().getB2DPolyPolygon());
2879
2880 if(aPolyPolygon.count())
2881 {
2882 // transform geometry
2883 aPolyPolygon.transform(rPropertyHolders.Current().getTransformation());
2884
2885 // get and check if gradient is a real gradient
2886 const Gradient& rGradient = pMetaGradientExAction->GetGradient();
2888 basegfx::BColor aSingleColor;
2889
2890 if (aAttribute.getColorStops().isSingleColor(aSingleColor))
2891 {
2892 // not really a gradient
2893 rTargetHolders.Current().append(
2895 std::move(aPolyPolygon),
2896 aSingleColor));
2897 }
2898 else
2899 {
2900 // really a gradient
2901 rTargetHolders.Current().append(
2903 aPolyPolygon,
2904 std::move(aAttribute)));
2905 }
2906 }
2907 }
2908 }
2909 else if (pA->GetComment().equalsIgnoreAsciiCase("EMF_PLUS_HEADER_INFO"))
2910 {
2911 if (aEMFPlus)
2912 {
2913 // error: should not yet exist
2914 SAL_INFO("drawinglayer.emf", "Error: multiple EMF_PLUS_HEADER_INFO");
2915 }
2916 else
2917 {
2918 SAL_INFO("drawinglayer.emf", "EMF+ passed to canvas mtf renderer - header info, size: " << pA->GetDataSize());
2919 SvMemoryStream aMemoryStream(const_cast<sal_uInt8 *>(pA->GetData()), pA->GetDataSize(), StreamMode::READ);
2920
2921 aEMFPlus.reset(
2923 aMemoryStream,
2924 rTargetHolders,
2925 rPropertyHolders));
2926 }
2927 }
2928 else if (pA->GetComment().equalsIgnoreAsciiCase("EMF_PLUS"))
2929 {
2930 if (!aEMFPlus)
2931 {
2932 // error: should exist
2933 SAL_INFO("drawinglayer.emf", "Error: EMF_PLUS before EMF_PLUS_HEADER_INFO");
2934 }
2935 else
2936 {
2937 static int count = -1, limit = 0x7fffffff;
2938
2939 if (count == -1)
2940 {
2941 count = 0;
2942
2943 if (char *env = getenv("EMF_PLUS_LIMIT"))
2944 {
2945 limit = atoi(env);
2946 SAL_INFO("drawinglayer.emf", "EMF+ records limit: " << limit);
2947 }
2948 }
2949
2950 SAL_INFO("drawinglayer.emf", "EMF+ passed to canvas mtf renderer, size: " << pA->GetDataSize());
2951
2952 if (count < limit)
2953 {
2954 SvMemoryStream aMemoryStream(const_cast<sal_uInt8 *>(pA->GetData()), pA->GetDataSize(), StreamMode::READ);
2955
2956 aEMFPlus->processEmfPlusData(
2957 aMemoryStream,
2958 rViewInformation);
2959 }
2960
2961 count++;
2962 }
2963 }
2964
2965 break;
2966 }
2967 default:
2968 {
2969 OSL_FAIL("Unknown MetaFile Action (!)");
2970 break;
2971 }
2972 }
2973 }
2974 }
2975}
2976
2977namespace wmfemfhelper
2978{
2980 const GDIMetaFile& rMetaFile,
2981 const drawinglayer::geometry::ViewInformation2D& rViewInformation)
2982 {
2983 // prepare target and properties; each will have one default entry
2985 TargetHolders aTargetHolders;
2986 PropertyHolders aPropertyHolders;
2987
2988 // set target MapUnit at Properties
2989 aPropertyHolders.Current().setMapUnit(rMetaFile.GetPrefMapMode().GetMapUnit());
2990
2991 // interpret the Metafile
2992 implInterpretMetafile(rMetaFile, aTargetHolders, aPropertyHolders, rViewInformation);
2993
2994 // get the content. There should be only one target, as in the start condition,
2995 // but iterating will be the right thing to do when some push/pop is not closed
2996 while (aTargetHolders.size() > 1)
2997 {
2998 xRetval.append(
2999 aTargetHolders.Current().getPrimitive2DSequence(aPropertyHolders.Current()));
3000 aTargetHolders.Pop();
3001 }
3002
3003 xRetval.append(
3004 aTargetHolders.Current().getPrimitive2DSequence(aPropertyHolders.Current()));
3005
3006 return xRetval;
3007 }
3008
3009} // end of namespace wmfemfhelper
3010
3011/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
RasterOp
constexpr o3tl::Length MapToO3tlLength(MapUnit eU, o3tl::Length ePixelValue=o3tl::Length::px)
bool IsAlpha() const
bool IsEmpty() const
bool Crop(const tools::Rectangle &rRectPixel)
bool Crop(const tools::Rectangle &rRectPixel)
Bitmap CreateMask(const Color &rTransColor) const
Size GetSizePixel() const
bool IsEmpty() const
bool Erase(const Color &rFillColor)
basegfx::BColor getBColor() const
bool IsTransparent() const
size_t GetActionSize() const
const Size & GetPrefSize() const
MetaAction * GetAction(size_t nAction) const
const MapMode & GetPrefMapMode() const
sal_uInt16 GetStartIntensity() const
Degree10 GetAngle() const
sal_uInt16 GetEndIntensity() const
sal_uInt16 GetOfsX() const
sal_uInt16 GetBorder() const
const Color & GetEndColor() const
sal_uInt16 GetOfsY() const
const Color & GetStartColor() const
css::awt::GradientStyle GetStyle() const
sal_uInt16 GetSteps() const
Degree10 GetAngle() const
HatchStyle GetStyle() const
tools::Long GetDistance() const
const Color & GetColor() const
bool empty() const
const css::lang::Locale & getLocale(bool bResolveSystem=true) const
LineStyle GetStyle() const
double GetWidth() const
basegfx::B2DLineJoin GetLineJoin() const
std::vector< double > GetDotDashArray() const
css::drawing::LineCap GetLineCap() const
const Fraction & GetScaleX() const
MapUnit GetMapUnit() const
const Point & GetOrigin() const
const Fraction & GetScaleY() const
MetaActionType GetType() const
const Point & GetStartPoint() const
const tools::Rectangle & GetRect() const
const Point & GetEndPoint() const
const Bitmap & GetBitmap() const
const Point & GetPoint() const
const BitmapEx & GetBitmapEx() const
const Point & GetPoint() const
const Size & GetSize() const
const Point & GetPoint() const
const BitmapEx & GetBitmapEx() const
const Point & GetSrcPoint() const
const Size & GetDestSize() const
const Point & GetDestPoint() const
const Size & GetSrcSize() const
const BitmapEx & GetBitmapEx() const
const Point & GetPoint() const
const Size & GetSize() const
const Bitmap & GetBitmap() const
const Bitmap & GetBitmap() const
const Point & GetDestPoint() const
const Point & GetSrcPoint() const
const Size & GetSrcSize() const
const Size & GetDestSize() const
const tools::Rectangle & GetRect() const
const Point & GetStartPoint() const
const Point & GetEndPoint() const
const vcl::Region & GetRegion() const
bool IsClipping() const
const sal_uInt8 * GetData() const
const OString & GetComment() const
sal_uInt32 GetDataSize() const
const GDIMetaFile & GetSubstitute() const
const Point & GetPoint() const
const Size & GetSize() const
const GfxLink & GetLink() const
const tools::Rectangle & GetRect() const
const Color & GetColor() const
bool IsSetting() const
const Gradient & GetGradient() const
const Size & GetSize() const
const GDIMetaFile & GetGDIMetaFile() const
const Point & GetPoint() const
const vcl::Font & GetFont() const
const tools::Rectangle & GetRect() const
const Gradient & GetGradient() const
const tools::PolyPolygon & GetPolyPolygon() const
const Gradient & GetGradient() const
const tools::PolyPolygon & GetPolyPolygon() const
const Hatch & GetHatch() const
const tools::Rectangle & GetRect() const
const vcl::Region & GetRegion() const
vcl::text::ComplexTextLayoutFlags GetLayoutMode() const
const LineInfo & GetLineInfo() const
const Point & GetEndPoint() const
const Point & GetStartPoint() const
bool IsSetting() const
const Color & GetColor() const
const MapMode & GetMapMode() const
const Point & GetPoint() const
const Bitmap & GetBitmap() const
const Color & GetColor() const
const Bitmap & GetBitmap() const
const Point & GetPoint() const
const Color & GetColor() const
const Size & GetSize() const
const Bitmap & GetBitmap() const
const Point & GetSrcPoint() const
const Color & GetColor() const
const Size & GetSrcSize() const
const Point & GetDestPoint() const
const Size & GetDestSize() const
tools::Long GetVertMove() const
tools::Long GetHorzMove() const
const Color & GetColor() const
const Point & GetEndPoint() const
const Point & GetStartPoint() const
const tools::Rectangle & GetRect() const
const Point & GetPoint() const
const Color & GetColor() const
const Point & GetPoint() const
const LineInfo & GetLineInfo() const
const tools::Polygon & GetPolygon() const
const tools::PolyPolygon & GetPolyPolygon() const
const tools::Polygon & GetPolygon() const
vcl::PushFlags GetFlags() const
RasterOp GetRasterOp() const
const tools::Rectangle & GetRect() const
sal_uInt32 GetHorzRound() const
sal_uInt32 GetVertRound() const
const tools::Rectangle & GetRect() const
sal_uInt32 GetWidth() const
sal_Int32 GetLen() const
sal_Int32 GetIndex() const
const OUString & GetText() const
const Point & GetPoint() const
const Point & GetPoint() const
sal_Int32 GetLen() const
const OUString & GetText() const
sal_Int32 GetIndex() const
TextAlign GetTextAlign() const
sal_Int32 GetIndex() const
const KernArray & GetDXArray() const
sal_Int32 GetLen() const
const OUString & GetText() const
const Point & GetPoint() const
const std::vector< sal_Bool > & GetKashidaArray() const
const Color & GetColor() const
const Color & GetColor() const
LanguageType GetTextLanguage() const
const Point & GetStartPoint() const
tools::Long GetWidth() const
FontLineStyle GetUnderline() const
FontLineStyle GetOverline() const
FontStrikeout GetStrikeout() const
const Color & GetColor() const
DrawTextFlags GetStyle() const
const tools::Rectangle & GetRect() const
const OUString & GetText() const
sal_uInt16 GetTransparence() const
const tools::PolyPolygon & GetPolyPolygon() const
const Wallpaper & GetWallpaper() const
const tools::Rectangle & GetRect() const
SAL_WARN_UNUSED_RESULT Point LogicToLogic(const Point &rPtSource, const MapMode *pMapModeSource, const MapMode *pMapModeDest) const
constexpr tools::Long Y() const
constexpr tools::Long X() const
constexpr tools::Long Height() const
constexpr tools::Long Width() const
bool IsRect() const
const BitmapEx & GetBitmap() const
const Color & GetColor() const
bool IsBitmap() const
WallpaperStyle GetStyle() const
bool IsGradient() const
Gradient GetGradient() const
const tools::Rectangle & GetRect() const
void set(sal_uInt16 nRow, sal_uInt16 nColumn, double fValue)
void rotate(double fRadiant)
void translate(double fX, double fY)
void scale(double fX, double fY)
bool isIdentity() const
B2DPolygon const & getB2DPolygon(sal_uInt32 nIndex) const
void setB2DPolygon(sal_uInt32 nIndex, const B2DPolygon &rPolygon)
void transform(const basegfx::B2DHomMatrix &rMatrix)
B2DRange getB2DRange() const
sal_uInt32 count() const
bool isClosed() const
basegfx::B2DPoint const & getB2DPoint(sal_uInt32 nIndex) const
void transform(const basegfx::B2DHomMatrix &rMatrix)
void append(const basegfx::B2DPoint &rPoint, sal_uInt32 nCount)
sal_uInt32 count() const
void setClosed(bool bNew)
BASEGFX_DLLPUBLIC void transform(const B2DHomMatrix &rMatrix)
B2DPoint getCenter() const
bool isSingleColor(BColor &rSingleColor) const
double luminance() const
TYPE getWidth() const
TYPE getMinX() const
TYPE getMinY() const
bool isEmpty() const
bool equal(const Range2D &rRange) const
TYPE getHeight() const
TYPE getX() const
void setY(TYPE fY)
TYPE getY() const
const basegfx::BColorStops & getColorStops() const
void addTextRectActions(const tools::Rectangle &rRectangle, const OUString &rText, DrawTextFlags nStyle, GDIMetaFile &rGDIMetaFile) const
double getTextWidth(const OUString &rText, sal_uInt32 nIndex, sal_uInt32 nLength) const
void setFont(const vcl::Font &rFont)
tooling methods
::std::vector< double > getTextArray(const OUString &rText, sal_uInt32 nIndex, sal_uInt32 nLength, bool bCaret=false) const
::basegfx::B2DPolyPolygon getB2DPolyPolygon() const
::basegfx::B2DPolygon getB2DPolygon() const
constexpr tools::Long GetWidth() const
constexpr tools::Long Top() const
constexpr tools::Long GetHeight() const
constexpr tools::Long Left() const
constexpr bool IsEmpty() const
void SetFontSize(const Size &)
FontStrikeout GetStrikeout() const
bool IsShadow() const
FontLineStyle GetOverline() const
FontRelief GetRelief() const
FontEmphasisMark GetEmphasisMark() const
TextAlign GetAlignment() const
const Size & GetFontSize() const
LanguageType GetLanguage() const
const Color & GetColor() const
void SetAlignment(TextAlign)
FontLineStyle GetUnderline() const
bool IsVertical() const
LanguageType GetCJKContextLanguage() const
bool IsWordLineMode() const
Degree10 GetOrientation() const
const Color & GetFillColor() const
basegfx::B2DPolyPolygon GetAsB2DPolyPolygon() const
bool IsEmpty() const
helper class for graphic context
void setLayoutMode(vcl::text::ComplexTextLayoutFlags nNew)
void setFont(const vcl::Font &rFont)
const basegfx::B2DHomMatrix & getTransformation() const
read/write accesses
const basegfx::B2DPolyPolygon & getClipPolyPolygon() const
void setClipPolyPolygon(const basegfx::B2DPolyPolygon &rNew)
void setClipPolyPolygonActive(bool bNew)
void setLineColorActive(bool bNew)
void setTransformation(const basegfx::B2DHomMatrix &rNew)
const basegfx::BColor & getLineColor() const
void setFillColorActive(bool bNew)
vcl::text::ComplexTextLayoutFlags getLayoutMode() const
void setMapUnit(MapUnit eNew)
const basegfx::BColor & getFillColor() const
void setFillColor(const basegfx::BColor &rNew)
void setOverlineColorActive(bool bNew)
void setOverlineColor(const basegfx::BColor &rNew)
vcl::PushFlags getPushFlags() const
void setTextFillColorActive(bool bNew)
const basegfx::BColor & getTextLineColor() const
LanguageType getLanguageType() const
void setRasterOp(const RasterOp &rRasterOp)
void setLineColor(const basegfx::BColor &rNew)
const basegfx::BColor & getTextColor() const
const basegfx::BColor & getOverlineColor() const
void setTextLineColorActive(bool bNew)
void setTextLineColor(const basegfx::BColor &rNew)
const RasterOp & getRasterOp() const
void setTextColor(const basegfx::BColor &rNew)
PropertyHolder()
helper class for graphic context
const basegfx::BColor & getTextFillColor() const
const vcl::Font & getFont() const
void setTextFillColor(const basegfx::BColor &rNew)
void setTextColorActive(bool bNew)
void setPushFlags(vcl::PushFlags nNew)
void setLanguageType(LanguageType aNew)
void Push(vcl::PushFlags nPushFlags)
std::vector< PropertyHolder * > maPropertyHolders
PropertyHolders()
stack for properties
Helper class to buffer and hold a Primitive target vector.
void append(const rtl::Reference< drawinglayer::primitive2d::BasePrimitive2D > &pCandidate)
TargetHolder()
Helper class to buffer and hold a Primitive target vector.
drawinglayer::primitive2d::Primitive2DContainer getPrimitive2DSequence(const PropertyHolder &rPropertyHolder)
sal_uInt32 size() const
drawinglayer::primitive2d::Primitive2DContainer aTargets
Helper class which builds a stack on the TargetHolder class.
TargetHolders()
Helper class which builds a stack on the TargetHolder class.
std::vector< TargetHolder * > maTargetHolders
constexpr ::Color COL_WHITE(0xFF, 0xFF, 0xFF)
constexpr ::Color COL_BLACK(0x00, 0x00, 0x00)
constexpr ::Color COL_TRANSPARENT(ColorTransparency, 0xFF, 0xFF, 0xFF, 0xFF)
int nCount
double toRadians(D x)
FilterGroup & rTarget
LINESTYLE_NONE
STRIKEOUT_NONE
ALIGN_TOP
ALIGN_BASELINE
uno_Any a
#define LANGUAGE_JAPANESE
#define SAL_INFO(area, stream)
const css::uno::Reference< css::xml::crypto::XSecurityEnvironment > & env
MapUnit
def text(shape, orig_st)
NONE
bool more(const T &rfValA, const T &rfValB)
bool equalZero(const T &rfVal)
B2DPolygon createPolygonFromRect(const B2DRectangle &rRect, double fRadiusX, double fRadiusY)
B2DPolyPolygon clipPolyPolygonOnRange(const B2DPolyPolygon &rCandidate, const B2DRange &rRange, bool bInside, bool bStroke)
B2DPolyPolygon clipPolyPolygonOnPolyPolygon(const B2DPolyPolygon &rCandidate, const B2DPolyPolygon &rClip, bool bInside, bool bStroke, size_t *pPointLimit)
B2DHomMatrix createTranslateB2DHomMatrix(double fTranslateX, double fTranslateY)
B2DPolygon createPolygonFromEllipse(const B2DPoint &rCenter, double fRadiusX, double fRadiusY, sal_uInt32 nStartQuadrant=0)
rtl::Reference< BasePrimitive2D > Primitive2DReference
Definition: CommonTypes.hxx:27
TextRelief
TextRelief definition.
TextLine mapFontLineStyleToTextLine(FontLineStyle eLineStyle)
helper to convert LineStyle
TextStrikeout mapFontStrikeoutToTextStrikeout(FontStrikeout eFontStrikeout)
TextEmphasisMark
TextEmphasisMark definition.
TextStrikeout
FontStrikeout definition.
attribute::FontAttribute getFontAttributeFromVclFont(basegfx::B2DVector &o_rSize, const vcl::Font &rFont, bool bRTL, bool bBiDiStrong)
Generate FontAttribute DataSet derived from the given VCL-Font.
constexpr Point convert(const Point &rPoint, o3tl::Length eFrom, o3tl::Length eTo)
HSLColor interpolate(const HSLColor &rFrom, const HSLColor &rTo, double t, bool bCCW)
TextAlign
ComplexTextLayoutFlags
basegfx::B2DRange b2DRectangleFromRectangle(const ::tools::Rectangle &rRect)
PushFlags
drawinglayer::primitive2d::Primitive2DContainer interpretMetafile(const GDIMetaFile &rMetaFile, const drawinglayer::geometry::ViewInformation2D &rViewInformation)
static void createFontAttributeTransformAndAlignment(drawinglayer::attribute::FontAttribute &rFontAttribute, basegfx::B2DHomMatrix &rTextTransform, basegfx::B2DVector &rAlignmentOffset, PropertyHolder const &rProperty)
static void createFillPrimitive(const basegfx::B2DPolyPolygon &rFillPolyPolygon, TargetHolder &rTarget, PropertyHolder const &rProperties)
helper to create a PolyPolygonColorPrimitive2D based on current context
static drawinglayer::attribute::FillGradientAttribute createFillGradientAttribute(const Gradient &rGradient)
helper to convert from a VCL Gradient definition to the corresponding data for primitive representati...
static void processMetaTextAction(const Point &rTextStartPosition, const OUString &rText, sal_uInt16 nTextStart, sal_uInt16 nTextLength, std::vector< double > &&rDXArray, std::vector< sal_Bool > &&rKashidaArray, TargetHolder &rTarget, PropertyHolder const &rProperty)
helper which takes complete care for creating the needed text primitives.
static rtl::Reference< drawinglayer::primitive2d::BasePrimitive2D > CreateGradientWallpaper(const basegfx::B2DRange &rRange, const Gradient &rGradient, PropertyHolder const &rPropertyHolder)
helper to create needed data to emulate the VCL Wallpaper Metafile action.
static void createHairlinePrimitive(const basegfx::B2DPolygon &rLinePolygon, TargetHolder &rTarget, PropertyHolder const &rProperties)
helper to create a PolygonHairlinePrimitive2D based on current context
static void createPointArrayPrimitive(std::vector< basegfx::B2DPoint > &&rPositions, TargetHolder &rTarget, PropertyHolder const &rProperties, const basegfx::BColor &rBColor)
helper to create a PointArrayPrimitive2D based on current context
static void createLinePrimitive(const basegfx::B2DPolygon &rLinePolygon, const LineInfo &rLineInfo, TargetHolder &rTarget, PropertyHolder const &rProperties)
helper to create a PolygonStrokePrimitive2D based on current context
static BitmapEx createMaskBmpEx(const Bitmap &rBitmap, const Color &rMaskColor)
helper to create a regular BotmapEx from a MaskAction (definitions which use a bitmap without transpa...
static void createHairlineAndFillPrimitive(const basegfx::B2DPolygon &rPolygon, TargetHolder &rTarget, PropertyHolder const &rProperties)
helper to create needed line and fill primitives based on current context
static void createBitmapExPrimitive(const BitmapEx &rBitmapEx, const Point &rPoint, TargetHolder &rTarget, PropertyHolder const &rProperties)
helper to create DiscreteBitmapPrimitive2D based on current context.
static void HandleNewRasterOp(RasterOp aRasterOp, TargetHolders &rTargetHolders, PropertyHolders &rPropertyHolders)
helper to handle the change of RasterOp.
static rtl::Reference< drawinglayer::primitive2d::BasePrimitive2D > CreateColorWallpaper(const basegfx::B2DRange &rRange, const basegfx::BColor &rColor, PropertyHolder const &rPropertyHolder)
helper to create needed data to emulate the VCL Wallpaper Metafile action.
static void processMetaTextLineAction(const MetaTextLineAction &rAction, TargetHolder &rTarget, PropertyHolder const &rProperty)
helper which takes complete care for creating the needed textLine primitives
static void implInterpretMetafile(const GDIMetaFile &rMetaFile, TargetHolders &rTargetHolders, PropertyHolders &rPropertyHolders, const drawinglayer::geometry::ViewInformation2D &rViewInformation)
This is the main interpreter method.
static void CreateAndAppendBitmapWallpaper(basegfx::B2DRange aWallpaperRange, const Wallpaper &rWallpaper, TargetHolder &rTarget, PropertyHolder const &rProperty)
helper to create needed data to emulate the VCL Wallpaper Metafile action.
void HandleNewClipRegion(const basegfx::B2DPolyPolygon &rClipPolyPolygon, TargetHolders &rTargetHolders, PropertyHolders &rPropertyHolders)
helper to take needed action on ClipRegion change.
static drawinglayer::attribute::FillHatchAttribute createFillHatchAttribute(const Hatch &rHatch)
helper to convert from a VCL Hatch definition to the corresponding data for primitive representation
static bool isUnderlineAbove(const vcl::Font &rFont)
helper to decide UnderlineAbove for text primitives
unsigned char sal_uInt8
sal_uInt16 sal_Unicode
WallpaperStyle