Version 5.4.3.2, tag libreoffice-5.4.3.2
[LibreOffice.git] / vcl / workben / vcldemo.cxx
blobf86d3280d4543b307e7b9efabef90b288a7d49e3
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 <config_features.h>
12 #include <math.h>
13 #include <rtl/math.hxx>
15 #include <comphelper/processfactory.hxx>
16 #include <comphelper/random.hxx>
17 #include <cppuhelper/bootstrap.hxx>
18 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
19 #include <com/sun/star/lang/XInitialization.hpp>
20 #include <com/sun/star/registry/XSimpleRegistry.hpp>
21 #include <com/sun/star/ucb/UniversalContentBroker.hpp>
22 #include <com/sun/star/uno/Reference.hxx>
23 #include <com/sun/star/uno/Sequence.hxx>
24 #include <com/sun/star/container/XNameAccess.hpp>
26 #include <osl/time.h>
27 #include <vcl/vclmain.hxx>
28 #include <vcl/layout.hxx>
29 #include <salhelper/thread.hxx>
31 #include <tools/urlobj.hxx>
32 #include <tools/stream.hxx>
33 #include <vcl/svapp.hxx>
34 #include <vcl/pngread.hxx>
35 #include <vcl/wrkwin.hxx>
36 #include <vcl/virdev.hxx>
37 #include <vcl/graphicfilter.hxx>
38 #include <vcl/button.hxx>
39 #include <vcl/toolbox.hxx>
40 #include <vcl/pngwrite.hxx>
41 #include <vcl/floatwin.hxx>
42 #include <vcl/salbtype.hxx>
43 #include <vcl/bitmapaccess.hxx>
44 #include <vcl/help.hxx>
45 #include <vcl/menu.hxx>
46 #include <vcl/ImageTree.hxx>
48 #include <basegfx/numeric/ftools.hxx>
49 #include <basegfx/matrix/b2dhommatrix.hxx>
50 #include <opengl/zone.hxx>
52 // internal headers for OpenGLTests class.
53 #if HAVE_FEATURE_OPENGL
54 #include "salgdi.hxx"
55 #include "salframe.hxx"
56 #include "openglgdiimpl.hxx"
57 #include "opengl/texture.hxx"
58 #include "opengl/framebuffer.hxx"
59 #include <vcl/opengl/OpenGLHelper.hxx>
60 #endif
62 #define FIXME_SELF_INTERSECTING_WORKING 0
63 #define FIXME_BOUNCE_BUTTON 0
64 #define THUMB_REPEAT_FACTOR 10
66 using namespace com::sun::star;
68 namespace {
69 double getTimeNow()
71 TimeValue aValue;
72 osl_getSystemTime(&aValue);
73 return (double)aValue.Seconds * 1000 +
74 (double)aValue.Nanosec / (1000*1000);
79 using namespace css;
81 enum RenderStyle {
82 RENDER_THUMB, // small view <n> to a page
83 RENDER_EXPANDED, // expanded view of this renderer
86 class DemoRenderer
88 Bitmap maIntroBW;
89 BitmapEx maIntro;
91 int mnSegmentsX;
92 int mnSegmentsY;
94 struct RenderContext {
95 RenderStyle meStyle;
96 bool mbVDev;
97 DemoRenderer *mpDemoRenderer;
98 Size maSize;
100 struct RegionRenderer {
101 public:
102 RegionRenderer() :
103 sumTime(0),
104 countTime(0)
106 virtual ~RegionRenderer() {}
107 virtual OUString getName() = 0;
108 virtual sal_uInt16 getAccelerator() = 0;
109 virtual void RenderRegion(OutputDevice &rDev, tools::Rectangle r,
110 const RenderContext &rCtx) = 0;
111 // repeating count for profiling (to exceed the poor time resolution on Windows)
112 virtual sal_uInt16 getTestRepeatCount() = 0;
113 #define RENDER_DETAILS(name,key,repeat) \
114 virtual OUString getName() override \
115 { return OUString(SAL_STRINGIFY(name)); } \
116 virtual sal_uInt16 getAccelerator() override \
117 { return key; } \
118 virtual sal_uInt16 getTestRepeatCount() override \
119 { return repeat; }
121 double sumTime;
122 int countTime;
125 std::vector< RegionRenderer * > maRenderers;
126 sal_Int32 mnSelectedRenderer;
127 sal_Int32 iterCount;
129 void InitRenderers();
131 public:
132 DemoRenderer() : mnSegmentsX(0)
133 , mnSegmentsY(0)
134 , mnSelectedRenderer(-1)
135 , iterCount(0)
136 #if FIXME_BOUNCE_BUTTON
137 , mpButton(NULL)
138 , mpButtonWin(NULL)
139 , mnBounceX(1)
140 , mnBounceY(1)
141 #endif
143 if (!Application::LoadBrandBitmap("intro", maIntro))
144 Application::Abort("Failed to load intro image");
146 maIntroBW = maIntro.GetBitmap();
147 maIntroBW.Filter(BmpFilter::EmbossGrey);
149 InitRenderers();
150 mnSegmentsY = rtl::math::round(std::sqrt(maRenderers.size()), 0,
151 rtl_math_RoundingMode_Down);
152 mnSegmentsX = (maRenderers.size() + mnSegmentsY - 1)/mnSegmentsY;
155 OUString getRendererList();
156 double getAndResetBenchmark(RenderStyle style);
157 void selectRenderer(const OUString &rName);
158 int selectNextRenderer();
159 void setIterCount(sal_Int32 iterCount);
160 sal_Int32 getIterCount();
161 void addTime(int i, double t);
163 Size maSize;
164 void SetSizePixel(const Size &rSize) { maSize = rSize; }
165 const Size& GetSizePixel() const { return maSize; }
168 // more of a 'Window' concept - push upwards ?
169 #if FIXME_BOUNCE_BUTTON
170 // Bouncing windows on click ...
171 PushButton *mpButton;
172 FloatingWindow *mpButtonWin;
173 AutoTimer maBounce;
174 int mnBounceX, mnBounceY;
175 DECL_LINK(BounceTimerCb, Timer*, void);
176 #endif
178 bool MouseButtonDown(const MouseEvent& rMEvt);
179 void KeyInput(const KeyEvent& rKEvt);
181 static std::vector<tools::Rectangle> partition(const tools::Rectangle &rRect, int nX, int nY)
183 std::vector<tools::Rectangle> aRegions = partition(rRect.GetSize(), nX, nY);
184 for (auto it = aRegions.begin(); it != aRegions.end(); ++it)
185 it->Move(rRect.Left(), rRect.Top());
187 return aRegions;
190 static std::vector<tools::Rectangle> partition(const RenderContext &rCtx, int nX, int nY)
192 return partition(rCtx.maSize, nX, nY);
195 static std::vector<tools::Rectangle> partition(Size aSize, int nX, int nY)
197 tools::Rectangle r;
198 std::vector<tools::Rectangle> aRegions;
200 // Make small cleared area for these guys
201 long nBorderSize = std::min(aSize.Height() / 32, aSize.Width() / 32);
202 long nBoxWidth = (aSize.Width() - nBorderSize*(nX+1)) / nX;
203 long nBoxHeight = (aSize.Height() - nBorderSize*(nY+1)) / nY;
204 for (int y = 0; y < nY; y++)
206 for (int x = 0; x < nX; x++)
208 r.SetPos(Point(nBorderSize + (nBorderSize + nBoxWidth) * x,
209 nBorderSize + (nBorderSize + nBoxHeight) * y));
210 r.SetSize(Size(nBoxWidth, nBoxHeight));
211 aRegions.push_back(r);
215 return aRegions;
218 static void clearRects(OutputDevice &rDev, std::vector<tools::Rectangle> &rRects)
220 for (size_t i = 0; i < rRects.size(); i++)
222 // knock up a nice little border
223 rDev.SetLineColor(COL_GRAY);
224 rDev.SetFillColor(COL_LIGHTGRAY);
225 if (i % 2)
227 int nBorderSize = rRects[i].GetWidth() / 5;
228 rDev.DrawRect(rRects[i], nBorderSize, nBorderSize);
230 else
231 rDev.DrawRect(rRects[i]);
235 static void drawBackground(OutputDevice &rDev, const tools::Rectangle& r)
237 rDev.Erase();
238 Gradient aGradient;
239 aGradient.SetStartColor(COL_BLUE);
240 aGradient.SetEndColor(COL_GREEN);
241 aGradient.SetStyle(GradientStyle::Linear);
242 rDev.DrawGradient(r, aGradient);
245 struct DrawLines : public RegionRenderer
247 RENDER_DETAILS(lines,KEY_L,100)
248 virtual void RenderRegion(OutputDevice &rDev, tools::Rectangle r,
249 const RenderContext &rCtx) override
251 if (rCtx.meStyle == RENDER_EXPANDED)
253 AntialiasingFlags nOldAA = rDev.GetAntialiasing();
254 rDev.SetAntialiasing(AntialiasingFlags::EnableB2dDraw);
256 std::vector<tools::Rectangle> aRegions(DemoRenderer::partition(rCtx, 4, 4));
257 DemoRenderer::clearRects(rDev, aRegions);
259 #if 0 // FIXME: get this through to the backend ...
260 double nTransparency[] = {
261 1.0, 1.0, 1.0, 1.0,
262 0.8, 0.8, 0.8, 0.8,
263 0.5, 0.5, 0.5, 0.5,
264 0.1, 0.1, 0.1, 0.1
266 #endif
267 drawing::LineCap eLineCaps[] = {
268 drawing::LineCap_BUTT, drawing::LineCap_ROUND, drawing::LineCap_SQUARE, drawing::LineCap_BUTT,
269 drawing::LineCap_BUTT, drawing::LineCap_ROUND, drawing::LineCap_SQUARE, drawing::LineCap_BUTT,
270 drawing::LineCap_BUTT, drawing::LineCap_ROUND, drawing::LineCap_SQUARE, drawing::LineCap_BUTT,
271 drawing::LineCap_BUTT, drawing::LineCap_ROUND, drawing::LineCap_SQUARE, drawing::LineCap_BUTT
273 basegfx::B2DLineJoin eJoins[] = {
274 basegfx::B2DLineJoin::NONE, basegfx::B2DLineJoin::Bevel, basegfx::B2DLineJoin::Miter, basegfx::B2DLineJoin::Round,
275 basegfx::B2DLineJoin::NONE, basegfx::B2DLineJoin::Bevel, basegfx::B2DLineJoin::Miter, basegfx::B2DLineJoin::Round,
276 basegfx::B2DLineJoin::NONE, basegfx::B2DLineJoin::Bevel, basegfx::B2DLineJoin::Miter, basegfx::B2DLineJoin::Round,
277 basegfx::B2DLineJoin::NONE, basegfx::B2DLineJoin::Bevel, basegfx::B2DLineJoin::Miter, basegfx::B2DLineJoin::Round
279 double aLineWidths[] = {
280 10.0, 15.0, 20.0, 10.0,
281 10.0, 15.0, 20.0, 10.0,
282 10.0, 15.0, 20.0, 10.0,
283 0.1, 1.0, 10.0, 50.0
285 for (size_t i = 0; i < aRegions.size(); i++)
287 // Half of them not-anti-aliased ..
288 if (i >= aRegions.size()/2)
289 rDev.SetAntialiasing(nOldAA);
291 static const struct {
292 double nX, nY;
293 } aPoints[] = {
294 { 0.2, 0.2 }, { 0.8, 0.3 }, { 0.7, 0.8 }
296 rDev.SetLineColor(Color(COL_BLACK));
297 basegfx::B2DPolygon aPoly;
298 tools::Rectangle aSub(aRegions[i]);
299 for (size_t j = 0; j < SAL_N_ELEMENTS(aPoints); j++)
301 aPoly.append(basegfx::B2DPoint(aSub.Left() + aSub.GetWidth() * aPoints[j].nX,
302 aSub.Top() + aSub.GetHeight() * aPoints[j].nY));
304 rDev.DrawPolyLine(aPoly, aLineWidths[i], eJoins[i], eLineCaps[i]);
307 else
309 rDev.SetFillColor(Color(COL_LIGHTRED));
310 rDev.SetLineColor(Color(COL_BLACK));
311 rDev.DrawRect(r);
313 for(long i=0; i<r.GetHeight(); i+=15)
314 rDev.DrawLine(Point(r.Left(), r.Top()+i), Point(r.Right(), r.Bottom()-i));
315 for(long i=0; i<r.GetWidth(); i+=15)
316 rDev.DrawLine(Point(r.Left()+i, r.Bottom()), Point(r.Right()-i, r.Top()));
318 // Should draw a white-line across the middle
319 Color aLastPixel(COL_WHITE);
320 Point aCenter((r.Left() + r.Right())/2 - 4,
321 (r.Top() + r.Bottom())/2 - 4);
322 for(int i=0; i<8; i++)
324 rDev.DrawPixel(aCenter, aLastPixel);
325 aLastPixel = rDev.GetPixel(aCenter);
326 aCenter.Move(1,1);
332 struct DrawText : public RegionRenderer
334 RENDER_DETAILS(text,KEY_T,1)
336 virtual void RenderRegion(OutputDevice &rDev, tools::Rectangle r,
337 const RenderContext &rCtx) override
339 if (rCtx.meStyle == RENDER_EXPANDED)
341 std::vector<tools::Rectangle> aToplevelRegions(
342 DemoRenderer::partition(rCtx, 1, 3));
343 std::vector<tools::Rectangle> aSubRegions(
344 DemoRenderer::partition(aToplevelRegions[0], 4, 2));
345 tools::Rectangle aBottom(aToplevelRegions[1].TopLeft(),
346 aToplevelRegions[2].BottomRight());
347 DemoRenderer::clearRects(rDev,aSubRegions);
348 struct {
349 bool mbClip;
350 bool mbArabicText;
351 bool mbRotate;
352 } aRenderData[] = {
353 { false, false, false },
354 { false, true, false },
355 { false, true, true },
356 { false, false, true },
357 { true, false, true },
358 { true, true, true },
359 { true, true, false },
360 { true, false, false },
363 size_t i = 0;
364 for (int y = 0; y < 2; y++)
366 for (int x = 0; x < 4; x++)
368 assert(i < SAL_N_ELEMENTS(aRenderData));
369 drawText(rDev, aSubRegions[i], aRenderData[i].mbClip,
370 aRenderData[i].mbArabicText, aRenderData[i].mbRotate);
371 i++;
375 drawComplex(rDev, aBottom);
377 else
379 drawText(rDev, r, false, false, false);
383 static void drawText (OutputDevice &rDev, tools::Rectangle r, bool bClip, bool bArabicText, bool bRotate)
385 rDev.SetClipRegion( vcl::Region(r) );
387 OUString aLatinText("Click any rect to zoom!!!!");
389 const unsigned char pTextUTF8[] = {
390 0xd9, 0x88, 0xd8, 0xa7, 0xd8, 0xad, 0xd9, 0x90,
391 0xd8, 0xaf, 0xd9, 0x92, 0x20, 0xd8, 0xa5, 0xd8,
392 0xab, 0xd9, 0x8d, 0xd9, 0x86, 0xd9, 0x8a, 0xd9,
393 0x86, 0x20, 0xd8, 0xab, 0xd9, 0x84, 0xd8, 0xa7,
394 0xd8, 0xab, 0xd8, 0xa9, 0xd9, 0x8c, 0x00
396 OUString aArabicText( reinterpret_cast<char const *>(pTextUTF8),
397 SAL_N_ELEMENTS( pTextUTF8 ) - 1,
398 RTL_TEXTENCODING_UTF8 );
400 OUString aText;
402 // To have more text displayed one after the other (overlapping, and in different colours), then
403 // change this value
404 const int nPrintNumCopies=1;
406 if (bArabicText)
407 aText = aArabicText;
408 else
409 aText = aLatinText;
411 std::vector<OUString> aFontNames;
413 sal_uInt32 nCols[] = {
414 COL_BLACK, COL_BLUE, COL_GREEN, COL_CYAN, COL_RED, COL_MAGENTA,
415 COL_BROWN, COL_GRAY, COL_LIGHTGRAY, COL_LIGHTBLUE, COL_LIGHTGREEN,
416 COL_LIGHTCYAN, COL_LIGHTRED, COL_LIGHTMAGENTA, COL_YELLOW, COL_WHITE
419 // a few fonts to start with
420 const char *pNames[] = {
421 "Times", "Liberation Sans", "Arial", "Linux Biolinum G", "Linux Libertine Display G"
424 size_t nNumFontNames = SAL_N_ELEMENTS(pNames);
426 for (size_t i = 0; i < nNumFontNames; i++)
427 aFontNames.push_back(OUString::createFromAscii(pNames[i]));
429 if (bClip && !bRotate)
431 // only show the first quarter of the text
432 tools::Rectangle aRect( r.TopLeft(), Size( r.GetWidth()/2, r.GetHeight()/2 ) );
433 rDev.SetClipRegion( vcl::Region( aRect ) );
436 for (int i = 1; i < nPrintNumCopies+1; i++)
438 int nFontHeight=0, nFontIndex=0, nFontColorIndex=0;
440 if (nPrintNumCopies == 1)
442 float nFontMagnitude = 0.25f;
443 // random font size to avoid buffering
444 nFontHeight = 1 + nFontMagnitude * (0.9 + comphelper::rng::uniform_real_distribution(0.0, std::nextafter(0.1, DBL_MAX))) * (r.Bottom() - r.Top());
445 nFontIndex=0;
446 nFontColorIndex=0;
448 else
450 // random font size to avoid buffering
451 nFontHeight = 1 + i * (0.9 + comphelper::rng::uniform_real_distribution(0.0, std::nextafter(0.1, DBL_MAX))) * (r.Top() - r.Bottom()) / nPrintNumCopies;
452 nFontIndex = (i % aFontNames.size());
453 nFontColorIndex=(i % aFontNames.size());
456 rDev.SetTextColor(Color(nCols[nFontColorIndex]));
457 vcl::Font aFont( aFontNames[nFontIndex], Size(0, nFontHeight ));
459 if (bRotate)
461 tools::Rectangle aFontRect = r;
463 int nHeight = r.GetHeight();
465 // move the text to the bottom of the bounding rect before rotating
466 aFontRect.Top() += nHeight/2;
467 aFontRect.Bottom() += nHeight;
469 int nDegrees = 45;
471 aFont.SetOrientation(nDegrees * 10);
473 rDev.SetFont(aFont);
474 rDev.DrawText(aFontRect, aText);
476 if (bClip)
478 tools::Rectangle aClipRect( Point( r.Left(), r.Top() + ( r.GetHeight()/2 ) ) , Size( r.GetWidth()/2, r.GetHeight()/2 ) );
479 rDev.SetClipRegion( vcl::Region( aClipRect ) );
481 else
482 rDev.SetClipRegion( vcl::Region(r) );
484 else
486 rDev.SetFont(aFont);
487 rDev.DrawText(r, aText);
491 rDev.SetClipRegion();
494 static void drawComplex (OutputDevice &rDev, tools::Rectangle r)
496 const unsigned char pInvalid[] = { 0xfe, 0x1f, 0 };
497 const unsigned char pDiacritic1[] = { 0x61, 0xcc, 0x8a, 0xcc, 0x8c, 0 };
498 const unsigned char pDiacritic2[] = { 0x61, 0xcc, 0x88, 0xcc, 0x86, 0 };
499 const unsigned char pDiacritic3[] = { 0x61, 0xcc, 0x8b, 0xcc, 0x87, 0 };
500 const unsigned char pJustification[] = {
501 0x64, 0x20, 0xc3, 0xa1, 0xc3, 0xa9, 0x77, 0xc4, 0x8d,
502 0xc5, 0xa1, 0xc3, 0xbd, 0xc5, 0x99, 0x20, 0xc4, 0x9b, 0
504 const unsigned char pEmojis[] = {
505 0xf0, 0x9f, 0x8d, 0x80, 0xf0, 0x9f, 0x91, 0x98,
506 0xf0, 0x9f, 0x92, 0x8a, 0xf0, 0x9f, 0x92, 0x99,
507 0xf0, 0x9f, 0x92, 0xa4, 0xf0, 0x9f, 0x94, 0x90, 0
509 const unsigned char pThreeBowlG[] = {
510 0xe2, 0x9a, 0x82, 0xe2, 0x99, 0xa8, 0xc4, 0x9e, 0
512 const unsigned char pWavesAndDomino[] = {
513 0xe2, 0x99, 0x92, 0xf0, 0x9f, 0x81, 0xa0,
514 0xf0, 0x9f, 0x82, 0x93, 0
516 const unsigned char pSpadesAndBits[] = {
517 0xf0, 0x9f, 0x82, 0xa1, 0xc2, 0xa2, 0xc2, 0xa2, 0
520 struct {
521 const char *mpFont;
522 const char *mpString;
523 } aRuns[] = {
524 #define SET(font,string) { font, reinterpret_cast<const char *>(string) }
525 SET("sans", "a"), // logical font - no 'sans' font.
526 SET("opensymbol", "#$%"), // font fallback - $ is missing.
527 SET("sans", pInvalid), // unicode invalid character character
528 // tdf#96266 - stacking diacritics
529 SET("carlito", pDiacritic1),
530 SET("carlito", pDiacritic2),
531 SET("carlito", pDiacritic3),
532 SET("liberation sans", pDiacritic1),
533 SET("liberation sans", pDiacritic2),
534 SET("liberation sans", pDiacritic3),
535 SET("liberation sans", pDiacritic3),
537 // tdf#95222 - justification issue
538 // - FIXME: replicate justification
539 SET("gentium basic", pJustification),
541 // tdf#97319 - Unicode beyond BMP; SMP & Plane 2
542 SET("symbola", pEmojis),
543 SET("symbola", pThreeBowlG),
544 SET("symbola", pWavesAndDomino),
545 SET("symbola", pSpadesAndBits),
548 // Nice clean white background
549 rDev.DrawWallpaper(r, Wallpaper(COL_WHITE));
550 rDev.SetClipRegion(vcl::Region(r));
552 Point aPos(r.Left(), r.Top()+20);
554 long nMaxTextHeight = 0;
555 for (size_t i = 0; i < SAL_N_ELEMENTS(aRuns); ++i)
557 // Legend
558 vcl::Font aIndexFont("sans", Size(0,20));
559 aIndexFont.SetColor(COL_BLACK);
560 tools::Rectangle aTextRect;
561 rDev.SetFont(aIndexFont);
562 OUString aText = OUString::number(i) + ".";
563 rDev.DrawText(aPos, aText);
564 if (rDev.GetTextBoundRect(aTextRect, aText))
565 aPos.Move(aTextRect.GetWidth() + 8, 0);
567 // Text
568 FontWeight aWeights[] = { WEIGHT_NORMAL,
569 WEIGHT_BOLD,
570 WEIGHT_NORMAL };
571 FontItalic aItalics[] = { ITALIC_NONE,
572 ITALIC_NONE,
573 ITALIC_NORMAL };
574 vcl::Font aFont(OUString::createFromAscii(
575 aRuns[i].mpFont),
576 Size(0,42));
577 aFont.SetColor(COL_BLACK);
578 for (size_t j = 0; j < SAL_N_ELEMENTS(aWeights); ++j)
580 aFont.SetItalic(aItalics[j]);
581 aFont.SetWeight(aWeights[j]);
582 rDev.SetFont(aFont);
584 OUString aString(aRuns[i].mpString,
585 strlen(aRuns[i].mpString),
586 RTL_TEXTENCODING_UTF8);
587 long nNewX = drawStringBox(rDev, aPos, aString,
588 nMaxTextHeight);
590 aPos.X() = nNewX;
592 if (aPos.X() >= r.Right())
594 aPos = Point(r.Left(), aPos.Y() + nMaxTextHeight + 15);
595 nMaxTextHeight = 0;
596 if(j>0)
597 j--; // re-render the last point.
599 if (aPos.Y() > r.Bottom())
600 break;
602 if (aPos.Y() > r.Bottom())
603 break;
606 rDev.SetClipRegion();
608 // render text, bbox, DX arrays etc.
609 static long drawStringBox(OutputDevice &rDev, Point aPos,
610 const OUString &aText,
611 long &nMaxTextHeight)
613 rDev.Push();
615 tools::Rectangle aTextRect;
617 rDev.DrawText(aPos,aText);
619 if (rDev.GetTextBoundRect(aTextRect, aText))
621 aTextRect.Move(aPos.X(), aPos.Y());
622 rDev.SetFillColor();
623 rDev.SetLineColor(COL_BLACK);
624 rDev.DrawRect(aTextRect);
625 if (aTextRect.GetHeight() > nMaxTextHeight)
626 nMaxTextHeight = aTextRect.GetHeight();
627 // This should intersect with the text
628 tools::Rectangle aInnerRect(
629 aTextRect.Left()+1, aTextRect.Top()+1,
630 aTextRect.Right()-1, aTextRect.Bottom()-1);
631 rDev.SetLineColor(COL_WHITE);
632 rDev.SetRasterOp(RasterOp::Xor);
633 rDev.DrawRect(aInnerRect);
634 rDev.SetRasterOp(RasterOp::OverPaint);
637 // DX array rendering
638 long *pItems = new long[aText.getLength()+10];
639 rDev.GetTextArray(aText, pItems);
640 for (long j = 0; j < aText.getLength(); ++j)
642 Point aTop = aTextRect.TopLeft();
643 Point aBottom = aTop;
644 aTop.Move(pItems[j], 0);
645 aBottom.Move(pItems[j], aTextRect.GetHeight());
646 rDev.SetLineColor(COL_RED);
647 rDev.SetRasterOp(RasterOp::Xor);
648 rDev.DrawLine(aTop,aBottom);
649 rDev.SetRasterOp(RasterOp::OverPaint);
651 delete[] pItems;
653 aPos.Move(aTextRect.GetWidth() + 16, 0);
655 rDev.Pop();
656 return aPos.X();
660 struct DrawCheckered : public RegionRenderer
662 RENDER_DETAILS(checks,KEY_C,20)
663 virtual void RenderRegion(OutputDevice &rDev, tools::Rectangle r,
664 const RenderContext &rCtx) override
666 if (rCtx.meStyle == RENDER_EXPANDED)
668 std::vector<tools::Rectangle> aRegions(DemoRenderer::partition(rCtx, 2, 2));
669 for (size_t i = 0; i < aRegions.size(); i++)
671 vcl::Region aRegion;
672 tools::Rectangle aSub(aRegions[i]);
673 tools::Rectangle aSmaller(aSub);
674 aSmaller.Move(10,10);
675 aSmaller.setWidth(aSmaller.getWidth()-20);
676 aSmaller.setHeight(aSmaller.getHeight()-24);
677 switch (i) {
678 case 0:
679 aRegion = vcl::Region(aSub);
680 break;
681 case 1:
682 aRegion = vcl::Region(aSmaller);
683 aRegion.XOr(aSub);
684 break;
685 case 2:
687 tools::Polygon aPoly(aSub);
688 aPoly.Rotate(aSub.Center(), 450);
689 aPoly.Clip(aSmaller);
690 aRegion = vcl::Region(aPoly);
691 break;
693 case 3:
695 tools::PolyPolygon aPolyPoly;
696 sal_Int32 nTW = aSub.GetWidth()/6;
697 sal_Int32 nTH = aSub.GetHeight()/6;
698 tools::Rectangle aTiny(Point(4, 4), Size(nTW*2, nTH*2));
699 aPolyPoly.Insert( tools::Polygon(aTiny));
700 aTiny.Move(nTW*3, nTH*3);
701 aPolyPoly.Insert( tools::Polygon(aTiny));
702 aTiny.Move(nTW, nTH);
703 aPolyPoly.Insert( tools::Polygon(aTiny));
705 aRegion = vcl::Region(aPolyPoly);
706 break;
708 } // switch
709 rDev.SetClipRegion(aRegion);
710 rDev.DrawCheckered(aSub.TopLeft(), aSub.GetSize());
711 rDev.SetClipRegion();
714 else
716 rDev.DrawCheckered(r.TopLeft(), r.GetSize());
721 struct DrawPoly : public RegionRenderer
723 RENDER_DETAILS(poly,KEY_P,20)
724 DrawCheckered maCheckered;
725 virtual void RenderRegion(OutputDevice &rDev, tools::Rectangle r,
726 const RenderContext &rCtx) override
728 maCheckered.RenderRegion(rDev, r, rCtx);
730 long nDx = r.GetWidth()/20;
731 long nDy = r.GetHeight()/20;
732 tools::Rectangle aShrunk(r);
733 aShrunk.Move(nDx, nDy);
734 aShrunk.SetSize(Size(r.GetWidth()-nDx*2,
735 r.GetHeight()-nDy*2));
736 tools::Polygon aPoly(aShrunk);
737 tools::PolyPolygon aPPoly(aPoly);
738 rDev.SetLineColor(Color(COL_RED));
739 rDev.SetFillColor(Color(COL_RED));
740 // This hits the optional 'drawPolyPolygon' code-path
741 rDev.DrawTransparent(aPPoly, 64);
745 struct DrawEllipse : public RegionRenderer
747 RENDER_DETAILS(ellipse,KEY_E,500)
748 static void doInvert(OutputDevice &rDev, const tools::Rectangle &r,
749 InvertFlags nFlags)
751 rDev.Invert(r, nFlags);
752 if (r.GetWidth() > 10 && r.GetHeight() > 10)
754 tools::Rectangle aSmall(r.Center()-Point(4,4), Size(8,8));
755 rDev.Invert(aSmall,nFlags);
758 virtual void RenderRegion(OutputDevice &rDev, tools::Rectangle r,
759 const RenderContext &rCtx) override
761 rDev.SetLineColor(Color(COL_RED));
762 rDev.SetFillColor(Color(COL_GREEN));
763 rDev.DrawEllipse(r);
765 if (rCtx.meStyle == RENDER_EXPANDED)
767 auto aRegions = partition(rCtx, 2, 2);
768 doInvert(rDev, aRegions[0], InvertFlags::NONE);
769 doInvert(rDev, aRegions[1], InvertFlags::N50);
770 doInvert(rDev, aRegions[2], InvertFlags::Highlight);
771 doInvert(rDev, aRegions[3], (InvertFlags)0xffff);
776 struct DrawGradient : public RegionRenderer
778 RENDER_DETAILS(gradient,KEY_G,50)
779 virtual void RenderRegion(OutputDevice &rDev, tools::Rectangle r,
780 const RenderContext &rCtx) override
782 if (rCtx.meStyle == RENDER_EXPANDED)
784 std::vector<tools::Rectangle> aRegions(DemoRenderer::partition(rCtx,5, 4));
785 sal_uInt32 nStartCols[] = {
786 COL_RED, COL_RED, COL_RED, COL_GREEN, COL_GREEN,
787 COL_BLUE, COL_BLUE, COL_BLUE, COL_CYAN, COL_CYAN,
788 COL_BLACK, COL_LIGHTGRAY, COL_WHITE, COL_BLUE, COL_CYAN,
789 COL_WHITE, COL_WHITE, COL_WHITE, COL_BLACK, COL_BLACK
791 sal_uInt32 nEndCols[] = {
792 COL_WHITE, COL_WHITE, COL_WHITE, COL_BLACK, COL_BLACK,
793 COL_RED, COL_RED, COL_RED, COL_GREEN, COL_GREEN,
794 COL_GRAY, COL_GRAY, COL_LIGHTGRAY, COL_LIGHTBLUE, COL_LIGHTCYAN,
795 COL_BLUE, COL_BLUE, COL_BLUE, COL_CYAN, COL_CYAN
797 GradientStyle eStyles[] = {
798 GradientStyle::Linear, GradientStyle::Axial, GradientStyle::Radial, GradientStyle::Elliptical, GradientStyle::Square,
799 GradientStyle::Rect, GradientStyle::FORCE_EQUAL_SIZE, GradientStyle::Linear, GradientStyle::Radial, GradientStyle::Linear,
800 GradientStyle::Linear, GradientStyle::Axial, GradientStyle::Radial, GradientStyle::Elliptical, GradientStyle::Square,
801 GradientStyle::Rect, GradientStyle::FORCE_EQUAL_SIZE, GradientStyle::Linear, GradientStyle::Radial, GradientStyle::Linear
803 sal_uInt16 nAngles[] = {
804 0, 0, 0, 0, 0,
805 15, 30, 45, 60, 75,
806 90, 120, 135, 160, 180,
807 0, 0, 0, 0, 0
809 sal_uInt16 nBorders[] = {
810 0, 0, 0, 0, 0,
811 1, 10, 100, 10, 1,
812 0, 0, 0, 0, 0,
813 1, 10, 20, 10, 1,
814 0, 0, 0, 0, 0
816 DemoRenderer::clearRects(rDev, aRegions);
817 assert(aRegions.size() <= SAL_N_ELEMENTS(nStartCols));
818 assert(aRegions.size() <= SAL_N_ELEMENTS(nEndCols));
819 assert(aRegions.size() <= SAL_N_ELEMENTS(eStyles));
820 assert(aRegions.size() <= SAL_N_ELEMENTS(nAngles));
821 assert(aRegions.size() <= SAL_N_ELEMENTS(nBorders));
822 for (size_t i = 0; i < aRegions.size(); i++)
824 tools::Rectangle aSub = aRegions[i];
825 Gradient aGradient;
826 aGradient.SetStartColor(Color(nStartCols[i]));
827 aGradient.SetEndColor(Color(nEndCols[i]));
828 aGradient.SetStyle(eStyles[i]);
829 aGradient.SetAngle(nAngles[i]);
830 aGradient.SetBorder(nBorders[i]);
831 rDev.DrawGradient(aSub, aGradient);
834 else
836 Gradient aGradient;
837 aGradient.SetStartColor(COL_YELLOW);
838 aGradient.SetEndColor(COL_RED);
839 aGradient.SetStyle(GradientStyle::Rect);
840 aGradient.SetBorder(r.GetSize().Width()/20);
841 rDev.DrawGradient(r, aGradient);
846 struct DrawBitmap : public RegionRenderer
848 RENDER_DETAILS(bitmap,KEY_B,10)
850 // Simulate Page Borders rendering - which ultimately should
851 // be done with a shader / gradient
852 static void SimulateBorderStretch(OutputDevice &rDev, const tools::Rectangle& r)
854 BitmapEx aPageShadowMask("sw/res/page-shadow-mask.png");
856 BitmapEx aRight(aPageShadowMask);
857 sal_Int32 nSlice = (aPageShadowMask.GetSizePixel().Width() - 3) / 4;
858 // a width x 1 slice
859 aRight.Crop(tools::Rectangle(Point((nSlice * 3) + 3, (nSlice * 2) + 1),
860 Size(nSlice, 1)));
861 AlphaMask aAlphaMask(aRight.GetBitmap());
862 Bitmap aBlockColor = Bitmap(aAlphaMask.GetSizePixel(), 24);
863 aBlockColor.Erase(COL_RED);
864 BitmapEx aShadowStretch = BitmapEx(aBlockColor, aAlphaMask);
866 Point aRenderPt(r.TopLeft());
868 long aSizes[] = { 200, 100, 200, 100, 50, 5, 2 };
870 // and yes - we really do this in the page border rendering code ...
871 for (size_t i = 0; i < SAL_N_ELEMENTS(aSizes); i++)
873 aShadowStretch.Scale(Size(aShadowStretch.GetSizePixel().Width(), aSizes[i]),
874 BmpScaleFlag::Fast);
876 rDev.DrawBitmapEx(aRenderPt, aShadowStretch);
877 aRenderPt.Move(aShadowStretch.GetSizePixel().Width() + 4, 0);
880 AlphaMask aWholeMask(aPageShadowMask.GetBitmap());
881 aBlockColor = Bitmap(aPageShadowMask.GetSizePixel(), 24);
882 aBlockColor.Erase(COL_GREEN);
883 BitmapEx aWhole(aBlockColor, aWholeMask);
885 aRenderPt = Point(r.Center());
886 aRenderPt.Move(nSlice+1, 0);
888 // An offset background for alpha rendering
889 rDev.SetFillColor(COL_BLUE);
890 tools::Rectangle aSurround(r.Center(), Size(aPageShadowMask.GetSizePixel()));
891 rDev.DrawRect(aSurround);
892 rDev.DrawBitmapEx(aRenderPt, aWhole);
895 virtual void RenderRegion(OutputDevice &rDev, tools::Rectangle r,
896 const RenderContext &rCtx) override
898 Bitmap aBitmap(rCtx.mpDemoRenderer->maIntroBW);
899 aBitmap.Scale(r.GetSize(), BmpScaleFlag::BestQuality);
900 rDev.DrawBitmap(r.TopLeft(), aBitmap);
902 SimulateBorderStretch(rDev, r);
906 struct DrawBitmapEx : public RegionRenderer
908 RENDER_DETAILS(bitmapex,KEY_X,2)
909 DrawCheckered maCheckered;
910 virtual void RenderRegion(OutputDevice &rDev, tools::Rectangle r,
911 const RenderContext &rCtx) override
913 maCheckered.RenderRegion(rDev, r, rCtx);
915 BitmapEx aBitmap(rCtx.mpDemoRenderer->maIntro);
916 aBitmap.Scale(r.GetSize(), BmpScaleFlag::BestQuality);
917 AlphaMask aSemiTransp(aBitmap.GetSizePixel());
918 aSemiTransp.Erase(64);
919 rDev.DrawBitmapEx(r.TopLeft(), BitmapEx(aBitmap.GetBitmap(),
920 aSemiTransp));
924 struct DrawPolyPolygons : public RegionRenderer
926 RENDER_DETAILS(polypoly,KEY_N,100)
927 virtual void RenderRegion(OutputDevice &rDev, tools::Rectangle r,
928 const RenderContext &) override
930 struct {
931 double nX, nY;
932 } aPoints[] = { { 0.1, 0.1 }, { 0.9, 0.9 },
933 #if FIXME_SELF_INTERSECTING_WORKING
934 { 0.9, 0.1 }, { 0.1, 0.9 },
935 { 0.1, 0.1 }
936 #else
937 { 0.1, 0.9 }, { 0.5, 0.5 },
938 { 0.9, 0.1 }, { 0.1, 0.1 }
939 #endif
942 tools::PolyPolygon aPolyPoly;
943 // Render 4x polygons & aggregate into another PolyPolygon
944 for (int x = 0; x < 2; x++)
946 for (int y = 0; y < 2; y++)
948 tools::Rectangle aSubRect(r);
949 aSubRect.Move(x * r.GetWidth()/3, y * r.GetHeight()/3);
950 aSubRect.SetSize(Size(r.GetWidth()/2, r.GetHeight()/4));
951 tools::Polygon aPoly(SAL_N_ELEMENTS(aPoints));
952 for (size_t v = 0; v < SAL_N_ELEMENTS(aPoints); v++)
954 aPoly.SetPoint(Point(aSubRect.Left() +
955 aSubRect.GetWidth() * aPoints[v].nX,
956 aSubRect.Top() +
957 aSubRect.GetHeight() * aPoints[v].nY),
960 rDev.SetLineColor(Color(COL_YELLOW));
961 rDev.SetFillColor(Color(COL_BLACK));
962 rDev.DrawPolygon(aPoly);
964 // now move and add to the polypolygon
965 aPoly.Move(0, r.GetHeight()/2);
966 aPolyPoly.Insert(aPoly);
969 rDev.SetLineColor(Color(COL_LIGHTRED));
970 rDev.SetFillColor(Color(COL_GREEN));
971 rDev.DrawTransparent(aPolyPoly, 50);
975 struct DrawClipped : public RegionRenderer
977 RENDER_DETAILS(clip,KEY_D,10)
978 virtual void RenderRegion(OutputDevice &rDev, tools::Rectangle r,
979 const RenderContext &) override
981 std::vector<tools::Rectangle> aRegions(DemoRenderer::partition(r, 2, 2));
982 const int nLimits[] = { 4, -100 };
983 for (int i = 0; i < 2; ++i)
985 sal_uInt16 nHue = 0;
986 rDev.Push(PushFlags::CLIPREGION);
987 tools::Rectangle aOuter = aRegions[i];
988 tools::Rectangle aInner = aOuter;
989 while (aInner.GetWidth() > nLimits[i] && aInner.GetHeight() > nLimits[i])
991 aInner.expand(-1);
992 rDev.SetClipRegion(vcl::Region(aInner));
993 rDev.SetFillColor(Color::HSBtoRGB(nHue, 75, 100));
994 nHue = (nHue + 97) % 360;
995 rDev.DrawRect(aOuter);
997 rDev.Pop();
1001 sal_uInt16 nHue = 0;
1002 tools::Rectangle aOuter = aRegions[2];
1003 std::vector<tools::Rectangle> aPieces(DemoRenderer::partition(aOuter, 2, 2));
1004 for (int j = 0; j < std::min(aOuter.GetWidth(), aOuter.GetHeight())/5; ++j)
1006 rDev.Push(PushFlags::CLIPREGION);
1008 vcl::Region aClipRegion;
1009 for (int i = 0; i < 4; ++i)
1011 aPieces[i].expand(-1);
1012 aPieces[i].Move(2 - i/2, 2 - i/2);
1013 aClipRegion.Union(aPieces[i]);
1015 assert (aClipRegion.getRegionBand());
1016 rDev.SetClipRegion(vcl::Region(aClipRegion));
1017 rDev.SetFillColor(Color::HSBtoRGB(nHue, 75, 75));
1018 nHue = (nHue + 97) % 360;
1019 rDev.DrawRect(aOuter);
1021 rDev.Pop();
1026 sal_uInt16 nHue = 0;
1027 tools::Rectangle aOuter = aRegions[3];
1028 std::vector<tools::Rectangle> aPieces(DemoRenderer::partition(aOuter, 2, 2));
1029 bool bDone = false;
1030 for (int j = 0; !bDone; ++j)
1032 rDev.Push(PushFlags::CLIPREGION);
1034 for (int i = 0; i < 4; ++i)
1036 vcl::Region aClipRegion;
1037 tools::Polygon aPoly;
1038 switch (i) {
1039 case 3:
1040 case 0: // 45degree rectangle.
1041 aPoly = tools::Polygon(aPieces[i]);
1042 aPoly.Rotate(aPieces[i].Center(), 450);
1043 break;
1044 case 1: // arc
1045 aPoly = tools::Polygon(aPieces[i],
1046 aPieces[i].TopLeft(),
1047 aPieces[i].BottomRight());
1048 break;
1049 case 2:
1050 aPoly = tools::Polygon(aPieces[i],
1051 aPieces[i].GetWidth()/5,
1052 aPieces[i].GetHeight()/5);
1053 aPoly.Rotate(aPieces[i].Center(), 450);
1054 break;
1056 aClipRegion = vcl::Region(aPoly);
1057 aPieces[i].expand(-1);
1058 aPieces[i].Move(2 - i/2, 2 - i/2);
1060 bDone = aPieces[i].GetWidth() < 4 ||
1061 aPieces[i].GetHeight() < 4;
1063 if (!bDone)
1065 assert (!aClipRegion.getRegionBand());
1067 rDev.SetClipRegion(vcl::Region(aClipRegion));
1068 rDev.SetFillColor(Color::HSBtoRGB(nHue, 50, 75));
1069 nHue = (nHue + 97) % 360;
1070 rDev.DrawRect(aOuter);
1074 rDev.Pop();
1080 struct DrawToVirtualDevice : public RegionRenderer
1082 RENDER_DETAILS(vdev,KEY_V,1)
1083 enum RenderType {
1084 RENDER_AS_BITMAP,
1085 RENDER_AS_OUTDEV,
1086 RENDER_AS_BITMAPEX,
1087 RENDER_AS_ALPHA_OUTDEV
1090 static void SizeAndRender(OutputDevice &rDev, const tools::Rectangle& r, RenderType eType,
1091 const RenderContext &rCtx)
1093 ScopedVclPtr<VirtualDevice> pNested;
1095 if ((int)eType < RENDER_AS_BITMAPEX)
1096 pNested = VclPtr<VirtualDevice>::Create(rDev).get();
1097 else
1098 pNested = VclPtr<VirtualDevice>::Create(rDev,DeviceFormat::DEFAULT,DeviceFormat::DEFAULT).get();
1100 pNested->SetOutputSizePixel(r.GetSize());
1101 tools::Rectangle aWhole(Point(0,0), r.GetSize());
1103 // mini me
1104 rCtx.mpDemoRenderer->drawToDevice(*pNested, r.GetSize(), true);
1106 if (eType == RENDER_AS_BITMAP)
1108 Bitmap aBitmap(pNested->GetBitmap(Point(0,0),aWhole.GetSize()));
1109 rDev.DrawBitmap(r.TopLeft(), aBitmap);
1111 else if (eType == RENDER_AS_BITMAPEX)
1113 BitmapEx aBitmapEx(pNested->GetBitmapEx(Point(0,0),aWhole.GetSize()));
1114 rDev.DrawBitmapEx(r.TopLeft(), aBitmapEx);
1116 else if (eType == RENDER_AS_OUTDEV ||
1117 eType == RENDER_AS_ALPHA_OUTDEV)
1119 rDev.DrawOutDev(r.TopLeft(), r.GetSize(),
1120 aWhole.TopLeft(), aWhole.GetSize(),
1121 *pNested);
1124 virtual void RenderRegion(OutputDevice &rDev, tools::Rectangle r,
1125 const RenderContext &rCtx) override
1127 // avoid infinite recursion
1128 if (rCtx.mbVDev)
1129 return;
1131 if (rCtx.meStyle == RENDER_EXPANDED)
1133 std::vector<tools::Rectangle> aRegions(DemoRenderer::partition(rCtx,2, 2));
1134 DemoRenderer::clearRects(rDev, aRegions);
1136 RenderType eRenderTypes[] = { RENDER_AS_BITMAP, RENDER_AS_OUTDEV,
1137 RENDER_AS_BITMAPEX, RENDER_AS_ALPHA_OUTDEV };
1138 for (size_t i = 0; i < aRegions.size(); i++)
1139 SizeAndRender(rDev, aRegions[i], eRenderTypes[i], rCtx);
1141 else
1142 SizeAndRender(rDev, r, RENDER_AS_BITMAP, rCtx);
1146 struct DrawXOR : public RegionRenderer
1148 RENDER_DETAILS(xor,KEY_X,1)
1150 virtual void RenderRegion(OutputDevice &rDev, tools::Rectangle r,
1151 const RenderContext &rCtx) override
1153 // avoid infinite recursion
1154 if (rCtx.mbVDev)
1155 return;
1157 rDev.Push();
1159 AntialiasingFlags nFlags = rDev.GetAntialiasing();
1160 rDev.SetAntialiasing(nFlags & ~AntialiasingFlags::EnableB2dDraw);
1161 rDev.SetRasterOp( RasterOp::Xor );
1163 rCtx.mpDemoRenderer->drawThumbs(rDev, r, true);
1165 rDev.Pop();
1169 struct DrawIcons : public RegionRenderer
1171 RENDER_DETAILS(icons,KEY_I,1)
1173 std::vector<OUString> maIconNames;
1174 std::vector<BitmapEx> maIcons;
1175 bool bHasLoadedAll;
1176 DrawIcons() : bHasLoadedAll(false)
1178 // a few icons to start with
1179 const char *pNames[] = {
1180 "cmd/lc_openurl.png",
1181 "cmd/lc_newdoc.png",
1182 "cmd/lc_choosemacro.png",
1183 "cmd/lc_save.png",
1184 "cmd/lc_saveas.png",
1185 "cmd/lc_importdialog.png",
1186 "cmd/lc_sendmail.png",
1187 "cmd/lc_editdoc.png",
1188 "cmd/lc_print.png",
1189 "cmd/lc_combobox.png",
1190 "cmd/lc_insertformcombo.png",
1191 "cmd/lc_printpreview.png",
1192 "cmd/lc_cut.png",
1193 "cmd/lc_copy.png",
1194 "cmd/lc_paste.png",
1195 "cmd/sc_autopilotmenu.png",
1196 "cmd/lc_formatpaintbrush.png",
1197 "cmd/lc_undo.png",
1198 "cmd/lc_redo.png",
1199 "cmd/lc_marks.png",
1200 "cmd/lc_fieldnames.png",
1201 "cmd/lc_hyperlinkdialog.png",
1202 "cmd/lc_basicshapes.rectangle.png",
1203 "cmd/lc_basicshapes.round-rectangle.png"
1205 for (size_t i = 0; i < SAL_N_ELEMENTS(pNames); i++)
1207 maIconNames.push_back(OUString::createFromAscii(pNames[i]));
1208 maIcons.push_back(BitmapEx(maIconNames[i]));
1212 void LoadAllImages()
1214 if (bHasLoadedAll)
1215 return;
1216 bHasLoadedAll = true;
1218 css::uno::Reference<css::container::XNameAccess> xRef(ImageTree::get().getNameAccess());
1219 css::uno::Sequence< OUString > aAllIcons = xRef->getElementNames();
1221 for (sal_Int32 i = 0; i < aAllIcons.getLength(); i++)
1223 if (aAllIcons[i].endsWithIgnoreAsciiCase("svg"))
1224 continue; // too slow to load.
1225 maIconNames.push_back(aAllIcons[i]);
1226 maIcons.push_back(BitmapEx(aAllIcons[i]));
1230 void doDrawIcons(OutputDevice &rDev, tools::Rectangle r, bool bExpanded)
1232 long nMaxH = 0;
1233 Point p(r.LeftCenter());
1234 size_t nToRender = maIcons.size();
1236 if (!bExpanded && maIcons.size() > 64)
1237 nToRender = 64;
1238 for (size_t i = 0; i < nToRender; i++)
1240 Size aSize(maIcons[i].GetSizePixel());
1241 // sAL_DEBUG("Draw icon '" << maIconNames[i] << "'");
1243 if (!(i % 4))
1244 rDev.DrawBitmapEx(p, maIcons[i]);
1245 else
1247 basegfx::B2DHomMatrix aTransform;
1248 aTransform.scale(aSize.Width(), aSize.Height());
1249 switch (i % 4)
1251 case 2:
1252 aTransform.shearX((double)((i >> 2) % 8) / 8);
1253 aTransform.shearY((double)((i >> 4) % 8) / 8);
1254 break;
1255 case 3:
1256 aTransform.translate(-aSize.Width()/2, -aSize.Height()/2);
1257 aTransform.rotate(i);
1258 if (i & 0x100)
1260 aTransform.shearX((double)((i >> 2) % 8) / 8);
1261 aTransform.shearY((double)((i >> 4) % 8) / 8);
1263 aTransform.translate(aSize.Width()/2, aSize.Height()/2);
1264 break;
1265 default:
1266 aTransform.translate(-aSize.Width()/2, -aSize.Height()/2);
1267 aTransform.rotate(2 * F_2PI * i / nToRender);
1268 aTransform.translate(aSize.Width()/2, aSize.Height()/2);
1269 break;
1271 aTransform.translate(p.X(), p.Y());
1272 rDev.DrawTransformedBitmapEx(aTransform, maIcons[i]);
1275 // next position
1276 p.Move(aSize.Width(), 0);
1277 if (aSize.Height() > nMaxH)
1278 nMaxH = aSize.Height();
1279 if (p.X() >= r.Right()) // wrap to next line
1281 p = Point(r.Left(), p.Y() + nMaxH);
1282 nMaxH = 0;
1284 if (p.Y() >= r.Bottom()) // re-start at middle
1285 p = r.LeftCenter();
1289 static BitmapEx AlphaRecovery(OutputDevice &rDev, Point aPt, BitmapEx &aSrc)
1291 // Compositing onto 2x colors beyond our control
1292 ScopedVclPtrInstance< VirtualDevice > aWhite;
1293 ScopedVclPtrInstance< VirtualDevice > aBlack;
1294 aWhite->SetOutputSizePixel(aSrc.GetSizePixel());
1295 aWhite->SetBackground(Wallpaper(COL_WHITE));
1296 aWhite->Erase();
1297 aBlack->SetOutputSizePixel(aSrc.GetSizePixel());
1298 aBlack->SetBackground(Wallpaper(COL_BLACK));
1299 aBlack->Erase();
1300 aWhite->DrawBitmapEx(Point(), aSrc);
1301 aBlack->DrawBitmapEx(Point(), aSrc);
1303 // Now recover that alpha...
1304 Bitmap aWhiteBmp = aWhite->GetBitmap(Point(),aSrc.GetSizePixel());
1305 Bitmap aBlackBmp = aBlack->GetBitmap(Point(),aSrc.GetSizePixel());
1306 AlphaMask aMask(aSrc.GetSizePixel());
1307 Bitmap aRecovered(aSrc.GetSizePixel(), 24);
1309 AlphaMask::ScopedWriteAccess pMaskAcc(aMask);
1310 Bitmap::ScopedWriteAccess pRecAcc(aRecovered);
1311 Bitmap::ScopedReadAccess pAccW(aWhiteBmp); // a * pix + (1-a)
1312 Bitmap::ScopedReadAccess pAccB(aBlackBmp); // a * pix + 0
1313 int nSizeX = aSrc.GetSizePixel().Width();
1314 int nSizeY = aSrc.GetSizePixel().Height();
1315 for (int y = 0; y < nSizeY; y++)
1317 for (int x = 0; x < nSizeX; x++)
1319 BitmapColor aColW = pAccW->GetPixel(y,x);
1320 BitmapColor aColB = pAccB->GetPixel(y,x);
1321 long nAR = (long)(aColW.GetRed() - aColB.GetRed()); // (1-a)
1322 long nAG = (long)(aColW.GetGreen() - aColB.GetGreen()); // (1-a)
1323 long nAB = (long)(aColW.GetBlue() - aColB.GetBlue()); // (1-a)
1325 #define CLAMP(a,b,c) (((a)<=(b))?(b):(((a)>=(c))?(c):(a)))
1327 // we get the most precision from the largest delta
1328 long nInverseAlpha = std::max(nAR, std::max(nAG, nAB)); // (1-a)
1329 nInverseAlpha = CLAMP(nInverseAlpha, 0, 255);
1330 long nAlpha = 255 - nInverseAlpha;
1332 pMaskAcc->SetPixel(y,x,BitmapColor((sal_Int8)CLAMP(nInverseAlpha,0,255)));
1333 // now recover the pixels
1334 long nR = (aColW.GetRed() + aColB.GetRed() - nInverseAlpha) * 128;
1335 long nG = (aColW.GetGreen() + aColB.GetGreen() - nInverseAlpha) * 128;
1336 long nB = (aColW.GetBlue() + aColB.GetBlue() - nInverseAlpha) * 128;
1337 if (nAlpha == 0)
1338 { // doesn't matter what's behind transparency
1339 nR = nG = nB = 0;
1341 else
1343 nR /= nAlpha; nG /= nAlpha; nB /= nAlpha;
1345 pRecAcc->SetPixel(y,x,BitmapColor(
1346 (sal_uInt8)CLAMP(nR,0,255),
1347 (sal_uInt8)CLAMP(nG,0,255),
1348 (sal_uInt8)CLAMP(nB,0,255)));
1349 #undef CLAMP
1353 rDev.DrawBitmap(aPt, aWhiteBmp);
1354 aPt.Move(aSrc.GetSizePixel().Width(), 0);
1355 rDev.DrawBitmap(aPt, aBlackBmp);
1356 aPt.Move(aSrc.GetSizePixel().Width(), 0);
1357 rDev.DrawBitmap(aPt, aRecovered);
1358 aPt.Move(aSrc.GetSizePixel().Width(), 0);
1359 rDev.DrawBitmap(aPt, aMask.GetBitmap());
1360 aPt.Move(aSrc.GetSizePixel().Width(), 0);
1362 return BitmapEx(aRecovered, aMask);
1365 virtual void RenderRegion(OutputDevice &rDev, tools::Rectangle r,
1366 const RenderContext &rCtx) override
1368 if (rCtx.meStyle == RENDER_EXPANDED)
1370 LoadAllImages();
1372 Point aLocation(0,maIcons[0].GetSizePixel().Height() + 8);
1373 for (size_t i = 0; i < 100; i++)
1375 BitmapEx aSrc = maIcons[i];
1377 // original above
1378 Point aAbove(aLocation);
1379 aAbove.Move(0,-aSrc.GetSizePixel().Height() - 4);
1380 rDev.DrawBitmapEx(aAbove, aSrc);
1381 aAbove.Move(aSrc.GetSizePixel().Width(),0);
1382 aAbove.Move(aSrc.GetSizePixel().Width(),0);
1383 rDev.DrawBitmap(aAbove, aSrc.GetBitmap());
1384 aAbove.Move(aSrc.GetSizePixel().Width(),0);
1385 rDev.DrawBitmap(aAbove, aSrc.GetMask());
1387 // intermediates middle
1388 BitmapEx aResult = AlphaRecovery(rDev, aLocation, aSrc);
1390 // result below
1391 Point aBelow(aLocation);
1392 aBelow.Move(0,aResult.GetSizePixel().Height());
1393 rDev.DrawBitmapEx(aBelow, aResult);
1395 // mini convert test.
1396 aBelow.Move(aResult.GetSizePixel().Width()+4,0);
1397 rDev.DrawBitmapEx(aBelow, aResult);
1399 Bitmap aGrey = aSrc.GetBitmap();
1400 aGrey.Convert(BmpConversion::N8BitGreys);
1401 rDev.DrawBitmap(aBelow, aGrey);
1403 aBelow.Move(aGrey.GetSizePixel().Width(),0);
1404 BitmapEx aGreyMask(aSrc.GetBitmap(),
1405 AlphaMask(aSrc.GetMask()));
1406 rDev.DrawBitmapEx(aBelow, aGreyMask);
1408 aLocation.Move(aSrc.GetSizePixel().Width()*6,0);
1409 if (aLocation.X() > r.Right())
1410 aLocation = Point(0,aLocation.Y()+aSrc.GetSizePixel().Height()*3+4);
1413 // now go crazy with random foo
1414 doDrawIcons(rDev, r, true);
1416 else
1418 doDrawIcons(rDev, r, false);
1423 struct FetchDrawBitmap : public RegionRenderer
1425 RENDER_DETAILS(fetchdraw,KEY_F,50)
1426 virtual void RenderRegion(OutputDevice &rDev, tools::Rectangle r,
1427 const RenderContext &) override
1429 Bitmap aBitmap(rDev.GetBitmap(Point(0,0),rDev.GetOutputSizePixel()));
1430 aBitmap.Scale(r.GetSize(), BmpScaleFlag::BestQuality);
1431 rDev.DrawBitmap(r.TopLeft(), aBitmap);
1435 void drawThumbs(vcl::RenderContext& rDev, tools::Rectangle aRect, bool bVDev)
1437 RenderContext aCtx;
1438 aCtx.meStyle = RENDER_THUMB;
1439 aCtx.mbVDev = bVDev;
1440 aCtx.mpDemoRenderer = this;
1441 aCtx.maSize = aRect.GetSize();
1442 std::vector<tools::Rectangle> aRegions(partition(aRect, mnSegmentsX, mnSegmentsY));
1443 DemoRenderer::clearRects(rDev, aRegions);
1444 for (size_t i = 0; i < maRenderers.size(); i++)
1446 RegionRenderer * r = maRenderers[i];
1448 rDev.SetClipRegion( vcl::Region( aRegions[i] ) );
1450 // profiling?
1451 if (getIterCount() > 0)
1453 if (!bVDev)
1455 double nStartTime = getTimeNow();
1456 for (int j = 0; j < r->getTestRepeatCount() * THUMB_REPEAT_FACTOR; j++)
1457 r->RenderRegion(rDev, aRegions[i], aCtx);
1458 addTime(i, (getTimeNow() - nStartTime) / THUMB_REPEAT_FACTOR);
1459 } else
1460 for (int j = 0; j < r->getTestRepeatCount(); j++)
1461 r->RenderRegion(rDev, aRegions[i], aCtx);
1463 else
1464 r->RenderRegion(rDev, aRegions[i], aCtx);
1466 rDev.SetClipRegion();
1470 void drawToDevice(vcl::RenderContext& rDev, Size aSize, bool bVDev)
1472 RenderContext aCtx;
1473 aCtx.mbVDev = bVDev;
1474 aCtx.mpDemoRenderer = this;
1475 aCtx.maSize = aSize;
1476 tools::Rectangle aWholeWin(Point(0,0), rDev.GetOutputSizePixel());
1478 drawBackground(rDev, aWholeWin);
1480 if (!bVDev /* want everything in the vdev */ &&
1481 mnSelectedRenderer >= 0 &&
1482 static_cast<sal_uInt32>(mnSelectedRenderer) < maRenderers.size())
1484 aCtx.meStyle = RENDER_EXPANDED;
1485 RegionRenderer * r = maRenderers[mnSelectedRenderer];
1486 // profiling?
1487 if (getIterCount() > 0)
1489 double nStartTime = getTimeNow();
1490 for (int i = 0; i < r->getTestRepeatCount(); i++)
1491 r->RenderRegion(rDev, aWholeWin, aCtx);
1492 addTime(mnSelectedRenderer, getTimeNow() - nStartTime);
1493 } else
1494 r->RenderRegion(rDev, aWholeWin, aCtx);
1496 else
1497 drawThumbs(rDev, aWholeWin, bVDev);
1499 std::vector<VclPtr<vcl::Window> > maInvalidates;
1500 void addInvalidate(vcl::Window *pWindow) { maInvalidates.push_back(pWindow); };
1501 void removeInvalidate(vcl::Window *pWindow)
1503 for (auto aIt = maInvalidates.begin(); aIt != maInvalidates.end(); ++aIt)
1505 if (*aIt == pWindow)
1507 maInvalidates.erase(aIt);
1508 return;
1512 void Invalidate()
1514 for (size_t i = 0; i < maInvalidates.size(); ++i)
1515 maInvalidates[i]->Invalidate();
1519 #if FIXME_BOUNCE_BUTTON
1520 IMPL_LINK_NOARG(DemoRenderer,BounceTimerCb,Timer*,void)
1522 mpButton->Check(mnBounceX>0);
1523 mpButton->SetPressed(mnBounceY>0);
1525 Point aCur = mpButtonWin->GetPosPixel();
1526 static const int nMovePix = 10;
1527 aCur.Move(mnBounceX * nMovePix, mnBounceX * nMovePix);
1528 Size aWinSize = GetSizePixel();
1529 if (aCur.X() <= 0 || aCur.X() >= aWinSize.Width())
1530 mnBounceX *= -1;
1531 if (aCur.Y() <= 0 || aCur.Y() >= aWinSize.Height())
1532 mnBounceX *= -1;
1533 mpButtonWin->SetPosPixel(aCur);
1535 // All smoke and mirrors to test sub-region invalidation underneath
1536 Rectangle aRect(aCur, mpButtonWin->GetSizePixel());
1537 Invalidate(aRect);
1539 #endif
1541 void DemoRenderer::KeyInput(const KeyEvent &rKEvt)
1543 sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
1545 // click to zoom out
1546 if (mnSelectedRenderer >= 0)
1548 if (nCode == KEY_ESCAPE || nCode == KEY_BACKSPACE)
1550 mnSelectedRenderer = -1;
1551 Invalidate();
1552 return;
1555 else
1557 for (size_t i = 0; i < maRenderers.size(); i++)
1559 if (nCode == maRenderers[i]->getAccelerator())
1561 mnSelectedRenderer = i;
1562 Invalidate();
1563 return;
1569 bool DemoRenderer::MouseButtonDown(const MouseEvent& rMEvt)
1571 // click to zoom out
1572 if (mnSelectedRenderer >= 0)
1574 mnSelectedRenderer = -1;
1575 Invalidate();
1576 return true;
1579 // click on a region to zoom into it
1580 std::vector<tools::Rectangle> aRegions(partition(GetSizePixel(), mnSegmentsX, mnSegmentsY));
1581 for (size_t i = 0; i < aRegions.size(); i++)
1583 if (aRegions[i].IsInside(rMEvt.GetPosPixel()))
1585 mnSelectedRenderer = i;
1586 Invalidate();
1587 return true;
1591 #if FIXME_BOUNCE_BUTTON
1592 // otherwise bounce floating windows
1593 if (!mpButton)
1595 mpButtonWin = VclPtr<FloatingWindow>::Create(this);
1596 mpButton = VclPtr<PushButton>::Create(mpButtonWin);
1597 mpButton->SetSymbol(SymbolType::HELP);
1598 mpButton->SetText("PushButton demo");
1599 mpButton->SetPosSizePixel(Point(0,0), mpButton->GetOptimalSize());
1600 mpButton->Show();
1601 mpButtonWin->SetPosSizePixel(Point(0,0), mpButton->GetOptimalSize());
1602 mpButtonWin->Show();
1603 mnBounceX = 1; mnBounceX = 1;
1604 maBounce.SetInvokeHandler(LINK(this,DemoRenderer,BounceTimerCb));
1605 maBounce.SetTimeout(55);
1606 maBounce.Start();
1608 else
1610 maBounce.Stop();
1611 delete mpButtonWin;
1612 mpButtonWin = NULL;
1613 mpButton = NULL;
1615 #endif
1616 return false;
1619 void DemoRenderer::InitRenderers()
1621 maRenderers.push_back(new DrawLines);
1622 maRenderers.push_back(new DrawText);
1623 maRenderers.push_back(new DrawPoly);
1624 maRenderers.push_back(new DrawEllipse);
1625 maRenderers.push_back(new DrawCheckered);
1626 maRenderers.push_back(new DrawBitmapEx);
1627 maRenderers.push_back(new DrawBitmap);
1628 maRenderers.push_back(new DrawGradient);
1629 maRenderers.push_back(new DrawPolyPolygons);
1630 maRenderers.push_back(new DrawClipped);
1631 maRenderers.push_back(new DrawToVirtualDevice);
1632 maRenderers.push_back(new DrawXOR);
1633 maRenderers.push_back(new DrawIcons());
1634 maRenderers.push_back(new FetchDrawBitmap);
1637 OUString DemoRenderer::getRendererList()
1639 OUStringBuffer aBuf;
1640 for (size_t i = 0; i < maRenderers.size(); i++)
1642 aBuf.append(maRenderers[i]->getName());
1643 aBuf.append(' ');
1645 return aBuf.makeStringAndClear();
1648 double DemoRenderer::getAndResetBenchmark(const RenderStyle style)
1650 double geomean = 1.0;
1651 fprintf(stderr, "Rendering: %s, Times (ms):\n", style == RENDER_THUMB ? "THUMB": "EXPANDED");
1652 for (size_t i = 0; i < maRenderers.size(); i++)
1654 double avgtime = maRenderers[i]->sumTime / maRenderers[i]->countTime;
1655 geomean *= avgtime;
1656 fprintf(stderr, "%s: %f (iteration: %d*%d*%d)\n",
1657 rtl::OUStringToOString(maRenderers[i]->getName(),
1658 RTL_TEXTENCODING_UTF8).getStr(), avgtime,
1659 maRenderers[i]->countTime, maRenderers[i]->getTestRepeatCount(),
1660 (style == RENDER_THUMB) ? THUMB_REPEAT_FACTOR : 1);
1661 maRenderers[i]->sumTime = 0;
1662 maRenderers[i]->countTime = 0;
1664 geomean = pow(geomean, 1.0/maRenderers.size());
1665 fprintf(stderr, "GEOMEAN_%s: %f\n", style == RENDER_THUMB ? "THUMB": "EXPANDED", geomean);
1666 return geomean;
1669 void DemoRenderer::setIterCount(sal_Int32 i)
1671 iterCount = i;
1674 sal_Int32 DemoRenderer::getIterCount()
1676 return iterCount;
1679 void DemoRenderer::addTime(int i, double t)
1681 maRenderers[i]->sumTime += t / maRenderers[i]->getTestRepeatCount();
1682 maRenderers[i]->countTime++;
1685 void DemoRenderer::selectRenderer(const OUString &rName )
1687 for (size_t i = 0; i < maRenderers.size(); i++)
1689 if (maRenderers[i]->getName() == rName)
1691 mnSelectedRenderer = i;
1692 Invalidate();
1693 return;
1698 int DemoRenderer::selectNextRenderer()
1700 mnSelectedRenderer++;
1701 if (mnSelectedRenderer == (signed) maRenderers.size())
1702 mnSelectedRenderer = -1;
1703 Invalidate();
1704 return mnSelectedRenderer;
1707 class DemoWin : public WorkWindow
1709 DemoRenderer &mrRenderer;
1710 bool underTesting;
1711 bool testThreads;
1713 class RenderThread : public salhelper::Thread {
1714 DemoWin &mrWin;
1715 TimeValue maDelay;
1716 public:
1717 RenderThread(DemoWin &rWin, sal_uInt32 nDelaySecs)
1718 : Thread("vcldemo render thread")
1719 , mrWin(rWin)
1721 maDelay.Seconds = nDelaySecs;
1722 maDelay.Nanosec = 0;
1723 launch();
1725 virtual ~RenderThread() override
1727 join();
1729 virtual void execute() override
1731 osl_waitThread(&maDelay);
1733 SolarMutexGuard aGuard;
1734 fprintf (stderr, "render from a different thread\n");
1735 mrWin.Invalidate();
1738 rtl::Reference<RenderThread> mxThread;
1740 public:
1741 DemoWin(DemoRenderer &rRenderer, bool bThreads) :
1742 WorkWindow(nullptr, WB_APP | WB_STDWORK),
1743 mrRenderer(rRenderer),
1744 testThreads(bThreads)
1746 mrRenderer.addInvalidate(this);
1747 underTesting = false;
1749 virtual ~DemoWin() override
1751 disposeOnce();
1753 virtual void dispose() override
1755 mxThread.clear();
1756 mrRenderer.removeInvalidate(this);
1757 WorkWindow::dispose();
1759 virtual void MouseButtonDown(const MouseEvent& rMEvt) override
1761 mrRenderer.SetSizePixel(GetSizePixel());
1762 if (!mrRenderer.MouseButtonDown(rMEvt))
1764 if (testThreads)
1765 { // render this window asynchronously in a new thread
1766 sal_uInt32 nDelaySecs = 0;
1767 if (rMEvt.GetButtons() & MOUSE_RIGHT)
1768 nDelaySecs = 5;
1769 mxThread = new RenderThread(*this, nDelaySecs);
1771 else
1772 { // spawn another window
1773 VclPtrInstance<DemoWin> pNewWin(mrRenderer, testThreads);
1774 pNewWin->SetText("Another interactive VCL demo window");
1775 pNewWin->Show();
1779 virtual void KeyInput(const KeyEvent& rKEvt) override
1781 mrRenderer.SetSizePixel(GetSizePixel());
1782 mrRenderer.KeyInput(rKEvt);
1784 virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override
1786 mrRenderer.SetSizePixel(GetSizePixel());
1787 fprintf(stderr, "DemoWin::Paint(%ld,%ld,%ld,%ld)\n", rRect.getX(), rRect.getY(), rRect.getWidth(), rRect.getHeight());
1788 if (mrRenderer.getIterCount() == 0)
1789 mrRenderer.drawToDevice(rRenderContext, GetSizePixel(), false);
1790 else
1791 TestAndQuit(rRenderContext);
1794 void TestAndQuit(vcl::RenderContext& rRenderContext)
1796 if (underTesting)
1797 return;
1798 underTesting = true;
1799 for (sal_Int32 i = 0; i < mrRenderer.getIterCount(); i++)
1801 while (mrRenderer.selectNextRenderer() > -1)
1803 mrRenderer.drawToDevice(rRenderContext, GetSizePixel(), false);
1807 double expandedGEOMEAN = mrRenderer.getAndResetBenchmark(RENDER_EXPANDED);
1809 for (sal_Int32 i = 0; i < mrRenderer.getIterCount(); i++)
1810 mrRenderer.drawToDevice(rRenderContext, GetSizePixel(), false);
1812 double thumbGEOMEAN = mrRenderer.getAndResetBenchmark(RENDER_THUMB);
1814 fprintf(stderr, "GEOMEAN_TOTAL: %f\n", pow(thumbGEOMEAN * expandedGEOMEAN, 0.5));
1815 Application::Quit();
1819 class DemoWidgets : public WorkWindow
1821 VclPtr<MenuBar> mpBar;
1822 VclPtr<VclBox> mpBox;
1823 VclPtr<ToolBox> mpToolbox;
1824 VclPtr<PushButton> mpButton;
1825 VclPtr<VclHBox> mpHBox;
1826 VclPtr<CheckBox> mpGLCheck;
1827 VclPtr<ComboBox> mpGLCombo;
1828 VclPtr<PushButton> mpGLButton;
1830 DECL_LINK(GLTestClick, Button*, void);
1832 public:
1833 DemoWidgets() :
1834 WorkWindow(nullptr, WB_APP | WB_STDWORK),
1835 mpBox(VclPtrInstance<VclVBox>(this, false, 3)),
1836 mpToolbox(VclPtrInstance<ToolBox>(mpBox.get())),
1837 mpButton(VclPtrInstance<PushButton>(mpBox.get())),
1838 mpHBox(VclPtrInstance<VclHBox>(mpBox.get(), true, 3)),
1839 mpGLCheck(VclPtrInstance<CheckBox>(mpHBox.get())),
1840 mpGLCombo(VclPtrInstance<ComboBox>(mpHBox.get())),
1841 mpGLButton(VclPtrInstance<PushButton>(mpHBox.get()))
1843 SetText("VCL widget demo");
1845 Wallpaper aWallpaper(BitmapEx("sfx2/res/startcenter-logo.png"));
1846 aWallpaper.SetStyle(WallpaperStyle::BottomRight);
1847 aWallpaper.SetColor(COL_RED);
1849 mpBox->SetBackground(aWallpaper);
1850 mpBox->Show();
1852 Help::EnableBalloonHelp();
1853 mpToolbox->SetHelpText("Help text");
1854 mpToolbox->InsertItem(0, "Toolbar item");
1855 mpToolbox->SetQuickHelpText(0, "This is a tooltip popup");
1856 mpToolbox->InsertSeparator();
1857 mpToolbox->Show();
1859 mpButton->SetText("Click me; go on");
1860 mpButton->Show();
1862 mpGLCheck->SetText("Test in OGL zone");
1863 mpGLCheck->Show();
1864 mpGLCombo->InsertEntry("sleep 1 second");
1865 mpGLCombo->InsertEntry("sleep 3 seconds");
1866 mpGLCombo->InsertEntry("sleep 7 seconds");
1867 mpGLCombo->SelectEntryPos(2);
1868 mpGLCombo->Show();
1869 mpGLButton->SetText("Execute test");
1870 mpGLButton->SetClickHdl(LINK(this,DemoWidgets,GLTestClick));
1871 mpGLButton->Show();
1872 mpHBox->Show();
1874 mpBar = VclPtr<MenuBar>::Create();
1875 mpBar->InsertItem(0,"File");
1876 VclPtrInstance<PopupMenu> pPopup;
1877 pPopup->InsertItem(0,"Item");
1878 mpBar->SetPopupMenu(0, pPopup);
1879 SetMenuBar(mpBar);
1881 Show();
1883 virtual ~DemoWidgets() override { disposeOnce(); }
1884 virtual void dispose() override
1886 mpGLButton.disposeAndClear();
1887 mpGLCombo.disposeAndClear();
1888 mpGLCheck.disposeAndClear();
1889 mpHBox.disposeAndClear();
1890 mpToolbox.disposeAndClear();
1891 mpButton.disposeAndClear();
1892 mpBox.disposeAndClear();
1893 mpBar.disposeAndClear();
1894 WorkWindow::dispose();
1896 virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) override
1898 tools::Rectangle aWholeSize(Point(0, 0),GetOutputSizePixel());
1899 vcl::Region aClip(aWholeSize);
1900 tools::Rectangle aExclude(tools::Rectangle(Point(50,50),Size(100,100)));
1901 aClip.Exclude(aExclude);
1903 Wallpaper aWallpaper(COL_GREEN);
1905 rRenderContext.Push(PushFlags::CLIPREGION);
1906 rRenderContext.IntersectClipRegion(aClip);
1907 rRenderContext.DrawWallpaper(aWholeSize, aWallpaper);
1908 rRenderContext.Pop();
1910 ScopedVclPtrInstance< VirtualDevice > pDev(*this);
1911 pDev->EnableRTL(IsRTLEnabled());
1912 pDev->SetOutputSizePixel(aExclude.GetSize());
1914 tools::Rectangle aSubRect(aWholeSize);
1915 aSubRect.Move(-aExclude.Left(), -aExclude.Top());
1916 pDev->DrawWallpaper(aSubRect, aWallpaper );
1918 rRenderContext.DrawOutDev(aExclude.TopLeft(), aExclude.GetSize(),
1919 Point( 0, 0 ), aExclude.GetSize(), *pDev.get() );
1923 class OpenGLZoneTest {
1924 public:
1925 static void enter() { OpenGLZone::enter(); }
1926 static void leave() { OpenGLZone::leave(); }
1929 IMPL_LINK_NOARG(DemoWidgets, GLTestClick, Button*, void)
1931 sal_Int32 nSelected = mpGLCombo->GetSelectEntryPos();
1933 TimeValue aDelay;
1934 aDelay.Seconds = 0;
1935 aDelay.Nanosec = 0;
1936 switch (nSelected)
1938 case 0:
1939 aDelay.Seconds = 1;
1940 break;
1941 case 1:
1942 aDelay.Seconds = 3;
1943 break;
1944 case 2:
1945 aDelay.Seconds = 7;
1946 break;
1947 default:
1948 break;
1951 bool bEnterLeave = mpGLCheck->IsChecked();
1952 if (bEnterLeave)
1953 OpenGLZoneTest::enter();
1955 osl_waitThread(&aDelay);
1957 if (bEnterLeave)
1958 OpenGLZoneTest::leave();
1961 class DemoPopup : public FloatingWindow
1963 public:
1964 DemoPopup() : FloatingWindow( nullptr, WB_SYSTEMWINDOW|WB_TOOLTIPWIN)
1966 SetType( WindowType::HELPTEXTWINDOW );
1968 SetOutputSizePixel( Size( 300, 30 ) );
1969 SetBackground(Wallpaper(COL_YELLOW));
1971 Show( true, ShowFlags::NoActivate );
1972 Update();
1975 virtual void Paint(vcl::RenderContext& /*rRenderContext*/, const tools::Rectangle&) override
1977 // Interestingly in GL mode on Windows, this doesn't render.
1979 Size aSize = GetOutputSizePixel();
1980 tools::Rectangle aTextRect(Point(6, 6), aSize);
1982 SetTextColor(COL_BLACK);
1983 SetTextAlign(ALIGN_TOP);
1984 DrawText(aTextRect, "This is a standalone help text test",
1985 DrawTextFlags::MultiLine|DrawTextFlags::WordBreak|
1986 DrawTextFlags::Left|DrawTextFlags::Top);
1988 SetLineColor(COL_BLACK);
1989 SetFillColor();
1990 DrawRect( tools::Rectangle( Point(), aSize ) );
1991 aSize.Width() -= 2;
1992 aSize.Height() -= 2;
1993 Color aColor( GetLineColor() );
1994 SetLineColor( ( COL_GRAY ) );
1995 DrawRect( tools::Rectangle( Point( 1, 1 ), aSize ) );
1996 SetLineColor( aColor );
1999 virtual void MouseButtonDown( const MouseEvent & ) override
2001 Application::Quit();
2005 class OpenGLTests
2007 VclPtr<WorkWindow> mxWinA;
2008 VclPtr<WorkWindow> mxWinB;
2009 OpenGLSalGraphicsImpl *mpImplA;
2010 OpenGLSalGraphicsImpl *mpImplB;
2011 rtl::Reference<OpenGLContext> mpA;
2012 rtl::Reference<OpenGLContext> mpB;
2014 static OpenGLSalGraphicsImpl *getImpl(const VclPtr<OutputDevice> &xOut)
2016 SalGraphics *pGraphics = xOut->GetGraphics();
2017 return dynamic_cast<OpenGLSalGraphicsImpl *>(pGraphics->GetImpl());
2019 public:
2020 OpenGLTests() :
2021 mxWinA(VclPtr<WorkWindow>::Create(nullptr, WB_APP | WB_STDWORK)),
2022 mxWinB(VclPtr<WorkWindow>::Create(nullptr, WB_APP | WB_STDWORK))
2024 if (!OpenGLHelper::isVCLOpenGLEnabled())
2026 mpImplA = mpImplB = nullptr;
2027 fprintf (stderr, "OpenGL is not enabled: try SAL_FORCEGL=1\n");
2028 return;
2031 mpImplA = getImpl(mxWinA);
2032 mpImplB = getImpl(mxWinB);
2033 assert (mpImplA && mpImplB);
2034 mpA = mpImplA->GetOpenGLContext();
2035 mpB = mpImplB->GetOpenGLContext();
2037 assert (mpA.is() && mpB.is());
2038 assert (mpA != mpB);
2040 ~OpenGLTests()
2042 mxWinB.disposeAndClear();
2043 mxWinA.disposeAndClear();
2046 void testCurrentFramebuffer()
2048 fprintf(stderr,"test OpenGLContext's framebuffer association.\n");
2049 mpA->makeCurrent();
2050 OpenGLFramebuffer *pBuffer;
2052 OpenGLTexture aTexture(256,128);
2053 pBuffer = mpA->AcquireFramebuffer(aTexture);
2055 assert (pBuffer->IsFree()); (void)pBuffer;
2056 mpB->makeCurrent();
2057 assert (mpA->mpCurrentFramebuffer == nullptr);
2060 void testVirtualDevice()
2062 fprintf(stderr, "test sharing OpenGLContexts with virtual-devices reference counting\n");
2063 VclPtrInstance<WorkWindow> xTempWin(nullptr, WB_STDWORK);
2064 xTempWin->Show();
2065 // forcibly make this context current by rendering
2066 xTempWin->DrawPixel(Point(0, 0), COL_RED);
2068 // get some other guys to leach off this context
2069 VclPtrInstance<VirtualDevice> xVDev;
2070 rtl::Reference<OpenGLContext> pContext = getImpl(xVDev)->GetOpenGLContext();
2071 VclPtrInstance<VirtualDevice> xVDev2;
2072 rtl::Reference<OpenGLContext> pContext2 = getImpl(xVDev)->GetOpenGLContext();
2074 // sharing the same off-screen context.
2075 assert(pContext == pContext2);
2076 assert(pContext == getImpl(xTempWin)->GetOpenGLContext());
2077 assert(pContext != mpA && pContext != mpB);
2078 (void)pContext; (void)pContext2;
2080 // Kill the parent we free-ride on ...
2081 xTempWin.disposeAndClear();
2083 // This appears to continue working; fun.
2084 Point aPt(0, 0);
2085 xVDev->DrawPixel(aPt, COL_GREEN);
2086 assert(xVDev->GetPixel(aPt) == COL_GREEN);
2087 xVDev.disposeAndClear();
2089 // Switch context to see if we can switch back.
2090 mxWinA->DrawPixel(aPt, COL_WHITE);
2092 // Now try switching back to this guy ...
2093 xVDev2->DrawPixel(aPt, COL_BLUE);
2094 assert(xVDev2->GetPixel(aPt) == COL_BLUE);
2095 xVDev2.disposeAndClear();
2098 int execute()
2100 if (!OpenGLHelper::isVCLOpenGLEnabled())
2101 return 1;
2103 testCurrentFramebuffer();
2104 testVirtualDevice();
2106 return 0;
2110 namespace {
2111 void renderFonts(const std::vector<OUString> &aFontNames)
2113 ScopedVclPtrInstance<VirtualDevice> xDevice;
2114 Size aSize(1024, 1024);
2115 xDevice->SetOutputSizePixel(aSize);
2117 for (auto & aFontName : aFontNames)
2119 vcl::Font aFont(aFontName, Size(0,96));
2120 #if 0
2121 aFont.SetColor(COL_BLACK);
2122 xDevice->SetFont(aFont);
2123 xDevice->Erase();
2125 FontMetric aMetric = xDevice->GetFontMetric(aFont);
2127 FontCharMapRef xMap;
2128 if (xDevice->GetFontCharMap(xMap))
2130 ... iterate through glyphs ...
2134 bool GetGlyphBoundRects( const Point& rOrigin, const OUString& rStr, int nIndex,
2135 int nLen, int nBase, MetricVector& rVector );
2137 include/vcl/outdev.hxx:typedef std::vector< Rectangle > MetricVector;
2138 include/vcl/outdev.hxx: MetricVector* pVector = nullptr, OUString* pDisplayText = nullptr );
2139 include/vcl/outdev.hxx: MetricVector* pVector = nullptr, OUString* pDisplayText = nullptr,
2140 include/vcl/outdev.hxx: MetricVector* pVector, OUString* pDisplayText, vcl::ITextLayout& _rLayout );
2141 include/vcl/outdev.hxx: DrawTextFlags nStyle = DrawTextFlags::Mnemonic, MetricVector* pVector = nullp
2143 bool GetTextBoundRect( Rectangle& rRect,
2144 const OUString& rStr, sal_Int32 nBase = 0, sal_Int32 nIndex = 0, sal_Int32 nLen = -1,
2145 sal_uLong nLayoutWidth = 0, const long* pDXArray = nullptr ) const;
2148 void DrawText( const Point& rStartPt, const OUString& rStr,
2149 sal_Int32 nIndex = 0, sal_Int32 nLen = -1,
2150 MetricVector* pVector = nullptr, OUString* pDisplayText = nullptr );
2152 void DrawText( const Rectangle& rRect,
2153 const OUString& rStr, DrawTextFlags nStyle = DrawTextFlags::NONE,
2154 MetricVector* pVector = nullptr, OUString* pDisplayText = nullptr,
2155 vcl::ITextLayout* _pTextLayout = nullptr );
2157 Rectangle GetTextRect( const Rectangle& rRect,
2158 const OUString& rStr, DrawTextFlags nStyle = DrawTextFlags::WordBreak,
2159 TextRectInfo* pInfo = nullptr,
2160 const vcl::ITextLayout* _pTextLayout = nullptr ) const;
2162 #endif
2168 class DemoApp : public Application
2170 static int showHelp(DemoRenderer &rRenderer)
2172 fprintf(stderr,"vcldemo - a VCL test app\n");
2173 fprintf(stderr," --help - print this text\n");
2174 fprintf(stderr," --show <renderer> - start with a given renderer, options are:\n");
2175 OUString aRenderers(rRenderer.getRendererList());
2176 fprintf(stderr," %s\n",
2177 rtl::OUStringToOString(aRenderers, RTL_TEXTENCODING_UTF8).getStr());
2178 fprintf(stderr," --test <iterCount> - create benchmark data\n");
2179 fprintf(stderr," --widgets - launch the widget test.\n");
2180 fprintf(stderr," --threads - render from multiple threads.\n");
2181 fprintf(stderr," --gltest - run openGL regression tests.\n");
2182 fprintf(stderr, "\n");
2183 return 0;
2186 public:
2187 DemoApp() {}
2189 virtual int Main() override
2193 bool bWidgets = false, bThreads = false;
2194 bool bPopup = false, bGLTest = false;
2195 DemoRenderer aRenderer;
2196 std::vector<OUString> aFontNames;
2198 for (sal_uInt16 i = 0; i < GetCommandLineParamCount(); ++i)
2200 bool bLast = i == GetCommandLineParamCount() - 1;
2201 OUString aArg = GetCommandLineParam(i);
2202 if (aArg == "--help" || aArg == "-h")
2203 return showHelp(aRenderer);
2204 if (aArg == "--show")
2206 if (bLast)
2207 return showHelp(aRenderer);
2208 else
2209 aRenderer.selectRenderer(GetCommandLineParam(++i));
2211 else if (aArg == "--test")
2213 if (bLast)
2214 return showHelp(aRenderer);
2215 else
2216 aRenderer.setIterCount(GetCommandLineParam(++i).toInt32());
2218 else if (aArg == "--widgets")
2219 bWidgets = true;
2220 else if (aArg == "--popup")
2221 bPopup = true;
2222 else if (aArg == "--gltest")
2223 bGLTest = true;
2224 else if (aArg == "--threads")
2225 bThreads = true;
2226 else if (aArg == "--font" && !bLast)
2227 aFontNames.push_back(GetCommandLineParam(++i));
2228 else if (aArg.startsWith("--"))
2230 fprintf(stderr,"Unknown argument '%s'\n",
2231 rtl::OUStringToOString(aArg, RTL_TEXTENCODING_UTF8).getStr());
2232 return showHelp(aRenderer);
2236 ScopedVclPtrInstance<DemoWin> aMainWin(aRenderer, bThreads);
2237 VclPtr<DemoWidgets> xWidgets;
2238 VclPtr<DemoPopup> xPopup;
2240 aMainWin->SetText("Interactive VCL demo #1");
2241 #if HAVE_FEATURE_OPENGL
2242 if (bGLTest)
2244 OpenGLTests aTests;
2245 return aTests.execute();
2247 else
2248 #endif
2249 if (bWidgets)
2250 xWidgets = VclPtr< DemoWidgets >::Create ();
2251 else if (bPopup)
2252 xPopup = VclPtrInstance< DemoPopup> ();
2253 else if (aFontNames.size() > 0)
2254 renderFonts(aFontNames);
2255 else
2256 aMainWin->Show();
2258 Application::Execute();
2260 xWidgets.disposeAndClear();
2261 xPopup.disposeAndClear();
2263 catch (const css::uno::Exception& e)
2265 SAL_WARN("vcl.app", "Fatal exception: " << e.Message);
2266 return 1;
2268 catch (const std::exception& e)
2270 SAL_WARN("vcl.app", "Fatal exception: " << e.what());
2271 return 1;
2273 return 0;
2276 protected:
2277 uno::Reference<lang::XMultiServiceFactory> xMSF;
2278 void Init() override
2282 uno::Reference<uno::XComponentContext> xComponentContext
2283 = ::cppu::defaultBootstrap_InitialComponentContext();
2284 xMSF.set(xComponentContext->getServiceManager(), uno::UNO_QUERY);
2285 if(!xMSF.is())
2286 Application::Abort("Bootstrap failure - no service manager");
2288 ::comphelper::setProcessServiceFactory(xMSF);
2290 catch (const uno::Exception &e)
2292 Application::Abort("Bootstrap exception " + e.Message);
2295 void DeInit() override
2297 uno::Reference< lang::XComponent >(
2298 comphelper::getProcessComponentContext(),
2299 uno::UNO_QUERY_THROW)-> dispose();
2300 ::comphelper::setProcessServiceFactory(nullptr);
2304 void vclmain::createApplication()
2306 static DemoApp aApp;
2309 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */