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 <config_features.h>
13 #include <rtl/math.hxx>
14 #include <sal/log.hxx>
16 #include <comphelper/processfactory.hxx>
17 #include <comphelper/random.hxx>
18 #include <cppuhelper/bootstrap.hxx>
19 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
20 #include <com/sun/star/lang/XInitialization.hpp>
21 #include <com/sun/star/registry/XSimpleRegistry.hpp>
22 #include <com/sun/star/ucb/UniversalContentBroker.hpp>
23 #include <com/sun/star/uno/Reference.hxx>
24 #include <com/sun/star/uno/Sequence.hxx>
25 #include <com/sun/star/container/XNameAccess.hpp>
28 #include <vcl/gradient.hxx>
29 #include <vcl/vclmain.hxx>
30 #include <vcl/layout.hxx>
31 #include <vcl/ptrstyle.hxx>
32 #include <salhelper/thread.hxx>
34 #include <tools/diagnose_ex.h>
35 #include <tools/urlobj.hxx>
36 #include <tools/stream.hxx>
37 #include <vcl/svapp.hxx>
38 #include <vcl/pngread.hxx>
39 #include <vcl/wrkwin.hxx>
40 #include <vcl/virdev.hxx>
41 #include <vcl/graphicfilter.hxx>
42 #include <vcl/button.hxx>
43 #include <vcl/combobox.hxx>
44 #include <vcl/toolbox.hxx>
45 #include <vcl/pngwrite.hxx>
46 #include <vcl/floatwin.hxx>
47 #include <vcl/bitmapaccess.hxx>
48 #include <vcl/help.hxx>
49 #include <vcl/menu.hxx>
50 #include <vcl/ImageTree.hxx>
51 #include <vcl/BitmapEmbossGreyFilter.hxx>
52 #include <bitmapwriteaccess.hxx>
54 #include <basegfx/numeric/ftools.hxx>
55 #include <basegfx/matrix/b2dhommatrix.hxx>
56 #include <opengl/zone.hxx>
58 // internal headers for OpenGLTests class.
59 #if HAVE_FEATURE_OPENGL
61 #include <salframe.hxx>
62 #include <openglgdiimpl.hxx>
63 #include <opengl/texture.hxx>
64 #include <opengl/framebuffer.hxx>
65 #include <vcl/opengl/OpenGLHelper.hxx>
68 #define FIXME_SELF_INTERSECTING_WORKING 0
69 #define FIXME_BOUNCE_BUTTON 0
70 #define THUMB_REPEAT_FACTOR 10
72 using namespace com::sun::star
;
78 osl_getSystemTime(&aValue
);
79 return static_cast<double>(aValue
.Seconds
) * 1000 +
80 static_cast<double>(aValue
.Nanosec
) / (1000*1000);
86 RENDER_THUMB
, // small view <n> to a page
87 RENDER_EXPANDED
, // expanded view of this renderer
98 struct RenderContext
{
101 DemoRenderer
*mpDemoRenderer
;
104 struct RegionRenderer
{
110 virtual ~RegionRenderer() {}
111 virtual OUString
getName() = 0;
112 virtual sal_uInt16
getAccelerator() = 0;
113 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
114 const RenderContext
&rCtx
) = 0;
115 // repeating count for profiling (to exceed the poor time resolution on Windows)
116 virtual sal_uInt16
getTestRepeatCount() = 0;
117 #define RENDER_DETAILS(name,key,repeat) \
118 virtual OUString getName() override \
119 { return SAL_STRINGIFY(name); } \
120 virtual sal_uInt16 getAccelerator() override \
122 virtual sal_uInt16 getTestRepeatCount() override \
129 std::vector
< RegionRenderer
* > maRenderers
;
130 sal_Int32 mnSelectedRenderer
;
133 void InitRenderers();
136 DemoRenderer() : mnSegmentsX(0)
138 , mnSelectedRenderer(-1)
140 #if FIXME_BOUNCE_BUTTON
147 if (!Application::LoadBrandBitmap("intro", maIntro
))
148 Application::Abort("Failed to load intro image");
150 maIntroBW
= maIntro
.GetBitmap();
152 BitmapEx
aTmpBmpEx(maIntroBW
);
153 BitmapFilter::Filter(aTmpBmpEx
, BitmapEmbossGreyFilter(0, 0));
154 maIntroBW
= aTmpBmpEx
.GetBitmap();
157 mnSegmentsY
= rtl::math::round(std::sqrt(maRenderers
.size()), 0,
158 rtl_math_RoundingMode_Down
);
159 mnSegmentsX
= (maRenderers
.size() + mnSegmentsY
- 1)/mnSegmentsY
;
162 OUString
getRendererList();
163 double getAndResetBenchmark(RenderStyle style
);
164 void selectRenderer(const OUString
&rName
);
165 int selectNextRenderer();
166 void setIterCount(sal_Int32 iterCount
);
167 sal_Int32
getIterCount() const;
168 void addTime(int i
, double t
);
171 void SetSizePixel(const Size
&rSize
) { maSize
= rSize
; }
172 const Size
& GetSizePixel() const { return maSize
; }
175 // more of a 'Window' concept - push upwards ?
176 #if FIXME_BOUNCE_BUTTON
177 // Bouncing windows on click ...
178 PushButton
*mpButton
;
179 FloatingWindow
*mpButtonWin
;
181 int mnBounceX
, mnBounceY
;
182 DECL_LINK(BounceTimerCb
, Timer
*, void);
185 bool MouseButtonDown(const MouseEvent
& rMEvt
);
186 void KeyInput(const KeyEvent
& rKEvt
);
188 static std::vector
<tools::Rectangle
> partition(const tools::Rectangle
&rRect
, int nX
, int nY
)
190 std::vector
<tools::Rectangle
> aRegions
= partition(rRect
.GetSize(), nX
, nY
);
191 for (auto & region
: aRegions
)
192 region
.Move(rRect
.Left(), rRect
.Top());
197 static std::vector
<tools::Rectangle
> partition(const RenderContext
&rCtx
, int nX
, int nY
)
199 return partition(rCtx
.maSize
, nX
, nY
);
202 static std::vector
<tools::Rectangle
> partition(Size aSize
, int nX
, int nY
)
205 std::vector
<tools::Rectangle
> aRegions
;
207 // Make small cleared area for these guys
208 long nBorderSize
= std::min(aSize
.Height() / 32, aSize
.Width() / 32);
209 long nBoxWidth
= (aSize
.Width() - nBorderSize
*(nX
+1)) / nX
;
210 long nBoxHeight
= (aSize
.Height() - nBorderSize
*(nY
+1)) / nY
;
211 for (int y
= 0; y
< nY
; y
++)
213 for (int x
= 0; x
< nX
; x
++)
215 r
.SetPos(Point(nBorderSize
+ (nBorderSize
+ nBoxWidth
) * x
,
216 nBorderSize
+ (nBorderSize
+ nBoxHeight
) * y
));
217 r
.SetSize(Size(nBoxWidth
, nBoxHeight
));
218 aRegions
.push_back(r
);
225 static void clearRects(OutputDevice
&rDev
, std::vector
<tools::Rectangle
> &rRects
)
227 for (size_t i
= 0; i
< rRects
.size(); i
++)
229 // knock up a nice little border
230 rDev
.SetLineColor(COL_GRAY
);
231 rDev
.SetFillColor(COL_LIGHTGRAY
);
234 int nBorderSize
= rRects
[i
].GetWidth() / 5;
235 rDev
.DrawRect(rRects
[i
], nBorderSize
, nBorderSize
);
238 rDev
.DrawRect(rRects
[i
]);
242 static void drawBackground(OutputDevice
&rDev
, const tools::Rectangle
& r
)
246 aGradient
.SetStartColor(COL_BLUE
);
247 aGradient
.SetEndColor(COL_GREEN
);
248 aGradient
.SetStyle(GradientStyle::Linear
);
249 rDev
.DrawGradient(r
, aGradient
);
252 struct DrawLines
: public RegionRenderer
254 RENDER_DETAILS(lines
,KEY_L
,100)
255 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
256 const RenderContext
&rCtx
) override
258 if (rCtx
.meStyle
== RENDER_EXPANDED
)
260 AntialiasingFlags nOldAA
= rDev
.GetAntialiasing();
261 rDev
.SetAntialiasing(AntialiasingFlags::EnableB2dDraw
);
263 std::vector
<tools::Rectangle
> aRegions(DemoRenderer::partition(rCtx
, 4, 4));
264 DemoRenderer::clearRects(rDev
, aRegions
);
266 #if 0 // FIXME: get this through to the backend ...
267 double nTransparency
[] = {
274 drawing::LineCap
const eLineCaps
[] = {
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
,
277 drawing::LineCap_BUTT
, drawing::LineCap_ROUND
, drawing::LineCap_SQUARE
, drawing::LineCap_BUTT
,
278 drawing::LineCap_BUTT
, drawing::LineCap_ROUND
, drawing::LineCap_SQUARE
, drawing::LineCap_BUTT
280 basegfx::B2DLineJoin
const eJoins
[] = {
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
,
283 basegfx::B2DLineJoin::NONE
, basegfx::B2DLineJoin::Bevel
, basegfx::B2DLineJoin::Miter
, basegfx::B2DLineJoin::Round
,
284 basegfx::B2DLineJoin::NONE
, basegfx::B2DLineJoin::Bevel
, basegfx::B2DLineJoin::Miter
, basegfx::B2DLineJoin::Round
286 double const aLineWidths
[] = {
287 10.0, 15.0, 20.0, 10.0,
288 10.0, 15.0, 20.0, 10.0,
289 10.0, 15.0, 20.0, 10.0,
292 for (size_t i
= 0; i
< aRegions
.size(); i
++)
294 // Half of them not-anti-aliased ..
295 if (i
>= aRegions
.size()/2)
296 rDev
.SetAntialiasing(nOldAA
);
298 static const struct {
301 { 0.2, 0.2 }, { 0.8, 0.3 }, { 0.7, 0.8 }
303 rDev
.SetLineColor(COL_BLACK
);
304 basegfx::B2DPolygon aPoly
;
305 tools::Rectangle
aSub(aRegions
[i
]);
306 for (size_t j
= 0; j
< SAL_N_ELEMENTS(aPoints
); j
++)
308 aPoly
.append(basegfx::B2DPoint(aSub
.Left() + aSub
.GetWidth() * aPoints
[j
].nX
,
309 aSub
.Top() + aSub
.GetHeight() * aPoints
[j
].nY
));
311 rDev
.DrawPolyLine(aPoly
, aLineWidths
[i
], eJoins
[i
], eLineCaps
[i
]);
316 rDev
.SetFillColor(COL_LIGHTRED
);
317 rDev
.SetLineColor(COL_BLACK
);
320 for(long i
=0; i
<r
.GetHeight(); i
+=15)
321 rDev
.DrawLine(Point(r
.Left(), r
.Top()+i
), Point(r
.Right(), r
.Bottom()-i
));
322 for(long i
=0; i
<r
.GetWidth(); i
+=15)
323 rDev
.DrawLine(Point(r
.Left()+i
, r
.Bottom()), Point(r
.Right()-i
, r
.Top()));
325 // Should draw a white-line across the middle
326 Color
aLastPixel(COL_WHITE
);
327 Point
aCenter((r
.Left() + r
.Right())/2 - 4,
328 (r
.Top() + r
.Bottom())/2 - 4);
329 for(int i
=0; i
<8; i
++)
331 rDev
.DrawPixel(aCenter
, aLastPixel
);
332 aLastPixel
= rDev
.GetPixel(aCenter
);
339 struct DrawText
: public RegionRenderer
341 RENDER_DETAILS(text
,KEY_T
,1)
343 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
344 const RenderContext
&rCtx
) override
346 if (rCtx
.meStyle
== RENDER_EXPANDED
)
348 std::vector
<tools::Rectangle
> aToplevelRegions(
349 DemoRenderer::partition(rCtx
, 1, 3));
350 std::vector
<tools::Rectangle
> aSubRegions(
351 DemoRenderer::partition(aToplevelRegions
[0], 4, 2));
352 tools::Rectangle
aBottom(aToplevelRegions
[1].TopLeft(),
353 aToplevelRegions
[2].BottomRight());
354 DemoRenderer::clearRects(rDev
,aSubRegions
);
357 bool const mbArabicText
;
359 } const aRenderData
[] = {
360 { false, false, false },
361 { false, true, false },
362 { false, true, true },
363 { false, false, true },
364 { true, false, true },
365 { true, true, true },
366 { true, true, false },
367 { true, false, false },
371 for (int y
= 0; y
< 2; y
++)
373 for (int x
= 0; x
< 4; x
++)
375 assert(i
< SAL_N_ELEMENTS(aRenderData
));
376 drawText(rDev
, aSubRegions
[i
], aRenderData
[i
].mbClip
,
377 aRenderData
[i
].mbArabicText
, aRenderData
[i
].mbRotate
);
382 drawComplex(rDev
, aBottom
);
386 drawText(rDev
, r
, false, false, false);
390 static void drawText (OutputDevice
&rDev
, tools::Rectangle r
, bool bClip
, bool bArabicText
, bool bRotate
)
392 rDev
.SetClipRegion( vcl::Region(r
) );
394 OUString
const aLatinText("Click any rect to zoom!!!!");
396 const unsigned char pTextUTF8
[] = {
397 0xd9, 0x88, 0xd8, 0xa7, 0xd8, 0xad, 0xd9, 0x90,
398 0xd8, 0xaf, 0xd9, 0x92, 0x20, 0xd8, 0xa5, 0xd8,
399 0xab, 0xd9, 0x8d, 0xd9, 0x86, 0xd9, 0x8a, 0xd9,
400 0x86, 0x20, 0xd8, 0xab, 0xd9, 0x84, 0xd8, 0xa7,
401 0xd8, 0xab, 0xd8, 0xa9, 0xd9, 0x8c, 0x00
403 OUString
aArabicText( reinterpret_cast<char const *>(pTextUTF8
),
404 SAL_N_ELEMENTS( pTextUTF8
) - 1,
405 RTL_TEXTENCODING_UTF8
);
409 // To have more text displayed one after the other (overlapping, and in different colours), then
411 const int nPrintNumCopies
=1;
418 std::vector
<OUString
> aFontNames
;
420 static Color
const nCols
[] = {
421 COL_BLACK
, COL_BLUE
, COL_GREEN
, COL_CYAN
, COL_RED
, COL_MAGENTA
,
422 COL_BROWN
, COL_GRAY
, COL_LIGHTGRAY
, COL_LIGHTBLUE
, COL_LIGHTGREEN
,
423 COL_LIGHTCYAN
, COL_LIGHTRED
, COL_LIGHTMAGENTA
, COL_YELLOW
, COL_WHITE
426 // a few fonts to start with
427 const char *pNames
[] = {
428 "Times", "Liberation Sans", "Arial", "Linux Biolinum G", "Linux Libertine Display G"
431 for (size_t i
= 0; i
< SAL_N_ELEMENTS(pNames
); i
++)
432 aFontNames
.push_back(OUString::createFromAscii(pNames
[i
]));
434 if (bClip
&& !bRotate
)
436 // only show the first quarter of the text
437 tools::Rectangle
aRect( r
.TopLeft(), Size( r
.GetWidth()/2, r
.GetHeight()/2 ) );
438 rDev
.SetClipRegion( vcl::Region( aRect
) );
441 for (int i
= 1; i
< nPrintNumCopies
+1; i
++)
443 int nFontHeight
=0, nFontIndex
=0, nFontColorIndex
=0;
445 if (nPrintNumCopies
== 1)
447 float const nFontMagnitude
= 0.25f
;
448 // random font size to avoid buffering
449 nFontHeight
= 1 + nFontMagnitude
* (0.9 + comphelper::rng::uniform_real_distribution(0.0, std::nextafter(0.1, DBL_MAX
))) * (r
.Bottom() - r
.Top());
455 // random font size to avoid buffering
456 nFontHeight
= 1 + i
* (0.9 + comphelper::rng::uniform_real_distribution(0.0, std::nextafter(0.1, DBL_MAX
))) * (r
.Top() - r
.Bottom()) / nPrintNumCopies
;
457 nFontIndex
= (i
% aFontNames
.size());
458 nFontColorIndex
=(i
% aFontNames
.size());
461 rDev
.SetTextColor(nCols
[nFontColorIndex
]);
462 vcl::Font
aFont( aFontNames
[nFontIndex
], Size(0, nFontHeight
));
466 tools::Rectangle aFontRect
= r
;
468 int nHeight
= r
.GetHeight();
470 // move the text to the bottom of the bounding rect before rotating
471 aFontRect
.AdjustTop(nHeight
/2 );
472 aFontRect
.AdjustBottom(nHeight
);
474 aFont
.SetOrientation(45 * 10); // 45 degrees
477 rDev
.DrawText(aFontRect
, aText
);
481 tools::Rectangle
aClipRect( Point( r
.Left(), r
.Top() + ( r
.GetHeight()/2 ) ) , Size( r
.GetWidth()/2, r
.GetHeight()/2 ) );
482 rDev
.SetClipRegion( vcl::Region( aClipRect
) );
485 rDev
.SetClipRegion( vcl::Region(r
) );
490 rDev
.DrawText(r
, aText
);
494 rDev
.SetClipRegion();
497 static void drawComplex (OutputDevice
&rDev
, tools::Rectangle r
)
499 const unsigned char pInvalid
[] = { 0xfe, 0x1f, 0 };
500 const unsigned char pDiacritic1
[] = { 0x61, 0xcc, 0x8a, 0xcc, 0x8c, 0 };
501 const unsigned char pDiacritic2
[] = { 0x61, 0xcc, 0x88, 0xcc, 0x86, 0 };
502 const unsigned char pDiacritic3
[] = { 0x61, 0xcc, 0x8b, 0xcc, 0x87, 0 };
503 const unsigned char pJustification
[] = {
504 0x64, 0x20, 0xc3, 0xa1, 0xc3, 0xa9, 0x77, 0xc4, 0x8d,
505 0xc5, 0xa1, 0xc3, 0xbd, 0xc5, 0x99, 0x20, 0xc4, 0x9b, 0
507 const unsigned char pEmojis
[] = {
508 0xf0, 0x9f, 0x8d, 0x80, 0xf0, 0x9f, 0x91, 0x98,
509 0xf0, 0x9f, 0x92, 0x8a, 0xf0, 0x9f, 0x92, 0x99,
510 0xf0, 0x9f, 0x92, 0xa4, 0xf0, 0x9f, 0x94, 0x90, 0
512 const unsigned char pThreeBowlG
[] = {
513 0xe2, 0x9a, 0x82, 0xe2, 0x99, 0xa8, 0xc4, 0x9e, 0
515 const unsigned char pWavesAndDomino
[] = {
516 0xe2, 0x99, 0x92, 0xf0, 0x9f, 0x81, 0xa0,
517 0xf0, 0x9f, 0x82, 0x93, 0
519 const unsigned char pSpadesAndBits
[] = {
520 0xf0, 0x9f, 0x82, 0xa1, 0xc2, 0xa2, 0xc2, 0xa2, 0
525 const char *mpString
;
527 #define SET(font,string) { font, reinterpret_cast<const char *>(string) }
528 {"sans", "a"}, // logical font - no 'sans' font.
529 {"opensymbol", "#$%"}, // font fallback - $ is missing.
530 SET("sans", pInvalid
), // unicode invalid character
531 // tdf#96266 - stacking diacritics
532 SET("carlito", pDiacritic1
),
533 SET("carlito", pDiacritic2
),
534 SET("carlito", pDiacritic3
),
535 SET("liberation sans", pDiacritic1
),
536 SET("liberation sans", pDiacritic2
),
537 SET("liberation sans", pDiacritic3
),
538 SET("liberation sans", pDiacritic3
),
540 // tdf#95222 - justification issue
541 // - FIXME: replicate justification
542 SET("gentium basic", pJustification
),
544 // tdf#97319 - Unicode beyond BMP; SMP & Plane 2
545 SET("symbola", pEmojis
),
546 SET("symbola", pThreeBowlG
),
547 SET("symbola", pWavesAndDomino
),
548 SET("symbola", pSpadesAndBits
),
551 // Nice clean white background
552 rDev
.DrawWallpaper(r
, Wallpaper(COL_WHITE
));
553 rDev
.SetClipRegion(vcl::Region(r
));
555 Point
aPos(r
.Left(), r
.Top()+20);
557 long nMaxTextHeight
= 0;
558 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aRuns
); ++i
)
561 vcl::Font
aIndexFont("sans", Size(0,20));
562 aIndexFont
.SetColor( COL_BLACK
);
563 tools::Rectangle aTextRect
;
564 rDev
.SetFont(aIndexFont
);
565 OUString aText
= OUString::number(i
) + ".";
566 rDev
.DrawText(aPos
, aText
);
567 if (rDev
.GetTextBoundRect(aTextRect
, aText
))
568 aPos
.Move(aTextRect
.GetWidth() + 8, 0);
571 FontWeight aWeights
[] = { WEIGHT_NORMAL
,
574 FontItalic
const aItalics
[] = { ITALIC_NONE
,
577 vcl::Font
aFont(OUString::createFromAscii(
580 aFont
.SetColor(COL_BLACK
);
581 for (size_t j
= 0; j
< SAL_N_ELEMENTS(aWeights
); ++j
)
583 aFont
.SetItalic(aItalics
[j
]);
584 aFont
.SetWeight(aWeights
[j
]);
587 OUString
aString(aRuns
[i
].mpString
,
588 strlen(aRuns
[i
].mpString
),
589 RTL_TEXTENCODING_UTF8
);
590 long nNewX
= drawStringBox(rDev
, aPos
, aString
,
595 if (aPos
.X() >= r
.Right())
597 aPos
= Point(r
.Left(), aPos
.Y() + nMaxTextHeight
+ 15);
600 j
--; // re-render the last point.
602 if (aPos
.Y() > r
.Bottom())
605 if (aPos
.Y() > r
.Bottom())
609 rDev
.SetClipRegion();
611 // render text, bbox, DX arrays etc.
612 static long drawStringBox(OutputDevice
&rDev
, Point aPos
,
613 const OUString
&aText
,
614 long &nMaxTextHeight
)
618 tools::Rectangle aTextRect
;
620 rDev
.DrawText(aPos
,aText
);
622 if (rDev
.GetTextBoundRect(aTextRect
, aText
))
624 aTextRect
.Move(aPos
.X(), aPos
.Y());
626 rDev
.SetLineColor(COL_BLACK
);
627 rDev
.DrawRect(aTextRect
);
628 if (aTextRect
.GetHeight() > nMaxTextHeight
)
629 nMaxTextHeight
= aTextRect
.GetHeight();
630 // This should intersect with the text
631 tools::Rectangle
aInnerRect(
632 aTextRect
.Left()+1, aTextRect
.Top()+1,
633 aTextRect
.Right()-1, aTextRect
.Bottom()-1);
634 rDev
.SetLineColor(COL_WHITE
);
635 rDev
.SetRasterOp(RasterOp::Xor
);
636 rDev
.DrawRect(aInnerRect
);
637 rDev
.SetRasterOp(RasterOp::OverPaint
);
640 // DX array rendering
641 std::unique_ptr
<long[]> pItems(new long[aText
.getLength()+10]);
642 rDev
.GetTextArray(aText
, pItems
.get());
643 for (long j
= 0; j
< aText
.getLength(); ++j
)
645 Point aTop
= aTextRect
.TopLeft();
646 Point aBottom
= aTop
;
647 aTop
.Move(pItems
[j
], 0);
648 aBottom
.Move(pItems
[j
], aTextRect
.GetHeight());
649 rDev
.SetLineColor(COL_RED
);
650 rDev
.SetRasterOp(RasterOp::Xor
);
651 rDev
.DrawLine(aTop
,aBottom
);
652 rDev
.SetRasterOp(RasterOp::OverPaint
);
655 aPos
.Move(aTextRect
.GetWidth() + 16, 0);
662 struct DrawCheckered
: public RegionRenderer
664 RENDER_DETAILS(checks
,KEY_C
,20)
665 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
666 const RenderContext
&rCtx
) override
668 if (rCtx
.meStyle
== RENDER_EXPANDED
)
670 std::vector
<tools::Rectangle
> aRegions(DemoRenderer::partition(rCtx
, 2, 2));
671 for (size_t i
= 0; i
< aRegions
.size(); i
++)
674 tools::Rectangle
aSub(aRegions
[i
]);
675 tools::Rectangle
aSmaller(aSub
);
676 aSmaller
.Move(10,10);
677 aSmaller
.setWidth(aSmaller
.getWidth()-20);
678 aSmaller
.setHeight(aSmaller
.getHeight()-24);
681 aRegion
= vcl::Region(aSub
);
684 aRegion
= vcl::Region(aSmaller
);
689 tools::Polygon
aPoly(aSub
);
690 aPoly
.Rotate(aSub
.Center(), 450);
691 aPoly
.Clip(aSmaller
);
692 aRegion
= vcl::Region(aPoly
);
697 tools::PolyPolygon aPolyPoly
;
698 sal_Int32 nTW
= aSub
.GetWidth()/6;
699 sal_Int32 nTH
= aSub
.GetHeight()/6;
700 tools::Rectangle
aTiny(Point(4, 4), Size(nTW
*2, nTH
*2));
701 aPolyPoly
.Insert( tools::Polygon(aTiny
));
702 aTiny
.Move(nTW
*3, nTH
*3);
703 aPolyPoly
.Insert( tools::Polygon(aTiny
));
704 aTiny
.Move(nTW
, nTH
);
705 aPolyPoly
.Insert( tools::Polygon(aTiny
));
707 aRegion
= vcl::Region(aPolyPoly
);
711 rDev
.SetClipRegion(aRegion
);
712 rDev
.DrawCheckered(aSub
.TopLeft(), aSub
.GetSize());
713 rDev
.SetClipRegion();
718 rDev
.DrawCheckered(r
.TopLeft(), r
.GetSize());
723 struct DrawPoly
: public RegionRenderer
725 RENDER_DETAILS(poly
,KEY_P
,20)
726 DrawCheckered maCheckered
;
727 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
728 const RenderContext
&rCtx
) override
730 maCheckered
.RenderRegion(rDev
, r
, rCtx
);
732 long nDx
= r
.GetWidth()/20;
733 long nDy
= r
.GetHeight()/20;
734 tools::Rectangle
aShrunk(r
);
735 aShrunk
.Move(nDx
, nDy
);
736 aShrunk
.SetSize(Size(r
.GetWidth()-nDx
*2,
737 r
.GetHeight()-nDy
*2));
738 tools::Polygon
aPoly(aShrunk
);
739 tools::PolyPolygon
aPPoly(aPoly
);
740 rDev
.SetLineColor(COL_RED
);
741 rDev
.SetFillColor(COL_RED
);
742 // This hits the optional 'drawPolyPolygon' code-path
743 rDev
.DrawTransparent(aPPoly
, 64);
747 struct DrawEllipse
: public RegionRenderer
749 RENDER_DETAILS(ellipse
,KEY_E
,500)
750 static void doInvert(OutputDevice
&rDev
, const tools::Rectangle
&r
,
753 rDev
.Invert(r
, nFlags
);
754 if (r
.GetWidth() > 10 && r
.GetHeight() > 10)
756 tools::Rectangle
aSmall(r
.Center()-Point(4,4), Size(8,8));
757 rDev
.Invert(aSmall
,nFlags
);
760 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
761 const RenderContext
&rCtx
) override
763 rDev
.SetLineColor(COL_RED
);
764 rDev
.SetFillColor(COL_GREEN
);
767 if (rCtx
.meStyle
== RENDER_EXPANDED
)
769 auto aRegions
= partition(rCtx
, 2, 2);
770 doInvert(rDev
, aRegions
[0], InvertFlags::NONE
);
771 rDev
.DrawText(aRegions
[0], "InvertFlags::NONE");
772 doInvert(rDev
, aRegions
[1], InvertFlags::N50
);
773 rDev
.DrawText(aRegions
[1], "InvertFlags::N50");
774 doInvert(rDev
, aRegions
[3], InvertFlags::TrackFrame
);
775 rDev
.DrawText(aRegions
[3], "InvertFlags::TrackFrame");
780 struct DrawGradient
: public RegionRenderer
782 RENDER_DETAILS(gradient
,KEY_G
,50)
783 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
784 const RenderContext
&rCtx
) override
786 if (rCtx
.meStyle
== RENDER_EXPANDED
)
788 std::vector
<tools::Rectangle
> aRegions(DemoRenderer::partition(rCtx
,5, 4));
789 static Color
const nStartCols
[] = {
790 COL_RED
, COL_RED
, COL_RED
, COL_GREEN
, COL_GREEN
,
791 COL_BLUE
, COL_BLUE
, COL_BLUE
, COL_CYAN
, COL_CYAN
,
792 COL_BLACK
, COL_LIGHTGRAY
, COL_WHITE
, COL_BLUE
, COL_CYAN
,
793 COL_WHITE
, COL_WHITE
, COL_WHITE
, COL_BLACK
, COL_BLACK
795 static Color
const nEndCols
[] = {
796 COL_WHITE
, COL_WHITE
, COL_WHITE
, COL_BLACK
, COL_BLACK
,
797 COL_RED
, COL_RED
, COL_RED
, COL_GREEN
, COL_GREEN
,
798 COL_GRAY
, COL_GRAY
, COL_LIGHTGRAY
, COL_LIGHTBLUE
, COL_LIGHTCYAN
,
799 COL_BLUE
, COL_BLUE
, COL_BLUE
, COL_CYAN
, COL_CYAN
801 GradientStyle eStyles
[] = {
802 GradientStyle::Linear
, GradientStyle::Axial
, GradientStyle::Radial
, GradientStyle::Elliptical
, GradientStyle::Square
,
803 GradientStyle::Rect
, GradientStyle::FORCE_EQUAL_SIZE
, GradientStyle::Linear
, GradientStyle::Radial
, GradientStyle::Linear
,
804 GradientStyle::Linear
, GradientStyle::Axial
, GradientStyle::Radial
, GradientStyle::Elliptical
, GradientStyle::Square
,
805 GradientStyle::Rect
, GradientStyle::FORCE_EQUAL_SIZE
, GradientStyle::Linear
, GradientStyle::Radial
, GradientStyle::Linear
807 sal_uInt16 nAngles
[] = {
810 90, 120, 135, 160, 180,
813 sal_uInt16 nBorders
[] = {
820 DemoRenderer::clearRects(rDev
, aRegions
);
821 assert(aRegions
.size() <= SAL_N_ELEMENTS(nStartCols
));
822 assert(aRegions
.size() <= SAL_N_ELEMENTS(nEndCols
));
823 assert(aRegions
.size() <= SAL_N_ELEMENTS(eStyles
));
824 assert(aRegions
.size() <= SAL_N_ELEMENTS(nAngles
));
825 assert(aRegions
.size() <= SAL_N_ELEMENTS(nBorders
));
826 for (size_t i
= 0; i
< aRegions
.size(); i
++)
828 tools::Rectangle aSub
= aRegions
[i
];
830 aGradient
.SetStartColor(nStartCols
[i
]);
831 aGradient
.SetEndColor(nEndCols
[i
]);
832 aGradient
.SetStyle(eStyles
[i
]);
833 aGradient
.SetAngle(nAngles
[i
]);
834 aGradient
.SetBorder(nBorders
[i
]);
835 rDev
.DrawGradient(aSub
, aGradient
);
841 aGradient
.SetStartColor(COL_YELLOW
);
842 aGradient
.SetEndColor(COL_RED
);
843 aGradient
.SetStyle(GradientStyle::Rect
);
844 aGradient
.SetBorder(r
.GetSize().Width()/20);
845 rDev
.DrawGradient(r
, aGradient
);
850 struct DrawBitmap
: public RegionRenderer
852 RENDER_DETAILS(bitmap
,KEY_B
,10)
854 // Simulate Page Borders rendering - which ultimately should
855 // be done with a shader / gradient
856 static void SimulateBorderStretch(OutputDevice
&rDev
, const tools::Rectangle
& r
)
858 BitmapEx
aPageShadowMask("sw/res/page-shadow-mask.png");
860 BitmapEx
aRight(aPageShadowMask
);
861 sal_Int32 nSlice
= (aPageShadowMask
.GetSizePixel().Width() - 3) / 4;
863 aRight
.Crop(tools::Rectangle(Point((nSlice
* 3) + 3, (nSlice
* 2) + 1),
865 AlphaMask
aAlphaMask(aRight
.GetBitmap());
866 Bitmap
aBlockColor(aAlphaMask
.GetSizePixel(), 24);
867 aBlockColor
.Erase(COL_RED
);
868 BitmapEx
aShadowStretch(aBlockColor
, aAlphaMask
);
870 Point
aRenderPt(r
.TopLeft());
872 long aSizes
[] = { 200, 100, 200, 100, 50, 5, 2 };
874 // and yes - we really do this in the page border rendering code ...
875 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aSizes
); i
++)
877 aShadowStretch
.Scale(Size(aShadowStretch
.GetSizePixel().Width(), aSizes
[i
]),
880 rDev
.DrawBitmapEx(aRenderPt
, aShadowStretch
);
881 aRenderPt
.Move(aShadowStretch
.GetSizePixel().Width() + 4, 0);
884 AlphaMask
aWholeMask(aPageShadowMask
.GetBitmap());
885 aBlockColor
= Bitmap(aPageShadowMask
.GetSizePixel(), 24);
886 aBlockColor
.Erase(COL_GREEN
);
887 BitmapEx
aWhole(aBlockColor
, aWholeMask
);
889 aRenderPt
= r
.Center();
890 aRenderPt
.Move(nSlice
+1, 0);
892 // An offset background for alpha rendering
893 rDev
.SetFillColor(COL_BLUE
);
894 tools::Rectangle
aSurround(r
.Center(), aPageShadowMask
.GetSizePixel());
895 rDev
.DrawRect(aSurround
);
896 rDev
.DrawBitmapEx(aRenderPt
, aWhole
);
899 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
900 const RenderContext
&rCtx
) override
902 Bitmap
aBitmap(rCtx
.mpDemoRenderer
->maIntroBW
);
903 aBitmap
.Scale(r
.GetSize(), BmpScaleFlag::BestQuality
);
904 rDev
.DrawBitmap(r
.TopLeft(), aBitmap
);
906 SimulateBorderStretch(rDev
, r
);
910 struct DrawBitmapEx
: public RegionRenderer
912 RENDER_DETAILS(bitmapex
,KEY_X
,2)
913 DrawCheckered maCheckered
;
914 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
915 const RenderContext
&rCtx
) override
917 maCheckered
.RenderRegion(rDev
, r
, rCtx
);
919 BitmapEx
aBitmap(rCtx
.mpDemoRenderer
->maIntro
);
920 aBitmap
.Scale(r
.GetSize(), BmpScaleFlag::BestQuality
);
921 AlphaMask
aSemiTransp(aBitmap
.GetSizePixel());
922 aSemiTransp
.Erase(64);
923 rDev
.DrawBitmapEx(r
.TopLeft(), BitmapEx(aBitmap
.GetBitmap(),
928 struct DrawPolyPolygons
: public RegionRenderer
930 RENDER_DETAILS(polypoly
,KEY_N
,100)
931 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
932 const RenderContext
&) override
936 } const aPoints
[] = { { 0.1, 0.1 }, { 0.9, 0.9 },
937 #if FIXME_SELF_INTERSECTING_WORKING
938 { 0.9, 0.1 }, { 0.1, 0.9 },
941 { 0.1, 0.9 }, { 0.5, 0.5 },
942 { 0.9, 0.1 }, { 0.1, 0.1 }
946 tools::PolyPolygon aPolyPoly
;
947 // Render 4x polygons & aggregate into another PolyPolygon
948 for (int x
= 0; x
< 2; x
++)
950 for (int y
= 0; y
< 2; y
++)
952 tools::Rectangle
aSubRect(r
);
953 aSubRect
.Move(x
* r
.GetWidth()/3, y
* r
.GetHeight()/3);
954 aSubRect
.SetSize(Size(r
.GetWidth()/2, r
.GetHeight()/4));
955 tools::Polygon
aPoly(SAL_N_ELEMENTS(aPoints
));
956 for (size_t v
= 0; v
< SAL_N_ELEMENTS(aPoints
); v
++)
958 aPoly
.SetPoint(Point(aSubRect
.Left() +
959 aSubRect
.GetWidth() * aPoints
[v
].nX
,
961 aSubRect
.GetHeight() * aPoints
[v
].nY
),
964 rDev
.SetLineColor(COL_YELLOW
);
965 rDev
.SetFillColor(COL_BLACK
);
966 rDev
.DrawPolygon(aPoly
);
968 // now move and add to the polypolygon
969 aPoly
.Move(0, r
.GetHeight()/2);
970 aPolyPoly
.Insert(aPoly
);
973 rDev
.SetLineColor(COL_LIGHTRED
);
974 rDev
.SetFillColor(COL_GREEN
);
975 rDev
.DrawTransparent(aPolyPoly
, 50);
979 struct DrawClipped
: public RegionRenderer
981 RENDER_DETAILS(clip
,KEY_D
,10)
982 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
983 const RenderContext
&) override
985 std::vector
<tools::Rectangle
> aRegions(DemoRenderer::partition(r
, 2, 2));
986 const int nLimits
[] = { 4, -100 };
987 for (int i
= 0; i
< 2; ++i
)
990 rDev
.Push(PushFlags::CLIPREGION
);
991 tools::Rectangle aOuter
= aRegions
[i
];
992 tools::Rectangle aInner
= aOuter
;
993 while (aInner
.GetWidth() > nLimits
[i
] && aInner
.GetHeight() > nLimits
[i
])
996 rDev
.SetClipRegion(vcl::Region(aInner
));
997 rDev
.SetFillColor(Color::HSBtoRGB(nHue
, 75, 100));
998 nHue
= (nHue
+ 97) % 360;
999 rDev
.DrawRect(aOuter
);
1005 sal_uInt16 nHue
= 0;
1006 tools::Rectangle aOuter
= aRegions
[2];
1007 std::vector
<tools::Rectangle
> aPieces(DemoRenderer::partition(aOuter
, 2, 2));
1008 for (int j
= 0; j
< std::min(aOuter
.GetWidth(), aOuter
.GetHeight())/5; ++j
)
1010 rDev
.Push(PushFlags::CLIPREGION
);
1012 vcl::Region aClipRegion
;
1013 for (int i
= 0; i
< 4; ++i
)
1015 aPieces
[i
].expand(-1);
1016 aPieces
[i
].Move(2 - i
/2, 2 - i
/2);
1017 aClipRegion
.Union(aPieces
[i
]);
1019 assert (aClipRegion
.getRegionBand());
1020 rDev
.SetClipRegion(aClipRegion
);
1021 rDev
.SetFillColor(Color::HSBtoRGB(nHue
, 75, 75));
1022 nHue
= (nHue
+ 97) % 360;
1023 rDev
.DrawRect(aOuter
);
1030 sal_uInt16 nHue
= 0;
1031 tools::Rectangle aOuter
= aRegions
[3];
1032 std::vector
<tools::Rectangle
> aPieces(DemoRenderer::partition(aOuter
, 2, 2));
1034 for (int j
= 0; !bDone
; ++j
)
1036 rDev
.Push(PushFlags::CLIPREGION
);
1038 for (int i
= 0; i
< 4; ++i
)
1040 vcl::Region aClipRegion
;
1041 tools::Polygon aPoly
;
1044 case 0: // 45degree rectangle.
1045 aPoly
= tools::Polygon(aPieces
[i
]);
1046 aPoly
.Rotate(aPieces
[i
].Center(), 450);
1049 aPoly
= tools::Polygon(aPieces
[i
],
1050 aPieces
[i
].TopLeft(),
1051 aPieces
[i
].BottomRight());
1054 aPoly
= tools::Polygon(aPieces
[i
],
1055 aPieces
[i
].GetWidth()/5,
1056 aPieces
[i
].GetHeight()/5);
1057 aPoly
.Rotate(aPieces
[i
].Center(), 450);
1060 aClipRegion
= vcl::Region(aPoly
);
1061 aPieces
[i
].expand(-1);
1062 aPieces
[i
].Move(2 - i
/2, 2 - i
/2);
1064 bDone
= aPieces
[i
].GetWidth() < 4 ||
1065 aPieces
[i
].GetHeight() < 4;
1069 assert (!aClipRegion
.getRegionBand());
1071 rDev
.SetClipRegion(aClipRegion
);
1072 rDev
.SetFillColor(Color::HSBtoRGB(nHue
, 50, 75));
1073 nHue
= (nHue
+ 97) % 360;
1074 rDev
.DrawRect(aOuter
);
1084 struct DrawToVirtualDevice
: public RegionRenderer
1086 RENDER_DETAILS(vdev
,KEY_V
,1)
1091 RENDER_AS_ALPHA_OUTDEV
1094 static void SizeAndRender(OutputDevice
&rDev
, const tools::Rectangle
& r
, RenderType eType
,
1095 const RenderContext
&rCtx
)
1097 ScopedVclPtr
<VirtualDevice
> pNested
;
1099 if (static_cast<int>(eType
) < RENDER_AS_BITMAPEX
)
1100 pNested
= VclPtr
<VirtualDevice
>::Create(rDev
).get();
1102 pNested
= VclPtr
<VirtualDevice
>::Create(rDev
,DeviceFormat::DEFAULT
,DeviceFormat::DEFAULT
).get();
1104 pNested
->SetOutputSizePixel(r
.GetSize());
1105 tools::Rectangle
aWhole(Point(0,0), r
.GetSize());
1108 rCtx
.mpDemoRenderer
->drawToDevice(*pNested
, r
.GetSize(), true);
1110 if (eType
== RENDER_AS_BITMAP
)
1112 Bitmap
aBitmap(pNested
->GetBitmap(Point(0,0),aWhole
.GetSize()));
1113 rDev
.DrawBitmap(r
.TopLeft(), aBitmap
);
1115 else if (eType
== RENDER_AS_BITMAPEX
)
1117 BitmapEx
aBitmapEx(pNested
->GetBitmapEx(Point(0,0),aWhole
.GetSize()));
1118 rDev
.DrawBitmapEx(r
.TopLeft(), aBitmapEx
);
1120 else if (eType
== RENDER_AS_OUTDEV
||
1121 eType
== RENDER_AS_ALPHA_OUTDEV
)
1123 rDev
.DrawOutDev(r
.TopLeft(), r
.GetSize(),
1124 aWhole
.TopLeft(), aWhole
.GetSize(),
1128 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
1129 const RenderContext
&rCtx
) override
1131 // avoid infinite recursion
1135 if (rCtx
.meStyle
== RENDER_EXPANDED
)
1137 std::vector
<tools::Rectangle
> aRegions(DemoRenderer::partition(rCtx
,2, 2));
1138 DemoRenderer::clearRects(rDev
, aRegions
);
1140 RenderType
const eRenderTypes
[] { RENDER_AS_BITMAP
, RENDER_AS_OUTDEV
,
1141 RENDER_AS_BITMAPEX
, RENDER_AS_ALPHA_OUTDEV
};
1142 for (size_t i
= 0; i
< aRegions
.size(); i
++)
1143 SizeAndRender(rDev
, aRegions
[i
], eRenderTypes
[i
], rCtx
);
1146 SizeAndRender(rDev
, r
, RENDER_AS_BITMAP
, rCtx
);
1150 struct DrawXOR
: public RegionRenderer
1152 RENDER_DETAILS(xor,KEY_X
,1)
1154 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
1155 const RenderContext
&rCtx
) override
1157 // avoid infinite recursion
1163 AntialiasingFlags nFlags
= rDev
.GetAntialiasing();
1164 rDev
.SetAntialiasing(nFlags
& ~AntialiasingFlags::EnableB2dDraw
);
1165 rDev
.SetRasterOp( RasterOp::Xor
);
1167 rCtx
.mpDemoRenderer
->drawThumbs(rDev
, r
, true);
1173 struct DrawIcons
: public RegionRenderer
1175 RENDER_DETAILS(icons
,KEY_I
,1)
1177 std::vector
<OUString
> maIconNames
;
1178 std::vector
<BitmapEx
> maIcons
;
1180 DrawIcons() : bHasLoadedAll(false)
1182 // a few icons to start with
1183 const char *pNames
[] = {
1184 "cmd/lc_openurl.png",
1185 "cmd/lc_newdoc.png",
1186 "cmd/lc_choosemacro.png",
1188 "cmd/lc_saveas.png",
1189 "cmd/lc_importdialog.png",
1190 "cmd/lc_sendmail.png",
1191 "cmd/lc_editdoc.png",
1193 "cmd/lc_combobox.png",
1194 "cmd/lc_insertformcombo.png",
1195 "cmd/lc_printpreview.png",
1199 "cmd/sc_autopilotmenu.png",
1200 "cmd/lc_formatpaintbrush.png",
1204 "cmd/lc_fieldnames.png",
1205 "cmd/lc_hyperlinkdialog.png",
1206 "cmd/lc_basicshapes.rectangle.png",
1207 "cmd/lc_basicshapes.round-rectangle.png"
1209 for (size_t i
= 0; i
< SAL_N_ELEMENTS(pNames
); i
++)
1211 maIconNames
.push_back(OUString::createFromAscii(pNames
[i
]));
1212 maIcons
.emplace_back(maIconNames
[i
]);
1216 void LoadAllImages()
1220 bHasLoadedAll
= true;
1222 css::uno::Reference
<css::container::XNameAccess
> xRef(ImageTree::get().getNameAccess());
1223 const css::uno::Sequence
< OUString
> aAllIcons
= xRef
->getElementNames();
1225 for (const auto& rIcon
: aAllIcons
)
1227 if (rIcon
.endsWithIgnoreAsciiCase("svg"))
1228 continue; // too slow to load.
1229 maIconNames
.push_back(rIcon
);
1230 maIcons
.emplace_back(rIcon
);
1234 void doDrawIcons(OutputDevice
&rDev
, tools::Rectangle r
, bool bExpanded
)
1237 Point
p(r
.LeftCenter());
1238 size_t nToRender
= maIcons
.size();
1240 if (!bExpanded
&& maIcons
.size() > 64)
1242 for (size_t i
= 0; i
< nToRender
; i
++)
1244 Size
aSize(maIcons
[i
].GetSizePixel());
1245 // sAL_DEBUG("Draw icon '" << maIconNames[i] << "'");
1248 rDev
.DrawBitmapEx(p
, maIcons
[i
]);
1251 basegfx::B2DHomMatrix aTransform
;
1252 aTransform
.scale(aSize
.Width(), aSize
.Height());
1256 aTransform
.shearX(static_cast<double>((i
>> 2) % 8) / 8);
1257 aTransform
.shearY(static_cast<double>((i
>> 4) % 8) / 8);
1260 aTransform
.translate(-aSize
.Width()/2, -aSize
.Height()/2);
1261 aTransform
.rotate(i
);
1264 aTransform
.shearX(static_cast<double>((i
>> 2) % 8) / 8);
1265 aTransform
.shearY(static_cast<double>((i
>> 4) % 8) / 8);
1267 aTransform
.translate(aSize
.Width()/2, aSize
.Height()/2);
1270 aTransform
.translate(-aSize
.Width()/2, -aSize
.Height()/2);
1271 aTransform
.rotate(2 * F_2PI
* i
/ nToRender
);
1272 aTransform
.translate(aSize
.Width()/2, aSize
.Height()/2);
1275 aTransform
.translate(p
.X(), p
.Y());
1276 rDev
.DrawTransformedBitmapEx(aTransform
, maIcons
[i
]);
1280 p
.Move(aSize
.Width(), 0);
1281 if (aSize
.Height() > nMaxH
)
1282 nMaxH
= aSize
.Height();
1283 if (p
.X() >= r
.Right()) // wrap to next line
1285 p
= Point(r
.Left(), p
.Y() + nMaxH
);
1288 if (p
.Y() >= r
.Bottom()) // re-start at middle
1293 static BitmapEx
AlphaRecovery(OutputDevice
&rDev
, Point aPt
, BitmapEx
const &aSrc
)
1295 // Compositing onto 2x colors beyond our control
1296 ScopedVclPtrInstance
< VirtualDevice
> aWhite
;
1297 ScopedVclPtrInstance
< VirtualDevice
> aBlack
;
1298 aWhite
->SetOutputSizePixel(aSrc
.GetSizePixel());
1299 aWhite
->SetBackground(Wallpaper(COL_WHITE
));
1301 aBlack
->SetOutputSizePixel(aSrc
.GetSizePixel());
1302 aBlack
->SetBackground(Wallpaper(COL_BLACK
));
1304 aWhite
->DrawBitmapEx(Point(), aSrc
);
1305 aBlack
->DrawBitmapEx(Point(), aSrc
);
1307 // Now recover that alpha...
1308 Bitmap aWhiteBmp
= aWhite
->GetBitmap(Point(),aSrc
.GetSizePixel());
1309 Bitmap aBlackBmp
= aBlack
->GetBitmap(Point(),aSrc
.GetSizePixel());
1310 AlphaMask
aMask(aSrc
.GetSizePixel());
1311 Bitmap
aRecovered(aSrc
.GetSizePixel(), 24);
1313 AlphaScopedWriteAccess
pMaskAcc(aMask
);
1314 BitmapScopedWriteAccess
pRecAcc(aRecovered
);
1315 Bitmap::ScopedReadAccess
pAccW(aWhiteBmp
); // a * pix + (1-a)
1316 Bitmap::ScopedReadAccess
pAccB(aBlackBmp
); // a * pix + 0
1317 int nSizeX
= aSrc
.GetSizePixel().Width();
1318 int nSizeY
= aSrc
.GetSizePixel().Height();
1319 for (int y
= 0; y
< nSizeY
; y
++)
1321 Scanline pScanlineMask
= pMaskAcc
->GetScanline( y
);
1322 Scanline pScanlineRec
= pRecAcc
->GetScanline( y
);
1323 Scanline pScanlineW
= pAccW
->GetScanline( y
);
1324 Scanline pScanlineB
= pAccB
->GetScanline( y
);
1325 for (int x
= 0; x
< nSizeX
; x
++)
1327 BitmapColor aColW
= pAccW
->GetPixelFromData(pScanlineW
,x
);
1328 BitmapColor aColB
= pAccB
->GetPixelFromData(pScanlineB
,x
);
1329 long nAR
= static_cast<long>(aColW
.GetRed() - aColB
.GetRed()); // (1-a)
1330 long nAG
= static_cast<long>(aColW
.GetGreen() - aColB
.GetGreen()); // (1-a)
1331 long nAB
= static_cast<long>(aColW
.GetBlue() - aColB
.GetBlue()); // (1-a)
1333 #define CLAMP(a,b,c) (((a)<=(b))?(b):(((a)>=(c))?(c):(a)))
1335 // we get the most precision from the largest delta
1336 long nInverseAlpha
= std::max(nAR
, std::max(nAG
, nAB
)); // (1-a)
1337 nInverseAlpha
= CLAMP(nInverseAlpha
, 0, 255);
1338 long nAlpha
= 255 - nInverseAlpha
;
1340 pMaskAcc
->SetPixelOnData(pScanlineMask
,x
,BitmapColor(static_cast<sal_Int8
>(CLAMP(nInverseAlpha
,0,255))));
1341 // now recover the pixels
1342 long nR
= (aColW
.GetRed() + aColB
.GetRed() - nInverseAlpha
) * 128;
1343 long nG
= (aColW
.GetGreen() + aColB
.GetGreen() - nInverseAlpha
) * 128;
1344 long nB
= (aColW
.GetBlue() + aColB
.GetBlue() - nInverseAlpha
) * 128;
1346 { // doesn't matter what's behind transparency
1351 nR
/= nAlpha
; nG
/= nAlpha
; nB
/= nAlpha
;
1353 pRecAcc
->SetPixelOnData(pScanlineRec
,x
,BitmapColor(
1354 static_cast<sal_uInt8
>(CLAMP(nR
,0,255)),
1355 static_cast<sal_uInt8
>(CLAMP(nG
,0,255)),
1356 static_cast<sal_uInt8
>(CLAMP(nB
,0,255))));
1361 rDev
.DrawBitmap(aPt
, aWhiteBmp
);
1362 aPt
.Move(aSrc
.GetSizePixel().Width(), 0);
1363 rDev
.DrawBitmap(aPt
, aBlackBmp
);
1364 aPt
.Move(aSrc
.GetSizePixel().Width(), 0);
1365 rDev
.DrawBitmap(aPt
, aRecovered
);
1366 aPt
.Move(aSrc
.GetSizePixel().Width(), 0);
1367 rDev
.DrawBitmap(aPt
, aMask
.GetBitmap());
1368 aPt
.Move(aSrc
.GetSizePixel().Width(), 0);
1370 return BitmapEx(aRecovered
, aMask
);
1373 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
1374 const RenderContext
&rCtx
) override
1376 if (rCtx
.meStyle
== RENDER_EXPANDED
)
1380 Point
aLocation(0,maIcons
[0].GetSizePixel().Height() + 8);
1381 for (size_t i
= 0; i
< 100; i
++)
1383 BitmapEx aSrc
= maIcons
[i
];
1386 Point
aAbove(aLocation
);
1387 aAbove
.Move(0,-aSrc
.GetSizePixel().Height() - 4);
1388 rDev
.DrawBitmapEx(aAbove
, aSrc
);
1389 aAbove
.Move(aSrc
.GetSizePixel().Width(),0);
1390 aAbove
.Move(aSrc
.GetSizePixel().Width(),0);
1391 rDev
.DrawBitmap(aAbove
, aSrc
.GetBitmap());
1392 aAbove
.Move(aSrc
.GetSizePixel().Width(),0);
1393 rDev
.DrawBitmap(aAbove
, aSrc
.GetMask());
1395 // intermediates middle
1396 BitmapEx aResult
= AlphaRecovery(rDev
, aLocation
, aSrc
);
1399 Point
aBelow(aLocation
);
1400 aBelow
.Move(0,aResult
.GetSizePixel().Height());
1401 rDev
.DrawBitmapEx(aBelow
, aResult
);
1403 // mini convert test.
1404 aBelow
.Move(aResult
.GetSizePixel().Width()+4,0);
1405 rDev
.DrawBitmapEx(aBelow
, aResult
);
1407 Bitmap aGrey
= aSrc
.GetBitmap();
1408 aGrey
.Convert(BmpConversion::N8BitGreys
);
1409 rDev
.DrawBitmap(aBelow
, aGrey
);
1411 aBelow
.Move(aGrey
.GetSizePixel().Width(),0);
1412 BitmapEx
aGreyMask(aSrc
.GetBitmap(),
1413 AlphaMask(aSrc
.GetMask()));
1414 rDev
.DrawBitmapEx(aBelow
, aGreyMask
);
1416 aLocation
.Move(aSrc
.GetSizePixel().Width()*6,0);
1417 if (aLocation
.X() > r
.Right())
1418 aLocation
= Point(0,aLocation
.Y()+aSrc
.GetSizePixel().Height()*3+4);
1421 // now go crazy with random foo
1422 doDrawIcons(rDev
, r
, true);
1426 doDrawIcons(rDev
, r
, false);
1431 struct FetchDrawBitmap
: public RegionRenderer
1433 RENDER_DETAILS(fetchdraw
,KEY_F
,50)
1434 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
1435 const RenderContext
&) override
1437 Bitmap
aBitmap(rDev
.GetBitmap(Point(0,0),rDev
.GetOutputSizePixel()));
1438 aBitmap
.Scale(r
.GetSize(), BmpScaleFlag::BestQuality
);
1439 rDev
.DrawBitmap(r
.TopLeft(), aBitmap
);
1443 void drawThumbs(vcl::RenderContext
& rDev
, tools::Rectangle aRect
, bool bVDev
)
1446 aCtx
.meStyle
= RENDER_THUMB
;
1447 aCtx
.mbVDev
= bVDev
;
1448 aCtx
.mpDemoRenderer
= this;
1449 aCtx
.maSize
= aRect
.GetSize();
1450 std::vector
<tools::Rectangle
> aRegions(partition(aRect
, mnSegmentsX
, mnSegmentsY
));
1451 DemoRenderer::clearRects(rDev
, aRegions
);
1452 for (size_t i
= 0; i
< maRenderers
.size(); i
++)
1454 RegionRenderer
* r
= maRenderers
[i
];
1456 rDev
.SetClipRegion( vcl::Region( aRegions
[i
] ) );
1459 if (getIterCount() > 0)
1463 double nStartTime
= getTimeNow();
1464 for (int j
= 0; j
< r
->getTestRepeatCount() * THUMB_REPEAT_FACTOR
; j
++)
1465 r
->RenderRegion(rDev
, aRegions
[i
], aCtx
);
1466 addTime(i
, (getTimeNow() - nStartTime
) / THUMB_REPEAT_FACTOR
);
1468 for (int j
= 0; j
< r
->getTestRepeatCount(); j
++)
1469 r
->RenderRegion(rDev
, aRegions
[i
], aCtx
);
1472 r
->RenderRegion(rDev
, aRegions
[i
], aCtx
);
1474 rDev
.SetClipRegion();
1478 void drawToDevice(vcl::RenderContext
& rDev
, Size aSize
, bool bVDev
)
1481 aCtx
.mbVDev
= bVDev
;
1482 aCtx
.mpDemoRenderer
= this;
1483 aCtx
.maSize
= aSize
;
1484 tools::Rectangle
aWholeWin(Point(0,0), rDev
.GetOutputSizePixel());
1486 drawBackground(rDev
, aWholeWin
);
1488 if (!bVDev
/* want everything in the vdev */ &&
1489 mnSelectedRenderer
>= 0 &&
1490 static_cast<sal_uInt32
>(mnSelectedRenderer
) < maRenderers
.size())
1492 aCtx
.meStyle
= RENDER_EXPANDED
;
1493 RegionRenderer
* r
= maRenderers
[mnSelectedRenderer
];
1495 if (getIterCount() > 0)
1497 double nStartTime
= getTimeNow();
1498 for (int i
= 0; i
< r
->getTestRepeatCount(); i
++)
1499 r
->RenderRegion(rDev
, aWholeWin
, aCtx
);
1500 addTime(mnSelectedRenderer
, getTimeNow() - nStartTime
);
1502 r
->RenderRegion(rDev
, aWholeWin
, aCtx
);
1505 drawThumbs(rDev
, aWholeWin
, bVDev
);
1507 std::vector
<VclPtr
<vcl::Window
> > maInvalidates
;
1508 void addInvalidate(vcl::Window
*pWindow
) { maInvalidates
.emplace_back(pWindow
); };
1509 void removeInvalidate(vcl::Window
*pWindow
)
1511 auto aIt
= std::find(maInvalidates
.begin(), maInvalidates
.end(), pWindow
);
1512 if (aIt
!= maInvalidates
.end())
1513 maInvalidates
.erase(aIt
);
1517 for (auto const& invalidate
: maInvalidates
)
1518 invalidate
->Invalidate();
1522 #if FIXME_BOUNCE_BUTTON
1523 IMPL_LINK_NOARG(DemoRenderer
,BounceTimerCb
,Timer
*,void)
1525 mpButton
->Check(mnBounceX
>0);
1526 mpButton
->SetPressed(mnBounceY
>0);
1528 Point aCur
= mpButtonWin
->GetPosPixel();
1529 static const int nMovePix
= 10;
1530 aCur
.Move(mnBounceX
* nMovePix
, mnBounceX
* nMovePix
);
1531 Size aWinSize
= GetSizePixel();
1532 if (aCur
.X() <= 0 || aCur
.X() >= aWinSize
.Width())
1534 if (aCur
.Y() <= 0 || aCur
.Y() >= aWinSize
.Height())
1536 mpButtonWin
->SetPosPixel(aCur
);
1538 // All smoke and mirrors to test sub-region invalidation underneath
1539 Rectangle
aRect(aCur
, mpButtonWin
->GetSizePixel());
1544 void DemoRenderer::KeyInput(const KeyEvent
&rKEvt
)
1546 sal_uInt16 nCode
= rKEvt
.GetKeyCode().GetCode();
1548 // click to zoom out
1549 if (mnSelectedRenderer
>= 0)
1551 if (nCode
== KEY_ESCAPE
|| nCode
== KEY_BACKSPACE
)
1553 mnSelectedRenderer
= -1;
1560 for (size_t i
= 0; i
< maRenderers
.size(); i
++)
1562 if (nCode
== maRenderers
[i
]->getAccelerator())
1564 mnSelectedRenderer
= i
;
1572 bool DemoRenderer::MouseButtonDown(const MouseEvent
& rMEvt
)
1574 // click to zoom out
1575 if (mnSelectedRenderer
>= 0)
1577 mnSelectedRenderer
= -1;
1582 // click on a region to zoom into it
1583 std::vector
<tools::Rectangle
> aRegions(partition(GetSizePixel(), mnSegmentsX
, mnSegmentsY
));
1584 for (size_t i
= 0; i
< aRegions
.size(); i
++)
1586 if (aRegions
[i
].IsInside(rMEvt
.GetPosPixel()))
1588 mnSelectedRenderer
= i
;
1594 #if FIXME_BOUNCE_BUTTON
1595 // otherwise bounce floating windows
1598 mpButtonWin
= VclPtr
<FloatingWindow
>::Create(this);
1599 mpButton
= VclPtr
<PushButton
>::Create(mpButtonWin
);
1600 mpButton
->SetSymbol(SymbolType::HELP
);
1601 mpButton
->SetText("PushButton demo");
1602 mpButton
->SetPosSizePixel(Point(0,0), mpButton
->GetOptimalSize());
1604 mpButtonWin
->SetPosSizePixel(Point(0,0), mpButton
->GetOptimalSize());
1605 mpButtonWin
->Show();
1606 mnBounceX
= 1; mnBounceX
= 1;
1607 maBounce
.SetInvokeHandler(LINK(this,DemoRenderer
,BounceTimerCb
));
1608 maBounce
.SetTimeout(55);
1622 void DemoRenderer::InitRenderers()
1624 maRenderers
.push_back(new DrawLines
);
1625 maRenderers
.push_back(new DrawText
);
1626 maRenderers
.push_back(new DrawPoly
);
1627 maRenderers
.push_back(new DrawEllipse
);
1628 maRenderers
.push_back(new DrawCheckered
);
1629 maRenderers
.push_back(new DrawBitmapEx
);
1630 maRenderers
.push_back(new DrawBitmap
);
1631 maRenderers
.push_back(new DrawGradient
);
1632 maRenderers
.push_back(new DrawPolyPolygons
);
1633 maRenderers
.push_back(new DrawClipped
);
1634 maRenderers
.push_back(new DrawToVirtualDevice
);
1635 maRenderers
.push_back(new DrawXOR
);
1636 maRenderers
.push_back(new DrawIcons());
1637 maRenderers
.push_back(new FetchDrawBitmap
);
1640 OUString
DemoRenderer::getRendererList()
1642 OUStringBuffer aBuf
;
1643 for (size_t i
= 0; i
< maRenderers
.size(); i
++)
1645 aBuf
.append(maRenderers
[i
]->getName());
1648 return aBuf
.makeStringAndClear();
1651 double DemoRenderer::getAndResetBenchmark(const RenderStyle style
)
1653 double geomean
= 1.0;
1654 fprintf(stderr
, "Rendering: %s, Times (ms):\n", style
== RENDER_THUMB
? "THUMB": "EXPANDED");
1655 for (size_t i
= 0; i
< maRenderers
.size(); i
++)
1657 double avgtime
= maRenderers
[i
]->sumTime
/ maRenderers
[i
]->countTime
;
1659 fprintf(stderr
, "%s: %f (iteration: %d*%d*%d)\n",
1660 OUStringToOString(maRenderers
[i
]->getName(),
1661 RTL_TEXTENCODING_UTF8
).getStr(), avgtime
,
1662 maRenderers
[i
]->countTime
, maRenderers
[i
]->getTestRepeatCount(),
1663 (style
== RENDER_THUMB
) ? THUMB_REPEAT_FACTOR
: 1);
1664 maRenderers
[i
]->sumTime
= 0;
1665 maRenderers
[i
]->countTime
= 0;
1667 geomean
= pow(geomean
, 1.0/maRenderers
.size());
1668 fprintf(stderr
, "GEOMEAN_%s: %f\n", style
== RENDER_THUMB
? "THUMB": "EXPANDED", geomean
);
1672 void DemoRenderer::setIterCount(sal_Int32 i
)
1677 sal_Int32
DemoRenderer::getIterCount() const
1682 void DemoRenderer::addTime(int i
, double t
)
1684 maRenderers
[i
]->sumTime
+= t
/ maRenderers
[i
]->getTestRepeatCount();
1685 maRenderers
[i
]->countTime
++;
1688 void DemoRenderer::selectRenderer(const OUString
&rName
)
1690 for (size_t i
= 0; i
< maRenderers
.size(); i
++)
1692 if (maRenderers
[i
]->getName() == rName
)
1694 mnSelectedRenderer
= i
;
1701 int DemoRenderer::selectNextRenderer()
1703 mnSelectedRenderer
++;
1704 if (mnSelectedRenderer
== static_cast<signed>(maRenderers
.size()))
1705 mnSelectedRenderer
= -1;
1707 return mnSelectedRenderer
;
1710 class DemoWin
: public WorkWindow
1712 DemoRenderer
&mrRenderer
;
1716 class RenderThread
: public salhelper::Thread
{
1718 sal_uInt32
const mnDelaySecs
= 0;
1720 RenderThread(DemoWin
&rWin
, sal_uInt32 nDelaySecs
)
1721 : Thread("vcldemo render thread")
1723 , mnDelaySecs(nDelaySecs
)
1727 virtual ~RenderThread() override
1731 virtual void execute() override
1733 wait(std::chrono::seconds(mnDelaySecs
));
1735 SolarMutexGuard aGuard
;
1736 fprintf (stderr
, "render from a different thread\n");
1740 rtl::Reference
<RenderThread
> mxThread
;
1743 DemoWin(DemoRenderer
&rRenderer
, bool bThreads
) :
1744 WorkWindow(nullptr, WB_APP
| WB_STDWORK
),
1745 mrRenderer(rRenderer
),
1746 testThreads(bThreads
)
1748 mrRenderer
.addInvalidate(this);
1749 underTesting
= false;
1751 virtual ~DemoWin() override
1755 virtual void dispose() override
1758 mrRenderer
.removeInvalidate(this);
1759 WorkWindow::dispose();
1761 virtual void MouseButtonDown(const MouseEvent
& rMEvt
) override
1763 mrRenderer
.SetSizePixel(GetSizePixel());
1764 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");
1781 virtual void KeyInput(const KeyEvent
& rKEvt
) override
1783 mrRenderer
.SetSizePixel(GetSizePixel());
1784 mrRenderer
.KeyInput(rKEvt
);
1786 virtual void Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRect
) override
1788 mrRenderer
.SetSizePixel(GetSizePixel());
1789 fprintf(stderr
, "DemoWin::Paint(%ld,%ld,%ld,%ld)\n", rRect
.getX(), rRect
.getY(), rRect
.getWidth(), rRect
.getHeight());
1790 if (mrRenderer
.getIterCount() == 0)
1791 mrRenderer
.drawToDevice(rRenderContext
, GetSizePixel(), false);
1793 TestAndQuit(rRenderContext
);
1796 void TestAndQuit(vcl::RenderContext
& rRenderContext
)
1800 underTesting
= true;
1801 for (sal_Int32 i
= 0; i
< mrRenderer
.getIterCount(); i
++)
1803 while (mrRenderer
.selectNextRenderer() > -1)
1805 mrRenderer
.drawToDevice(rRenderContext
, GetSizePixel(), false);
1809 double expandedGEOMEAN
= mrRenderer
.getAndResetBenchmark(RENDER_EXPANDED
);
1811 for (sal_Int32 i
= 0; i
< mrRenderer
.getIterCount(); i
++)
1812 mrRenderer
.drawToDevice(rRenderContext
, GetSizePixel(), false);
1814 double thumbGEOMEAN
= mrRenderer
.getAndResetBenchmark(RENDER_THUMB
);
1816 fprintf(stderr
, "GEOMEAN_TOTAL: %f\n", pow(thumbGEOMEAN
* expandedGEOMEAN
, 0.5));
1817 Application::Quit();
1821 struct PointerData
{
1822 PointerStyle eStyle
;
1825 static const PointerData gvPointerData
[] = {
1826 { PointerStyle::Null
, "Null" },
1827 { PointerStyle::Magnify
, "Magnify" },
1828 { PointerStyle::Fill
, "Fill" },
1829 { PointerStyle::MoveData
, "MoveData" },
1830 { PointerStyle::CopyData
, "CopyData" },
1831 { PointerStyle::MoveFile
, "MoveFile" },
1832 { PointerStyle::CopyFile
, "CopyFile" },
1833 { PointerStyle::MoveFiles
, "MoveFiles" },
1834 { PointerStyle::CopyFiles
, "CopyFiles" },
1835 { PointerStyle::NotAllowed
, "NotAllowed" },
1836 { PointerStyle::Rotate
, "Rotate" },
1837 { PointerStyle::HShear
, "HShear" },
1838 { PointerStyle::VShear
, "VShear" },
1839 { PointerStyle::DrawLine
, "DrawLine" },
1840 { PointerStyle::DrawRect
, "DrawRect" },
1841 { PointerStyle::DrawPolygon
, "DrawPolygon" },
1842 { PointerStyle::DrawBezier
, "DrawBezier" },
1843 { PointerStyle::DrawArc
, "DrawArc" },
1844 { PointerStyle::DrawPie
, "DrawPie" },
1845 { PointerStyle::DrawCircleCut
, "DrawCircleCut" },
1846 { PointerStyle::DrawEllipse
, "DrawEllipse" },
1847 { PointerStyle::DrawConnect
, "DrawConnect" },
1848 { PointerStyle::DrawText
, "DrawText" },
1849 { PointerStyle::Mirror
, "Mirror" },
1850 { PointerStyle::Crook
, "Crook" },
1851 { PointerStyle::Crop
, "Crop" },
1852 { PointerStyle::MovePoint
, "MovePoint" },
1853 { PointerStyle::MoveBezierWeight
, "MoveBezierWeight" },
1854 { PointerStyle::DrawFreehand
, "DrawFreehand" },
1855 { PointerStyle::DrawCaption
, "DrawCaption" },
1856 { PointerStyle::LinkData
, "LinkData" },
1857 { PointerStyle::MoveDataLink
, "MoveDataLink" },
1858 { PointerStyle::CopyDataLink
, "CopyDataLink" },
1859 { PointerStyle::LinkFile
, "LinkFile" },
1860 { PointerStyle::MoveFileLink
, "MoveFileLink" },
1861 { PointerStyle::CopyFileLink
, "CopyFileLink" },
1862 { PointerStyle::Chart
, "Chart" },
1863 { PointerStyle::Detective
, "Detective" },
1864 { PointerStyle::PivotCol
, "PivotCol" },
1865 { PointerStyle::PivotRow
, "PivotRow" },
1866 { PointerStyle::PivotField
, "PivotField" },
1867 { PointerStyle::PivotDelete
, "PivotDelete" },
1868 { PointerStyle::Chain
, "Chain" },
1869 { PointerStyle::ChainNotAllowed
, "ChainNotAllowed" },
1870 { PointerStyle::AutoScrollN
, "AutoScrollN" },
1871 { PointerStyle::AutoScrollS
, "AutoScrollS" },
1872 { PointerStyle::AutoScrollW
, "AutoScrollW" },
1873 { PointerStyle::AutoScrollE
, "AutoScrollE" },
1874 { PointerStyle::AutoScrollNW
, "AutoScrollNW" },
1875 { PointerStyle::AutoScrollNE
, "AutoScrollNE" },
1876 { PointerStyle::AutoScrollSW
, "AutoScrollSW" },
1877 { PointerStyle::AutoScrollSE
, "AutoScrollSE" },
1878 { PointerStyle::AutoScrollNS
, "AutoScrollNS" },
1879 { PointerStyle::AutoScrollWE
, "AutoScrollWE" },
1880 { PointerStyle::AutoScrollNSWE
, "AutoScrollNSWE" },
1881 { PointerStyle::TextVertical
, "TextVertical" },
1882 { PointerStyle::TabSelectS
, "TabSelectS" },
1883 { PointerStyle::TabSelectE
, "TabSelectE" },
1884 { PointerStyle::TabSelectSE
, "TabSelectSE" },
1885 { PointerStyle::TabSelectW
, "TabSelectW" },
1886 { PointerStyle::TabSelectSW
, "TabSelectSW" },
1887 { PointerStyle::HideWhitespace
, "HideWhitespace" },
1888 { PointerStyle::ShowWhitespace
, "ShowWhitespace" },
1890 class DemoWidgets
: public WorkWindow
1892 VclPtr
<MenuBar
> mpBar
;
1893 VclPtr
<VclBox
> mpBox
;
1894 VclPtr
<ToolBox
> mpToolbox
;
1895 VclPtr
<PushButton
> mpButton
;
1896 VclPtr
<VclHBox
> mpHBox
;
1897 VclPtr
<CheckBox
> mpGLCheck
;
1898 VclPtr
<ComboBox
> mpGLCombo
;
1899 VclPtr
<PushButton
> mpGLButton
;
1900 std::vector
<VclPtr
<VclHBox
>> mvCursorBoxes
;
1901 std::vector
<VclPtr
<PushButton
>> mvCursorButtons
;
1903 DECL_LINK(GLTestClick
, Button
*, void);
1904 DECL_LINK(CursorButtonClick
, Button
*, void);
1908 WorkWindow(nullptr, WB_APP
| WB_STDWORK
),
1909 mpBox(VclPtrInstance
<VclVBox
>(this, false, 3)),
1910 mpToolbox(VclPtrInstance
<ToolBox
>(mpBox
.get())),
1911 mpButton(VclPtrInstance
<PushButton
>(mpBox
.get())),
1912 mpHBox(VclPtrInstance
<VclHBox
>(mpBox
.get(), true, 3)),
1913 mpGLCheck(VclPtrInstance
<CheckBox
>(mpHBox
.get())),
1914 mpGLCombo(VclPtrInstance
<ComboBox
>(mpHBox
.get())),
1915 mpGLButton(VclPtrInstance
<PushButton
>(mpHBox
.get()))
1917 SetText("VCL widget demo");
1919 Wallpaper
aWallpaper(BitmapEx("sfx2/res/startcenter-logo.png"));
1920 aWallpaper
.SetStyle(WallpaperStyle::BottomRight
);
1921 aWallpaper
.SetColor(COL_RED
);
1923 mpBox
->SetBackground(aWallpaper
);
1926 Help::EnableBalloonHelp();
1927 mpToolbox
->SetHelpText("Help text");
1928 mpToolbox
->InsertItem(0, "Toolbar item");
1929 mpToolbox
->SetQuickHelpText(0, "This is a tooltip popup");
1930 mpToolbox
->InsertSeparator();
1933 mpButton
->SetText("Click me; go on");
1936 mpGLCheck
->SetText("Test in OGL zone");
1938 mpGLCombo
->InsertEntry("sleep 1 second");
1939 mpGLCombo
->InsertEntry("sleep 3 seconds");
1940 mpGLCombo
->InsertEntry("sleep 7 seconds");
1941 mpGLCombo
->SelectEntryPos(2);
1943 mpGLButton
->SetText("Execute test");
1944 mpGLButton
->SetClickHdl(LINK(this,DemoWidgets
,GLTestClick
));
1949 VclHBox
* pCurrentCursorHBox
= nullptr;
1950 constexpr int numButtonsPerRow
= 9;
1951 for (auto & rData
: gvPointerData
)
1953 if (i
% numButtonsPerRow
== 0)
1955 mvCursorBoxes
.push_back(VclPtrInstance
<VclHBox
>(mpBox
.get(), true, numButtonsPerRow
));
1956 pCurrentCursorHBox
= mvCursorBoxes
.back().get();
1957 pCurrentCursorHBox
->Show();
1959 mvCursorButtons
.emplace_back(VclPtrInstance
<PushButton
>(pCurrentCursorHBox
));
1960 PushButton
& rButton
= *mvCursorButtons
.back();
1961 rButton
.SetText(OUString::createFromAscii(rData
.name
));
1962 rButton
.SetClickHdl(LINK(this,DemoWidgets
,CursorButtonClick
));
1967 mpBar
= VclPtr
<MenuBar
>::Create();
1968 mpBar
->InsertItem(0,"File");
1969 VclPtrInstance
<PopupMenu
> pPopup
;
1970 pPopup
->InsertItem(0,"Item");
1971 mpBar
->SetPopupMenu(0, pPopup
);
1976 virtual ~DemoWidgets() override
{ disposeOnce(); }
1977 virtual void dispose() override
1979 mpGLButton
.disposeAndClear();
1980 mpGLCombo
.disposeAndClear();
1981 mpGLCheck
.disposeAndClear();
1982 mpHBox
.disposeAndClear();
1983 for (auto & p
: mvCursorButtons
)
1984 p
.disposeAndClear();
1985 mvCursorButtons
.clear();
1986 for (auto & p
: mvCursorBoxes
)
1987 p
.disposeAndClear();
1988 mvCursorBoxes
.clear();
1989 mpToolbox
.disposeAndClear();
1990 mpButton
.disposeAndClear();
1991 mpBox
.disposeAndClear();
1992 mpBar
.disposeAndClear();
1993 WorkWindow::dispose();
1995 virtual void Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
&) override
1997 tools::Rectangle
aWholeSize(Point(0, 0),GetOutputSizePixel());
1998 vcl::Region
aClip(aWholeSize
);
1999 tools::Rectangle
aExclude(tools::Rectangle(Point(50,50),Size(100,100)));
2000 aClip
.Exclude(aExclude
);
2002 Wallpaper
aWallpaper(COL_GREEN
);
2004 rRenderContext
.Push(PushFlags::CLIPREGION
);
2005 rRenderContext
.IntersectClipRegion(aClip
);
2006 rRenderContext
.DrawWallpaper(aWholeSize
, aWallpaper
);
2007 rRenderContext
.Pop();
2009 ScopedVclPtrInstance
< VirtualDevice
> pDev(*this);
2010 pDev
->EnableRTL(IsRTLEnabled());
2011 pDev
->SetOutputSizePixel(aExclude
.GetSize());
2013 tools::Rectangle
aSubRect(aWholeSize
);
2014 aSubRect
.Move(-aExclude
.Left(), -aExclude
.Top());
2015 pDev
->DrawWallpaper(aSubRect
, aWallpaper
);
2017 rRenderContext
.DrawOutDev(aExclude
.TopLeft(), aExclude
.GetSize(),
2018 Point( 0, 0 ), aExclude
.GetSize(), *pDev
);
2022 class OpenGLZoneTest
{
2024 static void enter() { OpenGLZone::enter(); }
2025 static void leave() { OpenGLZone::leave(); }
2028 IMPL_LINK_NOARG(DemoWidgets
, GLTestClick
, Button
*, void)
2030 sal_Int32 nSelected
= mpGLCombo
->GetSelectedEntryPos();
2031 sal_uInt32 nDelaySeconds
= 0;
2048 bool bEnterLeave
= mpGLCheck
->IsChecked();
2050 OpenGLZoneTest::enter();
2052 osl::Thread::wait(std::chrono::seconds(nDelaySeconds
));
2055 OpenGLZoneTest::leave();
2058 IMPL_LINK(DemoWidgets
, CursorButtonClick
, Button
*, pButton
, void)
2060 for (size_t i
=0; i
<SAL_N_ELEMENTS(gvPointerData
); ++i
)
2062 if (mvCursorButtons
[i
].get() == pButton
)
2064 mpBox
->SetPointer( gvPointerData
[i
].eStyle
);
2071 class DemoPopup
: public FloatingWindow
2074 DemoPopup() : FloatingWindow( nullptr, WB_SYSTEMWINDOW
|WB_TOOLTIPWIN
)
2076 SetType( WindowType::HELPTEXTWINDOW
);
2078 SetOutputSizePixel( Size( 300, 30 ) );
2079 SetBackground(Wallpaper(COL_YELLOW
));
2081 Show( true, ShowFlags::NoActivate
);
2085 virtual void Paint(vcl::RenderContext
& /*rRenderContext*/, const tools::Rectangle
&) override
2087 // Interestingly in GL mode on Windows, this doesn't render.
2089 Size aSize
= GetOutputSizePixel();
2090 tools::Rectangle
aTextRect(Point(6, 6), aSize
);
2092 SetTextColor(COL_BLACK
);
2093 SetTextAlign(ALIGN_TOP
);
2094 DrawText(aTextRect
, "This is a standalone help text test",
2095 DrawTextFlags::MultiLine
|DrawTextFlags::WordBreak
|
2096 DrawTextFlags::Left
|DrawTextFlags::Top
);
2098 SetLineColor(COL_BLACK
);
2100 DrawRect( tools::Rectangle( Point(), aSize
) );
2101 aSize
.AdjustWidth( -2 );
2102 aSize
.AdjustHeight( -2 );
2103 Color
aColor( GetLineColor() );
2104 SetLineColor( COL_GRAY
);
2105 DrawRect( tools::Rectangle( Point( 1, 1 ), aSize
) );
2106 SetLineColor( aColor
);
2109 virtual void MouseButtonDown( const MouseEvent
& ) override
2111 Application::Quit();
2117 VclPtr
<WorkWindow
> mxWinA
;
2118 VclPtr
<WorkWindow
> mxWinB
;
2119 rtl::Reference
<OpenGLContext
> mpA
;
2120 rtl::Reference
<OpenGLContext
> mpB
;
2122 static OpenGLSalGraphicsImpl
*getImpl(const VclPtr
<OutputDevice
> &xOut
)
2124 SalGraphics
*pGraphics
= xOut
->GetGraphics();
2125 return dynamic_cast<OpenGLSalGraphicsImpl
*>(pGraphics
->GetImpl());
2129 mxWinA(VclPtr
<WorkWindow
>::Create(nullptr, WB_APP
| WB_STDWORK
)),
2130 mxWinB(VclPtr
<WorkWindow
>::Create(nullptr, WB_APP
| WB_STDWORK
))
2132 OpenGLSalGraphicsImpl
*pImplA
;
2133 OpenGLSalGraphicsImpl
*pImplB
;
2134 if (!OpenGLHelper::isVCLOpenGLEnabled())
2136 pImplA
= pImplB
= nullptr;
2137 fprintf (stderr
, "OpenGL is not enabled: try SAL_FORCEGL=1\n");
2141 pImplA
= getImpl(mxWinA
);
2142 pImplB
= getImpl(mxWinB
);
2143 assert (pImplA
&& pImplB
);
2144 mpA
= pImplA
->GetOpenGLContext();
2145 mpB
= pImplB
->GetOpenGLContext();
2147 assert (mpA
.is() && mpB
.is());
2148 assert (mpA
!= mpB
);
2152 mxWinB
.disposeAndClear();
2153 mxWinA
.disposeAndClear();
2156 void testCurrentFramebuffer()
2158 fprintf(stderr
,"test OpenGLContext's framebuffer association.\n");
2160 OpenGLFramebuffer
*pBuffer
;
2162 OpenGLTexture
aTexture(256,128);
2163 pBuffer
= mpA
->AcquireFramebuffer(aTexture
);
2165 assert (pBuffer
->IsFree()); (void)pBuffer
;
2167 assert (mpA
->mpCurrentFramebuffer
== nullptr);
2170 void testVirtualDevice()
2172 fprintf(stderr
, "test sharing OpenGLContexts with virtual-devices reference counting\n");
2173 VclPtrInstance
<WorkWindow
> xTempWin(nullptr, WB_STDWORK
);
2175 // forcibly make this context current by rendering
2176 xTempWin
->DrawPixel(Point(0, 0), COL_RED
);
2178 // get some other guys to leach off this context
2179 VclPtrInstance
<VirtualDevice
> xVDev
;
2180 OpenGLSalGraphicsImpl
* pImpl
= getImpl(xVDev
);
2182 rtl::Reference
<OpenGLContext
> pContext
= pImpl
->GetOpenGLContext();
2183 VclPtrInstance
<VirtualDevice
> xVDev2
;
2184 OpenGLSalGraphicsImpl
* pImpl2
= getImpl(xVDev2
);
2186 rtl::Reference
<OpenGLContext
> pContext2
= pImpl2
->GetOpenGLContext();
2188 // sharing the same off-screen context.
2189 assert(pContext
== pContext2
);
2190 assert(pContext
== getImpl(xTempWin
)->GetOpenGLContext());
2191 assert(pContext
!= mpA
&& pContext
!= mpB
);
2192 (void)pContext
; (void)pContext2
;
2194 // Kill the parent we free-ride on ...
2195 xTempWin
.disposeAndClear();
2197 // This appears to continue working; fun.
2199 xVDev
->DrawPixel(aPt
, COL_GREEN
);
2200 assert(xVDev
->GetPixel(aPt
) == COL_GREEN
);
2201 xVDev
.disposeAndClear();
2203 // Switch context to see if we can switch back.
2204 mxWinA
->DrawPixel(aPt
, COL_WHITE
);
2206 // Now try switching back to this guy ...
2207 xVDev2
->DrawPixel(aPt
, COL_BLUE
);
2208 assert(xVDev2
->GetPixel(aPt
) == COL_BLUE
);
2209 xVDev2
.disposeAndClear();
2214 if (!OpenGLHelper::isVCLOpenGLEnabled())
2217 testCurrentFramebuffer();
2218 testVirtualDevice();
2225 void renderFonts(const std::vector
<OUString
> &aFontNames
)
2227 ScopedVclPtrInstance
<VirtualDevice
> xDevice
;
2228 Size
aSize(1024, 1024);
2229 xDevice
->SetOutputSizePixel(aSize
);
2231 for (auto & aFontName
: aFontNames
)
2233 vcl::Font
aFont(aFontName
, Size(0,96));
2235 aFont
.SetCOL_BLACK
);
2236 xDevice
->SetFont(aFont
);
2239 FontMetric aMetric
= xDevice
->GetFontMetric(aFont
);
2241 FontCharMapRef xMap
;
2242 if (xDevice
->GetFontCharMap(xMap
))
2244 ... iterate through glyphs
...
2248 bool GetGlyphBoundRects( const Point
& rOrigin
, const OUString
& rStr
, int nIndex
,
2249 int nLen
, int nBase
, MetricVector
& rVector
);
2251 include
/vcl
/outdev
.hxx
:typedef std::vector
< Rectangle
> MetricVector
;
2252 include
/vcl
/outdev
.hxx
: MetricVector
* pVector
= nullptr, OUString
* pDisplayText
= nullptr );
2253 include
/vcl
/outdev
.hxx
: MetricVector
* pVector
= nullptr, OUString
* pDisplayText
= nullptr,
2254 include
/vcl
/outdev
.hxx
: MetricVector
* pVector
, OUString
* pDisplayText
, vcl::ITextLayout
& _rLayout
);
2255 include
/vcl
/outdev
.hxx
: DrawTextFlags nStyle
= DrawTextFlags::Mnemonic
, MetricVector
* pVector
= nullp
2257 bool GetTextBoundRect( Rectangle
& rRect
,
2258 const OUString
& rStr
, sal_Int32 nBase
= 0, sal_Int32 nIndex
= 0, sal_Int32 nLen
= -1,
2259 sal_uLong nLayoutWidth
= 0, const long* pDXArray
= nullptr ) const;
2262 void DrawText( const Point
& rStartPt
, const OUString
& rStr
,
2263 sal_Int32 nIndex
= 0, sal_Int32 nLen
= -1,
2264 MetricVector
* pVector
= nullptr, OUString
* pDisplayText
= nullptr );
2266 void DrawText( const Rectangle
& rRect
,
2267 const OUString
& rStr
, DrawTextFlags nStyle
= DrawTextFlags::NONE
,
2268 MetricVector
* pVector
= nullptr, OUString
* pDisplayText
= nullptr,
2269 vcl::ITextLayout
* _pTextLayout
= nullptr );
2271 Rectangle
GetTextRect( const Rectangle
& rRect
,
2272 const OUString
& rStr
, DrawTextFlags nStyle
= DrawTextFlags::WordBreak
,
2273 TextRectInfo
* pInfo
= nullptr,
2274 const vcl::ITextLayout
* _pTextLayout
= nullptr ) const;
2282 class DemoApp
: public Application
2284 static int showHelp(DemoRenderer
&rRenderer
)
2286 fprintf(stderr
,"vcldemo - a VCL test app\n");
2287 fprintf(stderr
," --help - print this text\n");
2288 fprintf(stderr
," --show <renderer> - start with a given renderer, options are:\n");
2289 OUString
aRenderers(rRenderer
.getRendererList());
2290 fprintf(stderr
," %s\n",
2291 OUStringToOString(aRenderers
, RTL_TEXTENCODING_UTF8
).getStr());
2292 fprintf(stderr
," --test <iterCount> - create benchmark data\n");
2293 fprintf(stderr
," --widgets - launch the widget test.\n");
2294 fprintf(stderr
," --popup - launch the popup test.\n");
2295 fprintf(stderr
," --threads - render from multiple threads.\n");
2296 fprintf(stderr
," --gltest - run openGL regression tests.\n");
2297 fprintf(stderr
," --font <fontname> - run the font render test.\n");
2298 fprintf(stderr
, "\n");
2305 virtual int Main() override
2309 bool bWidgets
= false, bThreads
= false;
2310 bool bPopup
= false, bGLTest
= false;
2311 DemoRenderer aRenderer
;
2312 std::vector
<OUString
> aFontNames
;
2314 for (sal_uInt16 i
= 0; i
< GetCommandLineParamCount(); ++i
)
2316 bool bLast
= i
== GetCommandLineParamCount() - 1;
2317 OUString aArg
= GetCommandLineParam(i
);
2318 if (aArg
== "--help" || aArg
== "-h")
2319 return showHelp(aRenderer
);
2320 if (aArg
== "--show")
2323 return showHelp(aRenderer
);
2325 aRenderer
.selectRenderer(GetCommandLineParam(++i
));
2327 else if (aArg
== "--test")
2330 return showHelp(aRenderer
);
2332 aRenderer
.setIterCount(GetCommandLineParam(++i
).toInt32());
2334 else if (aArg
== "--widgets")
2336 else if (aArg
== "--popup")
2338 else if (aArg
== "--gltest")
2340 else if (aArg
== "--threads")
2342 else if (aArg
== "--font" && !bLast
)
2343 aFontNames
.push_back(GetCommandLineParam(++i
));
2344 else if (aArg
.startsWith("--"))
2346 fprintf(stderr
,"Unknown argument '%s'\n",
2347 OUStringToOString(aArg
, RTL_TEXTENCODING_UTF8
).getStr());
2348 return showHelp(aRenderer
);
2352 ScopedVclPtrInstance
<DemoWin
> aMainWin(aRenderer
, bThreads
);
2353 VclPtr
<DemoWidgets
> xWidgets
;
2354 VclPtr
<DemoPopup
> xPopup
;
2356 aMainWin
->SetText("Interactive VCL demo #1");
2357 #if HAVE_FEATURE_OPENGL
2361 return aTests
.execute();
2366 xWidgets
= VclPtr
< DemoWidgets
>::Create ();
2368 xPopup
= VclPtrInstance
< DemoPopup
> ();
2369 else if (!aFontNames
.empty())
2370 renderFonts(aFontNames
);
2374 Application::Execute();
2376 xWidgets
.disposeAndClear();
2377 xPopup
.disposeAndClear();
2379 catch (const css::uno::Exception
&)
2381 TOOLS_WARN_EXCEPTION("vcl.app", "Fatal");
2384 catch (const std::exception
& e
)
2386 SAL_WARN("vcl.app", "Fatal: " << e
.what());
2393 void Init() override
2397 uno::Reference
<uno::XComponentContext
> xComponentContext
2398 = ::cppu::defaultBootstrap_InitialComponentContext();
2399 uno::Reference
<lang::XMultiServiceFactory
> xMSF
;
2400 xMSF
.set(xComponentContext
->getServiceManager(), uno::UNO_QUERY
);
2402 Application::Abort("Bootstrap failure - no service manager");
2404 ::comphelper::setProcessServiceFactory(xMSF
);
2406 catch (const uno::Exception
&e
)
2408 Application::Abort("Bootstrap exception " + e
.Message
);
2411 void DeInit() override
2413 uno::Reference
< lang::XComponent
>(
2414 comphelper::getProcessComponentContext(),
2415 uno::UNO_QUERY_THROW
)-> dispose();
2416 ::comphelper::setProcessServiceFactory(nullptr);
2420 void vclmain::createApplication()
2423 _putenv_s("LIBO_VCL_DEMO", "1");
2425 setenv("LIBO_VCL_DEMO", "1", 0);
2427 static DemoApp aApp
;
2430 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */