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>
14 #include <config_features.h>
17 #include <rtl/math.hxx>
18 #include <sal/log.hxx>
20 #include <comphelper/processfactory.hxx>
21 #include <comphelper/random.hxx>
22 #include <cppuhelper/bootstrap.hxx>
23 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
24 #include <com/sun/star/lang/XInitialization.hpp>
25 #include <com/sun/star/registry/XSimpleRegistry.hpp>
26 #include <com/sun/star/ucb/UniversalContentBroker.hpp>
27 #include <com/sun/star/uno/Reference.hxx>
28 #include <com/sun/star/uno/Sequence.hxx>
29 #include <com/sun/star/container/XNameAccess.hpp>
32 #include <vcl/gradient.hxx>
33 #include <vcl/vclmain.hxx>
34 #include <vcl/layout.hxx>
35 #include <vcl/ptrstyle.hxx>
36 #include <salhelper/thread.hxx>
38 #include <tools/diagnose_ex.h>
39 #include <tools/urlobj.hxx>
40 #include <tools/stream.hxx>
41 #include <vcl/svapp.hxx>
42 #include <vcl/pngread.hxx>
43 #include <vcl/wrkwin.hxx>
44 #include <vcl/virdev.hxx>
45 #include <vcl/graphicfilter.hxx>
46 #include <vcl/button.hxx>
47 #include <vcl/combobox.hxx>
48 #include <vcl/toolbox.hxx>
49 #include <vcl/pngwrite.hxx>
50 #include <vcl/floatwin.hxx>
51 #include <vcl/bitmapaccess.hxx>
52 #include <vcl/help.hxx>
53 #include <vcl/menu.hxx>
54 #include <vcl/ImageTree.hxx>
55 #include <vcl/BitmapEmbossGreyFilter.hxx>
56 #include <bitmapwriteaccess.hxx>
58 #include <basegfx/numeric/ftools.hxx>
59 #include <basegfx/matrix/b2dhommatrix.hxx>
60 #include <opengl/zone.hxx>
62 // internal headers for OpenGLTests class.
63 #if HAVE_FEATURE_OPENGL
65 #include <salframe.hxx>
66 #include <openglgdiimpl.hxx>
67 #include <opengl/texture.hxx>
68 #include <opengl/framebuffer.hxx>
69 #include <vcl/opengl/OpenGLHelper.hxx>
72 #define FIXME_SELF_INTERSECTING_WORKING 0
73 #define FIXME_BOUNCE_BUTTON 0
74 #define THUMB_REPEAT_FACTOR 10
76 using namespace com::sun::star
;
82 osl_getSystemTime(&aValue
);
83 return static_cast<double>(aValue
.Seconds
) * 1000 +
84 static_cast<double>(aValue
.Nanosec
) / (1000*1000);
90 RENDER_THUMB
, // small view <n> to a page
91 RENDER_EXPANDED
, // expanded view of this renderer
102 struct RenderContext
{
105 DemoRenderer
*mpDemoRenderer
;
108 struct RegionRenderer
{
114 virtual ~RegionRenderer() {}
115 virtual OUString
getName() = 0;
116 virtual sal_uInt16
getAccelerator() = 0;
117 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
118 const RenderContext
&rCtx
) = 0;
119 // repeating count for profiling (to exceed the poor time resolution on Windows)
120 virtual sal_uInt16
getTestRepeatCount() = 0;
121 #define RENDER_DETAILS(name,key,repeat) \
122 virtual OUString getName() override \
123 { return SAL_STRINGIFY(name); } \
124 virtual sal_uInt16 getAccelerator() override \
126 virtual sal_uInt16 getTestRepeatCount() override \
133 std::vector
< RegionRenderer
* > maRenderers
;
134 sal_Int32 mnSelectedRenderer
;
137 void InitRenderers();
140 DemoRenderer() : mnSegmentsX(0)
142 , mnSelectedRenderer(-1)
144 #if FIXME_BOUNCE_BUTTON
151 if (!Application::LoadBrandBitmap("intro", maIntro
))
152 Application::Abort("Failed to load intro image");
154 maIntroBW
= maIntro
.GetBitmap();
156 BitmapEx
aTmpBmpEx(maIntroBW
);
157 BitmapFilter::Filter(aTmpBmpEx
, BitmapEmbossGreyFilter(0, 0));
158 maIntroBW
= aTmpBmpEx
.GetBitmap();
161 mnSegmentsY
= rtl::math::round(std::sqrt(maRenderers
.size()), 0,
162 rtl_math_RoundingMode_Down
);
163 mnSegmentsX
= (maRenderers
.size() + mnSegmentsY
- 1)/mnSegmentsY
;
166 OUString
getRendererList();
167 double getAndResetBenchmark(RenderStyle style
);
168 void selectRenderer(const OUString
&rName
);
169 int selectNextRenderer();
170 void setIterCount(sal_Int32 iterCount
);
171 sal_Int32
getIterCount() const;
172 void addTime(int i
, double t
);
175 void SetSizePixel(const Size
&rSize
) { maSize
= rSize
; }
176 const Size
& GetSizePixel() const { return maSize
; }
179 // more of a 'Window' concept - push upwards ?
180 #if FIXME_BOUNCE_BUTTON
181 // Bouncing windows on click ...
182 PushButton
*mpButton
;
183 FloatingWindow
*mpButtonWin
;
185 int mnBounceX
, mnBounceY
;
186 DECL_LINK(BounceTimerCb
, Timer
*, void);
189 bool MouseButtonDown(const MouseEvent
& rMEvt
);
190 void KeyInput(const KeyEvent
& rKEvt
);
192 static std::vector
<tools::Rectangle
> partition(const tools::Rectangle
&rRect
, int nX
, int nY
)
194 std::vector
<tools::Rectangle
> aRegions
= partition(rRect
.GetSize(), nX
, nY
);
195 for (auto & region
: aRegions
)
196 region
.Move(rRect
.Left(), rRect
.Top());
201 static std::vector
<tools::Rectangle
> partition(const RenderContext
&rCtx
, int nX
, int nY
)
203 return partition(rCtx
.maSize
, nX
, nY
);
206 static std::vector
<tools::Rectangle
> partition(Size aSize
, int nX
, int nY
)
209 std::vector
<tools::Rectangle
> aRegions
;
211 // Make small cleared area for these guys
212 long nBorderSize
= std::min(aSize
.Height() / 32, aSize
.Width() / 32);
213 long nBoxWidth
= (aSize
.Width() - nBorderSize
*(nX
+1)) / nX
;
214 long nBoxHeight
= (aSize
.Height() - nBorderSize
*(nY
+1)) / nY
;
215 for (int y
= 0; y
< nY
; y
++)
217 for (int x
= 0; x
< nX
; x
++)
219 r
.SetPos(Point(nBorderSize
+ (nBorderSize
+ nBoxWidth
) * x
,
220 nBorderSize
+ (nBorderSize
+ nBoxHeight
) * y
));
221 r
.SetSize(Size(nBoxWidth
, nBoxHeight
));
222 aRegions
.push_back(r
);
229 static void clearRects(OutputDevice
&rDev
, std::vector
<tools::Rectangle
> &rRects
)
231 for (size_t i
= 0; i
< rRects
.size(); i
++)
233 // knock up a nice little border
234 rDev
.SetLineColor(COL_GRAY
);
235 rDev
.SetFillColor(COL_LIGHTGRAY
);
238 int nBorderSize
= rRects
[i
].GetWidth() / 5;
239 rDev
.DrawRect(rRects
[i
], nBorderSize
, nBorderSize
);
242 rDev
.DrawRect(rRects
[i
]);
246 static void drawBackground(OutputDevice
&rDev
, const tools::Rectangle
& r
)
250 aGradient
.SetStartColor(COL_BLUE
);
251 aGradient
.SetEndColor(COL_GREEN
);
252 aGradient
.SetStyle(GradientStyle::Linear
);
253 rDev
.DrawGradient(r
, aGradient
);
256 struct DrawLines
: public RegionRenderer
258 RENDER_DETAILS(lines
,KEY_L
,100)
259 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
260 const RenderContext
&rCtx
) override
262 if (rCtx
.meStyle
== RENDER_EXPANDED
)
264 AntialiasingFlags nOldAA
= rDev
.GetAntialiasing();
265 rDev
.SetAntialiasing(AntialiasingFlags::EnableB2dDraw
);
267 std::vector
<tools::Rectangle
> aRegions(DemoRenderer::partition(rCtx
, 4, 4));
268 DemoRenderer::clearRects(rDev
, aRegions
);
270 #if 0 // FIXME: get this through to the backend ...
271 double nTransparency
[] = {
278 drawing::LineCap
const eLineCaps
[] = {
279 drawing::LineCap_BUTT
, drawing::LineCap_ROUND
, drawing::LineCap_SQUARE
, drawing::LineCap_BUTT
,
280 drawing::LineCap_BUTT
, drawing::LineCap_ROUND
, drawing::LineCap_SQUARE
, drawing::LineCap_BUTT
,
281 drawing::LineCap_BUTT
, drawing::LineCap_ROUND
, drawing::LineCap_SQUARE
, drawing::LineCap_BUTT
,
282 drawing::LineCap_BUTT
, drawing::LineCap_ROUND
, drawing::LineCap_SQUARE
, drawing::LineCap_BUTT
284 basegfx::B2DLineJoin
const eJoins
[] = {
285 basegfx::B2DLineJoin::NONE
, basegfx::B2DLineJoin::Bevel
, basegfx::B2DLineJoin::Miter
, basegfx::B2DLineJoin::Round
,
286 basegfx::B2DLineJoin::NONE
, basegfx::B2DLineJoin::Bevel
, basegfx::B2DLineJoin::Miter
, basegfx::B2DLineJoin::Round
,
287 basegfx::B2DLineJoin::NONE
, basegfx::B2DLineJoin::Bevel
, basegfx::B2DLineJoin::Miter
, basegfx::B2DLineJoin::Round
,
288 basegfx::B2DLineJoin::NONE
, basegfx::B2DLineJoin::Bevel
, basegfx::B2DLineJoin::Miter
, basegfx::B2DLineJoin::Round
290 double const aLineWidths
[] = {
291 10.0, 15.0, 20.0, 10.0,
292 10.0, 15.0, 20.0, 10.0,
293 10.0, 15.0, 20.0, 10.0,
296 for (size_t i
= 0; i
< aRegions
.size(); i
++)
298 // Half of them not-anti-aliased ..
299 if (i
>= aRegions
.size()/2)
300 rDev
.SetAntialiasing(nOldAA
);
302 static const struct {
305 { 0.2, 0.2 }, { 0.8, 0.3 }, { 0.7, 0.8 }
307 rDev
.SetLineColor(COL_BLACK
);
308 basegfx::B2DPolygon aPoly
;
309 tools::Rectangle
aSub(aRegions
[i
]);
310 for (size_t j
= 0; j
< SAL_N_ELEMENTS(aPoints
); j
++)
312 aPoly
.append(basegfx::B2DPoint(aSub
.Left() + aSub
.GetWidth() * aPoints
[j
].nX
,
313 aSub
.Top() + aSub
.GetHeight() * aPoints
[j
].nY
));
315 rDev
.DrawPolyLine(aPoly
, aLineWidths
[i
], eJoins
[i
], eLineCaps
[i
]);
320 rDev
.SetFillColor(COL_LIGHTRED
);
321 rDev
.SetLineColor(COL_BLACK
);
324 for(long i
=0; i
<r
.GetHeight(); i
+=15)
325 rDev
.DrawLine(Point(r
.Left(), r
.Top()+i
), Point(r
.Right(), r
.Bottom()-i
));
326 for(long i
=0; i
<r
.GetWidth(); i
+=15)
327 rDev
.DrawLine(Point(r
.Left()+i
, r
.Bottom()), Point(r
.Right()-i
, r
.Top()));
329 // Should draw a white-line across the middle
330 Color
aLastPixel(COL_WHITE
);
331 Point
aCenter((r
.Left() + r
.Right())/2 - 4,
332 (r
.Top() + r
.Bottom())/2 - 4);
333 for(int i
=0; i
<8; i
++)
335 rDev
.DrawPixel(aCenter
, aLastPixel
);
336 aLastPixel
= rDev
.GetPixel(aCenter
);
343 struct DrawText
: public RegionRenderer
345 RENDER_DETAILS(text
,KEY_T
,1)
347 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
348 const RenderContext
&rCtx
) override
350 if (rCtx
.meStyle
== RENDER_EXPANDED
)
352 std::vector
<tools::Rectangle
> aToplevelRegions(
353 DemoRenderer::partition(rCtx
, 1, 3));
354 std::vector
<tools::Rectangle
> aSubRegions(
355 DemoRenderer::partition(aToplevelRegions
[0], 4, 2));
356 tools::Rectangle
aBottom(aToplevelRegions
[1].TopLeft(),
357 aToplevelRegions
[2].BottomRight());
358 DemoRenderer::clearRects(rDev
,aSubRegions
);
361 bool const mbArabicText
;
363 } const aRenderData
[] = {
364 { false, false, false },
365 { false, true, false },
366 { false, true, true },
367 { false, false, true },
368 { true, false, true },
369 { true, true, true },
370 { true, true, false },
371 { true, false, false },
375 for (int y
= 0; y
< 2; y
++)
377 for (int x
= 0; x
< 4; x
++)
379 assert(i
< SAL_N_ELEMENTS(aRenderData
));
380 drawText(rDev
, aSubRegions
[i
], aRenderData
[i
].mbClip
,
381 aRenderData
[i
].mbArabicText
, aRenderData
[i
].mbRotate
);
386 drawComplex(rDev
, aBottom
);
390 drawText(rDev
, r
, false, false, false);
394 static void drawText (OutputDevice
&rDev
, tools::Rectangle r
, bool bClip
, bool bArabicText
, bool bRotate
)
396 rDev
.SetClipRegion( vcl::Region(r
) );
398 OUString
const aLatinText("Click any rect to zoom!!!!");
400 const unsigned char pTextUTF8
[] = {
401 0xd9, 0x88, 0xd8, 0xa7, 0xd8, 0xad, 0xd9, 0x90,
402 0xd8, 0xaf, 0xd9, 0x92, 0x20, 0xd8, 0xa5, 0xd8,
403 0xab, 0xd9, 0x8d, 0xd9, 0x86, 0xd9, 0x8a, 0xd9,
404 0x86, 0x20, 0xd8, 0xab, 0xd9, 0x84, 0xd8, 0xa7,
405 0xd8, 0xab, 0xd8, 0xa9, 0xd9, 0x8c, 0x00
407 OUString
aArabicText( reinterpret_cast<char const *>(pTextUTF8
),
408 SAL_N_ELEMENTS( pTextUTF8
) - 1,
409 RTL_TEXTENCODING_UTF8
);
413 // To have more text displayed one after the other (overlapping, and in different colours), then
415 const int nPrintNumCopies
=1;
422 std::vector
<OUString
> aFontNames
;
424 static Color
const nCols
[] = {
425 COL_BLACK
, COL_BLUE
, COL_GREEN
, COL_CYAN
, COL_RED
, COL_MAGENTA
,
426 COL_BROWN
, COL_GRAY
, COL_LIGHTGRAY
, COL_LIGHTBLUE
, COL_LIGHTGREEN
,
427 COL_LIGHTCYAN
, COL_LIGHTRED
, COL_LIGHTMAGENTA
, COL_YELLOW
, COL_WHITE
430 // a few fonts to start with
431 const char *pNames
[] = {
432 "Times", "Liberation Sans", "Arial", "Linux Biolinum G", "Linux Libertine Display G"
435 for (size_t i
= 0; i
< SAL_N_ELEMENTS(pNames
); i
++)
436 aFontNames
.push_back(OUString::createFromAscii(pNames
[i
]));
438 if (bClip
&& !bRotate
)
440 // only show the first quarter of the text
441 tools::Rectangle
aRect( r
.TopLeft(), Size( r
.GetWidth()/2, r
.GetHeight()/2 ) );
442 rDev
.SetClipRegion( vcl::Region( aRect
) );
445 for (int i
= 1; i
< nPrintNumCopies
+1; i
++)
447 int nFontHeight
=0, nFontIndex
=0, nFontColorIndex
=0;
449 if (nPrintNumCopies
== 1)
451 float const nFontMagnitude
= 0.25f
;
452 // random font size to avoid buffering
453 nFontHeight
= 1 + nFontMagnitude
* (0.9 + comphelper::rng::uniform_real_distribution(0.0, std::nextafter(0.1, DBL_MAX
))) * (r
.Bottom() - r
.Top());
459 // random font size to avoid buffering
460 nFontHeight
= 1 + i
* (0.9 + comphelper::rng::uniform_real_distribution(0.0, std::nextafter(0.1, DBL_MAX
))) * (r
.Top() - r
.Bottom()) / nPrintNumCopies
;
461 nFontIndex
= (i
% aFontNames
.size());
462 nFontColorIndex
=(i
% aFontNames
.size());
465 rDev
.SetTextColor(nCols
[nFontColorIndex
]);
466 vcl::Font
aFont( aFontNames
[nFontIndex
], Size(0, nFontHeight
));
470 tools::Rectangle aFontRect
= r
;
472 int nHeight
= r
.GetHeight();
474 // move the text to the bottom of the bounding rect before rotating
475 aFontRect
.AdjustTop(nHeight
/2 );
476 aFontRect
.AdjustBottom(nHeight
);
478 aFont
.SetOrientation(45 * 10); // 45 degrees
481 rDev
.DrawText(aFontRect
, aText
);
485 tools::Rectangle
aClipRect( Point( r
.Left(), r
.Top() + ( r
.GetHeight()/2 ) ) , Size( r
.GetWidth()/2, r
.GetHeight()/2 ) );
486 rDev
.SetClipRegion( vcl::Region( aClipRect
) );
489 rDev
.SetClipRegion( vcl::Region(r
) );
494 rDev
.DrawText(r
, aText
);
498 rDev
.SetClipRegion();
501 static void drawComplex (OutputDevice
&rDev
, tools::Rectangle r
)
503 const unsigned char pInvalid
[] = { 0xfe, 0x1f, 0 };
504 const unsigned char pDiacritic1
[] = { 0x61, 0xcc, 0x8a, 0xcc, 0x8c, 0 };
505 const unsigned char pDiacritic2
[] = { 0x61, 0xcc, 0x88, 0xcc, 0x86, 0 };
506 const unsigned char pDiacritic3
[] = { 0x61, 0xcc, 0x8b, 0xcc, 0x87, 0 };
507 const unsigned char pJustification
[] = {
508 0x64, 0x20, 0xc3, 0xa1, 0xc3, 0xa9, 0x77, 0xc4, 0x8d,
509 0xc5, 0xa1, 0xc3, 0xbd, 0xc5, 0x99, 0x20, 0xc4, 0x9b, 0
511 const unsigned char pEmojis
[] = {
512 0xf0, 0x9f, 0x8d, 0x80, 0xf0, 0x9f, 0x91, 0x98,
513 0xf0, 0x9f, 0x92, 0x8a, 0xf0, 0x9f, 0x92, 0x99,
514 0xf0, 0x9f, 0x92, 0xa4, 0xf0, 0x9f, 0x94, 0x90, 0
516 const unsigned char pThreeBowlG
[] = {
517 0xe2, 0x9a, 0x82, 0xe2, 0x99, 0xa8, 0xc4, 0x9e, 0
519 const unsigned char pWavesAndDomino
[] = {
520 0xe2, 0x99, 0x92, 0xf0, 0x9f, 0x81, 0xa0,
521 0xf0, 0x9f, 0x82, 0x93, 0
523 const unsigned char pSpadesAndBits
[] = {
524 0xf0, 0x9f, 0x82, 0xa1, 0xc2, 0xa2, 0xc2, 0xa2, 0
529 const char *mpString
;
531 #define SET(font,string) { font, reinterpret_cast<const char *>(string) }
532 {"sans", "a"}, // logical font - no 'sans' font.
533 {"opensymbol", "#$%"}, // font fallback - $ is missing.
534 SET("sans", pInvalid
), // unicode invalid character
535 // tdf#96266 - stacking diacritics
536 SET("carlito", pDiacritic1
),
537 SET("carlito", pDiacritic2
),
538 SET("carlito", pDiacritic3
),
539 SET("liberation sans", pDiacritic1
),
540 SET("liberation sans", pDiacritic2
),
541 SET("liberation sans", pDiacritic3
),
542 SET("liberation sans", pDiacritic3
),
544 // tdf#95222 - justification issue
545 // - FIXME: replicate justification
546 SET("gentium basic", pJustification
),
548 // tdf#97319 - Unicode beyond BMP; SMP & Plane 2
549 SET("symbola", pEmojis
),
550 SET("symbola", pThreeBowlG
),
551 SET("symbola", pWavesAndDomino
),
552 SET("symbola", pSpadesAndBits
),
555 // Nice clean white background
556 rDev
.DrawWallpaper(r
, Wallpaper(COL_WHITE
));
557 rDev
.SetClipRegion(vcl::Region(r
));
559 Point
aPos(r
.Left(), r
.Top()+20);
561 long nMaxTextHeight
= 0;
562 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aRuns
); ++i
)
565 vcl::Font
aIndexFont("sans", Size(0,20));
566 aIndexFont
.SetColor( COL_BLACK
);
567 tools::Rectangle aTextRect
;
568 rDev
.SetFont(aIndexFont
);
569 OUString aText
= OUString::number(i
) + ".";
570 rDev
.DrawText(aPos
, aText
);
571 if (rDev
.GetTextBoundRect(aTextRect
, aText
))
572 aPos
.Move(aTextRect
.GetWidth() + 8, 0);
575 FontWeight aWeights
[] = { WEIGHT_NORMAL
,
578 FontItalic
const aItalics
[] = { ITALIC_NONE
,
581 vcl::Font
aFont(OUString::createFromAscii(
584 aFont
.SetColor(COL_BLACK
);
585 for (size_t j
= 0; j
< SAL_N_ELEMENTS(aWeights
); ++j
)
587 aFont
.SetItalic(aItalics
[j
]);
588 aFont
.SetWeight(aWeights
[j
]);
591 OUString
aString(aRuns
[i
].mpString
,
592 strlen(aRuns
[i
].mpString
),
593 RTL_TEXTENCODING_UTF8
);
594 long nNewX
= drawStringBox(rDev
, aPos
, aString
,
599 if (aPos
.X() >= r
.Right())
601 aPos
= Point(r
.Left(), aPos
.Y() + nMaxTextHeight
+ 15);
604 j
--; // re-render the last point.
606 if (aPos
.Y() > r
.Bottom())
609 if (aPos
.Y() > r
.Bottom())
613 rDev
.SetClipRegion();
615 // render text, bbox, DX arrays etc.
616 static long drawStringBox(OutputDevice
&rDev
, Point aPos
,
617 const OUString
&aText
,
618 long &nMaxTextHeight
)
622 tools::Rectangle aTextRect
;
624 rDev
.DrawText(aPos
,aText
);
626 if (rDev
.GetTextBoundRect(aTextRect
, aText
))
628 aTextRect
.Move(aPos
.X(), aPos
.Y());
630 rDev
.SetLineColor(COL_BLACK
);
631 rDev
.DrawRect(aTextRect
);
632 if (aTextRect
.GetHeight() > nMaxTextHeight
)
633 nMaxTextHeight
= aTextRect
.GetHeight();
634 // This should intersect with the text
635 tools::Rectangle
aInnerRect(
636 aTextRect
.Left()+1, aTextRect
.Top()+1,
637 aTextRect
.Right()-1, aTextRect
.Bottom()-1);
638 rDev
.SetLineColor(COL_WHITE
);
639 rDev
.SetRasterOp(RasterOp::Xor
);
640 rDev
.DrawRect(aInnerRect
);
641 rDev
.SetRasterOp(RasterOp::OverPaint
);
644 // DX array rendering
645 std::unique_ptr
<long[]> pItems(new long[aText
.getLength()+10]);
646 rDev
.GetTextArray(aText
, pItems
.get());
647 for (long j
= 0; j
< aText
.getLength(); ++j
)
649 Point aTop
= aTextRect
.TopLeft();
650 Point aBottom
= aTop
;
651 aTop
.Move(pItems
[j
], 0);
652 aBottom
.Move(pItems
[j
], aTextRect
.GetHeight());
653 rDev
.SetLineColor(COL_RED
);
654 rDev
.SetRasterOp(RasterOp::Xor
);
655 rDev
.DrawLine(aTop
,aBottom
);
656 rDev
.SetRasterOp(RasterOp::OverPaint
);
659 aPos
.Move(aTextRect
.GetWidth() + 16, 0);
666 struct DrawCheckered
: public RegionRenderer
668 RENDER_DETAILS(checks
,KEY_C
,20)
669 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
670 const RenderContext
&rCtx
) override
672 if (rCtx
.meStyle
== RENDER_EXPANDED
)
674 std::vector
<tools::Rectangle
> aRegions(DemoRenderer::partition(rCtx
, 2, 2));
675 for (size_t i
= 0; i
< aRegions
.size(); i
++)
678 tools::Rectangle
aSub(aRegions
[i
]);
679 tools::Rectangle
aSmaller(aSub
);
680 aSmaller
.Move(10,10);
681 aSmaller
.setWidth(aSmaller
.getWidth()-20);
682 aSmaller
.setHeight(aSmaller
.getHeight()-24);
685 aRegion
= vcl::Region(aSub
);
688 aRegion
= vcl::Region(aSmaller
);
693 tools::Polygon
aPoly(aSub
);
694 aPoly
.Rotate(aSub
.Center(), 450);
695 aPoly
.Clip(aSmaller
);
696 aRegion
= vcl::Region(aPoly
);
701 tools::PolyPolygon aPolyPoly
;
702 sal_Int32 nTW
= aSub
.GetWidth()/6;
703 sal_Int32 nTH
= aSub
.GetHeight()/6;
704 tools::Rectangle
aTiny(Point(4, 4), Size(nTW
*2, nTH
*2));
705 aPolyPoly
.Insert( tools::Polygon(aTiny
));
706 aTiny
.Move(nTW
*3, nTH
*3);
707 aPolyPoly
.Insert( tools::Polygon(aTiny
));
708 aTiny
.Move(nTW
, nTH
);
709 aPolyPoly
.Insert( tools::Polygon(aTiny
));
711 aRegion
= vcl::Region(aPolyPoly
);
715 rDev
.SetClipRegion(aRegion
);
716 rDev
.DrawCheckered(aSub
.TopLeft(), aSub
.GetSize());
717 rDev
.SetClipRegion();
722 rDev
.DrawCheckered(r
.TopLeft(), r
.GetSize());
727 struct DrawPoly
: public RegionRenderer
729 RENDER_DETAILS(poly
,KEY_P
,20)
730 DrawCheckered maCheckered
;
731 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
732 const RenderContext
&rCtx
) override
734 maCheckered
.RenderRegion(rDev
, r
, rCtx
);
736 long nDx
= r
.GetWidth()/20;
737 long nDy
= r
.GetHeight()/20;
738 tools::Rectangle
aShrunk(r
);
739 aShrunk
.Move(nDx
, nDy
);
740 aShrunk
.SetSize(Size(r
.GetWidth()-nDx
*2,
741 r
.GetHeight()-nDy
*2));
742 tools::Polygon
aPoly(aShrunk
);
743 tools::PolyPolygon
aPPoly(aPoly
);
744 rDev
.SetLineColor(COL_RED
);
745 rDev
.SetFillColor(COL_RED
);
746 // This hits the optional 'drawPolyPolygon' code-path
747 rDev
.DrawTransparent(aPPoly
, 64);
751 struct DrawEllipse
: public RegionRenderer
753 RENDER_DETAILS(ellipse
,KEY_E
,500)
754 static void doInvert(OutputDevice
&rDev
, const tools::Rectangle
&r
,
757 rDev
.Invert(r
, nFlags
);
758 if (r
.GetWidth() > 10 && r
.GetHeight() > 10)
760 tools::Rectangle
aSmall(r
.Center()-Point(4,4), Size(8,8));
761 rDev
.Invert(aSmall
,nFlags
);
764 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
765 const RenderContext
&rCtx
) override
767 rDev
.SetLineColor(COL_RED
);
768 rDev
.SetFillColor(COL_GREEN
);
771 if (rCtx
.meStyle
== RENDER_EXPANDED
)
773 auto aRegions
= partition(rCtx
, 2, 2);
774 doInvert(rDev
, aRegions
[0], InvertFlags::NONE
);
775 rDev
.DrawText(aRegions
[0], "InvertFlags::NONE");
776 doInvert(rDev
, aRegions
[1], InvertFlags::N50
);
777 rDev
.DrawText(aRegions
[1], "InvertFlags::N50");
778 doInvert(rDev
, aRegions
[3], InvertFlags::TrackFrame
);
779 rDev
.DrawText(aRegions
[3], "InvertFlags::TrackFrame");
784 struct DrawGradient
: public RegionRenderer
786 RENDER_DETAILS(gradient
,KEY_G
,50)
787 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
788 const RenderContext
&rCtx
) override
790 if (rCtx
.meStyle
== RENDER_EXPANDED
)
792 std::vector
<tools::Rectangle
> aRegions(DemoRenderer::partition(rCtx
,5, 4));
793 static Color
const nStartCols
[] = {
794 COL_RED
, COL_RED
, COL_RED
, COL_GREEN
, COL_GREEN
,
795 COL_BLUE
, COL_BLUE
, COL_BLUE
, COL_CYAN
, COL_CYAN
,
796 COL_BLACK
, COL_LIGHTGRAY
, COL_WHITE
, COL_BLUE
, COL_CYAN
,
797 COL_WHITE
, COL_WHITE
, COL_WHITE
, COL_BLACK
, COL_BLACK
799 static Color
const nEndCols
[] = {
800 COL_WHITE
, COL_WHITE
, COL_WHITE
, COL_BLACK
, COL_BLACK
,
801 COL_RED
, COL_RED
, COL_RED
, COL_GREEN
, COL_GREEN
,
802 COL_GRAY
, COL_GRAY
, COL_LIGHTGRAY
, COL_LIGHTBLUE
, COL_LIGHTCYAN
,
803 COL_BLUE
, COL_BLUE
, COL_BLUE
, COL_CYAN
, COL_CYAN
805 GradientStyle eStyles
[] = {
806 GradientStyle::Linear
, GradientStyle::Axial
, GradientStyle::Radial
, GradientStyle::Elliptical
, GradientStyle::Square
,
807 GradientStyle::Rect
, GradientStyle::FORCE_EQUAL_SIZE
, GradientStyle::Linear
, GradientStyle::Radial
, GradientStyle::Linear
,
808 GradientStyle::Linear
, GradientStyle::Axial
, GradientStyle::Radial
, GradientStyle::Elliptical
, GradientStyle::Square
,
809 GradientStyle::Rect
, GradientStyle::FORCE_EQUAL_SIZE
, GradientStyle::Linear
, GradientStyle::Radial
, GradientStyle::Linear
811 sal_uInt16 nAngles
[] = {
814 90, 120, 135, 160, 180,
817 sal_uInt16 nBorders
[] = {
824 DemoRenderer::clearRects(rDev
, aRegions
);
825 assert(aRegions
.size() <= SAL_N_ELEMENTS(nStartCols
));
826 assert(aRegions
.size() <= SAL_N_ELEMENTS(nEndCols
));
827 assert(aRegions
.size() <= SAL_N_ELEMENTS(eStyles
));
828 assert(aRegions
.size() <= SAL_N_ELEMENTS(nAngles
));
829 assert(aRegions
.size() <= SAL_N_ELEMENTS(nBorders
));
830 for (size_t i
= 0; i
< aRegions
.size(); i
++)
832 tools::Rectangle aSub
= aRegions
[i
];
834 aGradient
.SetStartColor(nStartCols
[i
]);
835 aGradient
.SetEndColor(nEndCols
[i
]);
836 aGradient
.SetStyle(eStyles
[i
]);
837 aGradient
.SetAngle(nAngles
[i
]);
838 aGradient
.SetBorder(nBorders
[i
]);
839 rDev
.DrawGradient(aSub
, aGradient
);
845 aGradient
.SetStartColor(COL_YELLOW
);
846 aGradient
.SetEndColor(COL_RED
);
847 aGradient
.SetStyle(GradientStyle::Rect
);
848 aGradient
.SetBorder(r
.GetSize().Width()/20);
849 rDev
.DrawGradient(r
, aGradient
);
854 struct DrawBitmap
: public RegionRenderer
856 RENDER_DETAILS(bitmap
,KEY_B
,10)
858 // Simulate Page Borders rendering - which ultimately should
859 // be done with a shader / gradient
860 static void SimulateBorderStretch(OutputDevice
&rDev
, const tools::Rectangle
& r
)
862 BitmapEx
aPageShadowMask("sw/res/page-shadow-mask.png");
864 BitmapEx
aRight(aPageShadowMask
);
865 sal_Int32 nSlice
= (aPageShadowMask
.GetSizePixel().Width() - 3) / 4;
867 aRight
.Crop(tools::Rectangle(Point((nSlice
* 3) + 3, (nSlice
* 2) + 1),
869 AlphaMask
aAlphaMask(aRight
.GetBitmap());
870 Bitmap
aBlockColor(aAlphaMask
.GetSizePixel(), 24);
871 aBlockColor
.Erase(COL_RED
);
872 BitmapEx
aShadowStretch(aBlockColor
, aAlphaMask
);
874 Point
aRenderPt(r
.TopLeft());
876 long aSizes
[] = { 200, 100, 200, 100, 50, 5, 2 };
878 // and yes - we really do this in the page border rendering code ...
879 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aSizes
); i
++)
881 aShadowStretch
.Scale(Size(aShadowStretch
.GetSizePixel().Width(), aSizes
[i
]),
884 rDev
.DrawBitmapEx(aRenderPt
, aShadowStretch
);
885 aRenderPt
.Move(aShadowStretch
.GetSizePixel().Width() + 4, 0);
888 AlphaMask
aWholeMask(aPageShadowMask
.GetBitmap());
889 aBlockColor
= Bitmap(aPageShadowMask
.GetSizePixel(), 24);
890 aBlockColor
.Erase(COL_GREEN
);
891 BitmapEx
aWhole(aBlockColor
, aWholeMask
);
893 aRenderPt
= r
.Center();
894 aRenderPt
.Move(nSlice
+1, 0);
896 // An offset background for alpha rendering
897 rDev
.SetFillColor(COL_BLUE
);
898 tools::Rectangle
aSurround(r
.Center(), aPageShadowMask
.GetSizePixel());
899 rDev
.DrawRect(aSurround
);
900 rDev
.DrawBitmapEx(aRenderPt
, aWhole
);
903 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
904 const RenderContext
&rCtx
) override
906 Bitmap
aBitmap(rCtx
.mpDemoRenderer
->maIntroBW
);
907 aBitmap
.Scale(r
.GetSize(), BmpScaleFlag::BestQuality
);
908 rDev
.DrawBitmap(r
.TopLeft(), aBitmap
);
910 SimulateBorderStretch(rDev
, r
);
914 struct DrawBitmapEx
: public RegionRenderer
916 RENDER_DETAILS(bitmapex
,KEY_X
,2)
917 DrawCheckered maCheckered
;
918 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
919 const RenderContext
&rCtx
) override
921 maCheckered
.RenderRegion(rDev
, r
, rCtx
);
923 BitmapEx
aBitmap(rCtx
.mpDemoRenderer
->maIntro
);
924 aBitmap
.Scale(r
.GetSize(), BmpScaleFlag::BestQuality
);
925 AlphaMask
aSemiTransp(aBitmap
.GetSizePixel());
926 aSemiTransp
.Erase(64);
927 rDev
.DrawBitmapEx(r
.TopLeft(), BitmapEx(aBitmap
.GetBitmap(),
932 struct DrawPolyPolygons
: public RegionRenderer
934 RENDER_DETAILS(polypoly
,KEY_N
,100)
935 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
936 const RenderContext
&) override
940 } const aPoints
[] = { { 0.1, 0.1 }, { 0.9, 0.9 },
941 #if FIXME_SELF_INTERSECTING_WORKING
942 { 0.9, 0.1 }, { 0.1, 0.9 },
945 { 0.1, 0.9 }, { 0.5, 0.5 },
946 { 0.9, 0.1 }, { 0.1, 0.1 }
950 tools::PolyPolygon aPolyPoly
;
951 // Render 4x polygons & aggregate into another PolyPolygon
952 for (int x
= 0; x
< 2; x
++)
954 for (int y
= 0; y
< 2; y
++)
956 tools::Rectangle
aSubRect(r
);
957 aSubRect
.Move(x
* r
.GetWidth()/3, y
* r
.GetHeight()/3);
958 aSubRect
.SetSize(Size(r
.GetWidth()/2, r
.GetHeight()/4));
959 tools::Polygon
aPoly(SAL_N_ELEMENTS(aPoints
));
960 for (size_t v
= 0; v
< SAL_N_ELEMENTS(aPoints
); v
++)
962 aPoly
.SetPoint(Point(aSubRect
.Left() +
963 aSubRect
.GetWidth() * aPoints
[v
].nX
,
965 aSubRect
.GetHeight() * aPoints
[v
].nY
),
968 rDev
.SetLineColor(COL_YELLOW
);
969 rDev
.SetFillColor(COL_BLACK
);
970 rDev
.DrawPolygon(aPoly
);
972 // now move and add to the polypolygon
973 aPoly
.Move(0, r
.GetHeight()/2);
974 aPolyPoly
.Insert(aPoly
);
977 rDev
.SetLineColor(COL_LIGHTRED
);
978 rDev
.SetFillColor(COL_GREEN
);
979 rDev
.DrawTransparent(aPolyPoly
, 50);
983 struct DrawClipped
: public RegionRenderer
985 RENDER_DETAILS(clip
,KEY_D
,10)
986 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
987 const RenderContext
&) override
989 std::vector
<tools::Rectangle
> aRegions(DemoRenderer::partition(r
, 2, 2));
990 const int nLimits
[] = { 4, -100 };
991 for (int i
= 0; i
< 2; ++i
)
994 rDev
.Push(PushFlags::CLIPREGION
);
995 tools::Rectangle aOuter
= aRegions
[i
];
996 tools::Rectangle aInner
= aOuter
;
997 while (aInner
.GetWidth() > nLimits
[i
] && aInner
.GetHeight() > nLimits
[i
])
1000 rDev
.SetClipRegion(vcl::Region(aInner
));
1001 rDev
.SetFillColor(Color::HSBtoRGB(nHue
, 75, 100));
1002 nHue
= (nHue
+ 97) % 360;
1003 rDev
.DrawRect(aOuter
);
1009 sal_uInt16 nHue
= 0;
1010 tools::Rectangle aOuter
= aRegions
[2];
1011 std::vector
<tools::Rectangle
> aPieces(DemoRenderer::partition(aOuter
, 2, 2));
1012 for (int j
= 0; j
< std::min(aOuter
.GetWidth(), aOuter
.GetHeight())/5; ++j
)
1014 rDev
.Push(PushFlags::CLIPREGION
);
1016 vcl::Region aClipRegion
;
1017 for (int i
= 0; i
< 4; ++i
)
1019 aPieces
[i
].expand(-1);
1020 aPieces
[i
].Move(2 - i
/2, 2 - i
/2);
1021 aClipRegion
.Union(aPieces
[i
]);
1023 assert (aClipRegion
.getRegionBand());
1024 rDev
.SetClipRegion(aClipRegion
);
1025 rDev
.SetFillColor(Color::HSBtoRGB(nHue
, 75, 75));
1026 nHue
= (nHue
+ 97) % 360;
1027 rDev
.DrawRect(aOuter
);
1034 sal_uInt16 nHue
= 0;
1035 tools::Rectangle aOuter
= aRegions
[3];
1036 std::vector
<tools::Rectangle
> aPieces(DemoRenderer::partition(aOuter
, 2, 2));
1038 for (int j
= 0; !bDone
; ++j
)
1040 rDev
.Push(PushFlags::CLIPREGION
);
1042 for (int i
= 0; i
< 4; ++i
)
1044 vcl::Region aClipRegion
;
1045 tools::Polygon aPoly
;
1048 case 0: // 45degree rectangle.
1049 aPoly
= tools::Polygon(aPieces
[i
]);
1050 aPoly
.Rotate(aPieces
[i
].Center(), 450);
1053 aPoly
= tools::Polygon(aPieces
[i
],
1054 aPieces
[i
].TopLeft(),
1055 aPieces
[i
].BottomRight());
1058 aPoly
= tools::Polygon(aPieces
[i
],
1059 aPieces
[i
].GetWidth()/5,
1060 aPieces
[i
].GetHeight()/5);
1061 aPoly
.Rotate(aPieces
[i
].Center(), 450);
1064 aClipRegion
= vcl::Region(aPoly
);
1065 aPieces
[i
].expand(-1);
1066 aPieces
[i
].Move(2 - i
/2, 2 - i
/2);
1068 bDone
= aPieces
[i
].GetWidth() < 4 ||
1069 aPieces
[i
].GetHeight() < 4;
1073 assert (!aClipRegion
.getRegionBand());
1075 rDev
.SetClipRegion(aClipRegion
);
1076 rDev
.SetFillColor(Color::HSBtoRGB(nHue
, 50, 75));
1077 nHue
= (nHue
+ 97) % 360;
1078 rDev
.DrawRect(aOuter
);
1088 struct DrawToVirtualDevice
: public RegionRenderer
1090 RENDER_DETAILS(vdev
,KEY_V
,1)
1095 RENDER_AS_ALPHA_OUTDEV
1098 static void SizeAndRender(OutputDevice
&rDev
, const tools::Rectangle
& r
, RenderType eType
,
1099 const RenderContext
&rCtx
)
1101 ScopedVclPtr
<VirtualDevice
> pNested
;
1103 if (static_cast<int>(eType
) < RENDER_AS_BITMAPEX
)
1104 pNested
= VclPtr
<VirtualDevice
>::Create(rDev
).get();
1106 pNested
= VclPtr
<VirtualDevice
>::Create(rDev
,DeviceFormat::DEFAULT
,DeviceFormat::DEFAULT
).get();
1108 pNested
->SetOutputSizePixel(r
.GetSize());
1109 tools::Rectangle
aWhole(Point(0,0), r
.GetSize());
1112 rCtx
.mpDemoRenderer
->drawToDevice(*pNested
, r
.GetSize(), true);
1114 if (eType
== RENDER_AS_BITMAP
)
1116 Bitmap
aBitmap(pNested
->GetBitmap(Point(0,0),aWhole
.GetSize()));
1117 rDev
.DrawBitmap(r
.TopLeft(), aBitmap
);
1119 else if (eType
== RENDER_AS_BITMAPEX
)
1121 BitmapEx
aBitmapEx(pNested
->GetBitmapEx(Point(0,0),aWhole
.GetSize()));
1122 rDev
.DrawBitmapEx(r
.TopLeft(), aBitmapEx
);
1124 else if (eType
== RENDER_AS_OUTDEV
||
1125 eType
== RENDER_AS_ALPHA_OUTDEV
)
1127 rDev
.DrawOutDev(r
.TopLeft(), r
.GetSize(),
1128 aWhole
.TopLeft(), aWhole
.GetSize(),
1132 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
1133 const RenderContext
&rCtx
) override
1135 // avoid infinite recursion
1139 if (rCtx
.meStyle
== RENDER_EXPANDED
)
1141 std::vector
<tools::Rectangle
> aRegions(DemoRenderer::partition(rCtx
,2, 2));
1142 DemoRenderer::clearRects(rDev
, aRegions
);
1144 RenderType
const eRenderTypes
[] { RENDER_AS_BITMAP
, RENDER_AS_OUTDEV
,
1145 RENDER_AS_BITMAPEX
, RENDER_AS_ALPHA_OUTDEV
};
1146 for (size_t i
= 0; i
< aRegions
.size(); i
++)
1147 SizeAndRender(rDev
, aRegions
[i
], eRenderTypes
[i
], rCtx
);
1150 SizeAndRender(rDev
, r
, RENDER_AS_BITMAP
, rCtx
);
1154 struct DrawXOR
: public RegionRenderer
1156 RENDER_DETAILS(xor,KEY_X
,1)
1158 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
1159 const RenderContext
&rCtx
) override
1161 // avoid infinite recursion
1167 AntialiasingFlags nFlags
= rDev
.GetAntialiasing();
1168 rDev
.SetAntialiasing(nFlags
& ~AntialiasingFlags::EnableB2dDraw
);
1169 rDev
.SetRasterOp( RasterOp::Xor
);
1171 rCtx
.mpDemoRenderer
->drawThumbs(rDev
, r
, true);
1177 struct DrawIcons
: public RegionRenderer
1179 RENDER_DETAILS(icons
,KEY_I
,1)
1181 std::vector
<OUString
> maIconNames
;
1182 std::vector
<BitmapEx
> maIcons
;
1184 DrawIcons() : bHasLoadedAll(false)
1186 // a few icons to start with
1187 const char *pNames
[] = {
1188 "cmd/lc_openurl.png",
1189 "cmd/lc_newdoc.png",
1190 "cmd/lc_choosemacro.png",
1192 "cmd/lc_saveas.png",
1193 "cmd/lc_importdialog.png",
1194 "cmd/lc_sendmail.png",
1195 "cmd/lc_editdoc.png",
1197 "cmd/lc_combobox.png",
1198 "cmd/lc_insertformcombo.png",
1199 "cmd/lc_printpreview.png",
1203 "cmd/sc_autopilotmenu.png",
1204 "cmd/lc_formatpaintbrush.png",
1208 "cmd/lc_fieldnames.png",
1209 "cmd/lc_hyperlinkdialog.png",
1210 "cmd/lc_basicshapes.rectangle.png",
1211 "cmd/lc_basicshapes.round-rectangle.png"
1213 for (size_t i
= 0; i
< SAL_N_ELEMENTS(pNames
); i
++)
1215 maIconNames
.push_back(OUString::createFromAscii(pNames
[i
]));
1216 maIcons
.emplace_back(maIconNames
[i
]);
1220 void LoadAllImages()
1224 bHasLoadedAll
= true;
1226 css::uno::Reference
<css::container::XNameAccess
> xRef(ImageTree::get().getNameAccess());
1227 const css::uno::Sequence
< OUString
> aAllIcons
= xRef
->getElementNames();
1229 for (const auto& rIcon
: aAllIcons
)
1231 if (rIcon
.endsWithIgnoreAsciiCase("svg"))
1232 continue; // too slow to load.
1233 maIconNames
.push_back(rIcon
);
1234 maIcons
.emplace_back(rIcon
);
1238 void doDrawIcons(OutputDevice
&rDev
, tools::Rectangle r
, bool bExpanded
)
1241 Point
p(r
.LeftCenter());
1242 size_t nToRender
= maIcons
.size();
1244 if (!bExpanded
&& maIcons
.size() > 64)
1246 for (size_t i
= 0; i
< nToRender
; i
++)
1248 Size
aSize(maIcons
[i
].GetSizePixel());
1249 // sAL_DEBUG("Draw icon '" << maIconNames[i] << "'");
1252 rDev
.DrawBitmapEx(p
, maIcons
[i
]);
1255 basegfx::B2DHomMatrix aTransform
;
1256 aTransform
.scale(aSize
.Width(), aSize
.Height());
1260 aTransform
.shearX(static_cast<double>((i
>> 2) % 8) / 8);
1261 aTransform
.shearY(static_cast<double>((i
>> 4) % 8) / 8);
1264 aTransform
.translate(-aSize
.Width()/2, -aSize
.Height()/2);
1265 aTransform
.rotate(i
);
1268 aTransform
.shearX(static_cast<double>((i
>> 2) % 8) / 8);
1269 aTransform
.shearY(static_cast<double>((i
>> 4) % 8) / 8);
1271 aTransform
.translate(aSize
.Width()/2, aSize
.Height()/2);
1274 aTransform
.translate(-aSize
.Width()/2, -aSize
.Height()/2);
1275 aTransform
.rotate(2 * F_2PI
* i
/ nToRender
);
1276 aTransform
.translate(aSize
.Width()/2, aSize
.Height()/2);
1279 aTransform
.translate(p
.X(), p
.Y());
1280 rDev
.DrawTransformedBitmapEx(aTransform
, maIcons
[i
]);
1284 p
.Move(aSize
.Width(), 0);
1285 if (aSize
.Height() > nMaxH
)
1286 nMaxH
= aSize
.Height();
1287 if (p
.X() >= r
.Right()) // wrap to next line
1289 p
= Point(r
.Left(), p
.Y() + nMaxH
);
1292 if (p
.Y() >= r
.Bottom()) // re-start at middle
1297 static BitmapEx
AlphaRecovery(OutputDevice
&rDev
, Point aPt
, BitmapEx
const &aSrc
)
1299 // Compositing onto 2x colors beyond our control
1300 ScopedVclPtrInstance
< VirtualDevice
> aWhite
;
1301 ScopedVclPtrInstance
< VirtualDevice
> aBlack
;
1302 aWhite
->SetOutputSizePixel(aSrc
.GetSizePixel());
1303 aWhite
->SetBackground(Wallpaper(COL_WHITE
));
1305 aBlack
->SetOutputSizePixel(aSrc
.GetSizePixel());
1306 aBlack
->SetBackground(Wallpaper(COL_BLACK
));
1308 aWhite
->DrawBitmapEx(Point(), aSrc
);
1309 aBlack
->DrawBitmapEx(Point(), aSrc
);
1311 // Now recover that alpha...
1312 Bitmap aWhiteBmp
= aWhite
->GetBitmap(Point(),aSrc
.GetSizePixel());
1313 Bitmap aBlackBmp
= aBlack
->GetBitmap(Point(),aSrc
.GetSizePixel());
1314 AlphaMask
aMask(aSrc
.GetSizePixel());
1315 Bitmap
aRecovered(aSrc
.GetSizePixel(), 24);
1317 AlphaScopedWriteAccess
pMaskAcc(aMask
);
1318 BitmapScopedWriteAccess
pRecAcc(aRecovered
);
1319 Bitmap::ScopedReadAccess
pAccW(aWhiteBmp
); // a * pix + (1-a)
1320 Bitmap::ScopedReadAccess
pAccB(aBlackBmp
); // a * pix + 0
1321 int nSizeX
= aSrc
.GetSizePixel().Width();
1322 int nSizeY
= aSrc
.GetSizePixel().Height();
1323 for (int y
= 0; y
< nSizeY
; y
++)
1325 Scanline pScanlineMask
= pMaskAcc
->GetScanline( y
);
1326 Scanline pScanlineRec
= pRecAcc
->GetScanline( y
);
1327 Scanline pScanlineW
= pAccW
->GetScanline( y
);
1328 Scanline pScanlineB
= pAccB
->GetScanline( y
);
1329 for (int x
= 0; x
< nSizeX
; x
++)
1331 BitmapColor aColW
= pAccW
->GetPixelFromData(pScanlineW
,x
);
1332 BitmapColor aColB
= pAccB
->GetPixelFromData(pScanlineB
,x
);
1333 long nAR
= static_cast<long>(aColW
.GetRed() - aColB
.GetRed()); // (1-a)
1334 long nAG
= static_cast<long>(aColW
.GetGreen() - aColB
.GetGreen()); // (1-a)
1335 long nAB
= static_cast<long>(aColW
.GetBlue() - aColB
.GetBlue()); // (1-a)
1337 #define CLAMP(a,b,c) (((a)<=(b))?(b):(((a)>=(c))?(c):(a)))
1339 // we get the most precision from the largest delta
1340 long nInverseAlpha
= std::max(nAR
, std::max(nAG
, nAB
)); // (1-a)
1341 nInverseAlpha
= CLAMP(nInverseAlpha
, 0, 255);
1342 long nAlpha
= 255 - nInverseAlpha
;
1344 pMaskAcc
->SetPixelOnData(pScanlineMask
,x
,BitmapColor(static_cast<sal_Int8
>(CLAMP(nInverseAlpha
,0,255))));
1345 // now recover the pixels
1346 long nR
= (aColW
.GetRed() + aColB
.GetRed() - nInverseAlpha
) * 128;
1347 long nG
= (aColW
.GetGreen() + aColB
.GetGreen() - nInverseAlpha
) * 128;
1348 long nB
= (aColW
.GetBlue() + aColB
.GetBlue() - nInverseAlpha
) * 128;
1350 { // doesn't matter what's behind transparency
1355 nR
/= nAlpha
; nG
/= nAlpha
; nB
/= nAlpha
;
1357 pRecAcc
->SetPixelOnData(pScanlineRec
,x
,BitmapColor(
1358 static_cast<sal_uInt8
>(CLAMP(nR
,0,255)),
1359 static_cast<sal_uInt8
>(CLAMP(nG
,0,255)),
1360 static_cast<sal_uInt8
>(CLAMP(nB
,0,255))));
1365 rDev
.DrawBitmap(aPt
, aWhiteBmp
);
1366 aPt
.Move(aSrc
.GetSizePixel().Width(), 0);
1367 rDev
.DrawBitmap(aPt
, aBlackBmp
);
1368 aPt
.Move(aSrc
.GetSizePixel().Width(), 0);
1369 rDev
.DrawBitmap(aPt
, aRecovered
);
1370 aPt
.Move(aSrc
.GetSizePixel().Width(), 0);
1371 rDev
.DrawBitmap(aPt
, aMask
.GetBitmap());
1372 aPt
.Move(aSrc
.GetSizePixel().Width(), 0);
1374 return BitmapEx(aRecovered
, aMask
);
1377 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
1378 const RenderContext
&rCtx
) override
1380 if (rCtx
.meStyle
== RENDER_EXPANDED
)
1384 Point
aLocation(0,maIcons
[0].GetSizePixel().Height() + 8);
1385 for (size_t i
= 0; i
< maIcons
.size(); i
++)
1387 BitmapEx aSrc
= maIcons
[i
];
1390 Point
aAbove(aLocation
);
1391 aAbove
.Move(0,-aSrc
.GetSizePixel().Height() - 4);
1392 rDev
.DrawBitmapEx(aAbove
, aSrc
);
1393 aAbove
.Move(aSrc
.GetSizePixel().Width(),0);
1394 aAbove
.Move(aSrc
.GetSizePixel().Width(),0);
1395 rDev
.DrawBitmap(aAbove
, aSrc
.GetBitmap());
1396 aAbove
.Move(aSrc
.GetSizePixel().Width(),0);
1397 rDev
.DrawBitmap(aAbove
, aSrc
.GetMask());
1399 // intermediates middle
1400 BitmapEx aResult
= AlphaRecovery(rDev
, aLocation
, aSrc
);
1403 Point
aBelow(aLocation
);
1404 aBelow
.Move(0,aResult
.GetSizePixel().Height());
1405 rDev
.DrawBitmapEx(aBelow
, aResult
);
1407 // mini convert test.
1408 aBelow
.Move(aResult
.GetSizePixel().Width()+4,0);
1409 rDev
.DrawBitmapEx(aBelow
, aResult
);
1411 Bitmap aGrey
= aSrc
.GetBitmap();
1412 aGrey
.Convert(BmpConversion::N8BitGreys
);
1413 rDev
.DrawBitmap(aBelow
, aGrey
);
1415 aBelow
.Move(aGrey
.GetSizePixel().Width(),0);
1416 BitmapEx
aGreyMask(aSrc
.GetBitmap(),
1417 AlphaMask(aSrc
.GetMask()));
1418 rDev
.DrawBitmapEx(aBelow
, aGreyMask
);
1420 aLocation
.Move(aSrc
.GetSizePixel().Width()*6,0);
1421 if (aLocation
.X() > r
.Right())
1422 aLocation
= Point(0,aLocation
.Y()+aSrc
.GetSizePixel().Height()*3+4);
1425 // now go crazy with random foo
1426 doDrawIcons(rDev
, r
, true);
1430 doDrawIcons(rDev
, r
, false);
1435 struct FetchDrawBitmap
: public RegionRenderer
1437 RENDER_DETAILS(fetchdraw
,KEY_F
,50)
1438 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
1439 const RenderContext
&) override
1441 Bitmap
aBitmap(rDev
.GetBitmap(Point(0,0),rDev
.GetOutputSizePixel()));
1442 aBitmap
.Scale(r
.GetSize(), BmpScaleFlag::BestQuality
);
1443 rDev
.DrawBitmap(r
.TopLeft(), aBitmap
);
1447 void drawThumbs(vcl::RenderContext
& rDev
, tools::Rectangle aRect
, bool bVDev
)
1450 aCtx
.meStyle
= RENDER_THUMB
;
1451 aCtx
.mbVDev
= bVDev
;
1452 aCtx
.mpDemoRenderer
= this;
1453 aCtx
.maSize
= aRect
.GetSize();
1454 std::vector
<tools::Rectangle
> aRegions(partition(aRect
, mnSegmentsX
, mnSegmentsY
));
1455 DemoRenderer::clearRects(rDev
, aRegions
);
1456 for (size_t i
= 0; i
< maRenderers
.size(); i
++)
1458 RegionRenderer
* r
= maRenderers
[i
];
1460 rDev
.SetClipRegion( vcl::Region( aRegions
[i
] ) );
1463 if (getIterCount() > 0)
1467 double nStartTime
= getTimeNow();
1468 for (int j
= 0; j
< r
->getTestRepeatCount() * THUMB_REPEAT_FACTOR
; j
++)
1469 r
->RenderRegion(rDev
, aRegions
[i
], aCtx
);
1470 addTime(i
, (getTimeNow() - nStartTime
) / THUMB_REPEAT_FACTOR
);
1472 for (int j
= 0; j
< r
->getTestRepeatCount(); j
++)
1473 r
->RenderRegion(rDev
, aRegions
[i
], aCtx
);
1476 r
->RenderRegion(rDev
, aRegions
[i
], aCtx
);
1478 rDev
.SetClipRegion();
1482 void drawToDevice(vcl::RenderContext
& rDev
, Size aSize
, bool bVDev
)
1485 aCtx
.mbVDev
= bVDev
;
1486 aCtx
.mpDemoRenderer
= this;
1487 aCtx
.maSize
= aSize
;
1488 tools::Rectangle
aWholeWin(Point(0,0), rDev
.GetOutputSizePixel());
1490 drawBackground(rDev
, aWholeWin
);
1492 if (!bVDev
/* want everything in the vdev */ &&
1493 mnSelectedRenderer
>= 0 &&
1494 static_cast<sal_uInt32
>(mnSelectedRenderer
) < maRenderers
.size())
1496 aCtx
.meStyle
= RENDER_EXPANDED
;
1497 RegionRenderer
* r
= maRenderers
[mnSelectedRenderer
];
1499 if (getIterCount() > 0)
1501 double nStartTime
= getTimeNow();
1502 for (int i
= 0; i
< r
->getTestRepeatCount(); i
++)
1503 r
->RenderRegion(rDev
, aWholeWin
, aCtx
);
1504 addTime(mnSelectedRenderer
, getTimeNow() - nStartTime
);
1506 r
->RenderRegion(rDev
, aWholeWin
, aCtx
);
1509 drawThumbs(rDev
, aWholeWin
, bVDev
);
1511 std::vector
<VclPtr
<vcl::Window
> > maInvalidates
;
1512 void addInvalidate(vcl::Window
*pWindow
) { maInvalidates
.emplace_back(pWindow
); };
1513 void removeInvalidate(vcl::Window
*pWindow
)
1515 auto aIt
= std::find(maInvalidates
.begin(), maInvalidates
.end(), pWindow
);
1516 if (aIt
!= maInvalidates
.end())
1517 maInvalidates
.erase(aIt
);
1521 for (auto const& invalidate
: maInvalidates
)
1522 invalidate
->Invalidate();
1526 #if FIXME_BOUNCE_BUTTON
1527 IMPL_LINK_NOARG(DemoRenderer
,BounceTimerCb
,Timer
*,void)
1529 mpButton
->Check(mnBounceX
>0);
1530 mpButton
->SetPressed(mnBounceY
>0);
1532 Point aCur
= mpButtonWin
->GetPosPixel();
1533 static const int nMovePix
= 10;
1534 aCur
.Move(mnBounceX
* nMovePix
, mnBounceX
* nMovePix
);
1535 Size aWinSize
= GetSizePixel();
1536 if (aCur
.X() <= 0 || aCur
.X() >= aWinSize
.Width())
1538 if (aCur
.Y() <= 0 || aCur
.Y() >= aWinSize
.Height())
1540 mpButtonWin
->SetPosPixel(aCur
);
1542 // All smoke and mirrors to test sub-region invalidation underneath
1543 Rectangle
aRect(aCur
, mpButtonWin
->GetSizePixel());
1548 void DemoRenderer::KeyInput(const KeyEvent
&rKEvt
)
1550 sal_uInt16 nCode
= rKEvt
.GetKeyCode().GetCode();
1552 // click to zoom out
1553 if (mnSelectedRenderer
>= 0)
1555 if (nCode
== KEY_ESCAPE
|| nCode
== KEY_BACKSPACE
)
1557 mnSelectedRenderer
= -1;
1564 for (size_t i
= 0; i
< maRenderers
.size(); i
++)
1566 if (nCode
== maRenderers
[i
]->getAccelerator())
1568 mnSelectedRenderer
= i
;
1576 bool DemoRenderer::MouseButtonDown(const MouseEvent
& rMEvt
)
1578 // click to zoom out
1579 if (mnSelectedRenderer
>= 0)
1581 mnSelectedRenderer
= -1;
1586 // click on a region to zoom into it
1587 std::vector
<tools::Rectangle
> aRegions(partition(GetSizePixel(), mnSegmentsX
, mnSegmentsY
));
1588 for (size_t i
= 0; i
< aRegions
.size(); i
++)
1590 if (aRegions
[i
].IsInside(rMEvt
.GetPosPixel()))
1592 mnSelectedRenderer
= i
;
1598 #if FIXME_BOUNCE_BUTTON
1599 // otherwise bounce floating windows
1602 mpButtonWin
= VclPtr
<FloatingWindow
>::Create(this);
1603 mpButton
= VclPtr
<PushButton
>::Create(mpButtonWin
);
1604 mpButton
->SetSymbol(SymbolType::HELP
);
1605 mpButton
->SetText("PushButton demo");
1606 mpButton
->SetPosSizePixel(Point(0,0), mpButton
->GetOptimalSize());
1608 mpButtonWin
->SetPosSizePixel(Point(0,0), mpButton
->GetOptimalSize());
1609 mpButtonWin
->Show();
1610 mnBounceX
= 1; mnBounceX
= 1;
1611 maBounce
.SetInvokeHandler(LINK(this,DemoRenderer
,BounceTimerCb
));
1612 maBounce
.SetTimeout(55);
1626 void DemoRenderer::InitRenderers()
1628 maRenderers
.push_back(new DrawLines
);
1629 maRenderers
.push_back(new DrawText
);
1630 maRenderers
.push_back(new DrawPoly
);
1631 maRenderers
.push_back(new DrawEllipse
);
1632 maRenderers
.push_back(new DrawCheckered
);
1633 maRenderers
.push_back(new DrawBitmapEx
);
1634 maRenderers
.push_back(new DrawBitmap
);
1635 maRenderers
.push_back(new DrawGradient
);
1636 maRenderers
.push_back(new DrawPolyPolygons
);
1637 maRenderers
.push_back(new DrawClipped
);
1638 maRenderers
.push_back(new DrawToVirtualDevice
);
1639 maRenderers
.push_back(new DrawXOR
);
1640 maRenderers
.push_back(new DrawIcons());
1641 maRenderers
.push_back(new FetchDrawBitmap
);
1644 OUString
DemoRenderer::getRendererList()
1646 OUStringBuffer aBuf
;
1647 for (size_t i
= 0; i
< maRenderers
.size(); i
++)
1649 aBuf
.append(maRenderers
[i
]->getName());
1652 return aBuf
.makeStringAndClear();
1655 double DemoRenderer::getAndResetBenchmark(const RenderStyle style
)
1657 double geomean
= 1.0;
1658 fprintf(stderr
, "Rendering: %s, Times (ms):\n", style
== RENDER_THUMB
? "THUMB": "EXPANDED");
1659 for (size_t i
= 0; i
< maRenderers
.size(); i
++)
1661 double avgtime
= maRenderers
[i
]->sumTime
/ maRenderers
[i
]->countTime
;
1663 fprintf(stderr
, "%s: %f (iteration: %d*%d*%d)\n",
1664 OUStringToOString(maRenderers
[i
]->getName(),
1665 RTL_TEXTENCODING_UTF8
).getStr(), avgtime
,
1666 maRenderers
[i
]->countTime
, maRenderers
[i
]->getTestRepeatCount(),
1667 (style
== RENDER_THUMB
) ? THUMB_REPEAT_FACTOR
: 1);
1668 maRenderers
[i
]->sumTime
= 0;
1669 maRenderers
[i
]->countTime
= 0;
1671 geomean
= pow(geomean
, 1.0/maRenderers
.size());
1672 fprintf(stderr
, "GEOMEAN_%s: %f\n", style
== RENDER_THUMB
? "THUMB": "EXPANDED", geomean
);
1676 void DemoRenderer::setIterCount(sal_Int32 i
)
1681 sal_Int32
DemoRenderer::getIterCount() const
1686 void DemoRenderer::addTime(int i
, double t
)
1688 maRenderers
[i
]->sumTime
+= t
/ maRenderers
[i
]->getTestRepeatCount();
1689 maRenderers
[i
]->countTime
++;
1692 void DemoRenderer::selectRenderer(const OUString
&rName
)
1694 for (size_t i
= 0; i
< maRenderers
.size(); i
++)
1696 if (maRenderers
[i
]->getName() == rName
)
1698 mnSelectedRenderer
= i
;
1705 int DemoRenderer::selectNextRenderer()
1707 mnSelectedRenderer
++;
1708 if (mnSelectedRenderer
== static_cast<signed>(maRenderers
.size()))
1709 mnSelectedRenderer
= -1;
1711 return mnSelectedRenderer
;
1714 class DemoWin
: public WorkWindow
1716 DemoRenderer
&mrRenderer
;
1720 class RenderThread final
: public salhelper::Thread
{
1722 sal_uInt32
const mnDelaySecs
= 0;
1724 RenderThread(DemoWin
&rWin
, sal_uInt32 nDelaySecs
)
1725 : Thread("vcldemo render thread")
1727 , mnDelaySecs(nDelaySecs
)
1731 virtual ~RenderThread() override
1735 virtual void execute() override
1737 wait(std::chrono::seconds(mnDelaySecs
));
1739 SolarMutexGuard aGuard
;
1740 fprintf (stderr
, "render from a different thread\n");
1744 rtl::Reference
<RenderThread
> mxThread
;
1747 DemoWin(DemoRenderer
&rRenderer
, bool bThreads
) :
1748 WorkWindow(nullptr, WB_APP
| WB_STDWORK
),
1749 mrRenderer(rRenderer
),
1750 testThreads(bThreads
)
1752 mrRenderer
.addInvalidate(this);
1753 underTesting
= false;
1755 virtual ~DemoWin() override
1759 virtual void dispose() override
1762 mrRenderer
.removeInvalidate(this);
1763 WorkWindow::dispose();
1765 virtual void MouseButtonDown(const MouseEvent
& rMEvt
) override
1767 mrRenderer
.SetSizePixel(GetSizePixel());
1768 if (!mrRenderer
.MouseButtonDown(rMEvt
))
1771 { // render this window asynchronously in a new thread
1772 sal_uInt32 nDelaySecs
= 0;
1773 if (rMEvt
.GetButtons() & MOUSE_RIGHT
)
1775 mxThread
= new RenderThread(*this, nDelaySecs
);
1778 { // spawn another window
1779 VclPtrInstance
<DemoWin
> pNewWin(mrRenderer
, testThreads
);
1780 pNewWin
->SetText("Another interactive VCL demo window");
1785 virtual void KeyInput(const KeyEvent
& rKEvt
) override
1787 mrRenderer
.SetSizePixel(GetSizePixel());
1788 mrRenderer
.KeyInput(rKEvt
);
1790 virtual void Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRect
) override
1792 mrRenderer
.SetSizePixel(GetSizePixel());
1793 fprintf(stderr
, "DemoWin::Paint(%ld,%ld,%ld,%ld)\n", rRect
.getX(), rRect
.getY(), rRect
.getWidth(), rRect
.getHeight());
1794 if (mrRenderer
.getIterCount() == 0)
1795 mrRenderer
.drawToDevice(rRenderContext
, GetSizePixel(), false);
1797 TestAndQuit(rRenderContext
);
1800 void TestAndQuit(vcl::RenderContext
& rRenderContext
)
1804 underTesting
= true;
1805 for (sal_Int32 i
= 0; i
< mrRenderer
.getIterCount(); i
++)
1807 while (mrRenderer
.selectNextRenderer() > -1)
1809 mrRenderer
.drawToDevice(rRenderContext
, GetSizePixel(), false);
1813 double expandedGEOMEAN
= mrRenderer
.getAndResetBenchmark(RENDER_EXPANDED
);
1815 for (sal_Int32 i
= 0; i
< mrRenderer
.getIterCount(); i
++)
1816 mrRenderer
.drawToDevice(rRenderContext
, GetSizePixel(), false);
1818 double thumbGEOMEAN
= mrRenderer
.getAndResetBenchmark(RENDER_THUMB
);
1820 fprintf(stderr
, "GEOMEAN_TOTAL: %f\n", pow(thumbGEOMEAN
* expandedGEOMEAN
, 0.5));
1821 Application::Quit();
1825 struct PointerData
{
1826 PointerStyle eStyle
;
1829 static const PointerData gvPointerData
[] = {
1830 { PointerStyle::Null
, "Null" },
1831 { PointerStyle::Magnify
, "Magnify" },
1832 { PointerStyle::Fill
, "Fill" },
1833 { PointerStyle::MoveData
, "MoveData" },
1834 { PointerStyle::CopyData
, "CopyData" },
1835 { PointerStyle::MoveFile
, "MoveFile" },
1836 { PointerStyle::CopyFile
, "CopyFile" },
1837 { PointerStyle::MoveFiles
, "MoveFiles" },
1838 { PointerStyle::CopyFiles
, "CopyFiles" },
1839 { PointerStyle::NotAllowed
, "NotAllowed" },
1840 { PointerStyle::Rotate
, "Rotate" },
1841 { PointerStyle::HShear
, "HShear" },
1842 { PointerStyle::VShear
, "VShear" },
1843 { PointerStyle::DrawLine
, "DrawLine" },
1844 { PointerStyle::DrawRect
, "DrawRect" },
1845 { PointerStyle::DrawPolygon
, "DrawPolygon" },
1846 { PointerStyle::DrawBezier
, "DrawBezier" },
1847 { PointerStyle::DrawArc
, "DrawArc" },
1848 { PointerStyle::DrawPie
, "DrawPie" },
1849 { PointerStyle::DrawCircleCut
, "DrawCircleCut" },
1850 { PointerStyle::DrawEllipse
, "DrawEllipse" },
1851 { PointerStyle::DrawConnect
, "DrawConnect" },
1852 { PointerStyle::DrawText
, "DrawText" },
1853 { PointerStyle::Mirror
, "Mirror" },
1854 { PointerStyle::Crook
, "Crook" },
1855 { PointerStyle::Crop
, "Crop" },
1856 { PointerStyle::MovePoint
, "MovePoint" },
1857 { PointerStyle::MoveBezierWeight
, "MoveBezierWeight" },
1858 { PointerStyle::DrawFreehand
, "DrawFreehand" },
1859 { PointerStyle::DrawCaption
, "DrawCaption" },
1860 { PointerStyle::LinkData
, "LinkData" },
1861 { PointerStyle::MoveDataLink
, "MoveDataLink" },
1862 { PointerStyle::CopyDataLink
, "CopyDataLink" },
1863 { PointerStyle::LinkFile
, "LinkFile" },
1864 { PointerStyle::MoveFileLink
, "MoveFileLink" },
1865 { PointerStyle::CopyFileLink
, "CopyFileLink" },
1866 { PointerStyle::Chart
, "Chart" },
1867 { PointerStyle::Detective
, "Detective" },
1868 { PointerStyle::PivotCol
, "PivotCol" },
1869 { PointerStyle::PivotRow
, "PivotRow" },
1870 { PointerStyle::PivotField
, "PivotField" },
1871 { PointerStyle::PivotDelete
, "PivotDelete" },
1872 { PointerStyle::Chain
, "Chain" },
1873 { PointerStyle::ChainNotAllowed
, "ChainNotAllowed" },
1874 { PointerStyle::AutoScrollN
, "AutoScrollN" },
1875 { PointerStyle::AutoScrollS
, "AutoScrollS" },
1876 { PointerStyle::AutoScrollW
, "AutoScrollW" },
1877 { PointerStyle::AutoScrollE
, "AutoScrollE" },
1878 { PointerStyle::AutoScrollNW
, "AutoScrollNW" },
1879 { PointerStyle::AutoScrollNE
, "AutoScrollNE" },
1880 { PointerStyle::AutoScrollSW
, "AutoScrollSW" },
1881 { PointerStyle::AutoScrollSE
, "AutoScrollSE" },
1882 { PointerStyle::AutoScrollNS
, "AutoScrollNS" },
1883 { PointerStyle::AutoScrollWE
, "AutoScrollWE" },
1884 { PointerStyle::AutoScrollNSWE
, "AutoScrollNSWE" },
1885 { PointerStyle::TextVertical
, "TextVertical" },
1886 { PointerStyle::TabSelectS
, "TabSelectS" },
1887 { PointerStyle::TabSelectE
, "TabSelectE" },
1888 { PointerStyle::TabSelectSE
, "TabSelectSE" },
1889 { PointerStyle::TabSelectW
, "TabSelectW" },
1890 { PointerStyle::TabSelectSW
, "TabSelectSW" },
1891 { PointerStyle::HideWhitespace
, "HideWhitespace" },
1892 { PointerStyle::ShowWhitespace
, "ShowWhitespace" },
1894 class DemoWidgets
: public WorkWindow
1896 VclPtr
<MenuBar
> mpBar
;
1897 VclPtr
<VclBox
> mpBox
;
1898 VclPtr
<ToolBox
> mpToolbox
;
1899 VclPtr
<PushButton
> mpButton
;
1900 VclPtr
<VclHBox
> mpHBox
;
1901 VclPtr
<CheckBox
> mpGLCheck
;
1902 VclPtr
<ComboBox
> mpGLCombo
;
1903 VclPtr
<PushButton
> mpGLButton
;
1904 std::vector
<VclPtr
<VclHBox
>> mvCursorBoxes
;
1905 std::vector
<VclPtr
<PushButton
>> mvCursorButtons
;
1907 DECL_LINK(GLTestClick
, Button
*, void);
1908 DECL_LINK(CursorButtonClick
, Button
*, void);
1912 WorkWindow(nullptr, WB_APP
| WB_STDWORK
),
1913 mpBox(VclPtrInstance
<VclVBox
>(this, false, 3)),
1914 mpToolbox(VclPtrInstance
<ToolBox
>(mpBox
.get())),
1915 mpButton(VclPtrInstance
<PushButton
>(mpBox
.get())),
1916 mpHBox(VclPtrInstance
<VclHBox
>(mpBox
.get(), true, 3)),
1917 mpGLCheck(VclPtrInstance
<CheckBox
>(mpHBox
.get())),
1918 mpGLCombo(VclPtrInstance
<ComboBox
>(mpHBox
.get())),
1919 mpGLButton(VclPtrInstance
<PushButton
>(mpHBox
.get()))
1921 SetText("VCL widget demo");
1923 Wallpaper
aWallpaper(BitmapEx("sfx2/res/startcenter-logo.png"));
1924 aWallpaper
.SetStyle(WallpaperStyle::BottomRight
);
1925 aWallpaper
.SetColor(COL_RED
);
1927 mpBox
->SetBackground(aWallpaper
);
1930 Help::EnableBalloonHelp();
1931 mpToolbox
->SetHelpText("Help text");
1932 mpToolbox
->InsertItem(0, "Toolbar item");
1933 mpToolbox
->SetQuickHelpText(0, "This is a tooltip popup");
1934 mpToolbox
->InsertSeparator();
1937 mpButton
->SetText("Click me; go on");
1940 mpGLCheck
->SetText("Test in OGL zone");
1942 mpGLCombo
->InsertEntry("sleep 1 second");
1943 mpGLCombo
->InsertEntry("sleep 3 seconds");
1944 mpGLCombo
->InsertEntry("sleep 7 seconds");
1945 mpGLCombo
->SelectEntryPos(2);
1947 mpGLButton
->SetText("Execute test");
1948 mpGLButton
->SetClickHdl(LINK(this,DemoWidgets
,GLTestClick
));
1953 VclHBox
* pCurrentCursorHBox
= nullptr;
1954 constexpr int numButtonsPerRow
= 9;
1955 for (auto & rData
: gvPointerData
)
1957 if (i
% numButtonsPerRow
== 0)
1959 mvCursorBoxes
.push_back(VclPtrInstance
<VclHBox
>(mpBox
.get(), true, numButtonsPerRow
));
1960 pCurrentCursorHBox
= mvCursorBoxes
.back().get();
1961 pCurrentCursorHBox
->Show();
1963 mvCursorButtons
.emplace_back(VclPtrInstance
<PushButton
>(pCurrentCursorHBox
));
1964 PushButton
& rButton
= *mvCursorButtons
.back();
1965 rButton
.SetText(OUString::createFromAscii(rData
.name
));
1966 rButton
.SetClickHdl(LINK(this,DemoWidgets
,CursorButtonClick
));
1971 mpBar
= VclPtr
<MenuBar
>::Create();
1972 mpBar
->InsertItem(0,"File");
1973 VclPtrInstance
<PopupMenu
> pPopup
;
1974 pPopup
->InsertItem(0,"Item");
1975 mpBar
->SetPopupMenu(0, pPopup
);
1980 virtual ~DemoWidgets() override
{ disposeOnce(); }
1981 virtual void dispose() override
1983 mpGLButton
.disposeAndClear();
1984 mpGLCombo
.disposeAndClear();
1985 mpGLCheck
.disposeAndClear();
1986 mpHBox
.disposeAndClear();
1987 for (auto & p
: mvCursorButtons
)
1988 p
.disposeAndClear();
1989 mvCursorButtons
.clear();
1990 for (auto & p
: mvCursorBoxes
)
1991 p
.disposeAndClear();
1992 mvCursorBoxes
.clear();
1993 mpToolbox
.disposeAndClear();
1994 mpButton
.disposeAndClear();
1995 mpBox
.disposeAndClear();
1996 mpBar
.disposeAndClear();
1997 WorkWindow::dispose();
1999 virtual void Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
&) override
2001 tools::Rectangle
aWholeSize(Point(0, 0),GetOutputSizePixel());
2002 vcl::Region
aClip(aWholeSize
);
2003 tools::Rectangle
aExclude(tools::Rectangle(Point(50,50),Size(100,100)));
2004 aClip
.Exclude(aExclude
);
2006 Wallpaper
aWallpaper(COL_GREEN
);
2008 rRenderContext
.Push(PushFlags::CLIPREGION
);
2009 rRenderContext
.IntersectClipRegion(aClip
);
2010 rRenderContext
.DrawWallpaper(aWholeSize
, aWallpaper
);
2011 rRenderContext
.Pop();
2013 ScopedVclPtrInstance
< VirtualDevice
> pDev(*this);
2014 pDev
->EnableRTL(IsRTLEnabled());
2015 pDev
->SetOutputSizePixel(aExclude
.GetSize());
2017 tools::Rectangle
aSubRect(aWholeSize
);
2018 aSubRect
.Move(-aExclude
.Left(), -aExclude
.Top());
2019 pDev
->DrawWallpaper(aSubRect
, aWallpaper
);
2021 rRenderContext
.DrawOutDev(aExclude
.TopLeft(), aExclude
.GetSize(),
2022 Point( 0, 0 ), aExclude
.GetSize(), *pDev
);
2026 IMPL_LINK_NOARG(DemoWidgets
, GLTestClick
, Button
*, void)
2028 sal_Int32 nSelected
= mpGLCombo
->GetSelectedEntryPos();
2029 sal_uInt32 nDelaySeconds
= 0;
2046 // Only create OpenGLZone RAII object if asked for:
2047 std::unique_ptr
<OpenGLZone
> zone
;
2048 if (mpGLCheck
->IsChecked()) {
2049 zone
.reset(new OpenGLZone
);
2052 osl::Thread::wait(std::chrono::seconds(nDelaySeconds
));
2055 IMPL_LINK(DemoWidgets
, CursorButtonClick
, Button
*, pButton
, void)
2057 for (size_t i
=0; i
<SAL_N_ELEMENTS(gvPointerData
); ++i
)
2059 if (mvCursorButtons
[i
].get() == pButton
)
2061 mpBox
->SetPointer( gvPointerData
[i
].eStyle
);
2068 class DemoPopup
: public FloatingWindow
2071 DemoPopup() : FloatingWindow( nullptr, WB_SYSTEMWINDOW
|WB_TOOLTIPWIN
)
2073 SetType( WindowType::HELPTEXTWINDOW
);
2075 SetOutputSizePixel( Size( 300, 30 ) );
2076 SetBackground(Wallpaper(COL_YELLOW
));
2078 Show( true, ShowFlags::NoActivate
);
2082 virtual void Paint(vcl::RenderContext
& /*rRenderContext*/, const tools::Rectangle
&) override
2084 // Interestingly in GL mode on Windows, this doesn't render.
2086 Size aSize
= GetOutputSizePixel();
2087 tools::Rectangle
aTextRect(Point(6, 6), aSize
);
2089 SetTextColor(COL_BLACK
);
2090 SetTextAlign(ALIGN_TOP
);
2091 DrawText(aTextRect
, "This is a standalone help text test",
2092 DrawTextFlags::MultiLine
|DrawTextFlags::WordBreak
|
2093 DrawTextFlags::Left
|DrawTextFlags::Top
);
2095 SetLineColor(COL_BLACK
);
2097 DrawRect( tools::Rectangle( Point(), aSize
) );
2098 aSize
.AdjustWidth( -2 );
2099 aSize
.AdjustHeight( -2 );
2100 Color
aColor( GetLineColor() );
2101 SetLineColor( COL_GRAY
);
2102 DrawRect( tools::Rectangle( Point( 1, 1 ), aSize
) );
2103 SetLineColor( aColor
);
2106 virtual void MouseButtonDown( const MouseEvent
& ) override
2108 Application::Quit();
2114 VclPtr
<WorkWindow
> mxWinA
;
2115 VclPtr
<WorkWindow
> mxWinB
;
2116 rtl::Reference
<OpenGLContext
> mpA
;
2117 rtl::Reference
<OpenGLContext
> mpB
;
2119 static OpenGLSalGraphicsImpl
*getImpl(const VclPtr
<OutputDevice
> &xOut
)
2121 SalGraphics
*pGraphics
= xOut
->GetGraphics();
2122 return dynamic_cast<OpenGLSalGraphicsImpl
*>(pGraphics
->GetImpl());
2126 mxWinA(VclPtr
<WorkWindow
>::Create(nullptr, WB_APP
| WB_STDWORK
)),
2127 mxWinB(VclPtr
<WorkWindow
>::Create(nullptr, WB_APP
| WB_STDWORK
))
2129 OpenGLSalGraphicsImpl
*pImplA
;
2130 OpenGLSalGraphicsImpl
*pImplB
;
2131 if (!OpenGLHelper::isVCLOpenGLEnabled())
2133 pImplA
= pImplB
= nullptr;
2134 fprintf (stderr
, "OpenGL is not enabled: try SAL_FORCEGL=1\n");
2138 pImplA
= getImpl(mxWinA
);
2139 pImplB
= getImpl(mxWinB
);
2140 assert (pImplA
&& pImplB
);
2141 mpA
= pImplA
->GetOpenGLContext();
2142 mpB
= pImplB
->GetOpenGLContext();
2144 assert (mpA
.is() && mpB
.is());
2145 assert (mpA
!= mpB
);
2149 mxWinB
.disposeAndClear();
2150 mxWinA
.disposeAndClear();
2153 void testCurrentFramebuffer()
2155 fprintf(stderr
,"test OpenGLContext's framebuffer association.\n");
2157 OpenGLFramebuffer
*pBuffer
;
2159 OpenGLTexture
aTexture(256,128);
2160 pBuffer
= mpA
->AcquireFramebuffer(aTexture
);
2162 assert (pBuffer
->IsFree()); (void)pBuffer
;
2164 assert (mpA
->mpCurrentFramebuffer
== nullptr);
2167 void testVirtualDevice()
2169 fprintf(stderr
, "test sharing OpenGLContexts with virtual-devices reference counting\n");
2170 VclPtrInstance
<WorkWindow
> xTempWin(nullptr, WB_STDWORK
);
2172 // forcibly make this context current by rendering
2173 xTempWin
->DrawPixel(Point(0, 0), COL_RED
);
2175 // get some other guys to leach off this context
2176 VclPtrInstance
<VirtualDevice
> xVDev
;
2177 OpenGLSalGraphicsImpl
* pImpl
= getImpl(xVDev
);
2179 rtl::Reference
<OpenGLContext
> pContext
= pImpl
->GetOpenGLContext();
2180 VclPtrInstance
<VirtualDevice
> xVDev2
;
2181 OpenGLSalGraphicsImpl
* pImpl2
= getImpl(xVDev2
);
2183 rtl::Reference
<OpenGLContext
> pContext2
= pImpl2
->GetOpenGLContext();
2185 // sharing the same off-screen context.
2186 assert(pContext
== pContext2
);
2187 assert(pContext
== getImpl(xTempWin
)->GetOpenGLContext());
2188 assert(pContext
!= mpA
&& pContext
!= mpB
);
2189 (void)pContext
; (void)pContext2
;
2191 // Kill the parent we free-ride on ...
2192 xTempWin
.disposeAndClear();
2194 // This appears to continue working; fun.
2196 xVDev
->DrawPixel(aPt
, COL_GREEN
);
2197 assert(xVDev
->GetPixel(aPt
) == COL_GREEN
);
2198 xVDev
.disposeAndClear();
2200 // Switch context to see if we can switch back.
2201 mxWinA
->DrawPixel(aPt
, COL_WHITE
);
2203 // Now try switching back to this guy ...
2204 xVDev2
->DrawPixel(aPt
, COL_BLUE
);
2205 assert(xVDev2
->GetPixel(aPt
) == COL_BLUE
);
2206 xVDev2
.disposeAndClear();
2211 if (!OpenGLHelper::isVCLOpenGLEnabled())
2214 testCurrentFramebuffer();
2215 testVirtualDevice();
2222 void renderFonts(const std::vector
<OUString
> &aFontNames
)
2224 ScopedVclPtrInstance
<VirtualDevice
> xDevice
;
2225 Size
aSize(1024, 1024);
2226 xDevice
->SetOutputSizePixel(aSize
);
2228 for (auto & aFontName
: aFontNames
)
2230 vcl::Font
aFont(aFontName
, Size(0,96));
2232 aFont
.SetCOL_BLACK
);
2233 xDevice
->SetFont(aFont
);
2236 FontMetric aMetric
= xDevice
->GetFontMetric(aFont
);
2238 FontCharMapRef xMap
;
2239 if (xDevice
->GetFontCharMap(xMap
))
2241 ... iterate through glyphs
...
2245 bool GetGlyphBoundRects( const Point
& rOrigin
, const OUString
& rStr
, int nIndex
,
2246 int nLen
, int nBase
, MetricVector
& rVector
);
2248 include
/vcl
/outdev
.hxx
:typedef std::vector
< Rectangle
> MetricVector
;
2249 include
/vcl
/outdev
.hxx
: MetricVector
* pVector
= nullptr, OUString
* pDisplayText
= nullptr );
2250 include
/vcl
/outdev
.hxx
: MetricVector
* pVector
= nullptr, OUString
* pDisplayText
= nullptr,
2251 include
/vcl
/outdev
.hxx
: MetricVector
* pVector
, OUString
* pDisplayText
, vcl::ITextLayout
& _rLayout
);
2252 include
/vcl
/outdev
.hxx
: DrawTextFlags nStyle
= DrawTextFlags::Mnemonic
, MetricVector
* pVector
= nullp
2254 bool GetTextBoundRect( Rectangle
& rRect
,
2255 const OUString
& rStr
, sal_Int32 nBase
= 0, sal_Int32 nIndex
= 0, sal_Int32 nLen
= -1,
2256 sal_uLong nLayoutWidth
= 0, const long* pDXArray
= nullptr ) const;
2259 void DrawText( const Point
& rStartPt
, const OUString
& rStr
,
2260 sal_Int32 nIndex
= 0, sal_Int32 nLen
= -1,
2261 MetricVector
* pVector
= nullptr, OUString
* pDisplayText
= nullptr );
2263 void DrawText( const Rectangle
& rRect
,
2264 const OUString
& rStr
, DrawTextFlags nStyle
= DrawTextFlags::NONE
,
2265 MetricVector
* pVector
= nullptr, OUString
* pDisplayText
= nullptr,
2266 vcl::ITextLayout
* _pTextLayout
= nullptr );
2268 Rectangle
GetTextRect( const Rectangle
& rRect
,
2269 const OUString
& rStr
, DrawTextFlags nStyle
= DrawTextFlags::WordBreak
,
2270 TextRectInfo
* pInfo
= nullptr,
2271 const vcl::ITextLayout
* _pTextLayout
= nullptr ) const;
2279 class DemoApp
: public Application
2281 static int showHelp(DemoRenderer
&rRenderer
)
2283 fprintf(stderr
,"vcldemo - a VCL test app\n");
2284 fprintf(stderr
," --help - print this text\n");
2285 fprintf(stderr
," --show <renderer> - start with a given renderer, options are:\n");
2286 OUString
aRenderers(rRenderer
.getRendererList());
2287 fprintf(stderr
," %s\n",
2288 OUStringToOString(aRenderers
, RTL_TEXTENCODING_UTF8
).getStr());
2289 fprintf(stderr
," --test <iterCount> - create benchmark data\n");
2290 fprintf(stderr
," --widgets - launch the widget test.\n");
2291 fprintf(stderr
," --popup - launch the popup test.\n");
2292 fprintf(stderr
," --threads - render from multiple threads.\n");
2293 fprintf(stderr
," --gltest - run openGL regression tests.\n");
2294 fprintf(stderr
," --font <fontname> - run the font render test.\n");
2295 fprintf(stderr
, "\n");
2302 virtual int Main() override
2306 bool bWidgets
= false, bThreads
= false;
2307 bool bPopup
= false, bGLTest
= false;
2308 DemoRenderer aRenderer
;
2309 std::vector
<OUString
> aFontNames
;
2311 for (sal_uInt16 i
= 0; i
< GetCommandLineParamCount(); ++i
)
2313 bool bLast
= i
== GetCommandLineParamCount() - 1;
2314 OUString aArg
= GetCommandLineParam(i
);
2315 if (aArg
== "--help" || aArg
== "-h")
2316 return showHelp(aRenderer
);
2317 if (aArg
== "--show")
2320 return showHelp(aRenderer
);
2322 aRenderer
.selectRenderer(GetCommandLineParam(++i
));
2324 else if (aArg
== "--test")
2327 return showHelp(aRenderer
);
2329 aRenderer
.setIterCount(GetCommandLineParam(++i
).toInt32());
2331 else if (aArg
== "--widgets")
2333 else if (aArg
== "--popup")
2335 else if (aArg
== "--gltest")
2337 else if (aArg
== "--threads")
2339 else if (aArg
== "--font" && !bLast
)
2340 aFontNames
.push_back(GetCommandLineParam(++i
));
2341 else if (aArg
.startsWith("--"))
2343 fprintf(stderr
,"Unknown argument '%s'\n",
2344 OUStringToOString(aArg
, RTL_TEXTENCODING_UTF8
).getStr());
2345 return showHelp(aRenderer
);
2349 ScopedVclPtrInstance
<DemoWin
> aMainWin(aRenderer
, bThreads
);
2350 VclPtr
<DemoWidgets
> xWidgets
;
2351 VclPtr
<DemoPopup
> xPopup
;
2353 aMainWin
->SetText("Interactive VCL demo #1");
2354 #if HAVE_FEATURE_OPENGL
2358 return aTests
.execute();
2363 xWidgets
= VclPtr
< DemoWidgets
>::Create ();
2365 xPopup
= VclPtrInstance
< DemoPopup
> ();
2366 else if (!aFontNames
.empty())
2367 renderFonts(aFontNames
);
2371 Application::Execute();
2373 xWidgets
.disposeAndClear();
2374 xPopup
.disposeAndClear();
2376 catch (const css::uno::Exception
&)
2378 TOOLS_WARN_EXCEPTION("vcl.app", "Fatal");
2381 catch (const std::exception
& e
)
2383 SAL_WARN("vcl.app", "Fatal: " << e
.what());
2390 void Init() override
2394 uno::Reference
<uno::XComponentContext
> xComponentContext
2395 = ::cppu::defaultBootstrap_InitialComponentContext();
2396 uno::Reference
<lang::XMultiServiceFactory
> xMSF
;
2397 xMSF
.set(xComponentContext
->getServiceManager(), uno::UNO_QUERY
);
2399 Application::Abort("Bootstrap failure - no service manager");
2401 ::comphelper::setProcessServiceFactory(xMSF
);
2403 catch (const uno::Exception
&e
)
2405 Application::Abort("Bootstrap exception " + e
.Message
);
2408 void DeInit() override
2410 uno::Reference
< lang::XComponent
>(
2411 comphelper::getProcessComponentContext(),
2412 uno::UNO_QUERY_THROW
)-> dispose();
2413 ::comphelper::setProcessServiceFactory(nullptr);
2417 void vclmain::createApplication()
2420 _putenv_s("LIBO_VCL_DEMO", "1");
2422 setenv("LIBO_VCL_DEMO", "1", 0);
2424 static DemoApp aApp
;
2427 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */