1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
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 */
9
10 #include <sal/config.h>
11
12 #include <memory>
13
14 #include <config_features.h>
15
16 #include <math.h>
17 #include <rtl/math.hxx>
18 #include <sal/log.hxx>
19
20 #include <comphelper/processfactory.hxx>
21 #include <comphelper/random.hxx>
22 #include <cppuhelper/bootstrap.hxx>
23 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
24 #include <com/sun/star/lang/XInitialization.hpp>
25 #include <com/sun/star/registry/XSimpleRegistry.hpp>
26 #include <com/sun/star/ucb/UniversalContentBroker.hpp>
27 #include <com/sun/star/uno/Reference.hxx>
28 #include <com/sun/star/uno/Sequence.hxx>
29 #include <com/sun/star/container/XNameAccess.hpp>
30 #include <o3tl/safeint.hxx>
31 #include <osl/time.h>
32 #include <vcl/gradient.hxx>
33 #include <vcl/vclmain.hxx>
34 #include <vcl/layout.hxx>
35 #include <vcl/ptrstyle.hxx>
36 #include <salhelper/thread.hxx>
37
38 #include <tools/diagnose_ex.h>
39 #include <tools/urlobj.hxx>
40 #include <tools/stream.hxx>
41 #include <vcl/svapp.hxx>
42 #include <vcl/wrkwin.hxx>
43 #include <vcl/virdev.hxx>
44 #include <vcl/graphicfilter.hxx>
45 #include <vcl/toolkit/button.hxx>
46 #include <vcl/toolkit/combobox.hxx>
47 #include <vcl/toolbox.hxx>
48 #include <vcl/pngwrite.hxx>
49 #include <vcl/toolkit/floatwin.hxx>
50 #include <vcl/help.hxx>
51 #include <vcl/menu.hxx>
52 #include <vcl/ImageTree.hxx>
53 #include <vcl/BitmapEmbossGreyFilter.hxx>
54
55 #include <bitmap/BitmapWriteAccess.hxx>
56
57 #include <basegfx/numeric/ftools.hxx>
58 #include <basegfx/matrix/b2dhommatrix.hxx>
59
60 #define FIXME_SELF_INTERSECTING_WORKING 0
61 #define FIXME_BOUNCE_BUTTON 0
62 #define THUMB_REPEAT_FACTOR 10
63
64 using namespace com::sun::star;
65
66 namespace {
getTimeNow()67 double getTimeNow()
68 {
69 TimeValue aValue;
70 osl_getSystemTime(&aValue);
71 return static_cast<double>(aValue.Seconds) * 1000 +
72 static_cast<double>(aValue.Nanosec) / (1000*1000);
73 }
74
75 }
76
77 namespace {
78
79 enum RenderStyle {
80 RENDER_THUMB, // small view <n> to a page
81 RENDER_EXPANDED, // expanded view of this renderer
82 };
83
84 class DemoRenderer
85 {
86 Bitmap maIntroBW;
87 BitmapEx maIntro;
88
89 int mnSegmentsX;
90 int mnSegmentsY;
91
92 struct RenderContext {
93 RenderStyle meStyle;
94 bool mbVDev;
95 DemoRenderer *mpDemoRenderer;
96 Size maSize;
97 };
98 struct RegionRenderer {
99 public:
RegionRenderer__anonae1f6d930211::DemoRenderer::RegionRenderer100 RegionRenderer() :
101 sumTime(0),
102 countTime(0)
103 { }
~RegionRenderer__anonae1f6d930211::DemoRenderer::RegionRenderer104 virtual ~RegionRenderer() {}
105 virtual OUString getName() = 0;
106 virtual sal_uInt16 getAccelerator() = 0;
107 virtual void RenderRegion(OutputDevice &rDev, tools::Rectangle r,
108 const RenderContext &rCtx) = 0;
109 // repeating count for profiling (to exceed the poor time resolution on Windows)
110 virtual sal_uInt16 getTestRepeatCount() = 0;
111 #define RENDER_DETAILS(name,key,repeat) \
112 virtual OUString getName() override \
113 { return SAL_STRINGIFY(name); } \
114 virtual sal_uInt16 getAccelerator() override \
115 { return key; } \
116 virtual sal_uInt16 getTestRepeatCount() override \
117 { return repeat; }
118
119 double sumTime;
120 int countTime;
121 };
122
123 std::vector< RegionRenderer * > maRenderers;
124 sal_Int32 mnSelectedRenderer;
125 sal_Int32 iterCount;
126
127 void InitRenderers();
128
129 public:
DemoRenderer()130 DemoRenderer() : mnSegmentsX(0)
131 , mnSegmentsY(0)
132 , mnSelectedRenderer(-1)
133 , iterCount(0)
134 #if FIXME_BOUNCE_BUTTON
135 , mpButton(NULL)
136 , mpButtonWin(NULL)
137 , mnBounceX(1)
138 , mnBounceY(1)
139 #endif
140 {
141 if (!Application::LoadBrandBitmap("intro", maIntro))
142 Application::Abort("Failed to load intro image");
143
144 maIntroBW = maIntro.GetBitmap();
145
146 BitmapEx aTmpBmpEx(maIntroBW);
147 BitmapFilter::Filter(aTmpBmpEx, BitmapEmbossGreyFilter(0, 0));
148 maIntroBW = aTmpBmpEx.GetBitmap();
149
150 InitRenderers();
151 mnSegmentsY = rtl::math::round(std::sqrt(maRenderers.size()), 0,
152 rtl_math_RoundingMode_Down);
153 mnSegmentsX = (maRenderers.size() + mnSegmentsY - 1)/mnSegmentsY;
154 }
155
156 OUString getRendererList();
157 double getAndResetBenchmark(RenderStyle style);
158 void selectRenderer(std::u16string_view rName);
159 int selectNextRenderer();
160 void setIterCount(sal_Int32 iterCount);
161 sal_Int32 getIterCount() const;
162 void addTime(int i, double t);
163
164 Size maSize;
SetSizePixel(const Size & rSize)165 void SetSizePixel(const Size &rSize) { maSize = rSize; }
GetSizePixel() const166 const Size& GetSizePixel() const { return maSize; }
167
168
169 // more of a 'Window' concept - push upwards ?
170 #if FIXME_BOUNCE_BUTTON
171 // Bouncing windows on click ...
172 PushButton *mpButton;
173 FloatingWindow *mpButtonWin;
174 AutoTimer maBounce;
175 int mnBounceX, mnBounceY;
176 DECL_LINK(BounceTimerCb, Timer*, void);
177 #endif
178
179 bool MouseButtonDown(const MouseEvent& rMEvt);
180 void KeyInput(const KeyEvent& rKEvt);
181
partition(const tools::Rectangle & rRect,int nX,int nY)182 static std::vector<tools::Rectangle> partition(const tools::Rectangle &rRect, int nX, int nY)
183 {
184 std::vector<tools::Rectangle> aRegions = partition(rRect.GetSize(), nX, nY);
185 for (auto & region : aRegions)
186 region.Move(rRect.Left(), rRect.Top());
187
188 return aRegions;
189 }
190
partition(const RenderContext & rCtx,int nX,int nY)191 static std::vector<tools::Rectangle> partition(const RenderContext &rCtx, int nX, int nY)
192 {
193 return partition(rCtx.maSize, nX, nY);
194 }
195
partition(Size aSize,int nX,int nY)196 static std::vector<tools::Rectangle> partition(Size aSize, int nX, int nY)
197 {
198 tools::Rectangle r;
199 std::vector<tools::Rectangle> aRegions;
200
201 // Make small cleared area for these guys
202 tools::Long nBorderSize = std::min(aSize.Height() / 32, aSize.Width() / 32);
203 tools::Long nBoxWidth = (aSize.Width() - nBorderSize*(nX+1)) / nX;
204 tools::Long nBoxHeight = (aSize.Height() - nBorderSize*(nY+1)) / nY;
205 for (int y = 0; y < nY; y++)
206 {
207 for (int x = 0; x < nX; x++)
208 {
209 r.SetPos(Point(nBorderSize + (nBorderSize + nBoxWidth) * x,
210 nBorderSize + (nBorderSize + nBoxHeight) * y));
211 r.SetSize(Size(nBoxWidth, nBoxHeight));
212 aRegions.push_back(r);
213 }
214 }
215
216 return aRegions;
217 }
218
clearRects(OutputDevice & rDev,std::vector<tools::Rectangle> & rRects)219 static void clearRects(OutputDevice &rDev, std::vector<tools::Rectangle> &rRects)
220 {
221 for (size_t i = 0; i < rRects.size(); i++)
222 {
223 // knock up a nice little border
224 rDev.SetLineColor(COL_GRAY);
225 rDev.SetFillColor(COL_LIGHTGRAY);
226 if (i % 2)
227 {
228 int nBorderSize = rRects[i].GetWidth() / 5;
229 rDev.DrawRect(rRects[i], nBorderSize, nBorderSize);
230 }
231 else
232 rDev.DrawRect(rRects[i]);
233 }
234 }
235
drawBackground(OutputDevice & rDev,const tools::Rectangle & r)236 static void drawBackground(OutputDevice &rDev, const tools::Rectangle& r)
237 {
238 rDev.Erase();
239 Gradient aGradient;
240 aGradient.SetStartColor(COL_BLUE);
241 aGradient.SetEndColor(COL_GREEN);
242 aGradient.SetStyle(GradientStyle::Linear);
243 rDev.DrawGradient(r, aGradient);
244 }
245
246 struct DrawLines : public RegionRenderer
247 {
248 RENDER_DETAILS(lines,KEY_L,100)
RenderRegion__anonae1f6d930211::DemoRenderer::DrawLines249 virtual void RenderRegion(OutputDevice &rDev, tools::Rectangle r,
250 const RenderContext &rCtx) override
251 {
252 if (rCtx.meStyle == RENDER_EXPANDED)
253 {
254 AntialiasingFlags nOldAA = rDev.GetAntialiasing();
255 rDev.SetAntialiasing(AntialiasingFlags::Enable);
256
257 std::vector<tools::Rectangle> aRegions(DemoRenderer::partition(rCtx, 4, 4));
258 DemoRenderer::clearRects(rDev, aRegions);
259
260 #if 0 // FIXME: get this through to the backend ...
261 double nTransparency[] = {
262 1.0, 1.0, 1.0, 1.0,
263 0.8, 0.8, 0.8, 0.8,
264 0.5, 0.5, 0.5, 0.5,
265 0.1, 0.1, 0.1, 0.1
266 };
267 #endif
268 drawing::LineCap const eLineCaps[] = {
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,
272 drawing::LineCap_BUTT, drawing::LineCap_ROUND, drawing::LineCap_SQUARE, drawing::LineCap_BUTT
273 };
274 basegfx::B2DLineJoin const eJoins[] = {
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,
278 basegfx::B2DLineJoin::NONE, basegfx::B2DLineJoin::Bevel, basegfx::B2DLineJoin::Miter, basegfx::B2DLineJoin::Round
279 };
280 double const aLineWidths[] = {
281 10.0, 15.0, 20.0, 10.0,
282 10.0, 15.0, 20.0, 10.0,
283 10.0, 15.0, 20.0, 10.0,
284 0.1, 1.0, 10.0, 50.0
285 };
286 for (size_t i = 0; i < aRegions.size(); i++)
287 {
288 // Half of them not-anti-aliased ..
289 if (i >= aRegions.size()/2)
290 rDev.SetAntialiasing(nOldAA);
291
292 static const struct {
293 double nX, nY;
294 } aPoints[] = {
295 { 0.2, 0.2 }, { 0.8, 0.3 }, { 0.7, 0.8 }
296 };
297 rDev.SetLineColor(COL_BLACK);
298 basegfx::B2DPolygon aPoly;
299 tools::Rectangle aSub(aRegions[i]);
300 for (size_t j = 0; j < SAL_N_ELEMENTS(aPoints); j++)
301 {
302 aPoly.append(basegfx::B2DPoint(aSub.Left() + aSub.GetWidth() * aPoints[j].nX,
303 aSub.Top() + aSub.GetHeight() * aPoints[j].nY));
304 }
305 rDev.DrawPolyLine(aPoly, aLineWidths[i], eJoins[i], eLineCaps[i]);
306 }
307 }
308 else
309 {
310 rDev.SetFillColor(COL_LIGHTRED);
311 rDev.SetLineColor(COL_BLACK);
312 rDev.DrawRect(r);
313
314 for(tools::Long i=0; i<r.GetHeight(); i+=15)
315 rDev.DrawLine(Point(r.Left(), r.Top()+i), Point(r.Right(), r.Bottom()-i));
316 for(tools::Long i=0; i<r.GetWidth(); i+=15)
317 rDev.DrawLine(Point(r.Left()+i, r.Bottom()), Point(r.Right()-i, r.Top()));
318
319 // Should draw a white-line across the middle
320 Color aLastPixel(COL_WHITE);
321 Point aCenter((r.Left() + r.Right())/2 - 4,
322 (r.Top() + r.Bottom())/2 - 4);
323 for(int i=0; i<8; i++)
324 {
325 rDev.DrawPixel(aCenter, aLastPixel);
326 aLastPixel = rDev.GetPixel(aCenter);
327 aCenter.Move(1,1);
328 }
329 }
330 }
331 };
332
333 struct DrawText : public RegionRenderer
334 {
335 RENDER_DETAILS(text,KEY_T,1)
336
RenderRegion__anonae1f6d930211::DemoRenderer::DrawText337 virtual void RenderRegion(OutputDevice &rDev, tools::Rectangle r,
338 const RenderContext &rCtx) override
339 {
340 if (rCtx.meStyle == RENDER_EXPANDED)
341 {
342 std::vector<tools::Rectangle> aToplevelRegions(
343 DemoRenderer::partition(rCtx, 1, 3));
344 std::vector<tools::Rectangle> aSubRegions(
345 DemoRenderer::partition(aToplevelRegions[0], 4, 2));
346 tools::Rectangle aBottom(aToplevelRegions[1].TopLeft(),
347 aToplevelRegions[2].BottomRight());
348 DemoRenderer::clearRects(rDev,aSubRegions);
349 static struct {
350 bool mbClip;
351 bool mbArabicText;
352 bool mbRotate;
353 } const aRenderData[] = {
354 { false, false, false },
355 { false, true, false },
356 { false, true, true },
357 { false, false, true },
358 { true, false, true },
359 { true, true, true },
360 { true, true, false },
361 { true, false, false },
362 };
363
364 size_t i = 0;
365 for (int y = 0; y < 2; y++)
366 {
367 for (int x = 0; x < 4; x++)
368 {
369 assert(i < SAL_N_ELEMENTS(aRenderData));
370 drawText(rDev, aSubRegions[i], aRenderData[i].mbClip,
371 aRenderData[i].mbArabicText, aRenderData[i].mbRotate);
372 i++;
373 }
374 }
375
376 drawComplex(rDev, aBottom);
377 }
378 else
379 {
380 drawText(rDev, r, false, false, false);
381 }
382 }
383
drawText__anonae1f6d930211::DemoRenderer::DrawText384 static void drawText (OutputDevice &rDev, tools::Rectangle r, bool bClip, bool bArabicText, bool bRotate)
385 {
386 rDev.SetClipRegion( vcl::Region(r) );
387
388 const unsigned char pTextUTF8[] = {
389 0xd9, 0x88, 0xd8, 0xa7, 0xd8, 0xad, 0xd9, 0x90,
390 0xd8, 0xaf, 0xd9, 0x92, 0x20, 0xd8, 0xa5, 0xd8,
391 0xab, 0xd9, 0x8d, 0xd9, 0x86, 0xd9, 0x8a, 0xd9,
392 0x86, 0x20, 0xd8, 0xab, 0xd9, 0x84, 0xd8, 0xa7,
393 0xd8, 0xab, 0xd8, 0xa9, 0xd9, 0x8c, 0x00
394 };
395 OUString aArabicText( reinterpret_cast<char const *>(pTextUTF8),
396 SAL_N_ELEMENTS( pTextUTF8 ) - 1,
397 RTL_TEXTENCODING_UTF8 );
398
399 OUString aText;
400
401 // To have more text displayed one after the other (overlapping, and in different colours), then
402 // change this value
403 const int nPrintNumCopies=1;
404
405 if (bArabicText)
406 aText = aArabicText;
407 else
408 aText = "Click any rect to zoom!!!!";
409
410 std::vector<OUString> aFontNames;
411
412 static Color const nCols[] = {
413 COL_BLACK, COL_BLUE, COL_GREEN, COL_CYAN, COL_RED, COL_MAGENTA,
414 COL_BROWN, COL_GRAY, COL_LIGHTGRAY, COL_LIGHTBLUE, COL_LIGHTGREEN,
415 COL_LIGHTCYAN, COL_LIGHTRED, COL_LIGHTMAGENTA, COL_YELLOW, COL_WHITE
416 };
417
418 // a few fonts to start with
419 const char *pNames[] = {
420 "Times", "Liberation Sans", "Arial", "Linux Biolinum G", "Linux Libertine Display G"
421 };
422
423 for (size_t i = 0; i < SAL_N_ELEMENTS(pNames); i++)
424 aFontNames.push_back(OUString::createFromAscii(pNames[i]));
425
426 if (bClip && !bRotate)
427 {
428 // only show the first quarter of the text
429 tools::Rectangle aRect( r.TopLeft(), Size( r.GetWidth()/2, r.GetHeight()/2 ) );
430 rDev.SetClipRegion( vcl::Region( aRect ) );
431 }
432
433 for (int i = 1; i < nPrintNumCopies+1; i++)
434 {
435 int nFontHeight=0, nFontIndex=0, nFontColorIndex=0;
436
437 if (nPrintNumCopies == 1)
438 {
439 float const nFontMagnitude = 0.25f;
440 // random font size to avoid buffering
441 nFontHeight = 1 + nFontMagnitude * (0.9 + comphelper::rng::uniform_real_distribution(0.0, std::nextafter(0.1, DBL_MAX))) * (r.Bottom() - r.Top());
442 nFontIndex=0;
443 nFontColorIndex=0;
444 }
445 else
446 {
447 // random font size to avoid buffering
448 nFontHeight = 1 + i * (0.9 + comphelper::rng::uniform_real_distribution(0.0, std::nextafter(0.1, DBL_MAX))) * (r.Top() - r.Bottom()) / nPrintNumCopies;
449 nFontIndex = (i % aFontNames.size());
450 nFontColorIndex=(i % aFontNames.size());
451 }
452
453 rDev.SetTextColor(nCols[nFontColorIndex]);
454 vcl::Font aFont( aFontNames[nFontIndex], Size(0, nFontHeight ));
455
456 if (bRotate)
457 {
458 tools::Rectangle aFontRect = r;
459
460 int nHeight = r.GetHeight();
461
462 // move the text to the bottom of the bounding rect before rotating
463 aFontRect.AdjustTop(nHeight/2 );
464 aFontRect.AdjustBottom(nHeight );
465
466 aFont.SetOrientation(450_deg10); // 45 degrees
467
468 rDev.SetFont(aFont);
469 rDev.DrawText(aFontRect, aText);
470
471 if (bClip)
472 {
473 tools::Rectangle aClipRect( Point( r.Left(), r.Top() + ( r.GetHeight()/2 ) ) , Size( r.GetWidth()/2, r.GetHeight()/2 ) );
474 rDev.SetClipRegion( vcl::Region( aClipRect ) );
475 }
476 else
477 rDev.SetClipRegion( vcl::Region(r) );
478 }
479 else
480 {
481 rDev.SetFont(aFont);
482 rDev.DrawText(r, aText);
483 }
484 }
485
486 rDev.SetClipRegion();
487 }
488
drawComplex__anonae1f6d930211::DemoRenderer::DrawText489 static void drawComplex (OutputDevice &rDev, tools::Rectangle r)
490 {
491 const unsigned char pInvalid[] = { 0xfe, 0x1f, 0 };
492 const unsigned char pDiacritic1[] = { 0x61, 0xcc, 0x8a, 0xcc, 0x8c, 0 };
493 const unsigned char pDiacritic2[] = { 0x61, 0xcc, 0x88, 0xcc, 0x86, 0 };
494 const unsigned char pDiacritic3[] = { 0x61, 0xcc, 0x8b, 0xcc, 0x87, 0 };
495 const unsigned char pJustification[] = {
496 0x64, 0x20, 0xc3, 0xa1, 0xc3, 0xa9, 0x77, 0xc4, 0x8d,
497 0xc5, 0xa1, 0xc3, 0xbd, 0xc5, 0x99, 0x20, 0xc4, 0x9b, 0
498 };
499 const unsigned char pEmojis[] = {
500 0xf0, 0x9f, 0x8d, 0x80, 0xf0, 0x9f, 0x91, 0x98,
501 0xf0, 0x9f, 0x92, 0x8a, 0xf0, 0x9f, 0x92, 0x99,
502 0xf0, 0x9f, 0x92, 0xa4, 0xf0, 0x9f, 0x94, 0x90, 0
503 };
504 const unsigned char pThreeBowlG[] = {
505 0xe2, 0x9a, 0x82, 0xe2, 0x99, 0xa8, 0xc4, 0x9e, 0
506 };
507 const unsigned char pWavesAndDomino[] = {
508 0xe2, 0x99, 0x92, 0xf0, 0x9f, 0x81, 0xa0,
509 0xf0, 0x9f, 0x82, 0x93, 0
510 };
511 const unsigned char pSpadesAndBits[] = {
512 0xf0, 0x9f, 0x82, 0xa1, 0xc2, 0xa2, 0xc2, 0xa2, 0
513 };
514
515 static struct {
516 const char *mpFont;
517 const char *mpString;
518 } const aRuns[] = {
519 #define SET(font,string) { font, reinterpret_cast<const char *>(string) }
520 {"sans", "a"}, // logical font - no 'sans' font.
521 {"opensymbol", "#$%"}, // font fallback - $ is missing.
522 SET("sans", pInvalid), // unicode invalid character
523 // tdf#96266 - stacking diacritics
524 SET("carlito", pDiacritic1),
525 SET("carlito", pDiacritic2),
526 SET("carlito", pDiacritic3),
527 SET("liberation sans", pDiacritic1),
528 SET("liberation sans", pDiacritic2),
529 SET("liberation sans", pDiacritic3),
530 SET("liberation sans", pDiacritic3),
531
532 // tdf#95222 - justification issue
533 // - FIXME: replicate justification
534 SET("gentium basic", pJustification),
535
536 // tdf#97319 - Unicode beyond BMP; SMP & Plane 2
537 SET("symbola", pEmojis),
538 SET("symbola", pThreeBowlG),
539 SET("symbola", pWavesAndDomino),
540 SET("symbola", pSpadesAndBits),
541 };
542
543 // Nice clean white background
544 rDev.DrawWallpaper(r, Wallpaper(COL_WHITE));
545 rDev.SetClipRegion(vcl::Region(r));
546
547 Point aPos(r.Left(), r.Top()+20);
548
549 tools::Long nMaxTextHeight = 0;
550 for (size_t i = 0; i < SAL_N_ELEMENTS(aRuns); ++i)
551 {
552 // Legend
553 vcl::Font aIndexFont("sans", Size(0,20));
554 aIndexFont.SetColor( COL_BLACK);
555 tools::Rectangle aTextRect;
556 rDev.SetFont(aIndexFont);
557 OUString aText = OUString::number(i) + ".";
558 rDev.DrawText(aPos, aText);
559 if (rDev.GetTextBoundRect(aTextRect, aText))
560 aPos.Move(aTextRect.GetWidth() + 8, 0);
561
562 // Text
563 FontWeight aWeights[] = { WEIGHT_NORMAL,
564 WEIGHT_BOLD,
565 WEIGHT_NORMAL };
566 FontItalic const aItalics[] = { ITALIC_NONE,
567 ITALIC_NONE,
568 ITALIC_NORMAL };
569 vcl::Font aFont(OUString::createFromAscii(
570 aRuns[i].mpFont),
571 Size(0,42));
572 aFont.SetColor(COL_BLACK);
573 for (size_t j = 0; j < SAL_N_ELEMENTS(aWeights); ++j)
574 {
575 aFont.SetItalic(aItalics[j]);
576 aFont.SetWeight(aWeights[j]);
577 rDev.SetFont(aFont);
578
579 OUString aString(aRuns[i].mpString,
580 strlen(aRuns[i].mpString),
581 RTL_TEXTENCODING_UTF8);
582 tools::Long nNewX = drawStringBox(rDev, aPos, aString,
583 nMaxTextHeight);
584
585 aPos.setX( nNewX );
586
587 if (aPos.X() >= r.Right())
588 {
589 aPos = Point(r.Left(), aPos.Y() + nMaxTextHeight + 15);
590 nMaxTextHeight = 0;
591 if(j>0)
592 j--; // re-render the last point.
593 }
594 if (aPos.Y() > r.Bottom())
595 break;
596 }
597 if (aPos.Y() > r.Bottom())
598 break;
599 }
600
601 rDev.SetClipRegion();
602 }
603 // render text, bbox, DX arrays etc.
drawStringBox__anonae1f6d930211::DemoRenderer::DrawText604 static tools::Long drawStringBox(OutputDevice &rDev, Point aPos,
605 const OUString &aText,
606 tools::Long &nMaxTextHeight)
607 {
608 rDev.Push();
609 {
610 tools::Rectangle aTextRect;
611
612 rDev.DrawText(aPos,aText);
613
614 if (rDev.GetTextBoundRect(aTextRect, aText))
615 {
616 aTextRect.Move(aPos.X(), aPos.Y());
617 rDev.SetFillColor();
618 rDev.SetLineColor(COL_BLACK);
619 rDev.DrawRect(aTextRect);
620 if (aTextRect.GetHeight() > nMaxTextHeight)
621 nMaxTextHeight = aTextRect.GetHeight();
622 // This should intersect with the text
623 tools::Rectangle aInnerRect(
624 aTextRect.Left()+1, aTextRect.Top()+1,
625 aTextRect.Right()-1, aTextRect.Bottom()-1);
626 rDev.SetLineColor(COL_WHITE);
627 rDev.SetRasterOp(RasterOp::Xor);
628 rDev.DrawRect(aInnerRect);
629 rDev.SetRasterOp(RasterOp::OverPaint);
630 }
631
632 // DX array rendering
633 std::unique_ptr<tools::Long[]> pItems(new tools::Long[aText.getLength()+10]);
634 rDev.GetTextArray(aText, pItems.get());
635 for (tools::Long j = 0; j < aText.getLength(); ++j)
636 {
637 Point aTop = aTextRect.TopLeft();
638 Point aBottom = aTop;
639 aTop.Move(pItems[j], 0);
640 aBottom.Move(pItems[j], aTextRect.GetHeight());
641 rDev.SetLineColor(COL_RED);
642 rDev.SetRasterOp(RasterOp::Xor);
643 rDev.DrawLine(aTop,aBottom);
644 rDev.SetRasterOp(RasterOp::OverPaint);
645 }
646
647 aPos.Move(aTextRect.GetWidth() + 16, 0);
648 }
649 rDev.Pop();
650 return aPos.X();
651 }
652 };
653
654 struct DrawCheckered : public RegionRenderer
655 {
656 RENDER_DETAILS(checks,KEY_C,20)
RenderRegion__anonae1f6d930211::DemoRenderer::DrawCheckered657 virtual void RenderRegion(OutputDevice &rDev, tools::Rectangle r,
658 const RenderContext &rCtx) override
659 {
660 if (rCtx.meStyle == RENDER_EXPANDED)
661 {
662 std::vector<tools::Rectangle> aRegions(DemoRenderer::partition(rCtx, 2, 2));
663 for (size_t i = 0; i < aRegions.size(); i++)
664 {
665 vcl::Region aRegion;
666 tools::Rectangle aSub(aRegions[i]);
667 tools::Rectangle aSmaller(aSub);
668 aSmaller.Move(10,10);
669 aSmaller.setWidth(aSmaller.getWidth()-20);
670 aSmaller.setHeight(aSmaller.getHeight()-24);
671 switch (i) {
672 case 0:
673 aRegion = vcl::Region(aSub);
674 break;
675 case 1:
676 aRegion = vcl::Region(aSmaller);
677 aRegion.XOr(aSub);
678 break;
679 case 2:
680 {
681 tools::Polygon aPoly(aSub);
682 aPoly.Rotate(aSub.Center(), 450_deg10);
683 aPoly.Clip(aSmaller);
684 aRegion = vcl::Region(aPoly);
685 break;
686 }
687 case 3:
688 {
689 tools::PolyPolygon aPolyPoly;
690 sal_Int32 nTW = aSub.GetWidth()/6;
691 sal_Int32 nTH = aSub.GetHeight()/6;
692 tools::Rectangle aTiny(Point(4, 4), Size(nTW*2, nTH*2));
693 aPolyPoly.Insert( tools::Polygon(aTiny));
694 aTiny.Move(nTW*3, nTH*3);
695 aPolyPoly.Insert( tools::Polygon(aTiny));
696 aTiny.Move(nTW, nTH);
697 aPolyPoly.Insert( tools::Polygon(aTiny));
698
699 aRegion = vcl::Region(aPolyPoly);
700 break;
701 }
702 } // switch
703 rDev.SetClipRegion(aRegion);
704 rDev.DrawCheckered(aSub.TopLeft(), aSub.GetSize());
705 rDev.SetClipRegion();
706 }
707 }
708 else
709 {
710 rDev.DrawCheckered(r.TopLeft(), r.GetSize());
711 }
712 }
713 };
714
715 struct DrawPoly : public RegionRenderer
716 {
717 RENDER_DETAILS(poly,KEY_P,20)
718 DrawCheckered maCheckered;
RenderRegion__anonae1f6d930211::DemoRenderer::DrawPoly719 virtual void RenderRegion(OutputDevice &rDev, tools::Rectangle r,
720 const RenderContext &rCtx) override
721 {
722 maCheckered.RenderRegion(rDev, r, rCtx);
723
724 tools::Long nDx = r.GetWidth()/20;
725 tools::Long nDy = r.GetHeight()/20;
726 tools::Rectangle aShrunk(r);
727 aShrunk.Move(nDx, nDy);
728 aShrunk.SetSize(Size(r.GetWidth()-nDx*2,
729 r.GetHeight()-nDy*2));
730 tools::Polygon aPoly(aShrunk);
731 tools::PolyPolygon aPPoly(aPoly);
732 rDev.SetLineColor(COL_RED);
733 rDev.SetFillColor(COL_RED);
734 // This hits the optional 'drawPolyPolygon' code-path
735 rDev.DrawTransparent(aPPoly, 64);
736 }
737 };
738
739 struct DrawEllipse : public RegionRenderer
740 {
741 RENDER_DETAILS(ellipse,KEY_E,500)
doInvert__anonae1f6d930211::DemoRenderer::DrawEllipse742 static void doInvert(OutputDevice &rDev, const tools::Rectangle &r,
743 InvertFlags nFlags)
744 {
745 rDev.Invert(r, nFlags);
746 if (r.GetWidth() > 10 && r.GetHeight() > 10)
747 {
748 tools::Rectangle aSmall(r.Center()-Point(4,4), Size(8,8));
749 rDev.Invert(aSmall,nFlags);
750 }
751 }
RenderRegion__anonae1f6d930211::DemoRenderer::DrawEllipse752 virtual void RenderRegion(OutputDevice &rDev, tools::Rectangle r,
753 const RenderContext &rCtx) override
754 {
755 rDev.SetLineColor(COL_RED);
756 rDev.SetFillColor(COL_GREEN);
757 rDev.DrawEllipse(r);
758
759 if (rCtx.meStyle == RENDER_EXPANDED)
760 {
761 auto aRegions = partition(rCtx, 2, 2);
762 doInvert(rDev, aRegions[0], InvertFlags::NONE);
763 rDev.DrawText(aRegions[0], "InvertFlags::NONE");
764 doInvert(rDev, aRegions[1], InvertFlags::N50);
765 rDev.DrawText(aRegions[1], "InvertFlags::N50");
766 doInvert(rDev, aRegions[3], InvertFlags::TrackFrame);
767 rDev.DrawText(aRegions[3], "InvertFlags::TrackFrame");
768 }
769 }
770 };
771
772 struct DrawGradient : public RegionRenderer
773 {
774 RENDER_DETAILS(gradient,KEY_G,50)
RenderRegion__anonae1f6d930211::DemoRenderer::DrawGradient775 virtual void RenderRegion(OutputDevice &rDev, tools::Rectangle r,
776 const RenderContext &rCtx) override
777 {
778 if (rCtx.meStyle == RENDER_EXPANDED)
779 {
780 std::vector<tools::Rectangle> aRegions(DemoRenderer::partition(rCtx,5, 4));
781 static Color const nStartCols[] = {
782 COL_RED, COL_RED, COL_RED, COL_GREEN, COL_GREEN,
783 COL_BLUE, COL_BLUE, COL_BLUE, COL_CYAN, COL_CYAN,
784 COL_BLACK, COL_LIGHTGRAY, COL_WHITE, COL_BLUE, COL_CYAN,
785 COL_WHITE, COL_WHITE, COL_WHITE, COL_BLACK, COL_BLACK
786 };
787 static Color const nEndCols[] = {
788 COL_WHITE, COL_WHITE, COL_WHITE, COL_BLACK, COL_BLACK,
789 COL_RED, COL_RED, COL_RED, COL_GREEN, COL_GREEN,
790 COL_GRAY, COL_GRAY, COL_LIGHTGRAY, COL_LIGHTBLUE, COL_LIGHTCYAN,
791 COL_BLUE, COL_BLUE, COL_BLUE, COL_CYAN, COL_CYAN
792 };
793 GradientStyle eStyles[] = {
794 GradientStyle::Linear, GradientStyle::Axial, GradientStyle::Radial, GradientStyle::Elliptical, GradientStyle::Square,
795 GradientStyle::Rect, GradientStyle::FORCE_EQUAL_SIZE, GradientStyle::Linear, GradientStyle::Radial, GradientStyle::Linear,
796 GradientStyle::Linear, GradientStyle::Axial, GradientStyle::Radial, GradientStyle::Elliptical, GradientStyle::Square,
797 GradientStyle::Rect, GradientStyle::FORCE_EQUAL_SIZE, GradientStyle::Linear, GradientStyle::Radial, GradientStyle::Linear
798 };
799 sal_uInt16 nAngles[] = {
800 0, 0, 0, 0, 0,
801 15, 30, 45, 60, 75,
802 90, 120, 135, 160, 180,
803 0, 0, 0, 0, 0
804 };
805 sal_uInt16 nBorders[] = {
806 0, 0, 0, 0, 0,
807 1, 10, 100, 10, 1,
808 0, 0, 0, 0, 0,
809 1, 10, 20, 10, 1,
810 0, 0, 0, 0, 0
811 };
812 DemoRenderer::clearRects(rDev, aRegions);
813 assert(aRegions.size() <= SAL_N_ELEMENTS(nStartCols));
814 assert(aRegions.size() <= SAL_N_ELEMENTS(nEndCols));
815 assert(aRegions.size() <= SAL_N_ELEMENTS(eStyles));
816 assert(aRegions.size() <= SAL_N_ELEMENTS(nAngles));
817 assert(aRegions.size() <= SAL_N_ELEMENTS(nBorders));
818 for (size_t i = 0; i < aRegions.size(); i++)
819 {
820 tools::Rectangle aSub = aRegions[i];
821 Gradient aGradient;
822 aGradient.SetStartColor(nStartCols[i]);
823 aGradient.SetEndColor(nEndCols[i]);
824 aGradient.SetStyle(eStyles[i]);
825 aGradient.SetAngle(Degree10(nAngles[i]));
826 aGradient.SetBorder(nBorders[i]);
827 rDev.DrawGradient(aSub, aGradient);
828 }
829 }
830 else
831 {
832 Gradient aGradient;
833 aGradient.SetStartColor(COL_YELLOW);
834 aGradient.SetEndColor(COL_RED);
835 aGradient.SetStyle(GradientStyle::Rect);
836 aGradient.SetBorder(r.GetSize().Width()/20);
837 rDev.DrawGradient(r, aGradient);
838 }
839 }
840 };
841
842 struct DrawBitmap : public RegionRenderer
843 {
844 RENDER_DETAILS(bitmap,KEY_B,10)
845
846 // Simulate Page Borders rendering - which ultimately should
847 // be done with a shader / gradient
SimulateBorderStretch__anonae1f6d930211::DemoRenderer::DrawBitmap848 static void SimulateBorderStretch(OutputDevice &rDev, const tools::Rectangle& r)
849 {
850 BitmapEx aPageShadowMask("sw/res/page-shadow-mask.png");
851
852 BitmapEx aRight(aPageShadowMask);
853 sal_Int32 nSlice = (aPageShadowMask.GetSizePixel().Width() - 3) / 4;
854 // a width x 1 slice
855 aRight.Crop(tools::Rectangle(Point((nSlice * 3) + 3, (nSlice * 2) + 1),
856 Size(nSlice, 1)));
857 AlphaMask aAlphaMask(aRight.GetBitmap());
858 Bitmap aBlockColor(aAlphaMask.GetSizePixel(), vcl::PixelFormat::N24_BPP);
859 aBlockColor.Erase(COL_RED);
860 BitmapEx aShadowStretch(aBlockColor, aAlphaMask);
861
862 Point aRenderPt(r.TopLeft());
863
864 tools::Long aSizes[] = { 200, 100, 200, 100, 50, 5, 2 };
865
866 // and yes - we really do this in the page border rendering code ...
867 for (size_t i = 0; i < SAL_N_ELEMENTS(aSizes); i++)
868 {
869 aShadowStretch.Scale(Size(aShadowStretch.GetSizePixel().Width(), aSizes[i]),
870 BmpScaleFlag::Fast);
871
872 rDev.DrawBitmapEx(aRenderPt, aShadowStretch);
873 aRenderPt.Move(aShadowStretch.GetSizePixel().Width() + 4, 0);
874 }
875
876 AlphaMask aWholeMask(aPageShadowMask.GetBitmap());
877 aBlockColor = Bitmap(aPageShadowMask.GetSizePixel(), vcl::PixelFormat::N24_BPP);
878 aBlockColor.Erase(COL_GREEN);
879 BitmapEx aWhole(aBlockColor, aWholeMask);
880
881 aRenderPt = r.Center();
882 aRenderPt.Move(nSlice+1, 0);
883
884 // An offset background for alpha rendering
885 rDev.SetFillColor(COL_BLUE);
886 tools::Rectangle aSurround(r.Center(), aPageShadowMask.GetSizePixel());
887 rDev.DrawRect(aSurround);
888 rDev.DrawBitmapEx(aRenderPt, aWhole);
889 }
890
RenderRegion__anonae1f6d930211::DemoRenderer::DrawBitmap891 virtual void RenderRegion(OutputDevice &rDev, tools::Rectangle r,
892 const RenderContext &rCtx) override
893 {
894 Bitmap aBitmap(rCtx.mpDemoRenderer->maIntroBW);
895 aBitmap.Scale(r.GetSize(), BmpScaleFlag::BestQuality);
896 rDev.DrawBitmap(r.TopLeft(), aBitmap);
897
898 SimulateBorderStretch(rDev, r);
899 }
900 };
901
902 struct DrawBitmapEx : public RegionRenderer
903 {
904 RENDER_DETAILS(bitmapex,KEY_X,2)
905 DrawCheckered maCheckered;
RenderRegion__anonae1f6d930211::DemoRenderer::DrawBitmapEx906 virtual void RenderRegion(OutputDevice &rDev, tools::Rectangle r,
907 const RenderContext &rCtx) override
908 {
909 maCheckered.RenderRegion(rDev, r, rCtx);
910
911 BitmapEx aBitmap(rCtx.mpDemoRenderer->maIntro);
912 aBitmap.Scale(r.GetSize(), BmpScaleFlag::BestQuality);
913 AlphaMask aSemiTransp(aBitmap.GetSizePixel());
914 aSemiTransp.Erase(64);
915 rDev.DrawBitmapEx(r.TopLeft(), BitmapEx(aBitmap.GetBitmap(),
916 aSemiTransp));
917 }
918 };
919
920 struct DrawPolyPolygons : public RegionRenderer
921 {
922 RENDER_DETAILS(polypoly,KEY_N,100)
RenderRegion__anonae1f6d930211::DemoRenderer::DrawPolyPolygons923 virtual void RenderRegion(OutputDevice &rDev, tools::Rectangle r,
924 const RenderContext &) override
925 {
926 static struct {
927 double nX, nY;
928 } const aPoints[] = { { 0.1, 0.1 }, { 0.9, 0.9 },
929 #if FIXME_SELF_INTERSECTING_WORKING
930 { 0.9, 0.1 }, { 0.1, 0.9 },
931 { 0.1, 0.1 }
932 #else
933 { 0.1, 0.9 }, { 0.5, 0.5 },
934 { 0.9, 0.1 }, { 0.1, 0.1 }
935 #endif
936 };
937
938 tools::PolyPolygon aPolyPoly;
939 // Render 4x polygons & aggregate into another PolyPolygon
940 for (int x = 0; x < 2; x++)
941 {
942 for (int y = 0; y < 2; y++)
943 {
944 tools::Rectangle aSubRect(r);
945 aSubRect.Move(x * r.GetWidth()/3, y * r.GetHeight()/3);
946 aSubRect.SetSize(Size(r.GetWidth()/2, r.GetHeight()/4));
947 tools::Polygon aPoly(SAL_N_ELEMENTS(aPoints));
948 for (size_t v = 0; v < SAL_N_ELEMENTS(aPoints); v++)
949 {
950 aPoly.SetPoint(Point(aSubRect.Left() +
951 aSubRect.GetWidth() * aPoints[v].nX,
952 aSubRect.Top() +
953 aSubRect.GetHeight() * aPoints[v].nY),
954 v);
955 }
956 rDev.SetLineColor(COL_YELLOW);
957 rDev.SetFillColor(COL_BLACK);
958 rDev.DrawPolygon(aPoly);
959
960 // now move and add to the polypolygon
961 aPoly.Move(0, r.GetHeight()/2);
962 aPolyPoly.Insert(aPoly);
963 }
964 }
965 rDev.SetLineColor(COL_LIGHTRED);
966 rDev.SetFillColor(COL_GREEN);
967 rDev.DrawTransparent(aPolyPoly, 50);
968 }
969 };
970
971 struct DrawClipped : public RegionRenderer
972 {
973 RENDER_DETAILS(clip,KEY_D,10)
RenderRegion__anonae1f6d930211::DemoRenderer::DrawClipped974 virtual void RenderRegion(OutputDevice &rDev, tools::Rectangle r,
975 const RenderContext &) override
976 {
977 std::vector<tools::Rectangle> aRegions(DemoRenderer::partition(r, 2, 2));
978 const int nLimits[] = { 4, -100 };
979 for (int i = 0; i < 2; ++i)
980 {
981 sal_uInt16 nHue = 0;
982 rDev.Push(PushFlags::CLIPREGION);
983 tools::Rectangle aOuter = aRegions[i];
984 tools::Rectangle aInner = aOuter;
985 while (aInner.GetWidth() > nLimits[i] && aInner.GetHeight() > nLimits[i])
986 {
987 aInner.expand(-1);
988 rDev.SetClipRegion(vcl::Region(aInner));
989 rDev.SetFillColor(Color::HSBtoRGB(nHue, 75, 100));
990 nHue = (nHue + 97) % 360;
991 rDev.DrawRect(aOuter);
992 }
993 rDev.Pop();
994 }
995
996 {
997 sal_uInt16 nHue = 0;
998 tools::Rectangle aOuter = aRegions[2];
999 std::vector<tools::Rectangle> aPieces(DemoRenderer::partition(aOuter, 2, 2));
1000 for (int j = 0; j < std::min(aOuter.GetWidth(), aOuter.GetHeight())/5; ++j)
1001 {
1002 rDev.Push(PushFlags::CLIPREGION);
1003
1004 vcl::Region aClipRegion;
1005 for (int i = 0; i < 4; ++i)
1006 {
1007 aPieces[i].expand(-1);
1008 aPieces[i].Move(2 - i/2, 2 - i/2);
1009 aClipRegion.Union(aPieces[i]);
1010 }
1011 assert (aClipRegion.getRegionBand());
1012 rDev.SetClipRegion(aClipRegion);
1013 rDev.SetFillColor(Color::HSBtoRGB(nHue, 75, 75));
1014 nHue = (nHue + 97) % 360;
1015 rDev.DrawRect(aOuter);
1016
1017 rDev.Pop();
1018 }
1019 }
1020
1021 {
1022 sal_uInt16 nHue = 0;
1023 tools::Rectangle aOuter = aRegions[3];
1024 std::vector<tools::Rectangle> aPieces(DemoRenderer::partition(aOuter, 2, 2));
1025 bool bDone = false;
1026 for (int j = 0; !bDone; ++j)
1027 {
1028 rDev.Push(PushFlags::CLIPREGION);
1029
1030 for (int i = 0; i < 4; ++i)
1031 {
1032 vcl::Region aClipRegion;
1033 tools::Polygon aPoly;
1034 switch (i) {
1035 case 3:
1036 case 0: // 45degree rectangle.
1037 aPoly = tools::Polygon(aPieces[i]);
1038 aPoly.Rotate(aPieces[i].Center(), 450_deg10);
1039 break;
1040 case 1: // arc
1041 aPoly = tools::Polygon(aPieces[i],
1042 aPieces[i].TopLeft(),
1043 aPieces[i].BottomRight());
1044 break;
1045 case 2:
1046 aPoly = tools::Polygon(aPieces[i],
1047 aPieces[i].GetWidth()/5,
1048 aPieces[i].GetHeight()/5);
1049 aPoly.Rotate(aPieces[i].Center(), 450_deg10);
1050 break;
1051 }
1052 aClipRegion = vcl::Region(aPoly);
1053 aPieces[i].expand(-1);
1054 aPieces[i].Move(2 - i/2, 2 - i/2);
1055
1056 bDone = aPieces[i].GetWidth() < 4 ||
1057 aPieces[i].GetHeight() < 4;
1058
1059 if (!bDone)
1060 {
1061 assert (!aClipRegion.getRegionBand());
1062
1063 rDev.SetClipRegion(aClipRegion);
1064 rDev.SetFillColor(Color::HSBtoRGB(nHue, 50, 75));
1065 nHue = (nHue + 97) % 360;
1066 rDev.DrawRect(aOuter);
1067 }
1068 }
1069
1070 rDev.Pop();
1071 }
1072 }
1073 }
1074 };
1075
1076 struct DrawToVirtualDevice : public RegionRenderer
1077 {
1078 RENDER_DETAILS(vdev,KEY_V,1)
1079 enum RenderType {
1080 RENDER_AS_BITMAP,
1081 RENDER_AS_OUTDEV,
1082 RENDER_AS_BITMAPEX,
1083 RENDER_AS_ALPHA_OUTDEV
1084 };
1085
SizeAndRender__anonae1f6d930211::DemoRenderer::DrawToVirtualDevice1086 static void SizeAndRender(OutputDevice &rDev, const tools::Rectangle& r, RenderType eType,
1087 const RenderContext &rCtx)
1088 {
1089 ScopedVclPtr<VirtualDevice> pNested;
1090
1091 if (static_cast<int>(eType) < RENDER_AS_BITMAPEX)
1092 pNested = VclPtr<VirtualDevice>::Create(rDev).get();
1093 else
1094 pNested = VclPtr<VirtualDevice>::Create(rDev,DeviceFormat::DEFAULT,DeviceFormat::DEFAULT).get();
1095
1096 pNested->SetOutputSizePixel(r.GetSize());
1097 tools::Rectangle aWhole(Point(0,0), r.GetSize());
1098
1099 // mini me
1100 rCtx.mpDemoRenderer->drawToDevice(*pNested, r.GetSize(), true);
1101
1102 if (eType == RENDER_AS_BITMAP)
1103 {
1104 Bitmap aBitmap(pNested->GetBitmap(Point(0,0),aWhole.GetSize()));
1105 rDev.DrawBitmap(r.TopLeft(), aBitmap);
1106 }
1107 else if (eType == RENDER_AS_BITMAPEX)
1108 {
1109 BitmapEx aBitmapEx(pNested->GetBitmapEx(Point(0,0),aWhole.GetSize()));
1110 rDev.DrawBitmapEx(r.TopLeft(), aBitmapEx);
1111 }
1112 else if (eType == RENDER_AS_OUTDEV ||
1113 eType == RENDER_AS_ALPHA_OUTDEV)
1114 {
1115 rDev.DrawOutDev(r.TopLeft(), r.GetSize(),
1116 aWhole.TopLeft(), aWhole.GetSize(),
1117 *pNested);
1118 }
1119 }
RenderRegion__anonae1f6d930211::DemoRenderer::DrawToVirtualDevice1120 virtual void RenderRegion(OutputDevice &rDev, tools::Rectangle r,
1121 const RenderContext &rCtx) override
1122 {
1123 // avoid infinite recursion
1124 if (rCtx.mbVDev)
1125 return;
1126
1127 if (rCtx.meStyle == RENDER_EXPANDED)
1128 {
1129 std::vector<tools::Rectangle> aRegions(DemoRenderer::partition(rCtx,2, 2));
1130 DemoRenderer::clearRects(rDev, aRegions);
1131
1132 RenderType const eRenderTypes[] { RENDER_AS_BITMAP, RENDER_AS_OUTDEV,
1133 RENDER_AS_BITMAPEX, RENDER_AS_ALPHA_OUTDEV };
1134 for (size_t i = 0; i < aRegions.size(); i++)
1135 SizeAndRender(rDev, aRegions[i], eRenderTypes[i], rCtx);
1136 }
1137 else
1138 SizeAndRender(rDev, r, RENDER_AS_BITMAP, rCtx);
1139 }
1140 };
1141
1142 struct DrawXOR : public RegionRenderer
1143 {
1144 RENDER_DETAILS(xor,KEY_X,1)
1145
RenderRegion__anonae1f6d930211::DemoRenderer::DrawXOR1146 virtual void RenderRegion(OutputDevice &rDev, tools::Rectangle r,
1147 const RenderContext &rCtx) override
1148 {
1149 // avoid infinite recursion
1150 if (rCtx.mbVDev)
1151 return;
1152
1153 rDev.Push();
1154
1155 AntialiasingFlags nFlags = rDev.GetAntialiasing();
1156 rDev.SetAntialiasing(nFlags & ~AntialiasingFlags::Enable);
1157 rDev.SetRasterOp( RasterOp::Xor );
1158
1159 rCtx.mpDemoRenderer->drawThumbs(rDev, r, true);
1160
1161 rDev.Pop();
1162 }
1163 };
1164
1165 struct DrawIcons : public RegionRenderer
1166 {
1167 RENDER_DETAILS(icons,KEY_I,1)
1168
1169 std::vector<OUString> maIconNames;
1170 std::vector<BitmapEx> maIcons;
1171 bool bHasLoadedAll;
DrawIcons__anonae1f6d930211::DemoRenderer::DrawIcons1172 DrawIcons() : bHasLoadedAll(false)
1173 {
1174 // a few icons to start with
1175 const char *pNames[] = {
1176 "cmd/lc_openurl.png",
1177 "cmd/lc_newdoc.png",
1178 "cmd/lc_choosemacro.png",
1179 "cmd/lc_save.png",
1180 "cmd/lc_saveas.png",
1181 "cmd/lc_importdialog.png",
1182 "cmd/lc_sendmail.png",
1183 "cmd/lc_editdoc.png",
1184 "cmd/lc_print.png",
1185 "cmd/lc_combobox.png",
1186 "cmd/lc_insertformcombo.png",
1187 "cmd/lc_printpreview.png",
1188 "cmd/lc_cut.png",
1189 "cmd/lc_copy.png",
1190 "cmd/lc_paste.png",
1191 "cmd/sc_autopilotmenu.png",
1192 "cmd/lc_formatpaintbrush.png",
1193 "cmd/lc_undo.png",
1194 "cmd/lc_redo.png",
1195 "cmd/lc_marks.png",
1196 "cmd/lc_fieldnames.png",
1197 "cmd/lc_hyperlinkdialog.png",
1198 "cmd/lc_basicshapes.rectangle.png",
1199 "cmd/lc_basicshapes.round-rectangle.png"
1200 };
1201 for (size_t i = 0; i < SAL_N_ELEMENTS(pNames); i++)
1202 {
1203 maIconNames.push_back(OUString::createFromAscii(pNames[i]));
1204 maIcons.emplace_back(maIconNames[i]);
1205 }
1206 }
1207
LoadAllImages__anonae1f6d930211::DemoRenderer::DrawIcons1208 void LoadAllImages()
1209 {
1210 if (bHasLoadedAll)
1211 return;
1212 bHasLoadedAll = true;
1213
1214 css::uno::Reference<css::container::XNameAccess> xRef(ImageTree::get().getNameAccess());
1215 const css::uno::Sequence< OUString > aAllIcons = xRef->getElementNames();
1216
1217 for (const auto& rIcon : aAllIcons)
1218 {
1219 if (rIcon.endsWithIgnoreAsciiCase("svg"))
1220 continue; // too slow to load.
1221 maIconNames.push_back(rIcon);
1222 maIcons.emplace_back(rIcon);
1223 }
1224 }
1225
doDrawIcons__anonae1f6d930211::DemoRenderer::DrawIcons1226 void doDrawIcons(OutputDevice &rDev, tools::Rectangle r, bool bExpanded)
1227 {
1228 tools::Long nMaxH = 0;
1229 Point p(r.LeftCenter());
1230 size_t nToRender = maIcons.size();
1231
1232 if (!bExpanded && maIcons.size() > 64)
1233 nToRender = 64;
1234 for (size_t i = 0; i < nToRender; i++)
1235 {
1236 Size aSize(maIcons[i].GetSizePixel());
1237 // sAL_DEBUG("Draw icon '" << maIconNames[i] << "'");
1238
1239 if (!(i % 4))
1240 rDev.DrawBitmapEx(p, maIcons[i]);
1241 else
1242 {
1243 basegfx::B2DHomMatrix aTransform;
1244 aTransform.scale(aSize.Width(), aSize.Height());
1245 switch (i % 4)
1246 {
1247 case 2:
1248 aTransform.shearX(static_cast<double>((i >> 2) % 8) / 8);
1249 aTransform.shearY(static_cast<double>((i >> 4) % 8) / 8);
1250 break;
1251 case 3:
1252 aTransform.translate(-aSize.Width()/2, -aSize.Height()/2);
1253 aTransform.rotate(i);
1254 if (i & 0x100)
1255 {
1256 aTransform.shearX(static_cast<double>((i >> 2) % 8) / 8);
1257 aTransform.shearY(static_cast<double>((i >> 4) % 8) / 8);
1258 }
1259 aTransform.translate(aSize.Width()/2, aSize.Height()/2);
1260 break;
1261 default:
1262 aTransform.translate(-aSize.Width()/2, -aSize.Height()/2);
1263 aTransform.rotate(2 * F_2PI * i / nToRender);
1264 aTransform.translate(aSize.Width()/2, aSize.Height()/2);
1265 break;
1266 }
1267 aTransform.translate(p.X(), p.Y());
1268 rDev.DrawTransformedBitmapEx(aTransform, maIcons[i]);
1269 }
1270
1271 // next position
1272 p.Move(aSize.Width(), 0);
1273 if (aSize.Height() > nMaxH)
1274 nMaxH = aSize.Height();
1275 if (p.X() >= r.Right()) // wrap to next line
1276 {
1277 p = Point(r.Left(), p.Y() + nMaxH);
1278 nMaxH = 0;
1279 }
1280 if (p.Y() >= r.Bottom()) // re-start at middle
1281 p = r.LeftCenter();
1282 }
1283 }
1284
AlphaRecovery__anonae1f6d930211::DemoRenderer::DrawIcons1285 static BitmapEx AlphaRecovery(OutputDevice &rDev, Point aPt, BitmapEx const &aSrc)
1286 {
1287 // Compositing onto 2x colors beyond our control
1288 ScopedVclPtrInstance< VirtualDevice > aWhite;
1289 ScopedVclPtrInstance< VirtualDevice > aBlack;
1290 aWhite->SetOutputSizePixel(aSrc.GetSizePixel());
1291 aWhite->SetBackground(Wallpaper(COL_WHITE));
1292 aWhite->Erase();
1293 aBlack->SetOutputSizePixel(aSrc.GetSizePixel());
1294 aBlack->SetBackground(Wallpaper(COL_BLACK));
1295 aBlack->Erase();
1296 aWhite->DrawBitmapEx(Point(), aSrc);
1297 aBlack->DrawBitmapEx(Point(), aSrc);
1298
1299 // Now recover that alpha...
1300 Bitmap aWhiteBmp = aWhite->GetBitmap(Point(),aSrc.GetSizePixel());
1301 Bitmap aBlackBmp = aBlack->GetBitmap(Point(),aSrc.GetSizePixel());
1302 AlphaMask aMask(aSrc.GetSizePixel());
1303 Bitmap aRecovered(aSrc.GetSizePixel(), vcl::PixelFormat::N24_BPP);
1304 {
1305 AlphaScopedWriteAccess pMaskAcc(aMask);
1306 BitmapScopedWriteAccess pRecAcc(aRecovered);
1307 Bitmap::ScopedReadAccess pAccW(aWhiteBmp); // a * pix + (1-a)
1308 Bitmap::ScopedReadAccess pAccB(aBlackBmp); // a * pix + 0
1309 int nSizeX = aSrc.GetSizePixel().Width();
1310 int nSizeY = aSrc.GetSizePixel().Height();
1311 for (int y = 0; y < nSizeY; y++)
1312 {
1313 Scanline pScanlineMask = pMaskAcc->GetScanline( y );
1314 Scanline pScanlineRec = pRecAcc->GetScanline( y );
1315 Scanline pScanlineW = pAccW->GetScanline( y );
1316 Scanline pScanlineB = pAccB->GetScanline( y );
1317 for (int x = 0; x < nSizeX; x++)
1318 {
1319 BitmapColor aColW = pAccW->GetPixelFromData(pScanlineW,x);
1320 BitmapColor aColB = pAccB->GetPixelFromData(pScanlineB,x);
1321 tools::Long nAR = static_cast<tools::Long>(aColW.GetRed() - aColB.GetRed()); // (1-a)
1322 tools::Long nAG = static_cast<tools::Long>(aColW.GetGreen() - aColB.GetGreen()); // (1-a)
1323 tools::Long nAB = static_cast<tools::Long>(aColW.GetBlue() - aColB.GetBlue()); // (1-a)
1324
1325 #define CLAMP(a,b,c) (((a)<=(b))?(b):(((a)>=(c))?(c):(a)))
1326
1327 // we get the most precision from the largest delta
1328 tools::Long nInverseAlpha = std::max(nAR, std::max(nAG, nAB)); // (1-a)
1329 nInverseAlpha = CLAMP(nInverseAlpha, 0, 255);
1330 tools::Long nAlpha = 255 - nInverseAlpha;
1331
1332 pMaskAcc->SetPixelOnData(pScanlineMask,x,BitmapColor(static_cast<sal_Int8>(CLAMP(nInverseAlpha,0,255))));
1333 // now recover the pixels
1334 tools::Long nR = (aColW.GetRed() + aColB.GetRed() - nInverseAlpha) * 128;
1335 tools::Long nG = (aColW.GetGreen() + aColB.GetGreen() - nInverseAlpha) * 128;
1336 tools::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;
1340 }
1341 else
1342 {
1343 nR /= nAlpha; nG /= nAlpha; nB /= nAlpha;
1344 }
1345 pRecAcc->SetPixelOnData(pScanlineRec,x,BitmapColor(
1346 static_cast<sal_uInt8>(CLAMP(nR,0,255)),
1347 static_cast<sal_uInt8>(CLAMP(nG,0,255)),
1348 static_cast<sal_uInt8>(CLAMP(nB,0,255))));
1349 #undef CLAMP
1350 }
1351 }
1352 }
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);
1361
1362 return BitmapEx(aRecovered, aMask);
1363 }
1364
RenderRegion__anonae1f6d930211::DemoRenderer::DrawIcons1365 virtual void RenderRegion(OutputDevice &rDev, tools::Rectangle r,
1366 const RenderContext &rCtx) override
1367 {
1368 if (rCtx.meStyle == RENDER_EXPANDED)
1369 {
1370 LoadAllImages();
1371
1372 Point aLocation(0,maIcons[0].GetSizePixel().Height() + 8);
1373 for (size_t i = 0; i < maIcons.size(); i++)
1374 {
1375 BitmapEx aSrc = maIcons[i];
1376
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.GetAlpha());
1386
1387 // intermediates middle
1388 BitmapEx aResult = AlphaRecovery(rDev, aLocation, aSrc);
1389
1390 // result below
1391 Point aBelow(aLocation);
1392 aBelow.Move(0,aResult.GetSizePixel().Height());
1393 rDev.DrawBitmapEx(aBelow, aResult);
1394
1395 // mini convert test.
1396 aBelow.Move(aResult.GetSizePixel().Width()+4,0);
1397 rDev.DrawBitmapEx(aBelow, aResult);
1398
1399 Bitmap aGrey = aSrc.GetBitmap();
1400 aGrey.Convert(BmpConversion::N8BitGreys);
1401 rDev.DrawBitmap(aBelow, aGrey);
1402
1403 aBelow.Move(aGrey.GetSizePixel().Width(),0);
1404 BitmapEx aGreyMask(aSrc.GetBitmap(),
1405 aSrc.GetAlpha());
1406 rDev.DrawBitmapEx(aBelow, aGreyMask);
1407
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);
1411 }
1412
1413 // now go crazy with random foo
1414 doDrawIcons(rDev, r, true);
1415 }
1416 else
1417 {
1418 doDrawIcons(rDev, r, false);
1419 }
1420 }
1421 };
1422
1423 struct FetchDrawBitmap : public RegionRenderer
1424 {
1425 RENDER_DETAILS(fetchdraw,KEY_F,50)
RenderRegion__anonae1f6d930211::DemoRenderer::FetchDrawBitmap1426 virtual void RenderRegion(OutputDevice &rDev, tools::Rectangle r,
1427 const RenderContext &) override
1428 {
1429 Bitmap aBitmap(rDev.GetBitmap(Point(0,0),rDev.GetOutputSizePixel()));
1430 aBitmap.Scale(r.GetSize(), BmpScaleFlag::BestQuality);
1431 rDev.DrawBitmap(r.TopLeft(), aBitmap);
1432 }
1433 };
1434
drawThumbs(vcl::RenderContext & rDev,tools::Rectangle aRect,bool bVDev)1435 void drawThumbs(vcl::RenderContext& rDev, tools::Rectangle aRect, bool bVDev)
1436 {
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++)
1445 {
1446 RegionRenderer * r = maRenderers[i];
1447
1448 rDev.SetClipRegion( vcl::Region( aRegions[i] ) );
1449
1450 // profiling?
1451 if (getIterCount() > 0)
1452 {
1453 if (!bVDev)
1454 {
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);
1462 }
1463 else
1464 r->RenderRegion(rDev, aRegions[i], aCtx);
1465
1466 rDev.SetClipRegion();
1467 }
1468 }
1469
drawToDevice(vcl::RenderContext & rDev,Size aSize,bool bVDev)1470 void drawToDevice(vcl::RenderContext& rDev, Size aSize, bool bVDev)
1471 {
1472 RenderContext aCtx;
1473 aCtx.mbVDev = bVDev;
1474 aCtx.mpDemoRenderer = this;
1475 aCtx.maSize = aSize;
1476 tools::Rectangle aWholeWin(Point(0,0), rDev.GetOutputSizePixel());
1477
1478 drawBackground(rDev, aWholeWin);
1479
1480 if (!bVDev /* want everything in the vdev */ &&
1481 mnSelectedRenderer >= 0 &&
1482 o3tl::make_unsigned(mnSelectedRenderer) < maRenderers.size())
1483 {
1484 aCtx.meStyle = RENDER_EXPANDED;
1485 RegionRenderer * r = maRenderers[mnSelectedRenderer];
1486 // profiling?
1487 if (getIterCount() > 0)
1488 {
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);
1495 }
1496 else
1497 drawThumbs(rDev, aWholeWin, bVDev);
1498 }
1499 std::vector<VclPtr<vcl::Window> > maInvalidates;
addInvalidate(vcl::Window * pWindow)1500 void addInvalidate(vcl::Window *pWindow) { maInvalidates.emplace_back(pWindow); };
removeInvalidate(vcl::Window * pWindow)1501 void removeInvalidate(vcl::Window *pWindow)
1502 {
1503 auto aIt = std::find(maInvalidates.begin(), maInvalidates.end(), pWindow);
1504 if (aIt != maInvalidates.end())
1505 maInvalidates.erase(aIt);
1506 }
Invalidate()1507 void Invalidate()
1508 {
1509 for (auto const& invalidate : maInvalidates)
1510 invalidate->Invalidate();
1511 }
1512 };
1513
1514 }
1515
1516 #if FIXME_BOUNCE_BUTTON
IMPL_LINK_NOARG(DemoRenderer,BounceTimerCb,Timer *,void)1517 IMPL_LINK_NOARG(DemoRenderer,BounceTimerCb,Timer*,void)
1518 {
1519 mpButton->Check(mnBounceX>0);
1520 mpButton->SetPressed(mnBounceY>0);
1521
1522 Point aCur = mpButtonWin->GetPosPixel();
1523 static const int nMovePix = 10;
1524 aCur.Move(mnBounceX * nMovePix, mnBounceX * nMovePix);
1525 Size aWinSize = GetSizePixel();
1526 if (aCur.X() <= 0 || aCur.X() >= aWinSize.Width())
1527 mnBounceX *= -1;
1528 if (aCur.Y() <= 0 || aCur.Y() >= aWinSize.Height())
1529 mnBounceX *= -1;
1530 mpButtonWin->SetPosPixel(aCur);
1531
1532 // All smoke and mirrors to test sub-region invalidation underneath
1533 Rectangle aRect(aCur, mpButtonWin->GetSizePixel());
1534 Invalidate(aRect);
1535 }
1536 #endif
1537
KeyInput(const KeyEvent & rKEvt)1538 void DemoRenderer::KeyInput(const KeyEvent &rKEvt)
1539 {
1540 sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
1541
1542 // click to zoom out
1543 if (mnSelectedRenderer >= 0)
1544 {
1545 if (nCode == KEY_ESCAPE || nCode == KEY_BACKSPACE)
1546 {
1547 mnSelectedRenderer = -1;
1548 Invalidate();
1549 return;
1550 }
1551 }
1552 else
1553 {
1554 for (size_t i = 0; i < maRenderers.size(); i++)
1555 {
1556 if (nCode == maRenderers[i]->getAccelerator())
1557 {
1558 mnSelectedRenderer = i;
1559 Invalidate();
1560 return;
1561 }
1562 }
1563 }
1564 }
1565
MouseButtonDown(const MouseEvent & rMEvt)1566 bool DemoRenderer::MouseButtonDown(const MouseEvent& rMEvt)
1567 {
1568 // click to zoom out
1569 if (mnSelectedRenderer >= 0)
1570 {
1571 mnSelectedRenderer = -1;
1572 Invalidate();
1573 return true;
1574 }
1575
1576 // click on a region to zoom into it
1577 std::vector<tools::Rectangle> aRegions(partition(GetSizePixel(), mnSegmentsX, mnSegmentsY));
1578 for (size_t i = 0; i < aRegions.size(); i++)
1579 {
1580 if (aRegions[i].IsInside(rMEvt.GetPosPixel()))
1581 {
1582 mnSelectedRenderer = i;
1583 Invalidate();
1584 return true;
1585 }
1586 }
1587
1588 #if FIXME_BOUNCE_BUTTON
1589 // otherwise bounce floating windows
1590 if (!mpButton)
1591 {
1592 mpButtonWin = VclPtr<FloatingWindow>::Create(this);
1593 mpButton = VclPtr<PushButton>::Create(mpButtonWin);
1594 mpButton->SetSymbol(SymbolType::HELP);
1595 mpButton->SetText("PushButton demo");
1596 mpButton->SetPosSizePixel(Point(0,0), mpButton->GetOptimalSize());
1597 mpButton->Show();
1598 mpButtonWin->SetPosSizePixel(Point(0,0), mpButton->GetOptimalSize());
1599 mpButtonWin->Show();
1600 mnBounceX = 1; mnBounceX = 1;
1601 maBounce.SetInvokeHandler(LINK(this,DemoRenderer,BounceTimerCb));
1602 maBounce.SetTimeout(55);
1603 maBounce.Start();
1604 }
1605 else
1606 {
1607 maBounce.Stop();
1608 delete mpButtonWin;
1609 mpButtonWin = NULL;
1610 mpButton = NULL;
1611 }
1612 #endif
1613 return false;
1614 }
1615
InitRenderers()1616 void DemoRenderer::InitRenderers()
1617 {
1618 maRenderers.push_back(new DrawLines);
1619 maRenderers.push_back(new DrawText);
1620 maRenderers.push_back(new DrawPoly);
1621 maRenderers.push_back(new DrawEllipse);
1622 maRenderers.push_back(new DrawCheckered);
1623 maRenderers.push_back(new DrawBitmapEx);
1624 maRenderers.push_back(new DrawBitmap);
1625 maRenderers.push_back(new DrawGradient);
1626 maRenderers.push_back(new DrawPolyPolygons);
1627 maRenderers.push_back(new DrawClipped);
1628 maRenderers.push_back(new DrawToVirtualDevice);
1629 maRenderers.push_back(new DrawXOR);
1630 maRenderers.push_back(new DrawIcons());
1631 maRenderers.push_back(new FetchDrawBitmap);
1632 }
1633
getRendererList()1634 OUString DemoRenderer::getRendererList()
1635 {
1636 OUStringBuffer aBuf;
1637 for (size_t i = 0; i < maRenderers.size(); i++)
1638 {
1639 aBuf.append(maRenderers[i]->getName());
1640 aBuf.append(' ');
1641 }
1642 return aBuf.makeStringAndClear();
1643 }
1644
getAndResetBenchmark(const RenderStyle style)1645 double DemoRenderer::getAndResetBenchmark(const RenderStyle style)
1646 {
1647 double geomean = 1.0;
1648 fprintf(stderr, "Rendering: %s, Times (ms):\n", style == RENDER_THUMB ? "THUMB": "EXPANDED");
1649 for (size_t i = 0; i < maRenderers.size(); i++)
1650 {
1651 double avgtime = maRenderers[i]->sumTime / maRenderers[i]->countTime;
1652 geomean *= avgtime;
1653 fprintf(stderr, "%s: %f (iteration: %d*%d*%d)\n",
1654 OUStringToOString(maRenderers[i]->getName(),
1655 RTL_TEXTENCODING_UTF8).getStr(), avgtime,
1656 maRenderers[i]->countTime, maRenderers[i]->getTestRepeatCount(),
1657 (style == RENDER_THUMB) ? THUMB_REPEAT_FACTOR : 1);
1658 maRenderers[i]->sumTime = 0;
1659 maRenderers[i]->countTime = 0;
1660 }
1661 geomean = pow(geomean, 1.0/maRenderers.size());
1662 fprintf(stderr, "GEOMEAN_%s: %f\n", style == RENDER_THUMB ? "THUMB": "EXPANDED", geomean);
1663 return geomean;
1664 }
1665
setIterCount(sal_Int32 i)1666 void DemoRenderer::setIterCount(sal_Int32 i)
1667 {
1668 iterCount = i;
1669 }
1670
getIterCount() const1671 sal_Int32 DemoRenderer::getIterCount() const
1672 {
1673 return iterCount;
1674 }
1675
addTime(int i,double t)1676 void DemoRenderer::addTime(int i, double t)
1677 {
1678 maRenderers[i]->sumTime += t / maRenderers[i]->getTestRepeatCount();
1679 maRenderers[i]->countTime++;
1680 }
1681
selectRenderer(std::u16string_view rName)1682 void DemoRenderer::selectRenderer(std::u16string_view rName )
1683 {
1684 for (size_t i = 0; i < maRenderers.size(); i++)
1685 {
1686 if (maRenderers[i]->getName() == rName)
1687 {
1688 mnSelectedRenderer = i;
1689 Invalidate();
1690 return;
1691 }
1692 }
1693 }
1694
selectNextRenderer()1695 int DemoRenderer::selectNextRenderer()
1696 {
1697 mnSelectedRenderer++;
1698 if (mnSelectedRenderer == static_cast<signed>(maRenderers.size()))
1699 mnSelectedRenderer = -1;
1700 Invalidate();
1701 return mnSelectedRenderer;
1702 }
1703
1704 namespace {
1705
1706 class DemoWin : public WorkWindow
1707 {
1708 DemoRenderer &mrRenderer;
1709 bool underTesting;
1710 bool testThreads;
1711
1712 class RenderThread final : public salhelper::Thread {
1713 DemoWin &mrWin;
1714 sal_uInt32 const mnDelaySecs = 0;
1715 public:
RenderThread(DemoWin & rWin,sal_uInt32 nDelaySecs)1716 RenderThread(DemoWin &rWin, sal_uInt32 nDelaySecs)
1717 : Thread("vcldemo render thread")
1718 , mrWin(rWin)
1719 , mnDelaySecs(nDelaySecs)
1720 {
1721 launch();
1722 }
~RenderThread()1723 virtual ~RenderThread() override
1724 {
1725 join();
1726 }
execute()1727 virtual void execute() override
1728 {
1729 wait(std::chrono::seconds(mnDelaySecs));
1730
1731 SolarMutexGuard aGuard;
1732 fprintf (stderr, "render from a different thread\n");
1733 mrWin.Invalidate();
1734 }
1735 };
1736 rtl::Reference<RenderThread> mxThread;
1737
1738 public:
DemoWin(DemoRenderer & rRenderer,bool bThreads)1739 DemoWin(DemoRenderer &rRenderer, bool bThreads) :
1740 WorkWindow(nullptr, WB_APP | WB_STDWORK),
1741 mrRenderer(rRenderer),
1742 testThreads(bThreads)
1743 {
1744 mrRenderer.addInvalidate(this);
1745 underTesting = false;
1746 }
~DemoWin()1747 virtual ~DemoWin() override
1748 {
1749 disposeOnce();
1750 }
dispose()1751 virtual void dispose() override
1752 {
1753 mxThread.clear();
1754 mrRenderer.removeInvalidate(this);
1755 WorkWindow::dispose();
1756 }
MouseButtonDown(const MouseEvent & rMEvt)1757 virtual void MouseButtonDown(const MouseEvent& rMEvt) override
1758 {
1759 mrRenderer.SetSizePixel(GetSizePixel());
1760 if (mrRenderer.MouseButtonDown(rMEvt))
1761 return;
1762
1763 if (testThreads)
1764 { // render this window asynchronously in a new thread
1765 sal_uInt32 nDelaySecs = 0;
1766 if (rMEvt.GetButtons() & MOUSE_RIGHT)
1767 nDelaySecs = 5;
1768 mxThread = new RenderThread(*this, nDelaySecs);
1769 }
1770 else
1771 { // spawn another window
1772 VclPtrInstance<DemoWin> pNewWin(mrRenderer, testThreads);
1773 pNewWin->SetText("Another interactive VCL demo window");
1774 pNewWin->Show();
1775 }
1776 }
KeyInput(const KeyEvent & rKEvt)1777 virtual void KeyInput(const KeyEvent& rKEvt) override
1778 {
1779 mrRenderer.SetSizePixel(GetSizePixel());
1780 mrRenderer.KeyInput(rKEvt);
1781 }
Paint(vcl::RenderContext & rRenderContext,const tools::Rectangle & rRect)1782 virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override
1783 {
1784 mrRenderer.SetSizePixel(GetSizePixel());
1785 fprintf(stderr, "DemoWin::Paint(%" SAL_PRIdINT64 ",%" SAL_PRIdINT64 ",%" SAL_PRIdINT64 ",%" SAL_PRIdINT64 ")\n", sal_Int64(rRect.getX()), sal_Int64(rRect.getY()), sal_Int64(rRect.getWidth()), sal_Int64(rRect.getHeight()));
1786 if (mrRenderer.getIterCount() == 0)
1787 mrRenderer.drawToDevice(rRenderContext, GetSizePixel(), false);
1788 else
1789 TestAndQuit(rRenderContext);
1790 }
1791
TestAndQuit(vcl::RenderContext & rRenderContext)1792 void TestAndQuit(vcl::RenderContext& rRenderContext)
1793 {
1794 if (underTesting)
1795 return;
1796 underTesting = true;
1797 for (sal_Int32 i = 0; i < mrRenderer.getIterCount(); i++)
1798 {
1799 while (mrRenderer.selectNextRenderer() > -1)
1800 {
1801 mrRenderer.drawToDevice(rRenderContext, GetSizePixel(), false);
1802 }
1803 }
1804
1805 double expandedGEOMEAN = mrRenderer.getAndResetBenchmark(RENDER_EXPANDED);
1806
1807 for (sal_Int32 i = 0; i < mrRenderer.getIterCount(); i++)
1808 mrRenderer.drawToDevice(rRenderContext, GetSizePixel(), false);
1809
1810 double thumbGEOMEAN = mrRenderer.getAndResetBenchmark(RENDER_THUMB);
1811
1812 fprintf(stderr, "GEOMEAN_TOTAL: %f\n", pow(thumbGEOMEAN * expandedGEOMEAN, 0.5));
1813 Application::Quit();
1814 }
1815 };
1816
1817 struct PointerData {
1818 PointerStyle eStyle;
1819 const char * name;
1820 };
1821
1822 }
1823
1824 const PointerData gvPointerData [] = {
1825 { PointerStyle::Null, "Null" },
1826 { PointerStyle::Magnify, "Magnify" },
1827 { PointerStyle::Fill, "Fill" },
1828 { PointerStyle::MoveData, "MoveData" },
1829 { PointerStyle::CopyData, "CopyData" },
1830 { PointerStyle::MoveFile, "MoveFile" },
1831 { PointerStyle::CopyFile, "CopyFile" },
1832 { PointerStyle::MoveFiles, "MoveFiles" },
1833 { PointerStyle::CopyFiles, "CopyFiles" },
1834 { PointerStyle::NotAllowed, "NotAllowed" },
1835 { PointerStyle::Rotate, "Rotate" },
1836 { PointerStyle::HShear, "HShear" },
1837 { PointerStyle::VShear, "VShear" },
1838 { PointerStyle::DrawLine, "DrawLine" },
1839 { PointerStyle::DrawRect, "DrawRect" },
1840 { PointerStyle::DrawPolygon, "DrawPolygon" },
1841 { PointerStyle::DrawBezier, "DrawBezier" },
1842 { PointerStyle::DrawArc, "DrawArc" },
1843 { PointerStyle::DrawPie, "DrawPie" },
1844 { PointerStyle::DrawCircleCut, "DrawCircleCut" },
1845 { PointerStyle::DrawEllipse, "DrawEllipse" },
1846 { PointerStyle::DrawConnect, "DrawConnect" },
1847 { PointerStyle::DrawText, "DrawText" },
1848 { PointerStyle::Mirror, "Mirror" },
1849 { PointerStyle::Crook, "Crook" },
1850 { PointerStyle::Crop, "Crop" },
1851 { PointerStyle::MovePoint, "MovePoint" },
1852 { PointerStyle::MoveBezierWeight, "MoveBezierWeight" },
1853 { PointerStyle::DrawFreehand, "DrawFreehand" },
1854 { PointerStyle::DrawCaption, "DrawCaption" },
1855 { PointerStyle::LinkData, "LinkData" },
1856 { PointerStyle::MoveDataLink, "MoveDataLink" },
1857 { PointerStyle::CopyDataLink, "CopyDataLink" },
1858 { PointerStyle::LinkFile, "LinkFile" },
1859 { PointerStyle::MoveFileLink, "MoveFileLink" },
1860 { PointerStyle::CopyFileLink, "CopyFileLink" },
1861 { PointerStyle::Chart, "Chart" },
1862 { PointerStyle::Detective, "Detective" },
1863 { PointerStyle::PivotCol, "PivotCol" },
1864 { PointerStyle::PivotRow, "PivotRow" },
1865 { PointerStyle::PivotField, "PivotField" },
1866 { PointerStyle::PivotDelete, "PivotDelete" },
1867 { PointerStyle::Chain, "Chain" },
1868 { PointerStyle::ChainNotAllowed, "ChainNotAllowed" },
1869 { PointerStyle::AutoScrollN, "AutoScrollN" },
1870 { PointerStyle::AutoScrollS, "AutoScrollS" },
1871 { PointerStyle::AutoScrollW, "AutoScrollW" },
1872 { PointerStyle::AutoScrollE, "AutoScrollE" },
1873 { PointerStyle::AutoScrollNW, "AutoScrollNW" },
1874 { PointerStyle::AutoScrollNE, "AutoScrollNE" },
1875 { PointerStyle::AutoScrollSW, "AutoScrollSW" },
1876 { PointerStyle::AutoScrollSE, "AutoScrollSE" },
1877 { PointerStyle::AutoScrollNS, "AutoScrollNS" },
1878 { PointerStyle::AutoScrollWE, "AutoScrollWE" },
1879 { PointerStyle::AutoScrollNSWE, "AutoScrollNSWE" },
1880 { PointerStyle::TextVertical, "TextVertical" },
1881 { PointerStyle::TabSelectS, "TabSelectS" },
1882 { PointerStyle::TabSelectE, "TabSelectE" },
1883 { PointerStyle::TabSelectSE, "TabSelectSE" },
1884 { PointerStyle::TabSelectW, "TabSelectW" },
1885 { PointerStyle::TabSelectSW, "TabSelectSW" },
1886 { PointerStyle::HideWhitespace, "HideWhitespace" },
1887 { PointerStyle::ShowWhitespace, "ShowWhitespace" },
1888 { PointerStyle::FatCross, "FatCross" },
1889 };
1890
1891 namespace {
1892
1893 class DemoWidgets : public WorkWindow
1894 {
1895 VclPtr<MenuBar> mpBar;
1896 VclPtr<VclBox> mpBox;
1897 VclPtr<ToolBox> mpToolbox;
1898 VclPtr<PushButton> mpButton;
1899 std::vector<VclPtr<VclHBox>> mvCursorBoxes;
1900 std::vector<VclPtr<PushButton>> mvCursorButtons;
1901
1902 DECL_LINK(CursorButtonClick, Button*, void);
1903
1904 public:
DemoWidgets()1905 DemoWidgets() :
1906 WorkWindow(nullptr, WB_APP | WB_STDWORK),
1907 mpBox(VclPtrInstance<VclVBox>(this, false, 3)),
1908 mpToolbox(VclPtrInstance<ToolBox>(mpBox.get())),
1909 mpButton(VclPtrInstance<PushButton>(mpBox.get()))
1910 {
1911 SetText("VCL widget demo");
1912
1913 Wallpaper aWallpaper(BitmapEx("sfx2/res/128x128_writer_doc-p.png"));
1914 aWallpaper.SetStyle(WallpaperStyle::BottomRight);
1915 aWallpaper.SetColor(COL_RED);
1916
1917 mpBox->SetBackground(aWallpaper);
1918 mpBox->Show();
1919
1920 Help::EnableBalloonHelp();
1921 mpToolbox->SetHelpText("Help text");
1922 mpToolbox->InsertItem(ToolBoxItemId(0), "Toolbar item");
1923 mpToolbox->SetQuickHelpText(ToolBoxItemId(0), "This is a tooltip popup");
1924 mpToolbox->InsertSeparator();
1925 mpToolbox->Show();
1926
1927 mpButton->SetText("Click me; go on");
1928 mpButton->Show();
1929
1930 int i = 0;
1931 VclHBox* pCurrentCursorHBox = nullptr;
1932 constexpr int numButtonsPerRow = 9;
1933 for (auto & rData : gvPointerData)
1934 {
1935 if (i % numButtonsPerRow == 0)
1936 {
1937 mvCursorBoxes.push_back(VclPtrInstance<VclHBox>(mpBox.get(), true, numButtonsPerRow));
1938 pCurrentCursorHBox = mvCursorBoxes.back().get();
1939 pCurrentCursorHBox->Show();
1940 }
1941 mvCursorButtons.emplace_back(VclPtrInstance<PushButton>(pCurrentCursorHBox));
1942 PushButton& rButton = *mvCursorButtons.back();
1943 rButton.SetText(OUString::createFromAscii(rData.name));
1944 rButton.SetClickHdl(LINK(this,DemoWidgets,CursorButtonClick));
1945 rButton.Show();
1946 ++i;
1947 }
1948
1949 mpBar = VclPtr<MenuBar>::Create();
1950 mpBar->InsertItem(0,"File");
1951 VclPtrInstance<PopupMenu> pPopup;
1952 pPopup->InsertItem(0,"Item");
1953 mpBar->SetPopupMenu(0, pPopup);
1954 SetMenuBar(mpBar);
1955
1956 Show();
1957 }
~DemoWidgets()1958 virtual ~DemoWidgets() override { disposeOnce(); }
dispose()1959 virtual void dispose() override
1960 {
1961 for (auto & p : mvCursorButtons)
1962 p.disposeAndClear();
1963 mvCursorButtons.clear();
1964 for (auto & p : mvCursorBoxes)
1965 p.disposeAndClear();
1966 mvCursorBoxes.clear();
1967 mpToolbox.disposeAndClear();
1968 mpButton.disposeAndClear();
1969 mpBox.disposeAndClear();
1970 mpBar.disposeAndClear();
1971 WorkWindow::dispose();
1972 }
Paint(vcl::RenderContext & rRenderContext,const tools::Rectangle &)1973 virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) override
1974 {
1975 tools::Rectangle aWholeSize(Point(0, 0),GetOutputSizePixel());
1976 vcl::Region aClip(aWholeSize);
1977 tools::Rectangle aExclude(tools::Rectangle(Point(50,50),Size(100,100)));
1978 aClip.Exclude(aExclude);
1979
1980 Wallpaper aWallpaper(COL_GREEN);
1981
1982 rRenderContext.Push(PushFlags::CLIPREGION);
1983 rRenderContext.IntersectClipRegion(aClip);
1984 rRenderContext.DrawWallpaper(aWholeSize, aWallpaper);
1985 rRenderContext.Pop();
1986
1987 ScopedVclPtrInstance< VirtualDevice > pDev(*GetOutDev());
1988 pDev->EnableRTL(IsRTLEnabled());
1989 pDev->SetOutputSizePixel(aExclude.GetSize());
1990
1991 tools::Rectangle aSubRect(aWholeSize);
1992 aSubRect.Move(-aExclude.Left(), -aExclude.Top());
1993 pDev->DrawWallpaper(aSubRect, aWallpaper );
1994
1995 rRenderContext.DrawOutDev(aExclude.TopLeft(), aExclude.GetSize(),
1996 Point( 0, 0 ), aExclude.GetSize(), *pDev );
1997 }
1998 };
1999
2000 }
2001
IMPL_LINK(DemoWidgets,CursorButtonClick,Button *,pButton,void)2002 IMPL_LINK(DemoWidgets, CursorButtonClick, Button*, pButton, void)
2003 {
2004 for (size_t i=0; i<SAL_N_ELEMENTS(gvPointerData); ++i)
2005 {
2006 if (mvCursorButtons[i].get() == pButton)
2007 {
2008 mpBox->SetPointer( gvPointerData[i].eStyle );
2009 return;
2010 }
2011 }
2012 assert(false);
2013 }
2014
2015 namespace {
2016
2017 class DemoPopup : public FloatingWindow
2018 {
2019 public:
DemoPopup()2020 DemoPopup() : FloatingWindow( nullptr, WB_SYSTEMWINDOW|WB_TOOLTIPWIN)
2021 {
2022 SetType( WindowType::HELPTEXTWINDOW );
2023
2024 SetOutputSizePixel( Size( 300, 30 ) );
2025 SetBackground(Wallpaper(COL_YELLOW));
2026
2027 Show( true, ShowFlags::NoActivate );
2028 PaintImmediately();
2029 }
2030
Paint(vcl::RenderContext & rRenderContext,const tools::Rectangle &)2031 virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) override
2032 {
2033 Size aSize = GetOutputSizePixel();
2034 tools::Rectangle aTextRect(Point(6, 6), aSize);
2035
2036 SetTextColor(COL_BLACK);
2037 SetTextAlign(ALIGN_TOP);
2038 rRenderContext.DrawText(aTextRect, "This is a standalone help text test",
2039 DrawTextFlags::MultiLine|DrawTextFlags::WordBreak|
2040 DrawTextFlags::Left|DrawTextFlags::Top);
2041
2042 rRenderContext.SetLineColor(COL_BLACK);
2043 rRenderContext.SetFillColor();
2044 rRenderContext.DrawRect( tools::Rectangle( Point(), aSize ) );
2045 aSize.AdjustWidth( -2 );
2046 aSize.AdjustHeight( -2 );
2047 Color aColor( rRenderContext.GetLineColor() );
2048 rRenderContext.SetLineColor( COL_GRAY );
2049 rRenderContext.DrawRect( tools::Rectangle( Point( 1, 1 ), aSize ) );
2050 rRenderContext.SetLineColor( aColor );
2051 }
2052
MouseButtonDown(const MouseEvent &)2053 virtual void MouseButtonDown( const MouseEvent & ) override
2054 {
2055 Application::Quit();
2056 }
2057 };
2058
2059 }
2060
2061 namespace {
renderFonts()2062 void renderFonts()
2063 {
2064 ScopedVclPtrInstance<VirtualDevice> xDevice;
2065 Size aSize(1024, 1024);
2066 xDevice->SetOutputSizePixel(aSize);
2067
2068 #if 0
2069 for (auto & aFontName : aFontNames)
2070 {
2071 vcl::Font aFont(aFontName, Size(0,96));
2072
2073 aFont.Set(COL_BLACK);
2074 xDevice->SetFont(aFont);
2075 xDevice->Erase();
2076
2077 FontMetric aMetric = xDevice->GetFontMetric(aFont);
2078
2079 FontCharMapRef xMap;
2080 if (xDevice->GetFontCharMap(xMap))
2081 {
2082 ... iterate through glyphs ...
2083 }
2084
2085
2086 bool GetGlyphBoundRects( const Point& rOrigin, const OUString& rStr, int nIndex,
2087 int nLen, int nBase, MetricVector& rVector );
2088
2089 include/vcl/outdev.hxx:typedef std::vector< Rectangle > MetricVector;
2090 include/vcl/outdev.hxx: MetricVector* pVector = nullptr, OUString* pDisplayText = nullptr );
2091 include/vcl/outdev.hxx: MetricVector* pVector = nullptr, OUString* pDisplayText = nullptr,
2092 include/vcl/outdev.hxx: MetricVector* pVector, OUString* pDisplayText, vcl::ITextLayout& _rLayout );
2093 include/vcl/outdev.hxx: DrawTextFlags nStyle = DrawTextFlags::Mnemonic, MetricVector* pVector = nullp
2094
2095 bool GetTextBoundRect( Rectangle& rRect,
2096 const OUString& rStr, sal_Int32 nBase = 0, sal_Int32 nIndex = 0, sal_Int32 nLen = -1,
2097 sal_uLong nLayoutWidth = 0, const long* pDXArray = nullptr ) const;
2098
2099
2100 void DrawText( const Point& rStartPt, const OUString& rStr,
2101 sal_Int32 nIndex = 0, sal_Int32 nLen = -1,
2102 MetricVector* pVector = nullptr, OUString* pDisplayText = nullptr );
2103
2104 void DrawText( const Rectangle& rRect,
2105 const OUString& rStr, DrawTextFlags nStyle = DrawTextFlags::NONE,
2106 MetricVector* pVector = nullptr, OUString* pDisplayText = nullptr,
2107 vcl::ITextLayout* _pTextLayout = nullptr );
2108
2109 Rectangle GetTextRect( const Rectangle& rRect,
2110 const OUString& rStr, DrawTextFlags nStyle = DrawTextFlags::WordBreak,
2111 TextRectInfo* pInfo = nullptr,
2112 const vcl::ITextLayout* _pTextLayout = nullptr ) const;
2113
2114 }
2115 #endif
2116
2117 }
2118 };
2119
2120 namespace {
2121
2122 class DemoApp : public Application
2123 {
showHelp(DemoRenderer & rRenderer)2124 static int showHelp(DemoRenderer &rRenderer)
2125 {
2126 fprintf(stderr,"vcldemo - a VCL test app\n");
2127 fprintf(stderr," --help - print this text\n");
2128 fprintf(stderr," --show <renderer> - start with a given renderer, options are:\n");
2129 OUString aRenderers(rRenderer.getRendererList());
2130 fprintf(stderr," %s\n",
2131 OUStringToOString(aRenderers, RTL_TEXTENCODING_UTF8).getStr());
2132 fprintf(stderr," --test <iterCount> - create benchmark data\n");
2133 fprintf(stderr," --widgets - launch the widget test.\n");
2134 fprintf(stderr," --popup - launch the popup test.\n");
2135 fprintf(stderr," --threads - render from multiple threads.\n");
2136 fprintf(stderr," --font <fontname> - run the font render test.\n");
2137 fprintf(stderr, "\n");
2138 return 0;
2139 }
2140
2141 public:
DemoApp()2142 DemoApp() {}
2143
Main()2144 virtual int Main() override
2145 {
2146 try
2147 {
2148 bool bWidgets = false;
2149 bool bThreads = false;
2150 bool bPopup = false;
2151 DemoRenderer aRenderer;
2152 std::vector<OUString> aFontNames;
2153
2154 for (sal_uInt16 i = 0; i < GetCommandLineParamCount(); ++i)
2155 {
2156 bool bLast = i == GetCommandLineParamCount() - 1;
2157 OUString aArg = GetCommandLineParam(i);
2158 if (aArg == "--help" || aArg == "-h")
2159 return showHelp(aRenderer);
2160 if (aArg == "--show")
2161 {
2162 if (bLast)
2163 return showHelp(aRenderer);
2164 else
2165 aRenderer.selectRenderer(GetCommandLineParam(++i));
2166 }
2167 else if (aArg == "--test")
2168 {
2169 if (bLast)
2170 return showHelp(aRenderer);
2171 else
2172 aRenderer.setIterCount(GetCommandLineParam(++i).toInt32());
2173 }
2174 else if (aArg == "--widgets")
2175 bWidgets = true;
2176 else if (aArg == "--popup")
2177 bPopup = true;
2178 else if (aArg == "--threads")
2179 bThreads = true;
2180 else if (aArg == "--font" && !bLast)
2181 aFontNames.push_back(GetCommandLineParam(++i));
2182 else if (aArg.startsWith("--"))
2183 {
2184 fprintf(stderr,"Unknown argument '%s'\n",
2185 OUStringToOString(aArg, RTL_TEXTENCODING_UTF8).getStr());
2186 return showHelp(aRenderer);
2187 }
2188 }
2189
2190 ScopedVclPtrInstance<DemoWin> aMainWin(aRenderer, bThreads);
2191 VclPtr<DemoWidgets> xWidgets;
2192 VclPtr<DemoPopup> xPopup;
2193
2194 aMainWin->SetText("Interactive VCL demo #1");
2195 if (bWidgets)
2196 xWidgets = VclPtr< DemoWidgets >::Create ();
2197 else if (bPopup)
2198 xPopup = VclPtrInstance< DemoPopup> ();
2199 else if (!aFontNames.empty())
2200 renderFonts();
2201 else
2202 aMainWin->Show();
2203
2204 Application::Execute();
2205
2206 xWidgets.disposeAndClear();
2207 xPopup.disposeAndClear();
2208 }
2209 catch (const css::uno::Exception&)
2210 {
2211 TOOLS_WARN_EXCEPTION("vcl.app", "Fatal");
2212 return 1;
2213 }
2214 catch (const std::exception& e)
2215 {
2216 SAL_WARN("vcl.app", "Fatal: " << e.what());
2217 return 1;
2218 }
2219 return 0;
2220 }
2221
2222 protected:
Init()2223 void Init() override
2224 {
2225 try
2226 {
2227 uno::Reference<uno::XComponentContext> xComponentContext
2228 = ::cppu::defaultBootstrap_InitialComponentContext();
2229 uno::Reference<lang::XMultiServiceFactory> xMSF;
2230 xMSF.set(xComponentContext->getServiceManager(), uno::UNO_QUERY);
2231 if(!xMSF.is())
2232 Application::Abort("Bootstrap failure - no service manager");
2233
2234 ::comphelper::setProcessServiceFactory(xMSF);
2235 }
2236 catch (const uno::Exception &e)
2237 {
2238 Application::Abort("Bootstrap exception " + e.Message);
2239 }
2240 }
DeInit()2241 void DeInit() override
2242 {
2243 uno::Reference< lang::XComponent >(
2244 comphelper::getProcessComponentContext(),
2245 uno::UNO_QUERY_THROW)-> dispose();
2246 ::comphelper::setProcessServiceFactory(nullptr);
2247 }
2248 };
2249
2250 }
2251
createApplication()2252 void vclmain::createApplication()
2253 {
2254 #ifdef _WIN32
2255 _putenv_s("LIBO_VCL_DEMO", "1");
2256 #else
2257 setenv("LIBO_VCL_DEMO", "1", 0);
2258 #endif
2259 static DemoApp aApp;
2260 }
2261
2262 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2263