1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <sal/config.h>
15 #include <config_features.h>
18 #include <rtl/math.hxx>
19 #include <sal/log.hxx>
21 #include <comphelper/processfactory.hxx>
22 #include <comphelper/random.hxx>
23 #include <cppuhelper/bootstrap.hxx>
24 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
25 #include <com/sun/star/lang/XInitialization.hpp>
26 #include <com/sun/star/registry/XSimpleRegistry.hpp>
27 #include <com/sun/star/ucb/UniversalContentBroker.hpp>
28 #include <com/sun/star/uno/Reference.hxx>
29 #include <com/sun/star/uno/Sequence.hxx>
30 #include <com/sun/star/container/XNameAccess.hpp>
31 #include <o3tl/safeint.hxx>
33 #include <vcl/gradient.hxx>
34 #include <vcl/vclmain.hxx>
35 #include <vcl/layout.hxx>
36 #include <vcl/ptrstyle.hxx>
37 #include <salhelper/thread.hxx>
39 #include <comphelper/diagnose_ex.hxx>
40 #include <tools/urlobj.hxx>
41 #include <tools/stream.hxx>
42 #include <vcl/svapp.hxx>
43 #include <vcl/wrkwin.hxx>
44 #include <vcl/virdev.hxx>
45 #include <vcl/graphicfilter.hxx>
46 #include <vcl/toolkit/button.hxx>
47 #include <vcl/toolkit/combobox.hxx>
48 #include <vcl/toolbox.hxx>
49 #include <vcl/toolkit/floatwin.hxx>
50 #include <vcl/help.hxx>
51 #include <vcl/kernarray.hxx>
52 #include <vcl/menu.hxx>
53 #include <vcl/ImageTree.hxx>
54 #include <vcl/BitmapEmbossGreyFilter.hxx>
55 #include <vcl/BitmapWriteAccess.hxx>
57 #include <basegfx/numeric/ftools.hxx>
58 #include <basegfx/matrix/b2dhommatrix.hxx>
60 #include <framework/desktop.hxx>
61 #include <i18nlangtag/languagetag.hxx>
62 #include <i18nlangtag/mslangid.hxx>
64 #define FIXME_SELF_INTERSECTING_WORKING 0
65 #define FIXME_BOUNCE_BUTTON 0
66 #define THUMB_REPEAT_FACTOR 10
68 using namespace com::sun::star
;
74 osl_getSystemTime(&aValue
);
75 return static_cast<double>(aValue
.Seconds
) * 1000 +
76 static_cast<double>(aValue
.Nanosec
) / (1000*1000);
84 RENDER_THUMB
, // small view <n> to a page
85 RENDER_EXPANDED
, // expanded view of this renderer
96 struct RenderContext
{
99 DemoRenderer
*mpDemoRenderer
;
102 struct RegionRenderer
{
108 virtual ~RegionRenderer() {}
109 virtual OUString
getName() = 0;
110 virtual sal_uInt16
getAccelerator() = 0;
111 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
112 const RenderContext
&rCtx
) = 0;
113 // repeating count for profiling (to exceed the poor time resolution on Windows)
114 virtual sal_uInt16
getTestRepeatCount() = 0;
115 #define RENDER_DETAILS(name,key,repeat) \
116 virtual OUString getName() override \
117 { return SAL_STRINGIFY(name); } \
118 virtual sal_uInt16 getAccelerator() override \
120 virtual sal_uInt16 getTestRepeatCount() override \
127 std::vector
< RegionRenderer
* > maRenderers
;
128 sal_Int32 mnSelectedRenderer
;
131 void InitRenderers();
134 DemoRenderer() : mnSegmentsX(0)
136 , mnSelectedRenderer(-1)
138 #if FIXME_BOUNCE_BUTTON
145 if (!Application::LoadBrandBitmap(u
"intro", maIntro
))
146 Application::Abort("Failed to load intro image");
148 maIntroBW
= maIntro
.GetBitmap();
150 BitmapEx
aTmpBmpEx(maIntroBW
);
151 BitmapFilter::Filter(aTmpBmpEx
, BitmapEmbossGreyFilter(0_deg100
, 0_deg100
));
152 maIntroBW
= aTmpBmpEx
.GetBitmap();
155 mnSegmentsY
= rtl::math::round(std::sqrt(maRenderers
.size()), 0,
156 rtl_math_RoundingMode_Down
);
157 mnSegmentsX
= (maRenderers
.size() + mnSegmentsY
- 1)/mnSegmentsY
;
160 OUString
getRendererList();
161 double getAndResetBenchmark(RenderStyle style
);
162 void selectRenderer(std::u16string_view rName
);
163 int selectNextRenderer();
164 void setIterCount(sal_Int32 iterCount
);
165 sal_Int32
getIterCount() const;
166 void addTime(int i
, double t
);
169 void SetSizePixel(const Size
&rSize
) { maSize
= rSize
; }
170 const Size
& GetSizePixel() const { return maSize
; }
173 // more of a 'Window' concept - push upwards ?
174 #if FIXME_BOUNCE_BUTTON
175 // Bouncing windows on click ...
176 PushButton
*mpButton
;
177 FloatingWindow
*mpButtonWin
;
179 int mnBounceX
, mnBounceY
;
180 DECL_LINK(BounceTimerCb
, Timer
*, void);
183 bool MouseButtonDown(const MouseEvent
& rMEvt
);
184 void KeyInput(const KeyEvent
& rKEvt
);
186 static std::vector
<tools::Rectangle
> partition(const tools::Rectangle
&rRect
, int nX
, int nY
)
188 std::vector
<tools::Rectangle
> aRegions
= partition(rRect
.GetSize(), nX
, nY
);
189 for (auto & region
: aRegions
)
190 region
.Move(rRect
.Left(), rRect
.Top());
195 static std::vector
<tools::Rectangle
> partition(const RenderContext
&rCtx
, int nX
, int nY
)
197 return partition(rCtx
.maSize
, nX
, nY
);
200 static std::vector
<tools::Rectangle
> partition(Size aSize
, int nX
, int nY
)
203 std::vector
<tools::Rectangle
> aRegions
;
205 // Make small cleared area for these guys
206 tools::Long nBorderSize
= std::min(aSize
.Height() / 32, aSize
.Width() / 32);
207 tools::Long nBoxWidth
= (aSize
.Width() - nBorderSize
*(nX
+1)) / nX
;
208 tools::Long nBoxHeight
= (aSize
.Height() - nBorderSize
*(nY
+1)) / nY
;
209 for (int y
= 0; y
< nY
; y
++)
211 for (int x
= 0; x
< nX
; x
++)
213 r
.SetPos(Point(nBorderSize
+ (nBorderSize
+ nBoxWidth
) * x
,
214 nBorderSize
+ (nBorderSize
+ nBoxHeight
) * y
));
215 r
.SetSize(Size(nBoxWidth
, nBoxHeight
));
216 aRegions
.push_back(r
);
223 static void clearRects(OutputDevice
&rDev
, std::vector
<tools::Rectangle
> &rRects
)
225 for (size_t i
= 0; i
< rRects
.size(); i
++)
227 // knock up a nice little border
228 rDev
.SetLineColor(COL_GRAY
);
229 rDev
.SetFillColor(COL_LIGHTGRAY
);
232 int nBorderSize
= rRects
[i
].GetWidth() / 5;
233 rDev
.DrawRect(rRects
[i
], nBorderSize
, nBorderSize
);
236 rDev
.DrawRect(rRects
[i
]);
240 static void drawBackground(OutputDevice
&rDev
, const tools::Rectangle
& r
)
244 aGradient
.SetStartColor(COL_BLUE
);
245 aGradient
.SetEndColor(COL_GREEN
);
246 aGradient
.SetStyle(css::awt::GradientStyle_LINEAR
);
247 rDev
.DrawGradient(r
, aGradient
);
250 struct DrawLines
: public RegionRenderer
252 RENDER_DETAILS(lines
,KEY_L
,100)
253 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
254 const RenderContext
&rCtx
) override
256 if (rCtx
.meStyle
== RENDER_EXPANDED
)
258 AntialiasingFlags nOldAA
= rDev
.GetAntialiasing();
259 rDev
.SetAntialiasing(AntialiasingFlags::Enable
);
261 std::vector
<tools::Rectangle
> aRegions(DemoRenderer::partition(rCtx
, 4, 4));
262 DemoRenderer::clearRects(rDev
, aRegions
);
264 #if 0 // FIXME: get this through to the backend ...
265 double nTransparency
[] = {
272 drawing::LineCap
const eLineCaps
[] = {
273 drawing::LineCap_BUTT
, drawing::LineCap_ROUND
, drawing::LineCap_SQUARE
, drawing::LineCap_BUTT
,
274 drawing::LineCap_BUTT
, drawing::LineCap_ROUND
, drawing::LineCap_SQUARE
, drawing::LineCap_BUTT
,
275 drawing::LineCap_BUTT
, drawing::LineCap_ROUND
, drawing::LineCap_SQUARE
, drawing::LineCap_BUTT
,
276 drawing::LineCap_BUTT
, drawing::LineCap_ROUND
, drawing::LineCap_SQUARE
, drawing::LineCap_BUTT
278 basegfx::B2DLineJoin
const eJoins
[] = {
279 basegfx::B2DLineJoin::NONE
, basegfx::B2DLineJoin::Bevel
, basegfx::B2DLineJoin::Miter
, basegfx::B2DLineJoin::Round
,
280 basegfx::B2DLineJoin::NONE
, basegfx::B2DLineJoin::Bevel
, basegfx::B2DLineJoin::Miter
, basegfx::B2DLineJoin::Round
,
281 basegfx::B2DLineJoin::NONE
, basegfx::B2DLineJoin::Bevel
, basegfx::B2DLineJoin::Miter
, basegfx::B2DLineJoin::Round
,
282 basegfx::B2DLineJoin::NONE
, basegfx::B2DLineJoin::Bevel
, basegfx::B2DLineJoin::Miter
, basegfx::B2DLineJoin::Round
284 double const aLineWidths
[] = {
285 10.0, 15.0, 20.0, 10.0,
286 10.0, 15.0, 20.0, 10.0,
287 10.0, 15.0, 20.0, 10.0,
290 for (size_t i
= 0; i
< aRegions
.size(); i
++)
292 // Half of them not-anti-aliased ..
293 if (i
>= aRegions
.size()/2)
294 rDev
.SetAntialiasing(nOldAA
);
296 static const struct {
299 { 0.2, 0.2 }, { 0.8, 0.3 }, { 0.7, 0.8 }
301 rDev
.SetLineColor(COL_BLACK
);
302 basegfx::B2DPolygon aPoly
;
303 tools::Rectangle
aSub(aRegions
[i
]);
304 for (const auto& rPoint
: aPoints
)
306 aPoly
.append(basegfx::B2DPoint(aSub
.Left() + aSub
.GetWidth() * rPoint
.nX
,
307 aSub
.Top() + aSub
.GetHeight() * rPoint
.nY
));
309 rDev
.DrawPolyLine(aPoly
, aLineWidths
[i
], eJoins
[i
], eLineCaps
[i
]);
314 rDev
.SetFillColor(COL_LIGHTRED
);
315 rDev
.SetLineColor(COL_BLACK
);
318 for(tools::Long i
=0; i
<r
.GetHeight(); i
+=15)
319 rDev
.DrawLine(Point(r
.Left(), r
.Top()+i
), Point(r
.Right(), r
.Bottom()-i
));
320 for(tools::Long i
=0; i
<r
.GetWidth(); i
+=15)
321 rDev
.DrawLine(Point(r
.Left()+i
, r
.Bottom()), Point(r
.Right()-i
, r
.Top()));
323 // Should draw a white-line across the middle
324 Color
aLastPixel(COL_WHITE
);
325 Point
aCenter((r
.Left() + r
.Right())/2 - 4,
326 (r
.Top() + r
.Bottom())/2 - 4);
327 for(int i
=0; i
<8; i
++)
329 rDev
.DrawPixel(aCenter
, aLastPixel
);
330 aLastPixel
= rDev
.GetPixel(aCenter
);
337 struct DrawText
: public RegionRenderer
339 RENDER_DETAILS(text
,KEY_T
,1)
341 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
342 const RenderContext
&rCtx
) override
344 if (rCtx
.meStyle
== RENDER_EXPANDED
)
346 std::vector
<tools::Rectangle
> aToplevelRegions(
347 DemoRenderer::partition(rCtx
, 1, 3));
348 std::vector
<tools::Rectangle
> aSubRegions(
349 DemoRenderer::partition(aToplevelRegions
[0], 4, 2));
350 tools::Rectangle
aBottom(aToplevelRegions
[1].TopLeft(),
351 aToplevelRegions
[2].BottomRight());
352 DemoRenderer::clearRects(rDev
,aSubRegions
);
357 } const aRenderData
[] = {
358 { false, false, false },
359 { false, true, false },
360 { false, true, true },
361 { false, false, true },
362 { true, false, true },
363 { true, true, true },
364 { true, true, false },
365 { true, false, false },
369 for (int y
= 0; y
< 2; y
++)
371 for (int x
= 0; x
< 4; x
++)
373 assert(i
< std::size(aRenderData
));
374 drawText(rDev
, aSubRegions
[i
], aRenderData
[i
].mbClip
,
375 aRenderData
[i
].mbArabicText
, aRenderData
[i
].mbRotate
);
380 drawComplex(rDev
, aBottom
);
384 drawText(rDev
, r
, false, false, false);
388 static void drawText (OutputDevice
&rDev
, tools::Rectangle r
, bool bClip
, bool bArabicText
, bool bRotate
)
390 rDev
.SetClipRegion( vcl::Region(r
) );
392 const unsigned char pTextUTF8
[] = {
393 0xd9, 0x88, 0xd8, 0xa7, 0xd8, 0xad, 0xd9, 0x90,
394 0xd8, 0xaf, 0xd9, 0x92, 0x20, 0xd8, 0xa5, 0xd8,
395 0xab, 0xd9, 0x8d, 0xd9, 0x86, 0xd9, 0x8a, 0xd9,
396 0x86, 0x20, 0xd8, 0xab, 0xd9, 0x84, 0xd8, 0xa7,
397 0xd8, 0xab, 0xd8, 0xa9, 0xd9, 0x8c, 0x00
399 OUString
aArabicText( reinterpret_cast<char const *>(pTextUTF8
),
400 SAL_N_ELEMENTS( pTextUTF8
) - 1,
401 RTL_TEXTENCODING_UTF8
);
405 // To have more text displayed one after the other (overlapping, and in different colours), then
407 const int nPrintNumCopies
=1;
412 aText
= "Click any rect to zoom!!!!";
414 std::vector
<OUString
> aFontNames
;
416 static Color
const nCols
[] = {
417 COL_BLACK
, COL_BLUE
, COL_GREEN
, COL_CYAN
, COL_RED
, COL_MAGENTA
,
418 COL_BROWN
, COL_GRAY
, COL_LIGHTGRAY
, COL_LIGHTBLUE
, COL_LIGHTGREEN
,
419 COL_LIGHTCYAN
, COL_LIGHTRED
, COL_LIGHTMAGENTA
, COL_YELLOW
, COL_WHITE
422 // a few fonts to start with
423 const char *pNames
[] = {
424 "Times", "Liberation Sans", "Arial", "Linux Biolinum G", "Linux Libertine Display G"
427 for (size_t i
= 0; i
< SAL_N_ELEMENTS(pNames
); i
++)
428 aFontNames
.push_back(OUString::createFromAscii(pNames
[i
]));
430 if (bClip
&& !bRotate
)
432 // only show the first quarter of the text
433 tools::Rectangle
aRect( r
.TopLeft(), Size( r
.GetWidth()/2, r
.GetHeight()/2 ) );
434 rDev
.SetClipRegion( vcl::Region( aRect
) );
437 for (int i
= 1; i
< nPrintNumCopies
+1; i
++)
439 int nFontHeight
=0, nFontIndex
=0, nFontColorIndex
=0;
441 if (nPrintNumCopies
== 1)
443 float const nFontMagnitude
= 0.25f
;
444 // random font size to avoid buffering
445 nFontHeight
= 1 + nFontMagnitude
* (0.9 + comphelper::rng::uniform_real_distribution(0.0, std::nextafter(0.1, DBL_MAX
))) * (r
.Bottom() - r
.Top());
451 // random font size to avoid buffering
452 nFontHeight
= 1 + i
* (0.9 + comphelper::rng::uniform_real_distribution(0.0, std::nextafter(0.1, DBL_MAX
))) * (r
.Top() - r
.Bottom()) / nPrintNumCopies
;
453 nFontIndex
= (i
% aFontNames
.size());
454 nFontColorIndex
=(i
% aFontNames
.size());
457 rDev
.SetTextColor(nCols
[nFontColorIndex
]);
458 vcl::Font
aFont( aFontNames
[nFontIndex
], Size(0, nFontHeight
));
462 tools::Rectangle aFontRect
= r
;
464 int nHeight
= r
.GetHeight();
466 // move the text to the bottom of the bounding rect before rotating
467 aFontRect
.AdjustTop(nHeight
/2 );
468 aFontRect
.AdjustBottom(nHeight
);
470 aFont
.SetOrientation(450_deg10
); // 45 degrees
473 rDev
.DrawText(aFontRect
, aText
);
477 tools::Rectangle
aClipRect( Point( r
.Left(), r
.Top() + ( r
.GetHeight()/2 ) ) , Size( r
.GetWidth()/2, r
.GetHeight()/2 ) );
478 rDev
.SetClipRegion( vcl::Region( aClipRect
) );
481 rDev
.SetClipRegion( vcl::Region(r
) );
486 rDev
.DrawText(r
, aText
);
490 rDev
.SetClipRegion();
493 static void drawComplex (OutputDevice
&rDev
, tools::Rectangle r
)
495 const unsigned char pInvalid
[] = { 0xfe, 0x1f, 0 };
496 const unsigned char pDiacritic1
[] = { 0x61, 0xcc, 0x8a, 0xcc, 0x8c, 0 };
497 const unsigned char pDiacritic2
[] = { 0x61, 0xcc, 0x88, 0xcc, 0x86, 0 };
498 const unsigned char pDiacritic3
[] = { 0x61, 0xcc, 0x8b, 0xcc, 0x87, 0 };
499 const unsigned char pJustification
[] = {
500 0x64, 0x20, 0xc3, 0xa1, 0xc3, 0xa9, 0x77, 0xc4, 0x8d,
501 0xc5, 0xa1, 0xc3, 0xbd, 0xc5, 0x99, 0x20, 0xc4, 0x9b, 0
503 const unsigned char pEmojis
[] = {
504 0xf0, 0x9f, 0x8d, 0x80, 0xf0, 0x9f, 0x91, 0x98,
505 0xf0, 0x9f, 0x92, 0x8a, 0xf0, 0x9f, 0x92, 0x99,
506 0xf0, 0x9f, 0x92, 0xa4, 0xf0, 0x9f, 0x94, 0x90, 0
508 const unsigned char pThreeBowlG
[] = {
509 0xe2, 0x9a, 0x82, 0xe2, 0x99, 0xa8, 0xc4, 0x9e, 0
511 const unsigned char pWavesAndDomino
[] = {
512 0xe2, 0x99, 0x92, 0xf0, 0x9f, 0x81, 0xa0,
513 0xf0, 0x9f, 0x82, 0x93, 0
515 const unsigned char pSpadesAndBits
[] = {
516 0xf0, 0x9f, 0x82, 0xa1, 0xc2, 0xa2, 0xc2, 0xa2, 0
521 const char *mpString
;
523 #define SET(font,string) { font, reinterpret_cast<const char *>(string) }
524 {"sans", "a"}, // logical font - no 'sans' font.
525 {"opensymbol", "#$%"}, // font fallback - $ is missing.
526 SET("sans", pInvalid
), // unicode invalid character
527 // tdf#96266 - stacking diacritics
528 SET("carlito", pDiacritic1
),
529 SET("carlito", pDiacritic2
),
530 SET("carlito", pDiacritic3
),
531 SET("liberation sans", pDiacritic1
),
532 SET("liberation sans", pDiacritic2
),
533 SET("liberation sans", pDiacritic3
),
534 SET("liberation sans", pDiacritic3
),
536 // tdf#95222 - justification issue
537 // - FIXME: replicate justification
538 SET("gentium basic", pJustification
),
540 // tdf#97319 - Unicode beyond BMP; SMP & Plane 2
541 SET("symbola", pEmojis
),
542 SET("symbola", pThreeBowlG
),
543 SET("symbola", pWavesAndDomino
),
544 SET("symbola", pSpadesAndBits
),
547 // Nice clean white background
548 rDev
.DrawWallpaper(r
, Wallpaper(COL_WHITE
));
549 rDev
.SetClipRegion(vcl::Region(r
));
551 Point
aPos(r
.Left(), r
.Top()+20);
553 tools::Long nMaxTextHeight
= 0;
554 for (size_t i
= 0; i
< std::size(aRuns
); ++i
)
557 vcl::Font
aIndexFont("sans", Size(0,20));
558 aIndexFont
.SetColor( COL_BLACK
);
559 tools::Rectangle aTextRect
;
560 rDev
.SetFont(aIndexFont
);
561 OUString aText
= OUString::number(i
) + ".";
562 rDev
.DrawText(aPos
, aText
);
563 if (rDev
.GetTextBoundRect(aTextRect
, aText
))
564 aPos
.Move(aTextRect
.GetWidth() + 8, 0);
567 FontWeight aWeights
[] = { WEIGHT_NORMAL
,
570 FontItalic
const aItalics
[] = { ITALIC_NONE
,
573 vcl::Font
aFont(OUString::createFromAscii(
576 aFont
.SetColor(COL_BLACK
);
577 for (size_t j
= 0; j
< std::size(aWeights
); ++j
)
579 aFont
.SetItalic(aItalics
[j
]);
580 aFont
.SetWeight(aWeights
[j
]);
583 OUString
aString(aRuns
[i
].mpString
,
584 strlen(aRuns
[i
].mpString
),
585 RTL_TEXTENCODING_UTF8
);
586 tools::Long nNewX
= drawStringBox(rDev
, aPos
, aString
,
591 if (aPos
.X() >= r
.Right())
593 aPos
= Point(r
.Left(), aPos
.Y() + nMaxTextHeight
+ 15);
596 j
--; // re-render the last point.
598 if (aPos
.Y() > r
.Bottom())
601 if (aPos
.Y() > r
.Bottom())
605 rDev
.SetClipRegion();
607 // render text, bbox, DX arrays etc.
608 static tools::Long
drawStringBox(OutputDevice
&rDev
, Point aPos
,
609 const OUString
&aText
,
610 tools::Long
&nMaxTextHeight
)
614 tools::Rectangle aTextRect
;
616 rDev
.DrawText(aPos
,aText
);
618 if (rDev
.GetTextBoundRect(aTextRect
, aText
))
620 aTextRect
.Move(aPos
.X(), aPos
.Y());
622 rDev
.SetLineColor(COL_BLACK
);
623 rDev
.DrawRect(aTextRect
);
624 if (aTextRect
.GetHeight() > nMaxTextHeight
)
625 nMaxTextHeight
= aTextRect
.GetHeight();
626 // This should intersect with the text
627 tools::Rectangle
aInnerRect(
628 aTextRect
.Left()+1, aTextRect
.Top()+1,
629 aTextRect
.Right()-1, aTextRect
.Bottom()-1);
630 rDev
.SetLineColor(COL_WHITE
);
631 rDev
.SetRasterOp(RasterOp::Xor
);
632 rDev
.DrawRect(aInnerRect
);
633 rDev
.SetRasterOp(RasterOp::OverPaint
);
636 // DX array rendering
638 rDev
.GetTextArray(aText
, &aItems
);
639 for (tools::Long j
= 0; j
< aText
.getLength(); ++j
)
641 Point aTop
= aTextRect
.TopLeft();
642 Point aBottom
= aTop
;
643 aTop
.Move(aItems
[j
], 0);
644 aBottom
.Move(aItems
[j
], aTextRect
.GetHeight());
645 rDev
.SetLineColor(COL_RED
);
646 rDev
.SetRasterOp(RasterOp::Xor
);
647 rDev
.DrawLine(aTop
,aBottom
);
648 rDev
.SetRasterOp(RasterOp::OverPaint
);
651 aPos
.Move(aTextRect
.GetWidth() + 16, 0);
658 struct DrawCheckered
: public RegionRenderer
660 RENDER_DETAILS(checks
,KEY_C
,20)
661 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
662 const RenderContext
&rCtx
) override
664 if (rCtx
.meStyle
== RENDER_EXPANDED
)
666 std::vector
<tools::Rectangle
> aRegions(DemoRenderer::partition(rCtx
, 2, 2));
667 for (size_t i
= 0; i
< aRegions
.size(); i
++)
670 tools::Rectangle
aSub(aRegions
[i
]);
671 tools::Rectangle
aSmaller(aSub
);
672 aSmaller
.Move(10,10);
673 aSmaller
.setWidth(aSmaller
.getOpenWidth()-20);
674 aSmaller
.setHeight(aSmaller
.getOpenHeight()-24);
677 aRegion
= vcl::Region(aSub
);
680 aRegion
= vcl::Region(aSmaller
);
685 tools::Polygon
aPoly(aSub
);
686 aPoly
.Rotate(aSub
.Center(), 450_deg10
);
687 aPoly
.Clip(aSmaller
);
688 aRegion
= vcl::Region(aPoly
);
693 tools::PolyPolygon aPolyPoly
;
694 sal_Int32 nTW
= aSub
.GetWidth()/6;
695 sal_Int32 nTH
= aSub
.GetHeight()/6;
696 tools::Rectangle
aTiny(Point(4, 4), Size(nTW
*2, nTH
*2));
697 aPolyPoly
.Insert( tools::Polygon(aTiny
));
698 aTiny
.Move(nTW
*3, nTH
*3);
699 aPolyPoly
.Insert( tools::Polygon(aTiny
));
700 aTiny
.Move(nTW
, nTH
);
701 aPolyPoly
.Insert( tools::Polygon(aTiny
));
703 aRegion
= vcl::Region(aPolyPoly
);
707 rDev
.SetClipRegion(aRegion
);
708 rDev
.DrawCheckered(aSub
.TopLeft(), aSub
.GetSize());
709 rDev
.SetClipRegion();
714 rDev
.DrawCheckered(r
.TopLeft(), r
.GetSize());
719 struct DrawPoly
: public RegionRenderer
721 RENDER_DETAILS(poly
,KEY_P
,20)
722 DrawCheckered maCheckered
;
723 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
724 const RenderContext
&rCtx
) override
726 maCheckered
.RenderRegion(rDev
, r
, rCtx
);
728 tools::Long nDx
= r
.GetWidth()/20;
729 tools::Long nDy
= r
.GetHeight()/20;
730 tools::Rectangle
aShrunk(r
);
731 aShrunk
.Move(nDx
, nDy
);
732 aShrunk
.SetSize(Size(r
.GetWidth()-nDx
*2,
733 r
.GetHeight()-nDy
*2));
734 tools::Polygon
aPoly(aShrunk
);
735 tools::PolyPolygon
aPPoly(aPoly
);
736 rDev
.SetLineColor(COL_RED
);
737 rDev
.SetFillColor(COL_RED
);
738 // This hits the optional 'drawPolyPolygon' code-path
739 rDev
.DrawTransparent(aPPoly
, 64);
743 struct DrawEllipse
: public RegionRenderer
745 RENDER_DETAILS(ellipse
,KEY_E
,500)
746 static void doInvert(OutputDevice
&rDev
, const tools::Rectangle
&r
,
749 rDev
.Invert(r
, nFlags
);
750 if (r
.GetWidth() > 10 && r
.GetHeight() > 10)
752 tools::Rectangle
aSmall(r
.Center()-Point(4,4), Size(8,8));
753 rDev
.Invert(aSmall
,nFlags
);
756 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
757 const RenderContext
&rCtx
) override
759 rDev
.SetLineColor(COL_RED
);
760 rDev
.SetFillColor(COL_GREEN
);
763 if (rCtx
.meStyle
== RENDER_EXPANDED
)
765 auto aRegions
= partition(rCtx
, 2, 2);
766 doInvert(rDev
, aRegions
[0], InvertFlags::NONE
);
767 rDev
.DrawText(aRegions
[0], "InvertFlags::NONE");
768 doInvert(rDev
, aRegions
[1], InvertFlags::N50
);
769 rDev
.DrawText(aRegions
[1], "InvertFlags::N50");
770 doInvert(rDev
, aRegions
[3], InvertFlags::TrackFrame
);
771 rDev
.DrawText(aRegions
[3], "InvertFlags::TrackFrame");
776 struct DrawGradient
: public RegionRenderer
778 RENDER_DETAILS(gradient
,KEY_G
,50)
779 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
780 const RenderContext
&rCtx
) override
782 if (rCtx
.meStyle
== RENDER_EXPANDED
)
784 std::vector
<tools::Rectangle
> aRegions(DemoRenderer::partition(rCtx
,5, 4));
785 static Color
const nStartCols
[] = {
786 COL_RED
, COL_RED
, COL_RED
, COL_GREEN
, COL_GREEN
,
787 COL_BLUE
, COL_BLUE
, COL_BLUE
, COL_CYAN
, COL_CYAN
,
788 COL_BLACK
, COL_LIGHTGRAY
, COL_WHITE
, COL_BLUE
, COL_CYAN
,
789 COL_WHITE
, COL_WHITE
, COL_WHITE
, COL_BLACK
, COL_BLACK
791 static Color
const nEndCols
[] = {
792 COL_WHITE
, COL_WHITE
, COL_WHITE
, COL_BLACK
, COL_BLACK
,
793 COL_RED
, COL_RED
, COL_RED
, COL_GREEN
, COL_GREEN
,
794 COL_GRAY
, COL_GRAY
, COL_LIGHTGRAY
, COL_LIGHTBLUE
, COL_LIGHTCYAN
,
795 COL_BLUE
, COL_BLUE
, COL_BLUE
, COL_CYAN
, COL_CYAN
797 css::awt::GradientStyle eStyles
[] = {
798 css::awt::GradientStyle_LINEAR
, css::awt::GradientStyle_AXIAL
, css::awt::GradientStyle_RADIAL
, css::awt::GradientStyle_ELLIPTICAL
, css::awt::GradientStyle_SQUARE
,
799 css::awt::GradientStyle_RECT
, css::awt::GradientStyle::GradientStyle_MAKE_FIXED_SIZE
, css::awt::GradientStyle_LINEAR
, css::awt::GradientStyle_RADIAL
, css::awt::GradientStyle_LINEAR
,
800 css::awt::GradientStyle_LINEAR
, css::awt::GradientStyle_AXIAL
, css::awt::GradientStyle_RADIAL
, css::awt::GradientStyle_ELLIPTICAL
, css::awt::GradientStyle_SQUARE
,
801 css::awt::GradientStyle_RECT
, css::awt::GradientStyle::GradientStyle_MAKE_FIXED_SIZE
, css::awt::GradientStyle_LINEAR
, css::awt::GradientStyle_RADIAL
, css::awt::GradientStyle_LINEAR
803 sal_uInt16 nAngles
[] = {
806 90, 120, 135, 160, 180,
809 sal_uInt16 nBorders
[] = {
816 DemoRenderer::clearRects(rDev
, aRegions
);
817 assert(aRegions
.size() <= SAL_N_ELEMENTS(nStartCols
));
818 assert(aRegions
.size() <= SAL_N_ELEMENTS(nEndCols
));
819 assert(aRegions
.size() <= SAL_N_ELEMENTS(eStyles
));
820 assert(aRegions
.size() <= SAL_N_ELEMENTS(nAngles
));
821 assert(aRegions
.size() <= SAL_N_ELEMENTS(nBorders
));
822 for (size_t i
= 0; i
< aRegions
.size(); i
++)
824 tools::Rectangle aSub
= aRegions
[i
];
826 aGradient
.SetStartColor(nStartCols
[i
]);
827 aGradient
.SetEndColor(nEndCols
[i
]);
828 aGradient
.SetStyle(eStyles
[i
]);
829 aGradient
.SetAngle(Degree10(nAngles
[i
]));
830 aGradient
.SetBorder(nBorders
[i
]);
831 rDev
.DrawGradient(aSub
, aGradient
);
837 aGradient
.SetStartColor(COL_YELLOW
);
838 aGradient
.SetEndColor(COL_RED
);
839 aGradient
.SetStyle(css::awt::GradientStyle_RECT
);
840 aGradient
.SetBorder(r
.GetSize().Width()/20);
841 rDev
.DrawGradient(r
, aGradient
);
846 struct DrawBitmap
: public RegionRenderer
848 RENDER_DETAILS(bitmap
,KEY_B
,10)
850 // Simulate Page Borders rendering - which ultimately should
851 // be done with a shader / gradient
852 static void SimulateBorderStretch(OutputDevice
&rDev
, const tools::Rectangle
& r
)
854 BitmapEx
aPageShadowMask("sw/res/page-shadow-mask.png");
856 BitmapEx
aRight(aPageShadowMask
);
857 sal_Int32 nSlice
= (aPageShadowMask
.GetSizePixel().Width() - 3) / 4;
859 aRight
.Crop(tools::Rectangle(Point((nSlice
* 3) + 3, (nSlice
* 2) + 1),
861 AlphaMask
aAlphaMask(aRight
.GetBitmap());
862 Bitmap
aBlockColor(aAlphaMask
.GetSizePixel(), vcl::PixelFormat::N24_BPP
);
863 aBlockColor
.Erase(COL_RED
);
864 BitmapEx
aShadowStretch(aBlockColor
, aAlphaMask
);
866 Point
aRenderPt(r
.TopLeft());
868 tools::Long aSizes
[] = { 200, 100, 200, 100, 50, 5, 2 };
870 // and yes - we really do this in the page border rendering code ...
871 for (const auto& rSize
: aSizes
)
873 aShadowStretch
.Scale(Size(aShadowStretch
.GetSizePixel().Width(), rSize
),
876 rDev
.DrawBitmapEx(aRenderPt
, aShadowStretch
);
877 aRenderPt
.Move(aShadowStretch
.GetSizePixel().Width() + 4, 0);
880 AlphaMask
aWholeMask(aPageShadowMask
.GetBitmap());
881 aBlockColor
= Bitmap(aPageShadowMask
.GetSizePixel(), vcl::PixelFormat::N24_BPP
);
882 aBlockColor
.Erase(COL_GREEN
);
883 BitmapEx
aWhole(aBlockColor
, aWholeMask
);
885 aRenderPt
= r
.Center();
886 aRenderPt
.Move(nSlice
+1, 0);
888 // An offset background for alpha rendering
889 rDev
.SetFillColor(COL_BLUE
);
890 tools::Rectangle
aSurround(r
.Center(), aPageShadowMask
.GetSizePixel());
891 rDev
.DrawRect(aSurround
);
892 rDev
.DrawBitmapEx(aRenderPt
, aWhole
);
895 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
896 const RenderContext
&rCtx
) override
898 Bitmap
aBitmap(rCtx
.mpDemoRenderer
->maIntroBW
);
899 aBitmap
.Scale(r
.GetSize(), BmpScaleFlag::BestQuality
);
900 rDev
.DrawBitmap(r
.TopLeft(), aBitmap
);
902 SimulateBorderStretch(rDev
, r
);
906 struct DrawBitmapEx
: public RegionRenderer
908 RENDER_DETAILS(bitmapex
,KEY_X
,2)
909 DrawCheckered maCheckered
;
910 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
911 const RenderContext
&rCtx
) override
913 maCheckered
.RenderRegion(rDev
, r
, rCtx
);
915 BitmapEx
aBitmap(rCtx
.mpDemoRenderer
->maIntro
);
916 aBitmap
.Scale(r
.GetSize(), BmpScaleFlag::BestQuality
);
917 AlphaMask
aSemiTransp(aBitmap
.GetSizePixel());
918 aSemiTransp
.Erase(64);
919 rDev
.DrawBitmapEx(r
.TopLeft(), BitmapEx(aBitmap
.GetBitmap(),
924 struct DrawPolyPolygons
: public RegionRenderer
926 RENDER_DETAILS(polypoly
,KEY_N
,100)
927 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
928 const RenderContext
&) override
932 } const aPoints
[] = { { 0.1, 0.1 }, { 0.9, 0.9 },
933 #if FIXME_SELF_INTERSECTING_WORKING
934 { 0.9, 0.1 }, { 0.1, 0.9 },
937 { 0.1, 0.9 }, { 0.5, 0.5 },
938 { 0.9, 0.1 }, { 0.1, 0.1 }
942 tools::PolyPolygon aPolyPoly
;
943 // Render 4x polygons & aggregate into another PolyPolygon
944 for (int x
= 0; x
< 2; x
++)
946 for (int y
= 0; y
< 2; y
++)
948 tools::Rectangle
aSubRect(r
);
949 aSubRect
.Move(x
* r
.GetWidth()/3, y
* r
.GetHeight()/3);
950 aSubRect
.SetSize(Size(r
.GetWidth()/2, r
.GetHeight()/4));
951 tools::Polygon
aPoly(std::size(aPoints
));
952 for (size_t v
= 0; v
< std::size(aPoints
); v
++)
954 aPoly
.SetPoint(Point(aSubRect
.Left() +
955 aSubRect
.GetWidth() * aPoints
[v
].nX
,
957 aSubRect
.GetHeight() * aPoints
[v
].nY
),
960 rDev
.SetLineColor(COL_YELLOW
);
961 rDev
.SetFillColor(COL_BLACK
);
962 rDev
.DrawPolygon(aPoly
);
964 // now move and add to the polypolygon
965 aPoly
.Move(0, r
.GetHeight()/2);
966 aPolyPoly
.Insert(aPoly
);
969 rDev
.SetLineColor(COL_LIGHTRED
);
970 rDev
.SetFillColor(COL_GREEN
);
971 rDev
.DrawTransparent(aPolyPoly
, 50);
975 struct DrawClipped
: public RegionRenderer
977 RENDER_DETAILS(clip
,KEY_D
,10)
978 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
979 const RenderContext
&) override
981 std::vector
<tools::Rectangle
> aRegions(DemoRenderer::partition(r
, 2, 2));
982 const int nLimits
[] = { 4, -100 };
983 for (int i
= 0; i
< 2; ++i
)
986 rDev
.Push(vcl::PushFlags::CLIPREGION
);
987 tools::Rectangle aOuter
= aRegions
[i
];
988 tools::Rectangle aInner
= aOuter
;
989 while (aInner
.GetWidth() > nLimits
[i
] && aInner
.GetHeight() > nLimits
[i
])
992 rDev
.SetClipRegion(vcl::Region(aInner
));
993 rDev
.SetFillColor(Color::HSBtoRGB(nHue
, 75, 100));
994 nHue
= (nHue
+ 97) % 360;
995 rDev
.DrawRect(aOuter
);
1001 sal_uInt16 nHue
= 0;
1002 tools::Rectangle aOuter
= aRegions
[2];
1003 std::vector
<tools::Rectangle
> aPieces(DemoRenderer::partition(aOuter
, 2, 2));
1004 for (int j
= 0; j
< std::min(aOuter
.GetWidth(), aOuter
.GetHeight())/5; ++j
)
1006 rDev
.Push(vcl::PushFlags::CLIPREGION
);
1008 vcl::Region aClipRegion
;
1009 for (int i
= 0; i
< 4; ++i
)
1011 aPieces
[i
].expand(-1);
1012 aPieces
[i
].Move(2 - i
/2, 2 - i
/2);
1013 aClipRegion
.Union(aPieces
[i
]);
1015 assert (aClipRegion
.getRegionBand());
1016 rDev
.SetClipRegion(aClipRegion
);
1017 rDev
.SetFillColor(Color::HSBtoRGB(nHue
, 75, 75));
1018 nHue
= (nHue
+ 97) % 360;
1019 rDev
.DrawRect(aOuter
);
1026 sal_uInt16 nHue
= 0;
1027 tools::Rectangle aOuter
= aRegions
[3];
1028 std::vector
<tools::Rectangle
> aPieces(DemoRenderer::partition(aOuter
, 2, 2));
1032 rDev
.Push(vcl::PushFlags::CLIPREGION
);
1034 for (int i
= 0; i
< 4; ++i
)
1036 vcl::Region aClipRegion
;
1037 tools::Polygon aPoly
;
1040 case 0: // 45degree rectangle.
1041 aPoly
= tools::Polygon(aPieces
[i
]);
1042 aPoly
.Rotate(aPieces
[i
].Center(), 450_deg10
);
1045 aPoly
= tools::Polygon(aPieces
[i
],
1046 aPieces
[i
].TopLeft(),
1047 aPieces
[i
].BottomRight());
1050 aPoly
= tools::Polygon(aPieces
[i
],
1051 aPieces
[i
].GetWidth()/5,
1052 aPieces
[i
].GetHeight()/5);
1053 aPoly
.Rotate(aPieces
[i
].Center(), 450_deg10
);
1056 aClipRegion
= vcl::Region(aPoly
);
1057 aPieces
[i
].expand(-1);
1058 aPieces
[i
].Move(2 - i
/2, 2 - i
/2);
1060 bDone
= aPieces
[i
].GetWidth() < 4 ||
1061 aPieces
[i
].GetHeight() < 4;
1065 assert (!aClipRegion
.getRegionBand());
1067 rDev
.SetClipRegion(aClipRegion
);
1068 rDev
.SetFillColor(Color::HSBtoRGB(nHue
, 50, 75));
1069 nHue
= (nHue
+ 97) % 360;
1070 rDev
.DrawRect(aOuter
);
1080 struct DrawToVirtualDevice
: public RegionRenderer
1082 RENDER_DETAILS(vdev
,KEY_V
,1)
1087 RENDER_AS_ALPHA_OUTDEV
1090 static void SizeAndRender(OutputDevice
&rDev
, const tools::Rectangle
& r
, RenderType eType
,
1091 const RenderContext
&rCtx
)
1093 ScopedVclPtr
<VirtualDevice
> pNested
;
1095 if (static_cast<int>(eType
) < RENDER_AS_BITMAPEX
)
1096 pNested
= VclPtr
<VirtualDevice
>::Create(rDev
).get();
1098 pNested
= VclPtr
<VirtualDevice
>::Create(rDev
,DeviceFormat::WITH_ALPHA
).get();
1100 pNested
->SetOutputSizePixel(r
.GetSize());
1101 tools::Rectangle
aWhole(Point(0,0), r
.GetSize());
1104 rCtx
.mpDemoRenderer
->drawToDevice(*pNested
, r
.GetSize(), true);
1106 if (eType
== RENDER_AS_BITMAP
)
1108 Bitmap
aBitmap(pNested
->GetBitmap(Point(0,0),aWhole
.GetSize()));
1109 rDev
.DrawBitmap(r
.TopLeft(), aBitmap
);
1111 else if (eType
== RENDER_AS_BITMAPEX
)
1113 BitmapEx
aBitmapEx(pNested
->GetBitmapEx(Point(0,0),aWhole
.GetSize()));
1114 rDev
.DrawBitmapEx(r
.TopLeft(), aBitmapEx
);
1116 else if (eType
== RENDER_AS_OUTDEV
||
1117 eType
== RENDER_AS_ALPHA_OUTDEV
)
1119 rDev
.DrawOutDev(r
.TopLeft(), r
.GetSize(),
1120 aWhole
.TopLeft(), aWhole
.GetSize(),
1124 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
1125 const RenderContext
&rCtx
) override
1127 // avoid infinite recursion
1131 if (rCtx
.meStyle
== RENDER_EXPANDED
)
1133 std::vector
<tools::Rectangle
> aRegions(DemoRenderer::partition(rCtx
,2, 2));
1134 DemoRenderer::clearRects(rDev
, aRegions
);
1136 RenderType
const eRenderTypes
[] { RENDER_AS_BITMAP
, RENDER_AS_OUTDEV
,
1137 RENDER_AS_BITMAPEX
, RENDER_AS_ALPHA_OUTDEV
};
1138 for (size_t i
= 0; i
< aRegions
.size(); i
++)
1139 SizeAndRender(rDev
, aRegions
[i
], eRenderTypes
[i
], rCtx
);
1142 SizeAndRender(rDev
, r
, RENDER_AS_BITMAP
, rCtx
);
1146 struct DrawXOR
: public RegionRenderer
1148 RENDER_DETAILS(xor,KEY_X
,1)
1150 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
1151 const RenderContext
&rCtx
) override
1153 // avoid infinite recursion
1159 AntialiasingFlags nFlags
= rDev
.GetAntialiasing();
1160 rDev
.SetAntialiasing(nFlags
& ~AntialiasingFlags::Enable
);
1161 rDev
.SetRasterOp( RasterOp::Xor
);
1163 rCtx
.mpDemoRenderer
->drawThumbs(rDev
, r
, true);
1169 struct DrawIcons
: public RegionRenderer
1171 RENDER_DETAILS(icons
,KEY_I
,1)
1173 std::vector
<OUString
> maIconNames
;
1174 std::vector
<BitmapEx
> maIcons
;
1176 DrawIcons() : bHasLoadedAll(false)
1178 // a few icons to start with
1179 const char *pNames
[] = {
1180 "cmd/lc_openurl.png",
1181 "cmd/lc_newdoc.png",
1182 "cmd/lc_choosemacro.png",
1184 "cmd/lc_saveas.png",
1185 "cmd/lc_importdialog.png",
1186 "cmd/lc_sendmail.png",
1187 "cmd/lc_editdoc.png",
1189 "cmd/lc_combobox.png",
1190 "cmd/lc_insertformcombo.png",
1191 "cmd/lc_printpreview.png",
1195 "cmd/sc_autopilotmenu.png",
1196 "cmd/lc_formatpaintbrush.png",
1200 "cmd/lc_fieldnames.png",
1201 "cmd/lc_hyperlinkdialog.png",
1202 "cmd/lc_basicshapes.rectangle.png",
1203 "cmd/lc_basicshapes.round-rectangle.png"
1205 for (size_t i
= 0; i
< SAL_N_ELEMENTS(pNames
); i
++)
1207 maIconNames
.push_back(OUString::createFromAscii(pNames
[i
]));
1208 maIcons
.emplace_back(maIconNames
[i
]);
1212 void LoadAllImages()
1216 bHasLoadedAll
= true;
1218 css::uno::Reference
<css::container::XNameAccess
> xRef(ImageTree::get().getNameAccess());
1219 const css::uno::Sequence
< OUString
> aAllIcons
= xRef
->getElementNames();
1221 for (const auto& rIcon
: aAllIcons
)
1223 if (rIcon
.endsWithIgnoreAsciiCase("svg"))
1224 continue; // too slow to load.
1225 maIconNames
.push_back(rIcon
);
1226 maIcons
.emplace_back(rIcon
);
1230 void doDrawIcons(OutputDevice
&rDev
, tools::Rectangle r
, bool bExpanded
)
1232 tools::Long nMaxH
= 0;
1233 Point
p(r
.LeftCenter());
1234 size_t nToRender
= maIcons
.size();
1236 if (!bExpanded
&& maIcons
.size() > 64)
1238 for (size_t i
= 0; i
< nToRender
; i
++)
1240 Size
aSize(maIcons
[i
].GetSizePixel());
1241 // sAL_DEBUG("Draw icon '" << maIconNames[i] << "'");
1244 rDev
.DrawBitmapEx(p
, maIcons
[i
]);
1247 basegfx::B2DHomMatrix aTransform
;
1248 aTransform
.scale(aSize
.Width(), aSize
.Height());
1252 aTransform
.shearX(static_cast<double>((i
>> 2) % 8) / 8);
1253 aTransform
.shearY(static_cast<double>((i
>> 4) % 8) / 8);
1256 aTransform
.translate(-aSize
.Width()/2, -aSize
.Height()/2);
1257 aTransform
.rotate(i
);
1260 aTransform
.shearX(static_cast<double>((i
>> 2) % 8) / 8);
1261 aTransform
.shearY(static_cast<double>((i
>> 4) % 8) / 8);
1263 aTransform
.translate(aSize
.Width()/2, aSize
.Height()/2);
1266 aTransform
.translate(-aSize
.Width()/2, -aSize
.Height()/2);
1267 aTransform
.rotate(2 * 2 * M_PI
* i
/ nToRender
);
1268 aTransform
.translate(aSize
.Width()/2, aSize
.Height()/2);
1271 aTransform
.translate(p
.X(), p
.Y());
1272 rDev
.DrawTransformedBitmapEx(aTransform
, maIcons
[i
]);
1276 p
.Move(aSize
.Width(), 0);
1277 if (aSize
.Height() > nMaxH
)
1278 nMaxH
= aSize
.Height();
1279 if (p
.X() >= r
.Right()) // wrap to next line
1281 p
= Point(r
.Left(), p
.Y() + nMaxH
);
1284 if (p
.Y() >= r
.Bottom()) // re-start at middle
1289 static BitmapEx
AlphaRecovery(OutputDevice
&rDev
, Point aPt
, BitmapEx
const &aSrc
)
1291 // Compositing onto 2x colors beyond our control
1292 ScopedVclPtrInstance
< VirtualDevice
> aWhite
;
1293 ScopedVclPtrInstance
< VirtualDevice
> aBlack
;
1294 aWhite
->SetOutputSizePixel(aSrc
.GetSizePixel());
1295 aWhite
->SetBackground(Wallpaper(COL_WHITE
));
1297 aBlack
->SetOutputSizePixel(aSrc
.GetSizePixel());
1298 aBlack
->SetBackground(Wallpaper(COL_BLACK
));
1300 aWhite
->DrawBitmapEx(Point(), aSrc
);
1301 aBlack
->DrawBitmapEx(Point(), aSrc
);
1303 // Now recover that alpha...
1304 Bitmap aWhiteBmp
= aWhite
->GetBitmap(Point(),aSrc
.GetSizePixel());
1305 Bitmap aBlackBmp
= aBlack
->GetBitmap(Point(),aSrc
.GetSizePixel());
1306 AlphaMask
aMask(aSrc
.GetSizePixel());
1307 Bitmap
aRecovered(aSrc
.GetSizePixel(), vcl::PixelFormat::N24_BPP
);
1309 BitmapScopedWriteAccess
pMaskAcc(aMask
);
1310 BitmapScopedWriteAccess
pRecAcc(aRecovered
);
1311 BitmapScopedReadAccess
pAccW(aWhiteBmp
); // a * pix + (1-a)
1312 BitmapScopedReadAccess
pAccB(aBlackBmp
); // a * pix + 0
1313 int nSizeX
= aSrc
.GetSizePixel().Width();
1314 int nSizeY
= aSrc
.GetSizePixel().Height();
1315 for (int y
= 0; y
< nSizeY
; y
++)
1317 Scanline pScanlineMask
= pMaskAcc
->GetScanline( y
);
1318 Scanline pScanlineRec
= pRecAcc
->GetScanline( y
);
1319 Scanline pScanlineW
= pAccW
->GetScanline( y
);
1320 Scanline pScanlineB
= pAccB
->GetScanline( y
);
1321 for (int x
= 0; x
< nSizeX
; x
++)
1323 BitmapColor aColW
= pAccW
->GetPixelFromData(pScanlineW
,x
);
1324 BitmapColor aColB
= pAccB
->GetPixelFromData(pScanlineB
,x
);
1325 tools::Long nAR
= static_cast<tools::Long
>(aColW
.GetRed() - aColB
.GetRed()); // (1-a)
1326 tools::Long nAG
= static_cast<tools::Long
>(aColW
.GetGreen() - aColB
.GetGreen()); // (1-a)
1327 tools::Long nAB
= static_cast<tools::Long
>(aColW
.GetBlue() - aColB
.GetBlue()); // (1-a)
1329 #define CLAMP(a,b,c) (((a)<=(b))?(b):(((a)>=(c))?(c):(a)))
1331 // we get the most precision from the largest delta
1332 tools::Long nInverseAlpha
= std::max(nAR
, std::max(nAG
, nAB
)); // (1-a)
1333 nInverseAlpha
= CLAMP(nInverseAlpha
, 0, 255);
1334 tools::Long nAlpha
= 255 - nInverseAlpha
;
1336 pMaskAcc
->SetPixelOnData(pScanlineMask
,x
,BitmapColor(static_cast<sal_Int8
>(CLAMP(nInverseAlpha
,0,255))));
1337 // now recover the pixels
1338 tools::Long nR
= (aColW
.GetRed() + aColB
.GetRed() - nInverseAlpha
) * 128;
1339 tools::Long nG
= (aColW
.GetGreen() + aColB
.GetGreen() - nInverseAlpha
) * 128;
1340 tools::Long nB
= (aColW
.GetBlue() + aColB
.GetBlue() - nInverseAlpha
) * 128;
1342 { // doesn't matter what's behind transparency
1347 nR
/= nAlpha
; nG
/= nAlpha
; nB
/= nAlpha
;
1349 pRecAcc
->SetPixelOnData(pScanlineRec
,x
,BitmapColor(
1350 static_cast<sal_uInt8
>(CLAMP(nR
,0,255)),
1351 static_cast<sal_uInt8
>(CLAMP(nG
,0,255)),
1352 static_cast<sal_uInt8
>(CLAMP(nB
,0,255))));
1357 rDev
.DrawBitmap(aPt
, aWhiteBmp
);
1358 aPt
.Move(aSrc
.GetSizePixel().Width(), 0);
1359 rDev
.DrawBitmap(aPt
, aBlackBmp
);
1360 aPt
.Move(aSrc
.GetSizePixel().Width(), 0);
1361 rDev
.DrawBitmap(aPt
, aRecovered
);
1362 aPt
.Move(aSrc
.GetSizePixel().Width(), 0);
1363 rDev
.DrawBitmap(aPt
, aMask
.GetBitmap());
1364 aPt
.Move(aSrc
.GetSizePixel().Width(), 0);
1366 return BitmapEx(aRecovered
, aMask
);
1369 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
1370 const RenderContext
&rCtx
) override
1372 if (rCtx
.meStyle
== RENDER_EXPANDED
)
1376 Point
aLocation(0,maIcons
[0].GetSizePixel().Height() + 8);
1377 for (size_t i
= 0; i
< maIcons
.size(); i
++)
1379 BitmapEx aSrc
= maIcons
[i
];
1382 Point
aAbove(aLocation
);
1383 aAbove
.Move(0,-aSrc
.GetSizePixel().Height() - 4);
1384 rDev
.DrawBitmapEx(aAbove
, aSrc
);
1385 aAbove
.Move(aSrc
.GetSizePixel().Width(),0);
1386 aAbove
.Move(aSrc
.GetSizePixel().Width(),0);
1387 rDev
.DrawBitmap(aAbove
, aSrc
.GetBitmap());
1388 aAbove
.Move(aSrc
.GetSizePixel().Width(),0);
1389 rDev
.DrawBitmap(aAbove
, aSrc
.GetAlphaMask().GetBitmap());
1391 // intermediates middle
1392 BitmapEx aResult
= AlphaRecovery(rDev
, aLocation
, aSrc
);
1395 Point
aBelow(aLocation
);
1396 aBelow
.Move(0,aResult
.GetSizePixel().Height());
1397 rDev
.DrawBitmapEx(aBelow
, aResult
);
1399 // mini convert test.
1400 aBelow
.Move(aResult
.GetSizePixel().Width()+4,0);
1401 rDev
.DrawBitmapEx(aBelow
, aResult
);
1403 Bitmap aGrey
= aSrc
.GetBitmap();
1404 aGrey
.Convert(BmpConversion::N8BitGreys
);
1405 rDev
.DrawBitmap(aBelow
, aGrey
);
1407 aBelow
.Move(aGrey
.GetSizePixel().Width(),0);
1408 BitmapEx
aGreyMask(aSrc
);
1409 rDev
.DrawBitmapEx(aBelow
, aGreyMask
);
1411 aLocation
.Move(aSrc
.GetSizePixel().Width()*6,0);
1412 if (aLocation
.X() > r
.Right())
1413 aLocation
= Point(0,aLocation
.Y()+aSrc
.GetSizePixel().Height()*3+4);
1416 // now go crazy with random foo
1417 doDrawIcons(rDev
, r
, true);
1421 doDrawIcons(rDev
, r
, false);
1426 struct FetchDrawBitmap
: public RegionRenderer
1428 RENDER_DETAILS(fetchdraw
,KEY_F
,50)
1429 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
1430 const RenderContext
&) override
1432 Bitmap
aBitmap(rDev
.GetBitmap(Point(0,0),rDev
.GetOutputSizePixel()));
1433 aBitmap
.Scale(r
.GetSize(), BmpScaleFlag::BestQuality
);
1434 rDev
.DrawBitmap(r
.TopLeft(), aBitmap
);
1438 void drawThumbs(vcl::RenderContext
& rDev
, tools::Rectangle aRect
, bool bVDev
)
1441 aCtx
.meStyle
= RENDER_THUMB
;
1442 aCtx
.mbVDev
= bVDev
;
1443 aCtx
.mpDemoRenderer
= this;
1444 aCtx
.maSize
= aRect
.GetSize();
1445 std::vector
<tools::Rectangle
> aRegions(partition(aRect
, mnSegmentsX
, mnSegmentsY
));
1446 DemoRenderer::clearRects(rDev
, aRegions
);
1447 for (size_t i
= 0; i
< maRenderers
.size(); i
++)
1449 RegionRenderer
* r
= maRenderers
[i
];
1451 rDev
.SetClipRegion( vcl::Region( aRegions
[i
] ) );
1454 if (getIterCount() > 0)
1458 double nStartTime
= getTimeNow();
1459 for (int j
= 0; j
< r
->getTestRepeatCount() * THUMB_REPEAT_FACTOR
; j
++)
1460 r
->RenderRegion(rDev
, aRegions
[i
], aCtx
);
1461 addTime(i
, (getTimeNow() - nStartTime
) / THUMB_REPEAT_FACTOR
);
1463 for (int j
= 0; j
< r
->getTestRepeatCount(); j
++)
1464 r
->RenderRegion(rDev
, aRegions
[i
], aCtx
);
1467 r
->RenderRegion(rDev
, aRegions
[i
], aCtx
);
1469 rDev
.SetClipRegion();
1473 void drawToDevice(vcl::RenderContext
& rDev
, Size aSize
, bool bVDev
)
1476 aCtx
.mbVDev
= bVDev
;
1477 aCtx
.mpDemoRenderer
= this;
1478 aCtx
.maSize
= aSize
;
1479 tools::Rectangle
aWholeWin(Point(0,0), rDev
.GetOutputSizePixel());
1481 drawBackground(rDev
, aWholeWin
);
1483 if (!bVDev
/* want everything in the vdev */ &&
1484 mnSelectedRenderer
>= 0 &&
1485 o3tl::make_unsigned(mnSelectedRenderer
) < maRenderers
.size())
1487 aCtx
.meStyle
= RENDER_EXPANDED
;
1488 RegionRenderer
* r
= maRenderers
[mnSelectedRenderer
];
1490 if (getIterCount() > 0)
1492 double nStartTime
= getTimeNow();
1493 for (int i
= 0; i
< r
->getTestRepeatCount(); i
++)
1494 r
->RenderRegion(rDev
, aWholeWin
, aCtx
);
1495 addTime(mnSelectedRenderer
, getTimeNow() - nStartTime
);
1497 r
->RenderRegion(rDev
, aWholeWin
, aCtx
);
1500 drawThumbs(rDev
, aWholeWin
, bVDev
);
1502 std::vector
<VclPtr
<vcl::Window
> > maInvalidates
;
1503 void addInvalidate(vcl::Window
*pWindow
) { maInvalidates
.emplace_back(pWindow
); };
1504 void removeInvalidate(vcl::Window
*pWindow
)
1506 auto aIt
= std::find(maInvalidates
.begin(), maInvalidates
.end(), pWindow
);
1507 if (aIt
!= maInvalidates
.end())
1508 maInvalidates
.erase(aIt
);
1512 for (auto const& invalidate
: maInvalidates
)
1513 invalidate
->Invalidate();
1519 #if FIXME_BOUNCE_BUTTON
1520 IMPL_LINK_NOARG(DemoRenderer
,BounceTimerCb
,Timer
*,void)
1522 mpButton
->Check(mnBounceX
>0);
1523 mpButton
->SetPressed(mnBounceY
>0);
1525 Point aCur
= mpButtonWin
->GetPosPixel();
1526 static const int nMovePix
= 10;
1527 aCur
.Move(mnBounceX
* nMovePix
, mnBounceX
* nMovePix
);
1528 Size aWinSize
= GetSizePixel();
1529 if (aCur
.X() <= 0 || aCur
.X() >= aWinSize
.Width())
1531 if (aCur
.Y() <= 0 || aCur
.Y() >= aWinSize
.Height())
1533 mpButtonWin
->SetPosPixel(aCur
);
1535 // All smoke and mirrors to test sub-region invalidation underneath
1536 Rectangle
aRect(aCur
, mpButtonWin
->GetSizePixel());
1541 void DemoRenderer::KeyInput(const KeyEvent
&rKEvt
)
1543 sal_uInt16 nCode
= rKEvt
.GetKeyCode().GetCode();
1545 // click to zoom out
1546 if (mnSelectedRenderer
>= 0)
1548 if (nCode
== KEY_ESCAPE
|| nCode
== KEY_BACKSPACE
)
1550 mnSelectedRenderer
= -1;
1557 for (size_t i
= 0; i
< maRenderers
.size(); i
++)
1559 if (nCode
== maRenderers
[i
]->getAccelerator())
1561 mnSelectedRenderer
= i
;
1569 bool DemoRenderer::MouseButtonDown(const MouseEvent
& rMEvt
)
1571 // click to zoom out
1572 if (mnSelectedRenderer
>= 0)
1574 mnSelectedRenderer
= -1;
1579 // click on a region to zoom into it
1580 std::vector
<tools::Rectangle
> aRegions(partition(GetSizePixel(), mnSegmentsX
, mnSegmentsY
));
1581 for (size_t i
= 0; i
< aRegions
.size(); i
++)
1583 if (aRegions
[i
].Contains(rMEvt
.GetPosPixel()))
1585 mnSelectedRenderer
= i
;
1591 #if FIXME_BOUNCE_BUTTON
1592 // otherwise bounce floating windows
1595 mpButtonWin
= VclPtr
<FloatingWindow
>::Create(this);
1596 mpButton
= VclPtr
<PushButton
>::Create(mpButtonWin
);
1597 mpButton
->SetSymbol(SymbolType::HELP
);
1598 mpButton
->SetText("PushButton demo");
1599 mpButton
->SetPosSizePixel(Point(0,0), mpButton
->GetOptimalSize());
1601 mpButtonWin
->SetPosSizePixel(Point(0,0), mpButton
->GetOptimalSize());
1602 mpButtonWin
->Show();
1603 mnBounceX
= 1; mnBounceX
= 1;
1604 maBounce
.SetInvokeHandler(LINK(this,DemoRenderer
,BounceTimerCb
));
1605 maBounce
.SetTimeout(55);
1619 void DemoRenderer::InitRenderers()
1621 maRenderers
.push_back(new DrawLines
);
1622 maRenderers
.push_back(new DrawText
);
1623 maRenderers
.push_back(new DrawPoly
);
1624 maRenderers
.push_back(new DrawEllipse
);
1625 maRenderers
.push_back(new DrawCheckered
);
1626 maRenderers
.push_back(new DrawBitmapEx
);
1627 maRenderers
.push_back(new DrawBitmap
);
1628 maRenderers
.push_back(new DrawGradient
);
1629 maRenderers
.push_back(new DrawPolyPolygons
);
1630 maRenderers
.push_back(new DrawClipped
);
1631 maRenderers
.push_back(new DrawToVirtualDevice
);
1632 maRenderers
.push_back(new DrawXOR
);
1633 maRenderers
.push_back(new DrawIcons());
1634 maRenderers
.push_back(new FetchDrawBitmap
);
1637 OUString
DemoRenderer::getRendererList()
1639 OUStringBuffer aBuf
;
1640 for (size_t i
= 0; i
< maRenderers
.size(); i
++)
1642 aBuf
.append(maRenderers
[i
]->getName());
1645 return aBuf
.makeStringAndClear();
1648 double DemoRenderer::getAndResetBenchmark(const RenderStyle style
)
1650 double geomean
= 1.0;
1651 fprintf(stderr
, "Rendering: %s, Times (ms):\n", style
== RENDER_THUMB
? "THUMB": "EXPANDED");
1652 for (size_t i
= 0; i
< maRenderers
.size(); i
++)
1654 double avgtime
= maRenderers
[i
]->sumTime
/ maRenderers
[i
]->countTime
;
1656 fprintf(stderr
, "%s: %f (iteration: %d*%d*%d)\n",
1657 OUStringToOString(maRenderers
[i
]->getName(),
1658 RTL_TEXTENCODING_UTF8
).getStr(), avgtime
,
1659 maRenderers
[i
]->countTime
, maRenderers
[i
]->getTestRepeatCount(),
1660 (style
== RENDER_THUMB
) ? THUMB_REPEAT_FACTOR
: 1);
1661 maRenderers
[i
]->sumTime
= 0;
1662 maRenderers
[i
]->countTime
= 0;
1664 geomean
= pow(geomean
, 1.0/maRenderers
.size());
1665 fprintf(stderr
, "GEOMEAN_%s: %f\n", style
== RENDER_THUMB
? "THUMB": "EXPANDED", geomean
);
1669 void DemoRenderer::setIterCount(sal_Int32 i
)
1674 sal_Int32
DemoRenderer::getIterCount() const
1679 void DemoRenderer::addTime(int i
, double t
)
1681 maRenderers
[i
]->sumTime
+= t
/ maRenderers
[i
]->getTestRepeatCount();
1682 maRenderers
[i
]->countTime
++;
1685 void DemoRenderer::selectRenderer(std::u16string_view rName
)
1687 for (size_t i
= 0; i
< maRenderers
.size(); i
++)
1689 if (maRenderers
[i
]->getName() == rName
)
1691 mnSelectedRenderer
= i
;
1698 int DemoRenderer::selectNextRenderer()
1700 mnSelectedRenderer
++;
1701 if (mnSelectedRenderer
== static_cast<signed>(maRenderers
.size()))
1702 mnSelectedRenderer
= -1;
1704 return mnSelectedRenderer
;
1709 class DemoWin
: public WorkWindow
1711 DemoRenderer
&mrRenderer
;
1715 class RenderThread final
: public salhelper::Thread
{
1717 sal_uInt32
const mnDelaySecs
= 0;
1719 RenderThread(DemoWin
&rWin
, sal_uInt32 nDelaySecs
)
1720 : Thread("vcldemo render thread")
1722 , mnDelaySecs(nDelaySecs
)
1726 virtual ~RenderThread() override
1730 virtual void execute() override
1732 std::this_thread::sleep_for(std::chrono::seconds(mnDelaySecs
));
1734 SolarMutexGuard aGuard
;
1735 fprintf (stderr
, "render from a different thread\n");
1739 rtl::Reference
<RenderThread
> mxThread
;
1742 DemoWin(DemoRenderer
&rRenderer
, bool bThreads
) :
1743 WorkWindow(nullptr, WB_APP
| WB_STDWORK
),
1744 mrRenderer(rRenderer
),
1745 testThreads(bThreads
)
1747 mrRenderer
.addInvalidate(this);
1748 underTesting
= false;
1750 virtual ~DemoWin() override
1754 virtual void dispose() override
1757 mrRenderer
.removeInvalidate(this);
1758 WorkWindow::dispose();
1760 virtual void MouseButtonDown(const MouseEvent
& rMEvt
) override
1762 mrRenderer
.SetSizePixel(GetSizePixel());
1763 if (mrRenderer
.MouseButtonDown(rMEvt
))
1767 { // render this window asynchronously in a new thread
1768 sal_uInt32 nDelaySecs
= 0;
1769 if (rMEvt
.GetButtons() & MOUSE_RIGHT
)
1771 mxThread
= new RenderThread(*this, nDelaySecs
);
1774 { // spawn another window
1775 VclPtrInstance
<DemoWin
> pNewWin(mrRenderer
, testThreads
);
1776 pNewWin
->SetText("Another interactive VCL demo window");
1780 virtual void KeyInput(const KeyEvent
& rKEvt
) override
1782 mrRenderer
.SetSizePixel(GetSizePixel());
1783 mrRenderer
.KeyInput(rKEvt
);
1785 virtual void Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRect
) override
1787 mrRenderer
.SetSizePixel(GetSizePixel());
1788 fprintf(stderr
, "DemoWin::Paint(%" SAL_PRIdINT64
",%" SAL_PRIdINT64
",%" SAL_PRIdINT64
",%" SAL_PRIdINT64
")\n", sal_Int64(rRect
.Left()), sal_Int64(rRect
.Top()), sal_Int64(rRect
.getOpenWidth()), sal_Int64(rRect
.getOpenHeight()));
1789 if (mrRenderer
.getIterCount() == 0)
1790 mrRenderer
.drawToDevice(rRenderContext
, GetSizePixel(), false);
1792 TestAndQuit(rRenderContext
);
1795 void TestAndQuit(vcl::RenderContext
& rRenderContext
)
1799 underTesting
= true;
1800 for (sal_Int32 i
= 0; i
< mrRenderer
.getIterCount(); i
++)
1802 while (mrRenderer
.selectNextRenderer() > -1)
1804 mrRenderer
.drawToDevice(rRenderContext
, GetSizePixel(), false);
1808 double expandedGEOMEAN
= mrRenderer
.getAndResetBenchmark(RENDER_EXPANDED
);
1810 for (sal_Int32 i
= 0; i
< mrRenderer
.getIterCount(); i
++)
1811 mrRenderer
.drawToDevice(rRenderContext
, GetSizePixel(), false);
1813 double thumbGEOMEAN
= mrRenderer
.getAndResetBenchmark(RENDER_THUMB
);
1815 fprintf(stderr
, "GEOMEAN_TOTAL: %f\n", pow(thumbGEOMEAN
* expandedGEOMEAN
, 0.5));
1816 Application::Quit();
1820 struct PointerData
{
1821 PointerStyle eStyle
;
1827 const PointerData gvPointerData
[] = {
1828 { PointerStyle::Null
, "Null" },
1829 { PointerStyle::Magnify
, "Magnify" },
1830 { PointerStyle::Fill
, "Fill" },
1831 { PointerStyle::MoveData
, "MoveData" },
1832 { PointerStyle::CopyData
, "CopyData" },
1833 { PointerStyle::MoveFile
, "MoveFile" },
1834 { PointerStyle::CopyFile
, "CopyFile" },
1835 { PointerStyle::MoveFiles
, "MoveFiles" },
1836 { PointerStyle::CopyFiles
, "CopyFiles" },
1837 { PointerStyle::NotAllowed
, "NotAllowed" },
1838 { PointerStyle::Rotate
, "Rotate" },
1839 { PointerStyle::HShear
, "HShear" },
1840 { PointerStyle::VShear
, "VShear" },
1841 { PointerStyle::DrawLine
, "DrawLine" },
1842 { PointerStyle::DrawRect
, "DrawRect" },
1843 { PointerStyle::DrawPolygon
, "DrawPolygon" },
1844 { PointerStyle::DrawBezier
, "DrawBezier" },
1845 { PointerStyle::DrawArc
, "DrawArc" },
1846 { PointerStyle::DrawPie
, "DrawPie" },
1847 { PointerStyle::DrawCircleCut
, "DrawCircleCut" },
1848 { PointerStyle::DrawEllipse
, "DrawEllipse" },
1849 { PointerStyle::DrawConnect
, "DrawConnect" },
1850 { PointerStyle::DrawText
, "DrawText" },
1851 { PointerStyle::Mirror
, "Mirror" },
1852 { PointerStyle::Crook
, "Crook" },
1853 { PointerStyle::Crop
, "Crop" },
1854 { PointerStyle::MovePoint
, "MovePoint" },
1855 { PointerStyle::MoveBezierWeight
, "MoveBezierWeight" },
1856 { PointerStyle::DrawFreehand
, "DrawFreehand" },
1857 { PointerStyle::DrawCaption
, "DrawCaption" },
1858 { PointerStyle::LinkData
, "LinkData" },
1859 { PointerStyle::MoveDataLink
, "MoveDataLink" },
1860 { PointerStyle::CopyDataLink
, "CopyDataLink" },
1861 { PointerStyle::LinkFile
, "LinkFile" },
1862 { PointerStyle::MoveFileLink
, "MoveFileLink" },
1863 { PointerStyle::CopyFileLink
, "CopyFileLink" },
1864 { PointerStyle::Chart
, "Chart" },
1865 { PointerStyle::Detective
, "Detective" },
1866 { PointerStyle::PivotCol
, "PivotCol" },
1867 { PointerStyle::PivotRow
, "PivotRow" },
1868 { PointerStyle::PivotField
, "PivotField" },
1869 { PointerStyle::PivotDelete
, "PivotDelete" },
1870 { PointerStyle::Chain
, "Chain" },
1871 { PointerStyle::ChainNotAllowed
, "ChainNotAllowed" },
1872 { PointerStyle::AutoScrollN
, "AutoScrollN" },
1873 { PointerStyle::AutoScrollS
, "AutoScrollS" },
1874 { PointerStyle::AutoScrollW
, "AutoScrollW" },
1875 { PointerStyle::AutoScrollE
, "AutoScrollE" },
1876 { PointerStyle::AutoScrollNW
, "AutoScrollNW" },
1877 { PointerStyle::AutoScrollNE
, "AutoScrollNE" },
1878 { PointerStyle::AutoScrollSW
, "AutoScrollSW" },
1879 { PointerStyle::AutoScrollSE
, "AutoScrollSE" },
1880 { PointerStyle::AutoScrollNS
, "AutoScrollNS" },
1881 { PointerStyle::AutoScrollWE
, "AutoScrollWE" },
1882 { PointerStyle::AutoScrollNSWE
, "AutoScrollNSWE" },
1883 { PointerStyle::TextVertical
, "TextVertical" },
1884 { PointerStyle::TabSelectS
, "TabSelectS" },
1885 { PointerStyle::TabSelectE
, "TabSelectE" },
1886 { PointerStyle::TabSelectSE
, "TabSelectSE" },
1887 { PointerStyle::TabSelectW
, "TabSelectW" },
1888 { PointerStyle::TabSelectSW
, "TabSelectSW" },
1889 { PointerStyle::HideWhitespace
, "HideWhitespace" },
1890 { PointerStyle::ShowWhitespace
, "ShowWhitespace" },
1891 { PointerStyle::FatCross
, "FatCross" },
1896 class DemoWidgets
: public WorkWindow
1898 VclPtr
<MenuBar
> mpBar
;
1899 VclPtr
<VclBox
> mpBox
;
1900 VclPtr
<ToolBox
> mpToolbox
;
1901 VclPtr
<PushButton
> mpButton
;
1902 std::vector
<VclPtr
<VclHBox
>> mvCursorBoxes
;
1903 std::vector
<VclPtr
<PushButton
>> mvCursorButtons
;
1905 DECL_LINK(CursorButtonClick
, Button
*, void);
1909 WorkWindow(nullptr, WB_APP
| WB_STDWORK
),
1910 mpBox(VclPtrInstance
<VclVBox
>(this, false, 3)),
1911 mpToolbox(VclPtrInstance
<ToolBox
>(mpBox
.get())),
1912 mpButton(VclPtrInstance
<PushButton
>(mpBox
.get()))
1914 SetText("VCL widget demo");
1916 Wallpaper
aWallpaper(BitmapEx("sfx2/res/128x128_writer_doc-p.png"));
1917 aWallpaper
.SetStyle(WallpaperStyle::BottomRight
);
1918 aWallpaper
.SetColor(COL_RED
);
1920 mpBox
->SetBackground(aWallpaper
);
1923 Help::EnableBalloonHelp();
1924 mpToolbox
->SetHelpText("Help text");
1925 mpToolbox
->InsertItem(ToolBoxItemId(0), "Toolbar item", OUString());
1926 mpToolbox
->SetQuickHelpText(ToolBoxItemId(0), "This is a tooltip popup");
1927 mpToolbox
->InsertSeparator();
1930 mpButton
->SetText("Click me; go on");
1934 VclHBox
* pCurrentCursorHBox
= nullptr;
1935 constexpr int numButtonsPerRow
= 9;
1936 for (auto & rData
: gvPointerData
)
1938 if (i
% numButtonsPerRow
== 0)
1940 mvCursorBoxes
.push_back(VclPtrInstance
<VclHBox
>(mpBox
.get(), true, numButtonsPerRow
));
1941 pCurrentCursorHBox
= mvCursorBoxes
.back().get();
1942 pCurrentCursorHBox
->Show();
1944 mvCursorButtons
.emplace_back(VclPtrInstance
<PushButton
>(pCurrentCursorHBox
));
1945 PushButton
& rButton
= *mvCursorButtons
.back();
1946 rButton
.SetText(OUString::createFromAscii(rData
.name
));
1947 rButton
.SetClickHdl(LINK(this,DemoWidgets
,CursorButtonClick
));
1952 mpBar
= VclPtr
<MenuBar
>::Create();
1953 mpBar
->InsertItem(0,"File");
1954 VclPtrInstance
<PopupMenu
> pPopup
;
1955 pPopup
->InsertItem(0,"Item");
1956 mpBar
->SetPopupMenu(0, pPopup
);
1961 virtual ~DemoWidgets() override
{ disposeOnce(); }
1962 virtual void dispose() override
1964 for (auto & p
: mvCursorButtons
)
1965 p
.disposeAndClear();
1966 mvCursorButtons
.clear();
1967 for (auto & p
: mvCursorBoxes
)
1968 p
.disposeAndClear();
1969 mvCursorBoxes
.clear();
1970 mpToolbox
.disposeAndClear();
1971 mpButton
.disposeAndClear();
1972 mpBox
.disposeAndClear();
1973 mpBar
.disposeAndClear();
1974 WorkWindow::dispose();
1976 virtual void Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
&) override
1978 tools::Rectangle
aWholeSize(Point(0, 0),GetOutputSizePixel());
1979 vcl::Region
aClip(aWholeSize
);
1980 tools::Rectangle
aExclude(tools::Rectangle(Point(50,50),Size(100,100)));
1981 aClip
.Exclude(aExclude
);
1983 Wallpaper
aWallpaper(COL_GREEN
);
1985 rRenderContext
.Push(vcl::PushFlags::CLIPREGION
);
1986 rRenderContext
.IntersectClipRegion(aClip
);
1987 rRenderContext
.DrawWallpaper(aWholeSize
, aWallpaper
);
1988 rRenderContext
.Pop();
1990 ScopedVclPtrInstance
< VirtualDevice
> pDev(*GetOutDev());
1991 pDev
->EnableRTL(IsRTLEnabled());
1992 pDev
->SetOutputSizePixel(aExclude
.GetSize());
1994 tools::Rectangle
aSubRect(aWholeSize
);
1995 aSubRect
.Move(-aExclude
.Left(), -aExclude
.Top());
1996 pDev
->DrawWallpaper(aSubRect
, aWallpaper
);
1998 rRenderContext
.DrawOutDev(aExclude
.TopLeft(), aExclude
.GetSize(),
1999 Point( 0, 0 ), aExclude
.GetSize(), *pDev
);
2005 IMPL_LINK(DemoWidgets
, CursorButtonClick
, Button
*, pButton
, void)
2007 for (size_t i
=0; i
<SAL_N_ELEMENTS(gvPointerData
); ++i
)
2009 if (mvCursorButtons
[i
].get() == pButton
)
2011 mpBox
->SetPointer( gvPointerData
[i
].eStyle
);
2020 class DemoPopup
: public FloatingWindow
2023 DemoPopup() : FloatingWindow( nullptr, WB_SYSTEMWINDOW
|WB_TOOLTIPWIN
)
2025 SetType( WindowType::HELPTEXTWINDOW
);
2027 SetOutputSizePixel( Size( 300, 30 ) );
2028 SetBackground(Wallpaper(COL_YELLOW
));
2030 Show( true, ShowFlags::NoActivate
);
2034 virtual void Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
&) override
2036 Size aSize
= GetOutputSizePixel();
2037 tools::Rectangle
aTextRect(Point(6, 6), aSize
);
2039 SetTextColor(COL_BLACK
);
2040 SetTextAlign(ALIGN_TOP
);
2041 rRenderContext
.DrawText(aTextRect
, "This is a standalone help text test",
2042 DrawTextFlags::MultiLine
|DrawTextFlags::WordBreak
|
2043 DrawTextFlags::Left
|DrawTextFlags::Top
);
2045 rRenderContext
.SetLineColor(COL_BLACK
);
2046 rRenderContext
.SetFillColor();
2047 rRenderContext
.DrawRect( tools::Rectangle( Point(), aSize
) );
2048 aSize
.AdjustWidth( -2 );
2049 aSize
.AdjustHeight( -2 );
2050 Color
aColor( rRenderContext
.GetLineColor() );
2051 rRenderContext
.SetLineColor( COL_GRAY
);
2052 rRenderContext
.DrawRect( tools::Rectangle( Point( 1, 1 ), aSize
) );
2053 rRenderContext
.SetLineColor( aColor
);
2056 virtual void MouseButtonDown( const MouseEvent
& ) override
2058 Application::Quit();
2067 ScopedVclPtrInstance
<VirtualDevice
> xDevice
;
2068 Size
aSize(1024, 1024);
2069 xDevice
->SetOutputSizePixel(aSize
);
2072 for (auto & aFontName
: aFontNames
)
2074 vcl::Font
aFont(aFontName
, Size(0,96));
2076 aFont
.Set(COL_BLACK
);
2077 xDevice
->SetFont(aFont
);
2080 FontMetric aMetric
= xDevice
->GetFontMetric(aFont
);
2082 FontCharMapRef xMap
;
2083 if (xDevice
->GetFontCharMap(xMap
))
2085 ... iterate through glyphs
...
2089 bool GetGlyphBoundRects( const Point
& rOrigin
, const OUString
& rStr
, int nIndex
,
2090 int nLen
, int nBase
, MetricVector
& rVector
);
2092 include
/vcl
/outdev
.hxx
:typedef std::vector
< Rectangle
> MetricVector
;
2093 include
/vcl
/outdev
.hxx
: MetricVector
* pVector
= nullptr, OUString
* pDisplayText
= nullptr );
2094 include
/vcl
/outdev
.hxx
: MetricVector
* pVector
= nullptr, OUString
* pDisplayText
= nullptr,
2095 include
/vcl
/outdev
.hxx
: MetricVector
* pVector
, OUString
* pDisplayText
, vcl::ITextLayout
& _rLayout
);
2096 include
/vcl
/outdev
.hxx
: DrawTextFlags nStyle
= DrawTextFlags::Mnemonic
, MetricVector
* pVector
= nullp
2098 bool GetTextBoundRect( Rectangle
& rRect
,
2099 const OUString
& rStr
, sal_Int32 nBase
= 0, sal_Int32 nIndex
= 0, sal_Int32 nLen
= -1,
2100 sal_uLong nLayoutWidth
= 0, const long* pDXArray
= nullptr ) const;
2103 void DrawText( const Point
& rStartPt
, const OUString
& rStr
,
2104 sal_Int32 nIndex
= 0, sal_Int32 nLen
= -1,
2105 MetricVector
* pVector
= nullptr, OUString
* pDisplayText
= nullptr );
2107 void DrawText( const Rectangle
& rRect
,
2108 const OUString
& rStr
, DrawTextFlags nStyle
= DrawTextFlags::NONE
,
2109 MetricVector
* pVector
= nullptr, OUString
* pDisplayText
= nullptr,
2110 vcl::ITextLayout
* _pTextLayout
= nullptr );
2112 Rectangle
GetTextRect( const Rectangle
& rRect
,
2113 const OUString
& rStr
, DrawTextFlags nStyle
= DrawTextFlags::WordBreak
,
2114 TextRectInfo
* pInfo
= nullptr,
2115 const vcl::ITextLayout
* _pTextLayout
= nullptr ) const;
2125 class DemoApp
: public Application
2127 static int showHelp(DemoRenderer
&rRenderer
)
2129 fprintf(stderr
,"vcldemo - a VCL test app\n");
2130 fprintf(stderr
," --help - print this text\n");
2131 fprintf(stderr
," --show <renderer> - start with a given renderer, options are:\n");
2132 OUString
aRenderers(rRenderer
.getRendererList());
2133 fprintf(stderr
," %s\n",
2134 OUStringToOString(aRenderers
, RTL_TEXTENCODING_UTF8
).getStr());
2135 fprintf(stderr
," --test <iterCount> - create benchmark data\n");
2136 fprintf(stderr
," --widgets - launch the widget test.\n");
2137 fprintf(stderr
," --popup - launch the popup test.\n");
2138 fprintf(stderr
," --threads - render from multiple threads.\n");
2139 fprintf(stderr
," --font <fontname> - run the font render test.\n");
2140 fprintf(stderr
, "\n");
2147 virtual int Main() override
2151 bool bWidgets
= false;
2152 bool bThreads
= false;
2153 bool bPopup
= false;
2154 DemoRenderer aRenderer
;
2155 std::vector
<OUString
> aFontNames
;
2157 for (sal_uInt16 i
= 0; i
< GetCommandLineParamCount(); ++i
)
2159 bool bLast
= i
== GetCommandLineParamCount() - 1;
2160 OUString aArg
= GetCommandLineParam(i
);
2161 if (aArg
== "--help" || aArg
== "-h")
2162 return showHelp(aRenderer
);
2163 if (aArg
== "--show")
2166 return showHelp(aRenderer
);
2168 aRenderer
.selectRenderer(GetCommandLineParam(++i
));
2170 else if (aArg
== "--test")
2173 return showHelp(aRenderer
);
2175 aRenderer
.setIterCount(GetCommandLineParam(++i
).toInt32());
2177 else if (aArg
== "--widgets")
2179 else if (aArg
== "--popup")
2181 else if (aArg
== "--threads")
2183 else if (aArg
== "--font" && !bLast
)
2184 aFontNames
.push_back(GetCommandLineParam(++i
));
2185 else if (aArg
.startsWith("--"))
2187 fprintf(stderr
,"Unknown argument '%s'\n",
2188 OUStringToOString(aArg
, RTL_TEXTENCODING_UTF8
).getStr());
2189 return showHelp(aRenderer
);
2193 ScopedVclPtrInstance
<DemoWin
> aMainWin(aRenderer
, bThreads
);
2194 VclPtr
<DemoWidgets
> xWidgets
;
2195 VclPtr
<DemoPopup
> xPopup
;
2197 aMainWin
->SetText("Interactive VCL demo #1");
2199 xWidgets
= VclPtr
< DemoWidgets
>::Create ();
2201 xPopup
= VclPtrInstance
< DemoPopup
> ();
2202 else if (!aFontNames
.empty())
2207 Application::Execute();
2209 xWidgets
.disposeAndClear();
2210 xPopup
.disposeAndClear();
2212 catch (const css::uno::Exception
&)
2214 TOOLS_WARN_EXCEPTION("vcl.app", "Fatal");
2217 catch (const std::exception
& e
)
2219 SAL_WARN("vcl.app", "Fatal: " << e
.what());
2226 void Init() override
2228 LanguageTag::setConfiguredSystemLanguage(MsLangId::getSystemLanguage());
2232 uno::Reference
<uno::XComponentContext
> xComponentContext
2233 = ::cppu::defaultBootstrap_InitialComponentContext();
2234 uno::Reference
<lang::XMultiServiceFactory
> xMSF
;
2235 xMSF
.set(xComponentContext
->getServiceManager(), uno::UNO_QUERY
);
2237 Application::Abort("Bootstrap failure - no service manager");
2239 ::comphelper::setProcessServiceFactory(xMSF
);
2241 catch (const uno::Exception
&e
)
2243 Application::Abort("Bootstrap exception " + e
.Message
);
2246 void DeInit() override
2248 framework::getDesktop(::comphelper::getProcessComponentContext())->terminate();
2249 framework::getDesktop(::comphelper::getProcessComponentContext())->disposing();
2251 uno::Reference
< lang::XComponent
>(
2252 comphelper::getProcessComponentContext(),
2253 uno::UNO_QUERY_THROW
)-> dispose();
2254 ::comphelper::setProcessServiceFactory(nullptr);
2260 void vclmain::createApplication()
2263 _putenv_s("LIBO_VCL_DEMO", "1");
2265 setenv("LIBO_VCL_DEMO", "1", 0);
2267 static DemoApp aApp
;
2270 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */