bump product version to 5.0.4.1
[LibreOffice.git] / vcl / workben / vcldemo.cxx
blobfd8c01f8ab570bbb3f02e4a39c3a77a7d78ac084
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
10 #include <math.h>
11 #include <rtl/math.hxx>
13 #include <comphelper/processfactory.hxx>
14 #include <comphelper/random.hxx>
15 #include <cppuhelper/bootstrap.hxx>
16 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
17 #include <com/sun/star/lang/XInitialization.hpp>
18 #include <com/sun/star/registry/XSimpleRegistry.hpp>
19 #include <com/sun/star/ucb/UniversalContentBroker.hpp>
21 #include <osl/time.h>
22 #include <vcl/vclmain.hxx>
23 #include <vcl/layout.hxx>
24 #include <salhelper/thread.hxx>
26 #include <tools/urlobj.hxx>
27 #include <tools/stream.hxx>
28 #include <vcl/svapp.hxx>
29 #include <vcl/pngread.hxx>
30 #include <vcl/wrkwin.hxx>
31 #include <vcl/virdev.hxx>
32 #include <vcl/graphicfilter.hxx>
33 #include <vcl/button.hxx>
34 #include <vcl/toolbox.hxx>
35 #include <vcl/pngwrite.hxx>
36 #include <vcl/floatwin.hxx>
37 #include <vcl/salbtype.hxx>
38 #include <vcl/bmpacc.hxx>
39 #include <vcl/help.hxx>
41 #include <basegfx/numeric/ftools.hxx>
42 #include <basegfx/matrix/b2dhommatrix.hxx>
43 #include <vcldemo-debug.hxx>
44 #include <opengl/zone.hxx>
46 // internal headers for OpenGLTests class.
47 #include "salgdi.hxx"
48 #include "salframe.hxx"
49 #include "openglgdiimpl.hxx"
50 #include "opengl/texture.hxx"
51 #include "opengl/framebuffer.hxx"
52 #include <vcl/opengl/OpenGLHelper.hxx>
54 #include <rtl/math.hxx>
56 #define FIXME_SELF_INTERSECTING_WORKING 0
57 #define FIXME_BOUNCE_BUTTON 0
58 #define THUMB_REPEAT_FACTOR 10
60 using namespace com::sun::star;
62 namespace {
63 double getTimeNow()
65 TimeValue aValue;
66 osl_getSystemTime(&aValue);
67 return (double)aValue.Seconds * 1000 +
68 (double)aValue.Nanosec / (1000*1000);
73 using namespace css;
75 enum RenderStyle {
76 RENDER_THUMB, // small view <n> to a page
77 RENDER_EXPANDED, // expanded view of this renderer
80 class DemoRenderer
82 Bitmap maIntroBW;
83 BitmapEx maIntro;
85 int mnSegmentsX;
86 int mnSegmentsY;
88 struct RenderContext {
89 RenderStyle meStyle;
90 bool mbVDev;
91 DemoRenderer *mpDemoRenderer;
92 Size maSize;
94 struct RegionRenderer {
95 public:
96 RegionRenderer() :
97 sumTime(0),
98 countTime(0)
99 { }
100 virtual ~RegionRenderer() {}
101 virtual OUString getName() = 0;
102 virtual sal_uInt16 getAccelerator() = 0;
103 virtual void RenderRegion(OutputDevice &rDev, Rectangle r,
104 const RenderContext &rCtx) = 0;
105 // repeating count for profiling (to exceed the poor time resolution on Windows)
106 virtual sal_uInt16 getTestRepeatCount() = 0;
107 #define RENDER_DETAILS(name,key,repeat) \
108 virtual OUString getName() SAL_OVERRIDE \
109 { return OUString(SAL_STRINGIFY(name)); } \
110 virtual sal_uInt16 getAccelerator() SAL_OVERRIDE \
111 { return key; } \
112 virtual sal_uInt16 getTestRepeatCount() SAL_OVERRIDE \
113 { return repeat; }
115 double sumTime;
116 int countTime;
119 std::vector< RegionRenderer * > maRenderers;
120 sal_Int32 mnSelectedRenderer;
121 sal_Int32 iterCount;
123 void InitRenderers();
125 public:
126 DemoRenderer() : mnSegmentsX(0)
127 , mnSegmentsY(0)
128 , mnSelectedRenderer(-1)
129 , iterCount(0)
130 #if FIXME_BOUNCE_BUTTON
131 , mpButton(NULL)
132 , mpButtonWin(NULL)
133 , mnBounceX(1)
134 , mnBounceY(1)
135 #endif
137 if (!Application::LoadBrandBitmap("intro", maIntro))
138 Application::Abort("Failed to load intro image");
140 maIntroBW = maIntro.GetBitmap();
141 maIntroBW.Filter(BMP_FILTER_EMBOSS_GREY);
143 InitRenderers();
144 mnSegmentsX = rtl::math::round(sqrt(maRenderers.size()), 0,
145 rtl_math_RoundingMode_Up);
146 mnSegmentsY = rtl::math::round(sqrt(maRenderers.size()), 0,
147 rtl_math_RoundingMode_Down);
148 mnSegmentsY = floor(sqrt(maRenderers.size()));
151 OUString getRendererList();
152 double getAndResetBenchmark(RenderStyle style);
153 void selectRenderer(const OUString &rName);
154 int selectNextRenderer();
155 void setIterCount(sal_Int32 iterCount);
156 sal_Int32 getIterCount();
157 void addTime(int i, double t);
159 Size maSize;
160 void SetSizePixel(const Size &rSize) { maSize = rSize; }
161 Size GetSizePixel() const { return maSize; }
164 // more of a 'Window' concept - push upwards ?
165 #if FIXME_BOUNCE_BUTTON
166 // Bouncing windows on click ...
167 PushButton *mpButton;
168 FloatingWindow *mpButtonWin;
169 AutoTimer maBounce;
170 int mnBounceX, mnBounceY;
171 DECL_LINK(BounceTimerCb, void *);
172 #endif
174 bool MouseButtonDown(const MouseEvent& rMEvt);
175 void KeyInput(const KeyEvent& rKEvt);
177 static std::vector<Rectangle> partition(const RenderContext &rCtx, int nX, int nY)
179 return partition(rCtx.maSize, nX, nY);
182 static std::vector<Rectangle> partition(Size aSize, int nX, int nY)
184 Rectangle r;
185 std::vector<Rectangle> aRegions;
187 // Make small cleared area for these guys
188 long nBorderSize = aSize.Width() / 32;
189 long nBoxWidth = (aSize.Width() - nBorderSize*(nX+1)) / nX;
190 long nBoxHeight = (aSize.Height() - nBorderSize*(nY+1)) / nY;
191 for (int y = 0; y < nY; y++)
193 for (int x = 0; x < nX; x++)
195 r.SetPos(Point(nBorderSize + (nBorderSize + nBoxWidth) * x,
196 nBorderSize + (nBorderSize + nBoxHeight) * y));
197 r.SetSize(Size(nBoxWidth, nBoxHeight));
198 aRegions.push_back(r);
202 return aRegions;
205 static void clearRects(OutputDevice &rDev, std::vector<Rectangle> &rRects)
207 for (size_t i = 0; i < rRects.size(); i++)
209 // knock up a nice little border
210 rDev.SetLineColor(COL_GRAY);
211 rDev.SetFillColor(COL_LIGHTGRAY);
212 if (i % 2)
214 int nBorderSize = rRects[i].GetWidth() / 5;
215 rDev.DrawRect(rRects[i], nBorderSize, nBorderSize);
217 else
218 rDev.DrawRect(rRects[i]);
222 static void drawBackground(OutputDevice &rDev, const Rectangle& r)
224 rDev.Erase();
225 Gradient aGradient;
226 aGradient.SetStartColor(COL_BLUE);
227 aGradient.SetEndColor(COL_GREEN);
228 aGradient.SetStyle(GradientStyle_LINEAR);
229 rDev.DrawGradient(r, aGradient);
232 struct DrawLines : public RegionRenderer
234 RENDER_DETAILS(lines,KEY_L,100)
235 virtual void RenderRegion(OutputDevice &rDev, Rectangle r,
236 const RenderContext &rCtx) SAL_OVERRIDE
238 if (rCtx.meStyle == RENDER_EXPANDED)
240 AntialiasingFlags nOldAA = rDev.GetAntialiasing();
241 rDev.SetAntialiasing(AntialiasingFlags::EnableB2dDraw);
243 std::vector<Rectangle> aRegions(DemoRenderer::partition(rCtx, 4, 4));
244 DemoRenderer::clearRects(rDev, aRegions);
246 #if 0 // FIXME: get this through to the backend ...
247 double nTransparency[] = {
248 1.0, 1.0, 1.0, 1.0,
249 0.8, 0.8, 0.8, 0.8,
250 0.5, 0.5, 0.5, 0.5,
251 0.1, 0.1, 0.1, 0.1
253 #endif
254 drawing::LineCap eLineCaps[] = {
255 drawing::LineCap_BUTT, drawing::LineCap_ROUND, drawing::LineCap_SQUARE, drawing::LineCap_BUTT,
256 drawing::LineCap_BUTT, drawing::LineCap_ROUND, drawing::LineCap_SQUARE, drawing::LineCap_BUTT,
257 drawing::LineCap_BUTT, drawing::LineCap_ROUND, drawing::LineCap_SQUARE, drawing::LineCap_BUTT,
258 drawing::LineCap_BUTT, drawing::LineCap_ROUND, drawing::LineCap_SQUARE, drawing::LineCap_BUTT
260 ::basegfx::B2DLineJoin eJoins[] = {
261 basegfx::B2DLINEJOIN_NONE, basegfx::B2DLINEJOIN_MIDDLE, basegfx::B2DLINEJOIN_BEVEL, basegfx::B2DLINEJOIN_MITER,
262 basegfx::B2DLINEJOIN_ROUND, basegfx::B2DLINEJOIN_NONE, basegfx::B2DLINEJOIN_MIDDLE, basegfx::B2DLINEJOIN_BEVEL,
263 basegfx::B2DLINEJOIN_MITER, basegfx::B2DLINEJOIN_ROUND, basegfx::B2DLINEJOIN_NONE, basegfx::B2DLINEJOIN_MIDDLE,
264 basegfx::B2DLINEJOIN_BEVEL, basegfx::B2DLINEJOIN_MITER, basegfx::B2DLINEJOIN_ROUND, basegfx::B2DLINEJOIN_NONE
266 double aLineWidths[] = {
267 10.0, 15.0, 20.0, 10.0,
268 10.0, 15.0, 20.0, 10.0,
269 10.0, 15.0, 20.0, 10.0,
270 0.1, 1.0, 10.0, 50.0
272 for (size_t i = 0; i < aRegions.size(); i++)
274 // Half of them not-anti-aliased ..
275 if (i >= aRegions.size()/2)
276 rDev.SetAntialiasing(nOldAA);
278 static const struct {
279 double nX, nY;
280 } aPoints[] = {
281 { 0.2, 0.2 }, { 0.8, 0.3 }, { 0.7, 0.8 }
283 rDev.SetLineColor(Color(COL_BLACK));
284 basegfx::B2DPolygon aPoly;
285 Rectangle aSub(aRegions[i]);
286 for (size_t j = 0; j < SAL_N_ELEMENTS(aPoints); j++)
288 aPoly.append(basegfx::B2DPoint(aSub.Left() + aSub.GetWidth() * aPoints[j].nX,
289 aSub.Top() + aSub.GetHeight() * aPoints[j].nY));
291 rDev.DrawPolyLine(aPoly, aLineWidths[i], eJoins[i], eLineCaps[i]);
294 else
296 rDev.SetFillColor(Color(COL_LIGHTRED));
297 rDev.SetLineColor(Color(COL_BLACK));
298 rDev.DrawRect(r);
300 for(int i=0; i<r.GetHeight(); i+=15)
301 rDev.DrawLine(Point(r.Left(), r.Top()+i), Point(r.Right(), r.Bottom()-i));
302 for(int i=0; i<r.GetWidth(); i+=15)
303 rDev.DrawLine(Point(r.Left()+i, r.Bottom()), Point(r.Right()-i, r.Top()));
305 // Should draw a white-line across the middle
306 Color aLastPixel(COL_WHITE);
307 Point aCenter((r.Left() + r.Right())/2 - 4,
308 (r.Top() + r.Bottom())/2 - 4);
309 for(int i=0; i<8; i++)
311 rDev.DrawPixel(aCenter, aLastPixel);
312 aLastPixel = rDev.GetPixel(aCenter);
313 aCenter.Move(1,1);
319 struct DrawText : public RegionRenderer
321 RENDER_DETAILS(text,KEY_T,1)
323 virtual void RenderRegion(OutputDevice &rDev, Rectangle r,
324 const RenderContext &rCtx) SAL_OVERRIDE
326 if (rCtx.meStyle == RENDER_EXPANDED)
328 std::vector<Rectangle> aRegions(DemoRenderer::partition(rCtx, 4, 2));
329 DemoRenderer::clearRects(rDev, aRegions);
331 bool bClip=true, bArabicText=true, bRotate=true;
333 int nRegions=0;
335 for (int nClipRow=0; nClipRow < 2; nClipRow++)
337 if (!bArabicText)
338 bArabicText=true;
340 for (int nArabicRow=0; nArabicRow < 2; nArabicRow++)
342 if (!bRotate)
343 bRotate=true;
345 for (int nRotateRow=0; nRotateRow < 2; nRotateRow++)
347 drawText( rDev, aRegions[nRegions], bClip, bArabicText, bRotate );
349 nRegions++;
350 bRotate=false;
353 bArabicText=false;
356 bClip=false;
359 else
361 drawText(rDev, r, false, false, false);
365 static void drawText (OutputDevice &rDev, Rectangle r, bool bClip, bool bArabicText, bool bRotate)
367 rDev.SetClipRegion( vcl::Region(r) );
369 OUString aLatinText("Click any rect to zoom!!!!");
371 const unsigned char pTextUTF8[] = {
372 0xd9, 0x88, 0xd8, 0xa7, 0xd8, 0xad, 0xd9, 0x90,
373 0xd8, 0xaf, 0xd9, 0x92, 0x20, 0xd8, 0xa5, 0xd8,
374 0xab, 0xd9, 0x8d, 0xd9, 0x86, 0xd9, 0x8a, 0xd9,
375 0x86, 0x20, 0xd8, 0xab, 0xd9, 0x84, 0xd8, 0xa7,
376 0xd8, 0xab, 0xd8, 0xa9, 0xd9, 0x8c, 0x00
378 OUString aArabicText( reinterpret_cast<char const *>(pTextUTF8),
379 SAL_N_ELEMENTS( pTextUTF8 ) - 1,
380 RTL_TEXTENCODING_UTF8 );
382 OUString aText;
384 // To have more text displayed one after the other (overlapping, and in different colours), then
385 // change this value
386 const int nPrintNumCopies=1;
388 if (bArabicText)
389 aText = aArabicText;
390 else
391 aText = aLatinText;
393 std::vector<OUString> maFontNames;
395 sal_uInt32 nCols[] = {
396 COL_BLACK, COL_BLUE, COL_GREEN, COL_CYAN, COL_RED, COL_MAGENTA,
397 COL_BROWN, COL_GRAY, COL_LIGHTGRAY, COL_LIGHTBLUE, COL_LIGHTGREEN,
398 COL_LIGHTCYAN, COL_LIGHTRED, COL_LIGHTMAGENTA, COL_YELLOW, COL_WHITE
401 // a few fonts to start with
402 const char *pNames[] = {
403 "Times", "Liberation Sans", "Arial", "Linux Biolinum G", "Linux Libertine Display G"
406 size_t nNumFontNames = SAL_N_ELEMENTS(pNames);
408 for (size_t i = 0; i < nNumFontNames; i++)
409 maFontNames.push_back(OUString::createFromAscii(pNames[i]));
411 if (bClip && !bRotate)
413 // only show the first quarter of the text
414 Rectangle aRect( r.TopLeft(), Size( r.GetWidth()/2, r.GetHeight()/2 ) );
415 rDev.SetClipRegion( vcl::Region( aRect ) );
418 for (int i = 1; i < nPrintNumCopies+1; i++)
420 int nFontHeight=0, nFontIndex=0, nFontColorIndex=0;
422 if (nPrintNumCopies == 1)
424 float nFontMagnitude = 0.25f;
425 // random font size to avoid buffering
426 nFontHeight = 1 + nFontMagnitude * (0.9 + comphelper::rng::uniform_real_distribution(0.0, std::nextafter(0.1, DBL_MAX))) * (r.Bottom() - r.Top());
427 nFontIndex=0;
428 nFontColorIndex=0;
430 else
432 // random font size to avoid buffering
433 nFontHeight = 1 + i * (0.9 + comphelper::rng::uniform_real_distribution(0.0, std::nextafter(0.1, DBL_MAX))) * (r.Top() - r.Bottom()) / nPrintNumCopies;
434 nFontIndex = (i % maFontNames.size());
435 nFontColorIndex=(i % maFontNames.size());
438 rDev.SetTextColor(Color(nCols[nFontColorIndex]));
439 vcl::Font aFont( maFontNames[nFontIndex], Size(0, nFontHeight ));
441 if (bRotate)
443 Rectangle aFontRect = r;
445 int nHeight = r.GetHeight();
447 // move the text to the bottom of the bounding rect before rotating
448 aFontRect.Top() += nHeight;
449 aFontRect.Bottom() += nHeight;
451 int nDegrees = 45;
453 aFont.SetOrientation(nDegrees * 10);
455 rDev.SetFont(aFont);
456 rDev.DrawText(aFontRect, aText);
458 if (bClip)
460 Rectangle aClipRect( Point( r.Left(), r.Top() + ( r.GetHeight()/2 ) ) , Size( r.GetWidth()/2, r.GetHeight()/2 ) );
461 rDev.SetClipRegion( vcl::Region( aClipRect ) );
463 else
464 rDev.SetClipRegion( vcl::Region(r) );
466 else
468 rDev.SetFont(aFont);
469 rDev.DrawText(r, aText);
473 rDev.SetClipRegion();
477 struct DrawCheckered : public RegionRenderer
479 RENDER_DETAILS(checks,KEY_C,20)
480 virtual void RenderRegion(OutputDevice &rDev, Rectangle r,
481 const RenderContext &rCtx) SAL_OVERRIDE
483 if (rCtx.meStyle == RENDER_EXPANDED)
485 std::vector<Rectangle> aRegions(DemoRenderer::partition(rCtx, 2, 2));
486 for (size_t i = 0; i < aRegions.size(); i++)
488 vcl::Region aRegion;
489 Rectangle aSub(aRegions[i]);
490 Rectangle aSmaller(aSub);
491 aSmaller.Move(10,10);
492 aSmaller.setWidth(aSmaller.getWidth()-20);
493 aSmaller.setHeight(aSmaller.getHeight()-24);
494 switch (i) {
495 case 0:
496 aRegion = vcl::Region(aSub);
497 break;
498 case 1:
499 aRegion = vcl::Region(aSmaller);
500 aRegion.XOr(aSub);
501 break;
502 case 2:
504 Polygon aPoly(aSub);
505 aPoly.Rotate(aSub.Center(), 450);
506 aPoly.Clip(aSmaller);
507 aRegion = vcl::Region(aPoly);
508 break;
510 case 3:
512 tools::PolyPolygon aPolyPoly;
513 sal_Int32 nTW = aSub.GetWidth()/6;
514 sal_Int32 nTH = aSub.GetHeight()/6;
515 Rectangle aTiny(Point(4, 4), Size(nTW*2, nTH*2));
516 aPolyPoly.Insert(Polygon(aTiny));
517 aTiny.Move(nTW*3, nTH*3);
518 aPolyPoly.Insert(Polygon(aTiny));
519 aTiny.Move(nTW, nTH);
520 aPolyPoly.Insert(Polygon(aTiny));
522 aRegion = vcl::Region(aPolyPoly);
523 break;
525 } // switch
526 rDev.SetClipRegion(aRegion);
527 rDev.DrawCheckered(aSub.TopLeft(), aSub.GetSize());
528 rDev.SetClipRegion();
531 else
533 rDev.DrawCheckered(r.TopLeft(), r.GetSize());
538 struct DrawPoly : public RegionRenderer
540 RENDER_DETAILS(poly,KEY_P,20)
541 DrawCheckered maCheckered;
542 virtual void RenderRegion(OutputDevice &rDev, Rectangle r,
543 const RenderContext &rCtx) SAL_OVERRIDE
545 maCheckered.RenderRegion(rDev, r, rCtx);
547 long nDx = r.GetWidth()/20;
548 long nDy = r.GetHeight()/20;
549 Rectangle aShrunk(r);
550 aShrunk.Move(nDx, nDy);
551 aShrunk.SetSize(Size(r.GetWidth()-nDx*2,
552 r.GetHeight()-nDy*2));
553 Polygon aPoly(aShrunk);
554 tools::PolyPolygon aPPoly(aPoly);
555 rDev.SetLineColor(Color(COL_RED));
556 rDev.SetFillColor(Color(COL_RED));
557 // This hits the optional 'drawPolyPolygon' code-path
558 rDev.DrawTransparent(aPPoly, 64);
562 struct DrawEllipse : public RegionRenderer
564 RENDER_DETAILS(ellipse,KEY_E,5000)
565 virtual void RenderRegion(OutputDevice &rDev, Rectangle r,
566 const RenderContext &) SAL_OVERRIDE
568 rDev.SetLineColor(Color(COL_RED));
569 rDev.SetFillColor(Color(COL_GREEN));
570 rDev.DrawEllipse(r);
574 struct DrawGradient : public RegionRenderer
576 RENDER_DETAILS(gradient,KEY_G,50)
577 virtual void RenderRegion(OutputDevice &rDev, Rectangle r,
578 const RenderContext &rCtx) SAL_OVERRIDE
580 if (rCtx.meStyle == RENDER_EXPANDED)
582 std::vector<Rectangle> aRegions(DemoRenderer::partition(rCtx,5, 4));
583 sal_uInt32 nStartCols[] = {
584 COL_RED, COL_RED, COL_RED, COL_GREEN, COL_GREEN,
585 COL_BLUE, COL_BLUE, COL_BLUE, COL_CYAN, COL_CYAN,
586 COL_BLACK, COL_LIGHTGRAY, COL_WHITE, COL_BLUE, COL_CYAN,
587 COL_WHITE, COL_WHITE, COL_WHITE, COL_BLACK, COL_BLACK
589 sal_uInt32 nEndCols[] = {
590 COL_WHITE, COL_WHITE, COL_WHITE, COL_BLACK, COL_BLACK,
591 COL_RED, COL_RED, COL_RED, COL_GREEN, COL_GREEN,
592 COL_GRAY, COL_GRAY, COL_LIGHTGRAY, COL_LIGHTBLUE, COL_LIGHTCYAN,
593 COL_BLUE, COL_BLUE, COL_BLUE, COL_CYAN, COL_CYAN
595 GradientStyle eStyles[] = {
596 GradientStyle_LINEAR, GradientStyle_AXIAL, GradientStyle_RADIAL, GradientStyle_ELLIPTICAL, GradientStyle_SQUARE,
597 GradientStyle_RECT, GradientStyle_FORCE_EQUAL_SIZE, GradientStyle_LINEAR, GradientStyle_RADIAL, GradientStyle_LINEAR,
598 GradientStyle_LINEAR, GradientStyle_AXIAL, GradientStyle_RADIAL, GradientStyle_ELLIPTICAL, GradientStyle_SQUARE,
599 GradientStyle_RECT, GradientStyle_FORCE_EQUAL_SIZE, GradientStyle_LINEAR, GradientStyle_RADIAL, GradientStyle_LINEAR
601 sal_uInt16 nAngles[] = {
602 0, 0, 0, 0, 0,
603 15, 30, 45, 60, 75,
604 90, 120, 135, 160, 180,
605 0, 0, 0, 0, 0
607 sal_uInt16 nBorders[] = {
608 0, 0, 0, 0, 0,
609 1, 10, 100, 10, 1,
610 0, 0, 0, 0, 0,
611 1, 10, 20, 10, 1,
612 0, 0, 0, 0, 0
614 DemoRenderer::clearRects(rDev, aRegions);
615 assert(aRegions.size() <= SAL_N_ELEMENTS(nStartCols));
616 assert(aRegions.size() <= SAL_N_ELEMENTS(nEndCols));
617 assert(aRegions.size() <= SAL_N_ELEMENTS(eStyles));
618 assert(aRegions.size() <= SAL_N_ELEMENTS(nAngles));
619 assert(aRegions.size() <= SAL_N_ELEMENTS(nBorders));
620 for (size_t i = 0; i < aRegions.size(); i++)
622 Rectangle aSub = aRegions[i];
623 Gradient aGradient;
624 aGradient.SetStartColor(Color(nStartCols[i]));
625 aGradient.SetEndColor(Color(nEndCols[i]));
626 aGradient.SetStyle(eStyles[i]);
627 aGradient.SetAngle(nAngles[i]);
628 aGradient.SetBorder(nBorders[i]);
629 rDev.DrawGradient(aSub, aGradient);
632 else
634 Gradient aGradient;
635 aGradient.SetStartColor(COL_YELLOW);
636 aGradient.SetEndColor(COL_RED);
637 aGradient.SetStyle(GradientStyle_RECT);
638 aGradient.SetBorder(r.GetSize().Width()/20);
639 rDev.DrawGradient(r, aGradient);
644 struct DrawBitmap : public RegionRenderer
646 RENDER_DETAILS(bitmap,KEY_B,10)
648 // Simulate Page Borders rendering - which ultimately should
649 // be done with a shader / gradient
650 static void SimulateBorderStretch(OutputDevice &rDev, const Rectangle& r)
652 BitmapEx aPageShadowMask("sw/res/page-shadow-mask.png");
654 BitmapEx aRight(aPageShadowMask);
655 sal_Int32 nSlice = (aPageShadowMask.GetSizePixel().Width() - 3) / 4;
656 // a width x 1 slice
657 aRight.Crop(Rectangle(Point((nSlice * 3) + 3, (nSlice * 2) + 1),
658 Size(nSlice, 1)));
659 AlphaMask aAlphaMask(aRight.GetBitmap());
660 Bitmap aBlockColor = Bitmap(aAlphaMask.GetSizePixel(), 24);
661 aBlockColor.Erase(COL_RED);
662 BitmapEx aShadowStretch = BitmapEx(aBlockColor, aAlphaMask);
664 Point aRenderPt(r.TopLeft());
666 long aSizes[] = { 200, 100, 200, 100, 50, 5, 2 };
668 // and yes - we really do this in the page border rendering code ...
669 for (size_t i = 0; i < SAL_N_ELEMENTS(aSizes); i++)
671 aShadowStretch.Scale(Size(aShadowStretch.GetSizePixel().Width(), aSizes[i]),
672 BmpScaleFlag::Fast);
674 rDev.DrawBitmapEx(aRenderPt, aShadowStretch);
675 aRenderPt.Move(aShadowStretch.GetSizePixel().Width() + 4, 0);
678 AlphaMask aWholeMask(aPageShadowMask.GetBitmap());
679 aBlockColor = Bitmap(aPageShadowMask.GetSizePixel(), 24);
680 aBlockColor.Erase(COL_GREEN);
681 BitmapEx aWhole(aBlockColor, aWholeMask);
683 aRenderPt = Point(r.Center());
684 aRenderPt.Move(nSlice+1, 0);
686 // An offset background for alpha rendering
687 rDev.SetFillColor(COL_BLUE);
688 Rectangle aSurround(r.Center(), Size(aPageShadowMask.GetSizePixel()));
689 rDev.DrawRect(aSurround);
690 rDev.DrawBitmapEx(aRenderPt, aWhole);
693 virtual void RenderRegion(OutputDevice &rDev, Rectangle r,
694 const RenderContext &rCtx) SAL_OVERRIDE
696 Bitmap aBitmap(rCtx.mpDemoRenderer->maIntroBW);
697 aBitmap.Scale(r.GetSize(), BmpScaleFlag::BestQuality);
698 rDev.DrawBitmap(r.TopLeft(), aBitmap);
700 SimulateBorderStretch(rDev, r);
704 struct DrawBitmapEx : public RegionRenderer
706 RENDER_DETAILS(bitmapex,KEY_X,2)
707 DrawCheckered maCheckered;
708 virtual void RenderRegion(OutputDevice &rDev, Rectangle r,
709 const RenderContext &rCtx) SAL_OVERRIDE
711 maCheckered.RenderRegion(rDev, r, rCtx);
713 BitmapEx aBitmap(rCtx.mpDemoRenderer->maIntro);
714 aBitmap.Scale(r.GetSize(), BmpScaleFlag::BestQuality);
715 AlphaMask aSemiTransp(aBitmap.GetSizePixel());
716 aSemiTransp.Erase(64);
717 rDev.DrawBitmapEx(r.TopLeft(), BitmapEx(aBitmap.GetBitmap(),
718 aSemiTransp));
722 struct DrawPolyPolygons : public RegionRenderer
724 RENDER_DETAILS(polypoly,KEY_N,100)
725 virtual void RenderRegion(OutputDevice &rDev, Rectangle r,
726 const RenderContext &) SAL_OVERRIDE
728 struct {
729 double nX, nY;
730 } aPoints[] = { { 0.1, 0.1 }, { 0.9, 0.9 },
731 #if FIXME_SELF_INTERSECTING_WORKING
732 { 0.9, 0.1 }, { 0.1, 0.9 },
733 { 0.1, 0.1 }
734 #else
735 { 0.1, 0.9 }, { 0.5, 0.5 },
736 { 0.9, 0.1 }, { 0.1, 0.1 }
737 #endif
740 tools::PolyPolygon aPolyPoly;
741 // Render 4x polygons & aggregate into another PolyPolygon
742 for (int x = 0; x < 2; x++)
744 for (int y = 0; y < 2; y++)
746 Rectangle aSubRect(r);
747 aSubRect.Move(x * r.GetWidth()/3, y * r.GetHeight()/3);
748 aSubRect.SetSize(Size(r.GetWidth()/2, r.GetHeight()/4));
749 Polygon aPoly(SAL_N_ELEMENTS(aPoints));
750 for (size_t v = 0; v < SAL_N_ELEMENTS(aPoints); v++)
752 aPoly.SetPoint(Point(aSubRect.Left() +
753 aSubRect.GetWidth() * aPoints[v].nX,
754 aSubRect.Top() +
755 aSubRect.GetHeight() * aPoints[v].nY),
758 rDev.SetLineColor(Color(COL_YELLOW));
759 rDev.SetFillColor(Color(COL_BLACK));
760 rDev.DrawPolygon(aPoly);
762 // now move and add to the polypolygon
763 aPoly.Move(0, r.GetHeight()/2);
764 aPolyPoly.Insert(aPoly);
767 rDev.SetLineColor(Color(COL_LIGHTRED));
768 rDev.SetFillColor(Color(COL_GREEN));
769 rDev.DrawTransparent(aPolyPoly, 50);
773 struct DrawToVirtualDevice : public RegionRenderer
775 RENDER_DETAILS(vdev,KEY_V,1)
776 enum RenderType {
777 RENDER_AS_BITMAP,
778 RENDER_AS_OUTDEV,
779 RENDER_AS_BITMAPEX,
780 RENDER_AS_ALPHA_OUTDEV
783 static void SizeAndRender(OutputDevice &rDev, const Rectangle& r, RenderType eType,
784 const RenderContext &rCtx)
786 ScopedVclPtr<VirtualDevice> pNested;
788 if ((int)eType < RENDER_AS_BITMAPEX)
789 pNested = VclPtr<VirtualDevice>::Create(rDev).get();
790 else
791 pNested = VclPtr<VirtualDevice>::Create(rDev,0,0).get();
793 pNested->SetOutputSizePixel(r.GetSize());
794 Rectangle aWhole(Point(0,0), r.GetSize());
796 // mini me
797 rCtx.mpDemoRenderer->drawToDevice(*pNested, r.GetSize(), true);
799 if (eType == RENDER_AS_BITMAP)
801 Bitmap aBitmap(pNested->GetBitmap(Point(0,0),aWhole.GetSize()));
802 rDev.DrawBitmap(r.TopLeft(), aBitmap);
804 else if (eType == RENDER_AS_BITMAPEX)
806 BitmapEx aBitmapEx(pNested->GetBitmapEx(Point(0,0),aWhole.GetSize()));
807 rDev.DrawBitmapEx(r.TopLeft(), aBitmapEx);
809 else if (eType == RENDER_AS_OUTDEV ||
810 eType == RENDER_AS_ALPHA_OUTDEV)
812 rDev.DrawOutDev(r.TopLeft(), r.GetSize(),
813 aWhole.TopLeft(), aWhole.GetSize(),
814 *pNested);
817 virtual void RenderRegion(OutputDevice &rDev, Rectangle r,
818 const RenderContext &rCtx) SAL_OVERRIDE
820 // avoid infinite recursion
821 if (rCtx.mbVDev)
822 return;
824 if (rCtx.meStyle == RENDER_EXPANDED)
826 std::vector<Rectangle> aRegions(DemoRenderer::partition(rCtx,2, 2));
827 DemoRenderer::clearRects(rDev, aRegions);
829 RenderType eRenderTypes[] = { RENDER_AS_BITMAP, RENDER_AS_OUTDEV,
830 RENDER_AS_BITMAPEX, RENDER_AS_ALPHA_OUTDEV };
831 for (size_t i = 0; i < aRegions.size(); i++)
832 SizeAndRender(rDev, aRegions[i], eRenderTypes[i], rCtx);
834 else
835 SizeAndRender(rDev, r, RENDER_AS_BITMAP, rCtx);
839 struct DrawIcons : public RegionRenderer
841 RENDER_DETAILS(icons,KEY_I,1)
843 std::vector<OUString> maIconNames;
844 std::vector<BitmapEx> maIcons;
845 bool bHasLoadedAll;
846 DrawIcons() : bHasLoadedAll(false)
848 // a few icons to start with
849 const char *pNames[] = {
850 "cmd/lc_openurl.png",
851 "cmd/lc_newdoc.png",
852 "cmd/lc_choosemacro.png",
853 "cmd/lc_save.png",
854 "cmd/lc_saveas.png",
855 "cmd/lc_importdialog.png",
856 "cmd/lc_sendmail.png",
857 "cmd/lc_editdoc.png",
858 "cmd/lc_print.png",
859 "cmd/lc_combobox.png",
860 "cmd/lc_insertformcombo.png",
861 "cmd/lc_printpreview.png",
862 "cmd/lc_cut.png",
863 "cmd/lc_copy.png",
864 "cmd/lc_paste.png",
865 "cmd/sc_autopilotmenu.png",
866 "cmd/lc_formatpaintbrush.png",
867 "cmd/lc_undo.png",
868 "cmd/lc_redo.png",
869 "cmd/lc_marks.png",
870 "cmd/lc_fieldnames.png",
871 "cmd/lc_hyperlinkdialog.png",
873 for (size_t i = 0; i < SAL_N_ELEMENTS(pNames); i++)
875 maIconNames.push_back(OUString::createFromAscii(pNames[i]));
876 maIcons.push_back(BitmapEx(maIconNames[i]));
880 void LoadAllImages()
882 if (bHasLoadedAll)
883 return;
884 bHasLoadedAll = true;
886 css::uno::Sequence< OUString > aAllIcons = ImageTree_getAllImageNames();
887 for (sal_Int32 i = 0; i < aAllIcons.getLength(); i++)
889 maIconNames.push_back(aAllIcons[i]);
890 maIcons.push_back(BitmapEx(aAllIcons[i]));
894 void doDrawIcons(OutputDevice &rDev, Rectangle r, bool bExpanded)
896 long nMaxH = 0;
897 Point p(r.LeftCenter());
898 size_t nToRender = maIcons.size();
900 if (!bExpanded && maIcons.size() > 64)
901 nToRender = 64;
902 for (size_t i = 0; i < nToRender; i++)
904 Size aSize(maIcons[i].GetSizePixel());
905 // sAL_DEBUG("Draw icon '" << maIconNames[i] << "'");
907 if (!(i % 4))
908 rDev.DrawBitmapEx(p, maIcons[i]);
909 else
911 basegfx::B2DHomMatrix aTransform;
912 aTransform.scale(aSize.Width(), aSize.Height());
913 switch (i % 4)
915 case 2:
916 aTransform.shearX((double)((i >> 2) % 8) / 8);
917 aTransform.shearY((double)((i >> 4) % 8) / 8);
918 break;
919 case 3:
920 aTransform.translate(-aSize.Width()/2, -aSize.Height()/2);
921 aTransform.rotate(i);
922 if (i & 0x100)
924 aTransform.shearX((double)((i >> 2) % 8) / 8);
925 aTransform.shearY((double)((i >> 4) % 8) / 8);
927 aTransform.translate(aSize.Width()/2, aSize.Height()/2);
928 break;
929 default:
930 aTransform.translate(-aSize.Width()/2, -aSize.Height()/2);
931 aTransform.rotate(2 * F_2PI * i / nToRender);
932 aTransform.translate(aSize.Width()/2, aSize.Height()/2);
933 break;
935 aTransform.translate(p.X(), p.Y());
936 rDev.DrawTransformedBitmapEx(aTransform, maIcons[i]);
939 // next position
940 p.Move(aSize.Width(), 0);
941 if (aSize.Height() > nMaxH)
942 nMaxH = aSize.Height();
943 if (p.X() >= r.Right()) // wrap to next line
945 p = Point(r.Left(), p.Y() + nMaxH);
946 nMaxH = 0;
948 if (p.Y() >= r.Bottom()) // re-start at middle
949 p = r.LeftCenter();
953 static BitmapEx AlphaRecovery(OutputDevice &rDev, Point aPt, BitmapEx &aSrc)
955 // Compositing onto 2x colors beyond our control
956 ScopedVclPtrInstance< VirtualDevice > aWhite;
957 ScopedVclPtrInstance< VirtualDevice > aBlack;
958 aWhite->SetOutputSizePixel(aSrc.GetSizePixel());
959 aWhite->SetBackground(Wallpaper(COL_WHITE));
960 aWhite->Erase();
961 aBlack->SetOutputSizePixel(aSrc.GetSizePixel());
962 aBlack->SetBackground(Wallpaper(COL_BLACK));
963 aBlack->Erase();
964 aWhite->DrawBitmapEx(Point(), aSrc);
965 aBlack->DrawBitmapEx(Point(), aSrc);
967 // Now recover that alpha...
968 Bitmap aWhiteBmp = aWhite->GetBitmap(Point(),aSrc.GetSizePixel());
969 Bitmap aBlackBmp = aBlack->GetBitmap(Point(),aSrc.GetSizePixel());
970 AlphaMask aMask(aSrc.GetSizePixel());
971 Bitmap aRecovered(aSrc.GetSizePixel(), 24);
973 AlphaMask::ScopedWriteAccess pMaskAcc(aMask);
974 Bitmap::ScopedWriteAccess pRecAcc(aRecovered);
975 Bitmap::ScopedReadAccess pAccW(aWhiteBmp); // a * pix + (1-a)
976 Bitmap::ScopedReadAccess pAccB(aBlackBmp); // a * pix + 0
977 int nSizeX = aSrc.GetSizePixel().Width();
978 int nSizeY = aSrc.GetSizePixel().Height();
979 for (int y = 0; y < nSizeY; y++)
981 for (int x = 0; x < nSizeX; x++)
983 BitmapColor aColW = pAccW->GetPixel(y,x);
984 BitmapColor aColB = pAccB->GetPixel(y,x);
985 long nAR = (long)(aColW.GetRed() - aColB.GetRed()); // (1-a)
986 long nAG = (long)(aColW.GetGreen() - aColB.GetGreen()); // (1-a)
987 long nAB = (long)(aColW.GetBlue() - aColB.GetBlue()); // (1-a)
989 #define CLAMP(a,b,c) (((a)<=(b))?(b):(((a)>=(c))?(c):(a)))
991 // we get the most precision from the largest delta
992 long nInverseAlpha = std::max(nAR, std::max(nAG, nAB)); // (1-a)
993 nInverseAlpha = CLAMP(nInverseAlpha, 0, 255);
994 long nAlpha = 255 - nInverseAlpha;
996 pMaskAcc->SetPixel(y,x,BitmapColor((sal_Int8)CLAMP(nInverseAlpha,0,255)));
997 // now recover the pixels
998 long nR = (aColW.GetRed() + aColB.GetRed() - nInverseAlpha) * 128;
999 long nG = (aColW.GetGreen() + aColB.GetGreen() - nInverseAlpha) * 128;
1000 long nB = (aColW.GetBlue() + aColB.GetBlue() - nInverseAlpha) * 128;
1001 if (nAlpha == 0)
1002 { // doesn't matter what's behind transparency
1003 nR = nG = nB = 0;
1005 else
1007 nR /= nAlpha; nG /= nAlpha; nB /= nAlpha;
1009 pRecAcc->SetPixel(y,x,BitmapColor(
1010 (sal_uInt8)CLAMP(nR,0,255),
1011 (sal_uInt8)CLAMP(nG,0,255),
1012 (sal_uInt8)CLAMP(nB,0,255)));
1013 #undef CLAMP
1017 rDev.DrawBitmap(aPt, aWhiteBmp);
1018 aPt.Move(aSrc.GetSizePixel().Width(), 0);
1019 rDev.DrawBitmap(aPt, aBlackBmp);
1020 aPt.Move(aSrc.GetSizePixel().Width(), 0);
1021 rDev.DrawBitmap(aPt, aRecovered);
1022 aPt.Move(aSrc.GetSizePixel().Width(), 0);
1023 rDev.DrawBitmap(aPt, aMask.GetBitmap());
1024 aPt.Move(aSrc.GetSizePixel().Width(), 0);
1026 return BitmapEx(aRecovered, aMask);
1029 virtual void RenderRegion(OutputDevice &rDev, Rectangle r,
1030 const RenderContext &rCtx) SAL_OVERRIDE
1032 if (rCtx.meStyle == RENDER_EXPANDED)
1034 LoadAllImages();
1036 Point aLocation(0,maIcons[0].GetSizePixel().Height() + 8);
1037 for (size_t i = 0; i < 100; i++)
1039 BitmapEx aSrc = maIcons[i];
1041 // original above
1042 Point aAbove(aLocation);
1043 aAbove.Move(0,-aSrc.GetSizePixel().Height() - 4);
1044 rDev.DrawBitmapEx(aAbove, aSrc);
1045 aAbove.Move(aSrc.GetSizePixel().Width(),0);
1046 aAbove.Move(aSrc.GetSizePixel().Width(),0);
1047 rDev.DrawBitmap(aAbove, aSrc.GetBitmap());
1048 aAbove.Move(aSrc.GetSizePixel().Width(),0);
1049 rDev.DrawBitmap(aAbove, aSrc.GetMask());
1051 // intermediates middle
1052 BitmapEx aResult = AlphaRecovery(rDev, aLocation, aSrc);
1054 // result below
1055 Point aBelow(aLocation);
1056 aBelow.Move(0,aResult.GetSizePixel().Height());
1057 rDev.DrawBitmapEx(aBelow, aResult);
1059 aLocation.Move(aSrc.GetSizePixel().Width()*6,0);
1060 if (aLocation.X() > r.Right())
1061 aLocation = Point(0,aLocation.Y()+aSrc.GetSizePixel().Height()*3+4);
1064 // now go crazy with random foo
1065 doDrawIcons(rDev, r, true);
1067 else
1069 doDrawIcons(rDev, r, false);
1074 struct FetchDrawBitmap : public RegionRenderer
1076 RENDER_DETAILS(fetchdraw,KEY_F,50)
1077 virtual void RenderRegion(OutputDevice &rDev, Rectangle r,
1078 const RenderContext &) SAL_OVERRIDE
1080 Bitmap aBitmap(rDev.GetBitmap(Point(0,0),rDev.GetOutputSizePixel()));
1081 aBitmap.Scale(r.GetSize(), BmpScaleFlag::BestQuality);
1082 rDev.DrawBitmap(r.TopLeft(), aBitmap);
1086 void drawToDevice(vcl::RenderContext& rDev, Size aSize, bool bVDev)
1088 RenderContext aCtx;
1089 double mnStartTime;
1090 aCtx.mbVDev = bVDev;
1091 aCtx.mpDemoRenderer = this;
1092 aCtx.maSize = aSize;
1093 Rectangle aWholeWin(Point(0,0), rDev.GetOutputSizePixel());
1095 drawBackground(rDev, aWholeWin);
1097 if (!bVDev /* want everything in the vdev */ &&
1098 mnSelectedRenderer >= 0)
1100 aCtx.meStyle = RENDER_EXPANDED;
1101 RegionRenderer * r = maRenderers[mnSelectedRenderer];
1102 // profiling?
1103 if (getIterCount() > 0)
1105 mnStartTime = getTimeNow();
1106 for (int i = 0; i < r->getTestRepeatCount(); i++)
1107 r->RenderRegion(rDev, aWholeWin, aCtx);
1108 addTime(mnSelectedRenderer, getTimeNow() - mnStartTime);
1109 } else
1110 r->RenderRegion(rDev, aWholeWin, aCtx);
1112 else
1114 aCtx.meStyle = RENDER_THUMB;
1115 std::vector<Rectangle> aRegions(partition(aSize, mnSegmentsX, mnSegmentsY));
1116 DemoRenderer::clearRects(rDev, aRegions);
1117 for (size_t i = 0; i < maRenderers.size(); i++)
1119 RegionRenderer * r = maRenderers[i];
1121 rDev.SetClipRegion( vcl::Region( aRegions[i] ) );
1123 // profiling?
1124 if (getIterCount() > 0)
1126 if (!bVDev)
1128 mnStartTime = getTimeNow();
1129 for (int j = 0; j < r->getTestRepeatCount() * THUMB_REPEAT_FACTOR; j++)
1130 r->RenderRegion(rDev, aRegions[i], aCtx);
1131 addTime(i, (getTimeNow() - mnStartTime) / THUMB_REPEAT_FACTOR);
1132 } else
1133 for (int j = 0; j < r->getTestRepeatCount(); j++)
1134 r->RenderRegion(rDev, aRegions[i], aCtx);
1136 else
1138 r->RenderRegion(rDev, aRegions[i], aCtx);
1141 rDev.SetClipRegion();
1145 std::vector<VclPtr<vcl::Window> > maInvalidates;
1146 void addInvalidate(vcl::Window *pWindow) { maInvalidates.push_back(pWindow); };
1147 void removeInvalidate(vcl::Window *pWindow)
1149 for (auto aIt = maInvalidates.begin(); aIt != maInvalidates.end(); ++aIt)
1151 if (*aIt == pWindow)
1153 maInvalidates.erase(aIt);
1154 return;
1158 void Invalidate()
1160 for (size_t i = 0; i < maInvalidates.size(); ++i)
1161 maInvalidates[i]->Invalidate();
1165 #if FIXME_BOUNCE_BUTTON
1166 IMPL_LINK_NOARG(DemoRenderer,BounceTimerCb)
1168 mpButton->Check(mnBounceX>0);
1169 mpButton->SetPressed(mnBounceY>0);
1171 Point aCur = mpButtonWin->GetPosPixel();
1172 static const int nMovePix = 10;
1173 aCur.Move(mnBounceX * nMovePix, mnBounceX * nMovePix);
1174 Size aWinSize = GetSizePixel();
1175 if (aCur.X() <= 0 || aCur.X() >= aWinSize.Width())
1176 mnBounceX *= -1;
1177 if (aCur.Y() <= 0 || aCur.Y() >= aWinSize.Height())
1178 mnBounceX *= -1;
1179 mpButtonWin->SetPosPixel(aCur);
1181 // All smoke and mirrors to test sub-region invalidation underneath
1182 Rectangle aRect(aCur, mpButtonWin->GetSizePixel());
1183 Invalidate(aRect);
1184 return 0;
1186 #endif
1188 void DemoRenderer::KeyInput(const KeyEvent &rKEvt)
1190 sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
1192 // click to zoom out
1193 if (mnSelectedRenderer >= 0)
1195 if (nCode == KEY_ESCAPE || nCode == KEY_BACKSPACE)
1197 mnSelectedRenderer = -1;
1198 Invalidate();
1199 return;
1202 else
1204 for (size_t i = 0; i < maRenderers.size(); i++)
1206 if (nCode == maRenderers[i]->getAccelerator())
1208 mnSelectedRenderer = i;
1209 Invalidate();
1210 return;
1216 bool DemoRenderer::MouseButtonDown(const MouseEvent& rMEvt)
1218 // click to zoom out
1219 if (mnSelectedRenderer >= 0)
1221 mnSelectedRenderer = -1;
1222 Invalidate();
1223 return true;
1226 // click on a region to zoom into it
1227 std::vector<Rectangle> aRegions(partition(GetSizePixel(), mnSegmentsX, mnSegmentsY));
1228 for (size_t i = 0; i < aRegions.size(); i++)
1230 if (aRegions[i].IsInside(rMEvt.GetPosPixel()))
1232 mnSelectedRenderer = i;
1233 Invalidate();
1234 return true;
1238 #if FIXME_BOUNCE_BUTTON
1239 // otherwise bounce floating windows
1240 if (!mpButton)
1242 mpButtonWin = VclPtr<FloatingWindow>::Create(this);
1243 mpButton = VclPtr<PushButton>::Create(mpButtonWin);
1244 mpButton->SetSymbol(SymbolType::HELP);
1245 mpButton->SetText("PushButton demo");
1246 mpButton->SetPosSizePixel(Point(0,0), mpButton->GetOptimalSize());
1247 mpButton->Show();
1248 mpButtonWin->SetPosSizePixel(Point(0,0), mpButton->GetOptimalSize());
1249 mpButtonWin->Show();
1250 mnBounceX = 1; mnBounceX = 1;
1251 maBounce.SetTimeoutHdl(LINK(this,DemoRenderer,BounceTimerCb));
1252 maBounce.SetTimeout(55);
1253 maBounce.Start();
1255 else
1257 maBounce.Stop();
1258 delete mpButtonWin;
1259 mpButtonWin = NULL;
1260 mpButton = NULL;
1262 #endif
1263 return false;
1266 void DemoRenderer::InitRenderers()
1268 maRenderers.push_back(new DrawLines());
1269 maRenderers.push_back(new DrawText());
1270 maRenderers.push_back(new DrawPoly());
1271 maRenderers.push_back(new DrawEllipse());
1272 maRenderers.push_back(new DrawCheckered());
1273 maRenderers.push_back(new DrawBitmapEx());
1274 maRenderers.push_back(new DrawBitmap());
1275 maRenderers.push_back(new DrawGradient());
1276 maRenderers.push_back(new DrawPolyPolygons());
1277 maRenderers.push_back(new DrawToVirtualDevice());
1278 maRenderers.push_back(new DrawIcons());
1279 maRenderers.push_back(new FetchDrawBitmap());
1282 OUString DemoRenderer::getRendererList()
1284 OUStringBuffer aBuf;
1285 for (size_t i = 0; i < maRenderers.size(); i++)
1287 aBuf.append(maRenderers[i]->getName());
1288 aBuf.append(' ');
1290 return aBuf.makeStringAndClear();
1293 double DemoRenderer::getAndResetBenchmark(const RenderStyle style)
1295 double geomean = 1.0;
1296 fprintf(stderr, "Rendering: %s, Times (ms):\n", style == RENDER_THUMB ? "THUMB": "EXPANDED");
1297 for (size_t i = 0; i < maRenderers.size(); i++)
1299 double avgtime = maRenderers[i]->sumTime / maRenderers[i]->countTime;
1300 geomean *= avgtime;
1301 fprintf(stderr, "%s: %f (iteration: %d*%d*%d)\n",
1302 rtl::OUStringToOString(maRenderers[i]->getName(),
1303 RTL_TEXTENCODING_UTF8).getStr(), avgtime,
1304 maRenderers[i]->countTime, maRenderers[i]->getTestRepeatCount(),
1305 (style == RENDER_THUMB) ? THUMB_REPEAT_FACTOR : 1);
1306 maRenderers[i]->sumTime = 0;
1307 maRenderers[i]->countTime = 0;
1309 geomean = pow(geomean, static_cast<double>(1.0)/maRenderers.size());
1310 fprintf(stderr, "GEOMEAN_%s: %f\n", style == RENDER_THUMB ? "THUMB": "EXPANDED", geomean);
1311 return geomean;
1314 void DemoRenderer::setIterCount(sal_Int32 i)
1316 iterCount = i;
1319 sal_Int32 DemoRenderer::getIterCount()
1321 return iterCount;
1324 void DemoRenderer::addTime(int i, double t)
1326 maRenderers[i]->sumTime += t / maRenderers[i]->getTestRepeatCount();
1327 maRenderers[i]->countTime++;
1330 void DemoRenderer::selectRenderer(const OUString &rName )
1332 for (size_t i = 0; i < maRenderers.size(); i++)
1334 if (maRenderers[i]->getName() == rName)
1336 mnSelectedRenderer = i;
1337 Invalidate();
1338 return;
1343 int DemoRenderer::selectNextRenderer()
1345 mnSelectedRenderer++;
1346 if (mnSelectedRenderer == (signed) maRenderers.size())
1347 mnSelectedRenderer = -1;
1348 Invalidate();
1349 return mnSelectedRenderer;
1352 class DemoWin : public WorkWindow
1354 DemoRenderer &mrRenderer;
1355 bool underTesting;
1356 bool testThreads;
1358 class RenderThread : public salhelper::Thread {
1359 DemoWin &mrWin;
1360 TimeValue maDelay;
1361 public:
1362 RenderThread(DemoWin &rWin, sal_uInt32 nDelaySecs)
1363 : Thread("vcldemo render thread")
1364 , mrWin(rWin)
1366 maDelay.Seconds = nDelaySecs;
1367 maDelay.Nanosec = 0;
1368 launch();
1370 virtual ~RenderThread()
1372 join();
1374 virtual void execute() SAL_OVERRIDE
1376 osl_waitThread(&maDelay);
1378 SolarMutexGuard aGuard;
1379 fprintf (stderr, "render from a different thread\n");
1380 mrWin.Invalidate();
1383 rtl::Reference<RenderThread> mxThread;
1385 public:
1386 DemoWin(DemoRenderer &rRenderer, bool bThreads) :
1387 WorkWindow(NULL, WB_APP | WB_STDWORK),
1388 mrRenderer(rRenderer),
1389 testThreads(bThreads)
1391 mrRenderer.addInvalidate(this);
1392 underTesting = false;
1394 virtual ~DemoWin()
1396 disposeOnce();
1398 virtual void dispose() SAL_OVERRIDE
1400 mxThread.clear();
1401 mrRenderer.removeInvalidate(this);
1402 WorkWindow::dispose();
1404 virtual void MouseButtonDown(const MouseEvent& rMEvt) SAL_OVERRIDE
1406 mrRenderer.SetSizePixel(GetSizePixel());
1407 if (!mrRenderer.MouseButtonDown(rMEvt))
1409 if (testThreads)
1410 { // render this window asynchronously in a new thread
1411 sal_uInt32 nDelaySecs = 0;
1412 if (rMEvt.GetButtons() & MOUSE_RIGHT)
1413 nDelaySecs = 5;
1414 mxThread = new RenderThread(*this, nDelaySecs);
1416 else
1417 { // spawn another window
1418 VclPtrInstance<DemoWin> pNewWin(mrRenderer, testThreads);
1419 pNewWin->SetText("Another interactive VCL demo window");
1420 pNewWin->Show();
1424 virtual void KeyInput(const KeyEvent& rKEvt) SAL_OVERRIDE
1426 mrRenderer.SetSizePixel(GetSizePixel());
1427 mrRenderer.KeyInput(rKEvt);
1429 virtual void Paint(vcl::RenderContext& rRenderContext, const Rectangle& rRect) SAL_OVERRIDE
1431 mrRenderer.SetSizePixel(GetSizePixel());
1432 fprintf(stderr, "DemoWin::Paint(%ld,%ld,%ld,%ld)\n", rRect.getX(), rRect.getY(), rRect.getWidth(), rRect.getHeight());
1433 if (mrRenderer.getIterCount() == 0)
1434 mrRenderer.drawToDevice(rRenderContext, GetSizePixel(), false);
1435 else
1436 TestAndQuit(rRenderContext);
1439 void TestAndQuit(vcl::RenderContext& rRenderContext)
1441 if (underTesting)
1442 return;
1443 underTesting = true;
1444 for (sal_Int32 i = 0; i < mrRenderer.getIterCount(); i++)
1446 while (mrRenderer.selectNextRenderer() > -1)
1448 mrRenderer.drawToDevice(rRenderContext, GetSizePixel(), false);
1452 double expandedGEOMEAN = mrRenderer.getAndResetBenchmark(RENDER_EXPANDED);
1454 for (sal_Int32 i = 0; i < mrRenderer.getIterCount(); i++)
1455 mrRenderer.drawToDevice(rRenderContext, GetSizePixel(), false);
1457 double thumbGEOMEAN = mrRenderer.getAndResetBenchmark(RENDER_THUMB);
1459 fprintf(stderr, "GEOMEAN_TOTAL: %f\n", pow(thumbGEOMEAN * expandedGEOMEAN, static_cast<double>(0.5)));
1460 Application::Quit();
1464 class DemoWidgets : public WorkWindow
1466 VclPtr<VclBox> mpBox;
1467 VclPtr<ToolBox> mpToolbox;
1468 VclPtr<PushButton> mpButton;
1469 VclPtr<VclHBox> mpHBox;
1470 VclPtr<CheckBox> mpGLCheck;
1471 VclPtr<ComboBox> mpGLCombo;
1472 VclPtr<PushButton> mpGLButton;
1474 DECL_LINK(GLTestClick, void *);
1476 public:
1477 DemoWidgets() :
1478 WorkWindow(NULL, WB_STDWORK),
1479 mpBox(VclPtrInstance<VclVBox>(this, false, 3)),
1480 mpToolbox(VclPtrInstance<ToolBox>(mpBox.get())),
1481 mpButton(VclPtrInstance<PushButton>(mpBox.get())),
1482 mpHBox(VclPtrInstance<VclHBox>(mpBox.get(), true, 3)),
1483 mpGLCheck(VclPtrInstance<CheckBox>(mpHBox.get())),
1484 mpGLCombo(VclPtrInstance<ComboBox>(mpHBox.get())),
1485 mpGLButton(VclPtrInstance<PushButton>(mpHBox.get()))
1487 SetText("VCL widget demo");
1489 Wallpaper aWallpaper(BitmapEx("sfx2/res/startcenter-logo.png"));
1490 aWallpaper.SetStyle(WALLPAPER_BOTTOMRIGHT);
1491 aWallpaper.SetColor(COL_RED);
1493 mpBox->SetBackground(aWallpaper);
1494 mpBox->Show();
1496 Help::EnableBalloonHelp();
1497 mpToolbox->SetHelpText("Help text");
1498 mpToolbox->InsertItem(0, "Toolbar item");
1499 mpToolbox->SetQuickHelpText(0, "This is a tooltip popup");
1500 mpToolbox->InsertSeparator();
1501 mpToolbox->Show();
1503 mpButton->SetText("Click me; go on");
1504 mpButton->Show();
1506 mpGLCheck->SetText("Test in OGL zone");
1507 mpGLCheck->Show();
1508 mpGLCombo->InsertEntry("sleep 1 second");
1509 mpGLCombo->InsertEntry("sleep 3 seconds");
1510 mpGLCombo->InsertEntry("sleep 7 seconds");
1511 mpGLCombo->SelectEntryPos(2);
1512 mpGLCombo->Show();
1513 mpGLButton->SetText("Execute test");
1514 mpGLButton->SetClickHdl(LINK(this,DemoWidgets,GLTestClick));
1515 mpGLButton->Show();
1516 mpHBox->Show();
1518 Show();
1520 virtual ~DemoWidgets() { disposeOnce(); }
1521 virtual void dispose() SAL_OVERRIDE
1523 mpGLButton.disposeAndClear();
1524 mpGLCombo.disposeAndClear();
1525 mpGLCheck.disposeAndClear();
1526 mpHBox.disposeAndClear();
1527 mpBox.disposeAndClear();
1528 mpToolbox.disposeAndClear();
1529 mpButton.disposeAndClear();
1530 WorkWindow::dispose();
1532 virtual void Paint(vcl::RenderContext& /*rRenderContext*/, const Rectangle&) SAL_OVERRIDE
1534 Rectangle aWholeSize(Point(0, 0),GetOutputSizePixel());
1535 vcl::Region aClip(aWholeSize);
1536 Rectangle aExclude(Rectangle(Point(50,50),Size(100,100)));
1537 aClip.Exclude(aExclude);
1539 Wallpaper aWallpaper(COL_GREEN);
1541 Push(PushFlags::CLIPREGION);
1542 IntersectClipRegion(aClip);
1543 DrawWallpaper(aWholeSize, aWallpaper);
1544 Pop();
1546 ScopedVclPtrInstance< VirtualDevice > pDev(*this);
1547 pDev->EnableRTL(IsRTLEnabled());
1548 pDev->SetOutputSizePixel(aExclude.GetSize());
1550 Rectangle aSubRect(aWholeSize);
1551 aSubRect.Move(-aExclude.Left(), -aExclude.Top());
1552 pDev->DrawWallpaper(aSubRect, aWallpaper );
1554 DrawOutDev(aExclude.TopLeft(), aExclude.GetSize(),
1555 Point( 0, 0 ), aExclude.GetSize(), *pDev.get() );
1559 class OpenGLZoneTest {
1560 public:
1561 static void enter() { OpenGLZone::enter(); }
1562 static void leave() { OpenGLZone::leave(); }
1565 IMPL_LINK_NOARG(DemoWidgets,GLTestClick)
1567 sal_Int32 nSelected = mpGLCombo->GetSelectEntryPos();
1569 TimeValue aDelay;
1570 aDelay.Seconds = 0;
1571 aDelay.Nanosec = 0;
1572 switch (nSelected)
1574 case 0:
1575 aDelay.Seconds = 1;
1576 break;
1577 case 1:
1578 aDelay.Seconds = 3;
1579 break;
1580 case 2:
1581 aDelay.Seconds = 7;
1582 break;
1583 default:
1584 break;
1587 bool bEnterLeave = mpGLCheck->IsChecked();
1588 if (bEnterLeave)
1589 OpenGLZoneTest::enter();
1591 osl_waitThread(&aDelay);
1593 if (bEnterLeave)
1594 OpenGLZoneTest::leave();
1596 return 0;
1599 class DemoPopup : public FloatingWindow
1601 public:
1602 DemoPopup() : FloatingWindow( NULL, WB_SYSTEMWINDOW|WB_TOOLTIPWIN)
1604 SetType( WINDOW_HELPTEXTWINDOW );
1606 SetOutputSizePixel( Size( 300, 30 ) );
1607 SetBackground(Wallpaper(COL_YELLOW));
1609 Show( true, SHOW_NOACTIVATE );
1610 Update();
1613 virtual void Paint(vcl::RenderContext& /*rRenderContext*/, const Rectangle&) SAL_OVERRIDE
1615 // Interestingly in GL mode on Windows, this doesn't render.
1617 Size aSize = GetOutputSizePixel();
1618 Rectangle aTextRect(Point(6, 6), aSize);
1620 SetTextColor(COL_BLACK);
1621 SetTextAlign(ALIGN_TOP);
1622 DrawText(aTextRect, "This is a standalone help text test",
1623 DrawTextFlags::MultiLine|DrawTextFlags::WordBreak|
1624 DrawTextFlags::Left|DrawTextFlags::Top);
1626 SetLineColor(COL_BLACK);
1627 SetFillColor();
1628 DrawRect( Rectangle( Point(), aSize ) );
1629 aSize.Width() -= 2;
1630 aSize.Height() -= 2;
1631 Color aColor( GetLineColor() );
1632 SetLineColor( ( COL_GRAY ) );
1633 DrawRect( Rectangle( Point( 1, 1 ), aSize ) );
1634 SetLineColor( aColor );
1638 class OpenGLTests
1640 VclPtr<WorkWindow> mxWinA;
1641 VclPtr<WorkWindow> mxWinB;
1642 OpenGLSalGraphicsImpl *mpImplA;
1643 OpenGLSalGraphicsImpl *mpImplB;
1644 rtl::Reference<OpenGLContext> mpA;
1645 rtl::Reference<OpenGLContext> mpB;
1647 static OpenGLSalGraphicsImpl *getImpl(const VclPtr<WorkWindow> &xWin)
1649 SalGraphics *pGraphics = xWin->GetGraphics();
1650 return dynamic_cast<OpenGLSalGraphicsImpl *>(pGraphics->GetImpl());
1652 public:
1653 OpenGLTests() :
1654 mxWinA(VclPtr<WorkWindow>::Create(nullptr, WB_APP | WB_STDWORK)),
1655 mxWinB(VclPtr<WorkWindow>::Create(nullptr, WB_APP | WB_STDWORK))
1657 if (!OpenGLHelper::isVCLOpenGLEnabled())
1659 fprintf (stderr, "OpenGL is not enabled: try SAL_FORCEGL=1\n");
1660 return;
1663 mpImplA = getImpl(mxWinA);
1664 mpImplB = getImpl(mxWinB);
1665 assert (mpImplA && mpImplB);
1666 mpA = mpImplA->GetOpenGLContext();
1667 mpB = mpImplB->GetOpenGLContext();
1669 assert (mpA.is() && mpB.is());
1670 assert (mpA != mpB);
1672 ~OpenGLTests()
1674 mxWinB.disposeAndClear();
1675 mxWinA.disposeAndClear();
1678 void testCurrentFramebuffer()
1680 fprintf(stderr,"test OpenGLContext's framebuffer association.\n");
1681 mpA->makeCurrent();
1682 OpenGLFramebuffer *pBuffer;
1684 OpenGLTexture aTexture(256,128);
1685 pBuffer = mpA->AcquireFramebuffer(aTexture);
1686 pBuffer->DetachTexture(); // TESTME - remove this line too ...
1688 assert (pBuffer->IsFree());
1689 mpB->makeCurrent();
1690 assert (mpA->mpCurrentFramebuffer == NULL);
1693 int execute()
1695 if (!OpenGLHelper::isVCLOpenGLEnabled())
1696 return 1;
1698 testCurrentFramebuffer();
1700 return 0;
1704 class DemoApp : public Application
1706 static int showHelp(DemoRenderer &rRenderer)
1708 fprintf(stderr,"vcldemo - a VCL test app\n");
1709 fprintf(stderr," --help - print this text\n");
1710 fprintf(stderr," --show <renderer> - start with a given renderer, options are:\n");
1711 OUString aRenderers(rRenderer.getRendererList());
1712 fprintf(stderr," %s\n",
1713 rtl::OUStringToOString(aRenderers, RTL_TEXTENCODING_UTF8).getStr());
1714 fprintf(stderr," --test <iterCount> - create benchmark data\n");
1715 fprintf(stderr," --widgets - launch the widget test.\n");
1716 fprintf(stderr," --threads - render from multiple threads.\n");
1717 fprintf(stderr," --gltest - run openGL regression tests.\n");
1718 fprintf(stderr, "\n");
1719 return 0;
1722 public:
1723 DemoApp() {}
1725 virtual int Main() SAL_OVERRIDE
1729 bool bWidgets = false, bThreads = false;
1730 bool bPopup = false, bGLTest = false;
1731 DemoRenderer aRenderer;
1733 for (sal_Int32 i = 0; i < GetCommandLineParamCount(); i++)
1735 bool bLast = i == GetCommandLineParamCount() - 1;
1736 OUString aArg = GetCommandLineParam(i);
1737 if (aArg == "--help" || aArg == "-h")
1738 return showHelp(aRenderer);
1739 if (aArg == "--show")
1741 if (bLast)
1742 return showHelp(aRenderer);
1743 else
1744 aRenderer.selectRenderer(GetCommandLineParam(++i));
1746 else if (aArg == "--test")
1748 if (bLast)
1749 return showHelp(aRenderer);
1750 else
1751 aRenderer.setIterCount(GetCommandLineParam(++i).toInt32());
1753 else if (aArg == "--widgets")
1754 bWidgets = true;
1755 else if (aArg == "--popup")
1756 bPopup = true;
1757 else if (aArg == "--gltest")
1758 bGLTest = true;
1759 else if (aArg == "--threads")
1760 bThreads = true;
1761 else if (aArg.startsWith("--"))
1763 fprintf(stderr,"Unknown argument '%s'\n",
1764 rtl::OUStringToOString(aArg, RTL_TEXTENCODING_UTF8).getStr());
1765 return showHelp(aRenderer);
1769 ScopedVclPtrInstance<DemoWin> aMainWin(aRenderer, bThreads);
1770 VclPtr<DemoWidgets> xWidgets;
1771 VclPtr<DemoPopup> xPopup;
1773 aMainWin->SetText("Interactive VCL demo #1");
1775 if (bGLTest)
1777 OpenGLTests aTests;
1778 return aTests.execute();
1780 else if (bWidgets)
1781 xWidgets = VclPtr< DemoWidgets >::Create ();
1782 else if (bPopup)
1783 xPopup = VclPtrInstance< DemoPopup> ();
1784 else
1785 aMainWin->Show();
1787 Application::Execute();
1789 xWidgets.disposeAndClear();
1790 xPopup.disposeAndClear();
1792 catch (const css::uno::Exception& e)
1794 SAL_WARN("vcl.app", "Fatal exception: " << e.Message);
1795 return 1;
1797 catch (const std::exception& e)
1799 SAL_WARN("vcl.app", "Fatal exception: " << e.what());
1800 return 1;
1802 return 0;
1805 protected:
1806 uno::Reference<lang::XMultiServiceFactory> xMSF;
1807 void Init() SAL_OVERRIDE
1811 uno::Reference<uno::XComponentContext> xComponentContext
1812 = ::cppu::defaultBootstrap_InitialComponentContext();
1813 xMSF = uno::Reference<lang::XMultiServiceFactory>
1814 (xComponentContext->getServiceManager(), uno::UNO_QUERY);
1815 if(!xMSF.is())
1816 Application::Abort("Bootstrap failure - no service manager");
1818 ::comphelper::setProcessServiceFactory(xMSF);
1820 catch (const uno::Exception &e)
1822 Application::Abort("Bootstrap exception " + e.Message);
1825 void DeInit() SAL_OVERRIDE
1827 uno::Reference< lang::XComponent >(
1828 comphelper::getProcessComponentContext(),
1829 uno::UNO_QUERY_THROW)-> dispose();
1830 ::comphelper::setProcessServiceFactory(NULL);
1834 void vclmain::createApplication()
1836 static DemoApp aApp;
1839 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */