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