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