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/gradient.hxx>
28 #include <vcl/vclmain.hxx>
29 #include <vcl/layout.hxx>
30 #include <salhelper/thread.hxx>
32 #include <tools/urlobj.hxx>
33 #include <tools/stream.hxx>
34 #include <vcl/svapp.hxx>
35 #include <vcl/pngread.hxx>
36 #include <vcl/wrkwin.hxx>
37 #include <vcl/virdev.hxx>
38 #include <vcl/graphicfilter.hxx>
39 #include <vcl/button.hxx>
40 #include <vcl/toolbox.hxx>
41 #include <vcl/pngwrite.hxx>
42 #include <vcl/floatwin.hxx>
43 #include <vcl/salbtype.hxx>
44 #include <vcl/bitmapaccess.hxx>
45 #include <vcl/help.hxx>
46 #include <vcl/menu.hxx>
47 #include <vcl/ImageTree.hxx>
48 #include <vcl/BitmapEmbossGreyFilter.hxx>
49 #include <bitmapwriteaccess.hxx>
51 #include <basegfx/numeric/ftools.hxx>
52 #include <basegfx/matrix/b2dhommatrix.hxx>
53 #include <opengl/zone.hxx>
55 // internal headers for OpenGLTests class.
56 #if HAVE_FEATURE_OPENGL
58 #include <salframe.hxx>
59 #include <openglgdiimpl.hxx>
60 #include <opengl/texture.hxx>
61 #include <opengl/framebuffer.hxx>
62 #include <vcl/opengl/OpenGLHelper.hxx>
65 #define FIXME_SELF_INTERSECTING_WORKING 0
66 #define FIXME_BOUNCE_BUTTON 0
67 #define THUMB_REPEAT_FACTOR 10
69 using namespace com::sun::star
;
75 osl_getSystemTime(&aValue
);
76 return static_cast<double>(aValue
.Seconds
) * 1000 +
77 static_cast<double>(aValue
.Nanosec
) / (1000*1000);
83 RENDER_THUMB
, // small view <n> to a page
84 RENDER_EXPANDED
, // expanded view of this renderer
95 struct RenderContext
{
98 DemoRenderer
*mpDemoRenderer
;
101 struct RegionRenderer
{
107 virtual ~RegionRenderer() {}
108 virtual OUString
getName() = 0;
109 virtual sal_uInt16
getAccelerator() = 0;
110 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
111 const RenderContext
&rCtx
) = 0;
112 // repeating count for profiling (to exceed the poor time resolution on Windows)
113 virtual sal_uInt16
getTestRepeatCount() = 0;
114 #define RENDER_DETAILS(name,key,repeat) \
115 virtual OUString getName() override \
116 { return OUString(SAL_STRINGIFY(name)); } \
117 virtual sal_uInt16 getAccelerator() override \
119 virtual sal_uInt16 getTestRepeatCount() override \
126 std::vector
< RegionRenderer
* > maRenderers
;
127 sal_Int32 mnSelectedRenderer
;
130 void InitRenderers();
133 DemoRenderer() : mnSegmentsX(0)
135 , mnSelectedRenderer(-1)
137 #if FIXME_BOUNCE_BUTTON
144 if (!Application::LoadBrandBitmap("intro", maIntro
))
145 Application::Abort("Failed to load intro image");
147 maIntroBW
= maIntro
.GetBitmap();
149 BitmapEx
aTmpBmpEx(maIntroBW
);
150 BitmapFilter::Filter(aTmpBmpEx
, BitmapEmbossGreyFilter(0, 0));
151 maIntroBW
= aTmpBmpEx
.GetBitmap();
154 mnSegmentsY
= rtl::math::round(std::sqrt(maRenderers
.size()), 0,
155 rtl_math_RoundingMode_Down
);
156 mnSegmentsX
= (maRenderers
.size() + mnSegmentsY
- 1)/mnSegmentsY
;
159 OUString
getRendererList();
160 double getAndResetBenchmark(RenderStyle style
);
161 void selectRenderer(const OUString
&rName
);
162 int selectNextRenderer();
163 void setIterCount(sal_Int32 iterCount
);
164 sal_Int32
getIterCount();
165 void addTime(int i
, double t
);
168 void SetSizePixel(const Size
&rSize
) { maSize
= rSize
; }
169 const Size
& GetSizePixel() const { return maSize
; }
172 // more of a 'Window' concept - push upwards ?
173 #if FIXME_BOUNCE_BUTTON
174 // Bouncing windows on click ...
175 PushButton
*mpButton
;
176 FloatingWindow
*mpButtonWin
;
178 int mnBounceX
, mnBounceY
;
179 DECL_LINK(BounceTimerCb
, Timer
*, void);
182 bool MouseButtonDown(const MouseEvent
& rMEvt
);
183 void KeyInput(const KeyEvent
& rKEvt
);
185 static std::vector
<tools::Rectangle
> partition(const tools::Rectangle
&rRect
, int nX
, int nY
)
187 std::vector
<tools::Rectangle
> aRegions
= partition(rRect
.GetSize(), nX
, nY
);
188 for (auto & region
: aRegions
)
189 region
.Move(rRect
.Left(), rRect
.Top());
194 static std::vector
<tools::Rectangle
> partition(const RenderContext
&rCtx
, int nX
, int nY
)
196 return partition(rCtx
.maSize
, nX
, nY
);
199 static std::vector
<tools::Rectangle
> partition(Size aSize
, int nX
, int nY
)
202 std::vector
<tools::Rectangle
> aRegions
;
204 // Make small cleared area for these guys
205 long nBorderSize
= std::min(aSize
.Height() / 32, aSize
.Width() / 32);
206 long nBoxWidth
= (aSize
.Width() - nBorderSize
*(nX
+1)) / nX
;
207 long nBoxHeight
= (aSize
.Height() - nBorderSize
*(nY
+1)) / nY
;
208 for (int y
= 0; y
< nY
; y
++)
210 for (int x
= 0; x
< nX
; x
++)
212 r
.SetPos(Point(nBorderSize
+ (nBorderSize
+ nBoxWidth
) * x
,
213 nBorderSize
+ (nBorderSize
+ nBoxHeight
) * y
));
214 r
.SetSize(Size(nBoxWidth
, nBoxHeight
));
215 aRegions
.push_back(r
);
222 static void clearRects(OutputDevice
&rDev
, std::vector
<tools::Rectangle
> &rRects
)
224 for (size_t i
= 0; i
< rRects
.size(); i
++)
226 // knock up a nice little border
227 rDev
.SetLineColor(COL_GRAY
);
228 rDev
.SetFillColor(COL_LIGHTGRAY
);
231 int nBorderSize
= rRects
[i
].GetWidth() / 5;
232 rDev
.DrawRect(rRects
[i
], nBorderSize
, nBorderSize
);
235 rDev
.DrawRect(rRects
[i
]);
239 static void drawBackground(OutputDevice
&rDev
, const tools::Rectangle
& r
)
243 aGradient
.SetStartColor(COL_BLUE
);
244 aGradient
.SetEndColor(COL_GREEN
);
245 aGradient
.SetStyle(GradientStyle::Linear
);
246 rDev
.DrawGradient(r
, aGradient
);
249 struct DrawLines
: public RegionRenderer
251 RENDER_DETAILS(lines
,KEY_L
,100)
252 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
253 const RenderContext
&rCtx
) override
255 if (rCtx
.meStyle
== RENDER_EXPANDED
)
257 AntialiasingFlags nOldAA
= rDev
.GetAntialiasing();
258 rDev
.SetAntialiasing(AntialiasingFlags::EnableB2dDraw
);
260 std::vector
<tools::Rectangle
> aRegions(DemoRenderer::partition(rCtx
, 4, 4));
261 DemoRenderer::clearRects(rDev
, aRegions
);
263 #if 0 // FIXME: get this through to the backend ...
264 double nTransparency
[] = {
271 drawing::LineCap
const eLineCaps
[] = {
272 drawing::LineCap_BUTT
, drawing::LineCap_ROUND
, drawing::LineCap_SQUARE
, drawing::LineCap_BUTT
,
273 drawing::LineCap_BUTT
, drawing::LineCap_ROUND
, drawing::LineCap_SQUARE
, drawing::LineCap_BUTT
,
274 drawing::LineCap_BUTT
, drawing::LineCap_ROUND
, drawing::LineCap_SQUARE
, drawing::LineCap_BUTT
,
275 drawing::LineCap_BUTT
, drawing::LineCap_ROUND
, drawing::LineCap_SQUARE
, drawing::LineCap_BUTT
277 basegfx::B2DLineJoin
const eJoins
[] = {
278 basegfx::B2DLineJoin::NONE
, basegfx::B2DLineJoin::Bevel
, basegfx::B2DLineJoin::Miter
, basegfx::B2DLineJoin::Round
,
279 basegfx::B2DLineJoin::NONE
, basegfx::B2DLineJoin::Bevel
, basegfx::B2DLineJoin::Miter
, basegfx::B2DLineJoin::Round
,
280 basegfx::B2DLineJoin::NONE
, basegfx::B2DLineJoin::Bevel
, basegfx::B2DLineJoin::Miter
, basegfx::B2DLineJoin::Round
,
281 basegfx::B2DLineJoin::NONE
, basegfx::B2DLineJoin::Bevel
, basegfx::B2DLineJoin::Miter
, basegfx::B2DLineJoin::Round
283 double const aLineWidths
[] = {
284 10.0, 15.0, 20.0, 10.0,
285 10.0, 15.0, 20.0, 10.0,
286 10.0, 15.0, 20.0, 10.0,
289 for (size_t i
= 0; i
< aRegions
.size(); i
++)
291 // Half of them not-anti-aliased ..
292 if (i
>= aRegions
.size()/2)
293 rDev
.SetAntialiasing(nOldAA
);
295 static const struct {
298 { 0.2, 0.2 }, { 0.8, 0.3 }, { 0.7, 0.8 }
300 rDev
.SetLineColor(COL_BLACK
);
301 basegfx::B2DPolygon aPoly
;
302 tools::Rectangle
aSub(aRegions
[i
]);
303 for (size_t j
= 0; j
< SAL_N_ELEMENTS(aPoints
); j
++)
305 aPoly
.append(basegfx::B2DPoint(aSub
.Left() + aSub
.GetWidth() * aPoints
[j
].nX
,
306 aSub
.Top() + aSub
.GetHeight() * aPoints
[j
].nY
));
308 rDev
.DrawPolyLine(aPoly
, aLineWidths
[i
], eJoins
[i
], eLineCaps
[i
]);
313 rDev
.SetFillColor(COL_LIGHTRED
);
314 rDev
.SetLineColor(COL_BLACK
);
317 for(long i
=0; i
<r
.GetHeight(); i
+=15)
318 rDev
.DrawLine(Point(r
.Left(), r
.Top()+i
), Point(r
.Right(), r
.Bottom()-i
));
319 for(long i
=0; i
<r
.GetWidth(); i
+=15)
320 rDev
.DrawLine(Point(r
.Left()+i
, r
.Bottom()), Point(r
.Right()-i
, r
.Top()));
322 // Should draw a white-line across the middle
323 Color
aLastPixel(COL_WHITE
);
324 Point
aCenter((r
.Left() + r
.Right())/2 - 4,
325 (r
.Top() + r
.Bottom())/2 - 4);
326 for(int i
=0; i
<8; i
++)
328 rDev
.DrawPixel(aCenter
, aLastPixel
);
329 aLastPixel
= rDev
.GetPixel(aCenter
);
336 struct DrawText
: public RegionRenderer
338 RENDER_DETAILS(text
,KEY_T
,1)
340 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
341 const RenderContext
&rCtx
) override
343 if (rCtx
.meStyle
== RENDER_EXPANDED
)
345 std::vector
<tools::Rectangle
> aToplevelRegions(
346 DemoRenderer::partition(rCtx
, 1, 3));
347 std::vector
<tools::Rectangle
> aSubRegions(
348 DemoRenderer::partition(aToplevelRegions
[0], 4, 2));
349 tools::Rectangle
aBottom(aToplevelRegions
[1].TopLeft(),
350 aToplevelRegions
[2].BottomRight());
351 DemoRenderer::clearRects(rDev
,aSubRegions
);
357 { false, false, false },
358 { false, true, false },
359 { false, true, true },
360 { false, false, true },
361 { true, false, true },
362 { true, true, true },
363 { true, true, false },
364 { true, false, false },
368 for (int y
= 0; y
< 2; y
++)
370 for (int x
= 0; x
< 4; x
++)
372 assert(i
< SAL_N_ELEMENTS(aRenderData
));
373 drawText(rDev
, aSubRegions
[i
], aRenderData
[i
].mbClip
,
374 aRenderData
[i
].mbArabicText
, aRenderData
[i
].mbRotate
);
379 drawComplex(rDev
, aBottom
);
383 drawText(rDev
, r
, false, false, false);
387 static void drawText (OutputDevice
&rDev
, tools::Rectangle r
, bool bClip
, bool bArabicText
, bool bRotate
)
389 rDev
.SetClipRegion( vcl::Region(r
) );
391 OUString
const aLatinText("Click any rect to zoom!!!!");
393 const unsigned char pTextUTF8
[] = {
394 0xd9, 0x88, 0xd8, 0xa7, 0xd8, 0xad, 0xd9, 0x90,
395 0xd8, 0xaf, 0xd9, 0x92, 0x20, 0xd8, 0xa5, 0xd8,
396 0xab, 0xd9, 0x8d, 0xd9, 0x86, 0xd9, 0x8a, 0xd9,
397 0x86, 0x20, 0xd8, 0xab, 0xd9, 0x84, 0xd8, 0xa7,
398 0xd8, 0xab, 0xd8, 0xa9, 0xd9, 0x8c, 0x00
400 OUString
aArabicText( reinterpret_cast<char const *>(pTextUTF8
),
401 SAL_N_ELEMENTS( pTextUTF8
) - 1,
402 RTL_TEXTENCODING_UTF8
);
406 // To have more text displayed one after the other (overlapping, and in different colours), then
408 const int nPrintNumCopies
=1;
415 std::vector
<OUString
> aFontNames
;
417 static Color
const nCols
[] = {
418 COL_BLACK
, COL_BLUE
, COL_GREEN
, COL_CYAN
, COL_RED
, COL_MAGENTA
,
419 COL_BROWN
, COL_GRAY
, COL_LIGHTGRAY
, COL_LIGHTBLUE
, COL_LIGHTGREEN
,
420 COL_LIGHTCYAN
, COL_LIGHTRED
, COL_LIGHTMAGENTA
, COL_YELLOW
, COL_WHITE
423 // a few fonts to start with
424 const char *pNames
[] = {
425 "Times", "Liberation Sans", "Arial", "Linux Biolinum G", "Linux Libertine Display G"
428 for (size_t i
= 0; i
< SAL_N_ELEMENTS(pNames
); i
++)
429 aFontNames
.push_back(OUString::createFromAscii(pNames
[i
]));
431 if (bClip
&& !bRotate
)
433 // only show the first quarter of the text
434 tools::Rectangle
aRect( r
.TopLeft(), Size( r
.GetWidth()/2, r
.GetHeight()/2 ) );
435 rDev
.SetClipRegion( vcl::Region( aRect
) );
438 for (int i
= 1; i
< nPrintNumCopies
+1; i
++)
440 int nFontHeight
=0, nFontIndex
=0, nFontColorIndex
=0;
442 if (nPrintNumCopies
== 1)
444 float const nFontMagnitude
= 0.25f
;
445 // random font size to avoid buffering
446 nFontHeight
= 1 + nFontMagnitude
* (0.9 + comphelper::rng::uniform_real_distribution(0.0, std::nextafter(0.1, DBL_MAX
))) * (r
.Bottom() - r
.Top());
452 // random font size to avoid buffering
453 nFontHeight
= 1 + i
* (0.9 + comphelper::rng::uniform_real_distribution(0.0, std::nextafter(0.1, DBL_MAX
))) * (r
.Top() - r
.Bottom()) / nPrintNumCopies
;
454 nFontIndex
= (i
% aFontNames
.size());
455 nFontColorIndex
=(i
% aFontNames
.size());
458 rDev
.SetTextColor(nCols
[nFontColorIndex
]);
459 vcl::Font
aFont( aFontNames
[nFontIndex
], Size(0, nFontHeight
));
463 tools::Rectangle aFontRect
= r
;
465 int nHeight
= r
.GetHeight();
467 // move the text to the bottom of the bounding rect before rotating
468 aFontRect
.AdjustTop(nHeight
/2 );
469 aFontRect
.AdjustBottom(nHeight
);
471 aFont
.SetOrientation(45 * 10); // 45 degrees
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
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
const 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(COL_RED
);
739 rDev
.SetFillColor(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(COL_RED
);
762 rDev
.SetFillColor(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 static Color
const 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 static Color
const 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(nStartCols
[i
]);
827 aGradient
.SetEndColor(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
= 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(COL_YELLOW
);
961 rDev
.SetFillColor(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(COL_LIGHTRED
);
970 rDev
.SetFillColor(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(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(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 (static_cast<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
const 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
.emplace_back(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
.emplace_back(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(static_cast<double>((i
>> 2) % 8) / 8);
1253 aTransform
.shearY(static_cast<double>((i
>> 4) % 8) / 8);
1256 aTransform
.translate(-aSize
.Width()/2, -aSize
.Height()/2);
1257 aTransform
.rotate(i
);
1260 aTransform
.shearX(static_cast<double>((i
>> 2) % 8) / 8);
1261 aTransform
.shearY(static_cast<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
const &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 AlphaScopedWriteAccess
pMaskAcc(aMask
);
1310 BitmapScopedWriteAccess
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 Scanline pScanlineMask
= pMaskAcc
->GetScanline( y
);
1318 Scanline pScanlineRec
= pRecAcc
->GetScanline( y
);
1319 Scanline pScanlineW
= pAccW
->GetScanline( y
);
1320 Scanline pScanlineB
= pAccB
->GetScanline( y
);
1321 for (int x
= 0; x
< nSizeX
; x
++)
1323 BitmapColor aColW
= pAccW
->GetPixelFromData(pScanlineW
,x
);
1324 BitmapColor aColB
= pAccB
->GetPixelFromData(pScanlineB
,x
);
1325 long nAR
= static_cast<long>(aColW
.GetRed() - aColB
.GetRed()); // (1-a)
1326 long nAG
= static_cast<long>(aColW
.GetGreen() - aColB
.GetGreen()); // (1-a)
1327 long nAB
= static_cast<long>(aColW
.GetBlue() - aColB
.GetBlue()); // (1-a)
1329 #define CLAMP(a,b,c) (((a)<=(b))?(b):(((a)>=(c))?(c):(a)))
1331 // we get the most precision from the largest delta
1332 long nInverseAlpha
= std::max(nAR
, std::max(nAG
, nAB
)); // (1-a)
1333 nInverseAlpha
= CLAMP(nInverseAlpha
, 0, 255);
1334 long nAlpha
= 255 - nInverseAlpha
;
1336 pMaskAcc
->SetPixelOnData(pScanlineMask
,x
,BitmapColor(static_cast<sal_Int8
>(CLAMP(nInverseAlpha
,0,255))));
1337 // now recover the pixels
1338 long nR
= (aColW
.GetRed() + aColB
.GetRed() - nInverseAlpha
) * 128;
1339 long nG
= (aColW
.GetGreen() + aColB
.GetGreen() - nInverseAlpha
) * 128;
1340 long nB
= (aColW
.GetBlue() + aColB
.GetBlue() - nInverseAlpha
) * 128;
1342 { // doesn't matter what's behind transparency
1347 nR
/= nAlpha
; nG
/= nAlpha
; nB
/= nAlpha
;
1349 pRecAcc
->SetPixelOnData(pScanlineRec
,x
,BitmapColor(
1350 static_cast<sal_uInt8
>(CLAMP(nR
,0,255)),
1351 static_cast<sal_uInt8
>(CLAMP(nG
,0,255)),
1352 static_cast<sal_uInt8
>(CLAMP(nB
,0,255))));
1357 rDev
.DrawBitmap(aPt
, aWhiteBmp
);
1358 aPt
.Move(aSrc
.GetSizePixel().Width(), 0);
1359 rDev
.DrawBitmap(aPt
, aBlackBmp
);
1360 aPt
.Move(aSrc
.GetSizePixel().Width(), 0);
1361 rDev
.DrawBitmap(aPt
, aRecovered
);
1362 aPt
.Move(aSrc
.GetSizePixel().Width(), 0);
1363 rDev
.DrawBitmap(aPt
, aMask
.GetBitmap());
1364 aPt
.Move(aSrc
.GetSizePixel().Width(), 0);
1366 return BitmapEx(aRecovered
, aMask
);
1369 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
1370 const RenderContext
&rCtx
) override
1372 if (rCtx
.meStyle
== RENDER_EXPANDED
)
1376 Point
aLocation(0,maIcons
[0].GetSizePixel().Height() + 8);
1377 for (size_t i
= 0; i
< 100; i
++)
1379 BitmapEx aSrc
= maIcons
[i
];
1382 Point
aAbove(aLocation
);
1383 aAbove
.Move(0,-aSrc
.GetSizePixel().Height() - 4);
1384 rDev
.DrawBitmapEx(aAbove
, aSrc
);
1385 aAbove
.Move(aSrc
.GetSizePixel().Width(),0);
1386 aAbove
.Move(aSrc
.GetSizePixel().Width(),0);
1387 rDev
.DrawBitmap(aAbove
, aSrc
.GetBitmap());
1388 aAbove
.Move(aSrc
.GetSizePixel().Width(),0);
1389 rDev
.DrawBitmap(aAbove
, aSrc
.GetMask());
1391 // intermediates middle
1392 BitmapEx aResult
= AlphaRecovery(rDev
, aLocation
, aSrc
);
1395 Point
aBelow(aLocation
);
1396 aBelow
.Move(0,aResult
.GetSizePixel().Height());
1397 rDev
.DrawBitmapEx(aBelow
, aResult
);
1399 // mini convert test.
1400 aBelow
.Move(aResult
.GetSizePixel().Width()+4,0);
1401 rDev
.DrawBitmapEx(aBelow
, aResult
);
1403 Bitmap aGrey
= aSrc
.GetBitmap();
1404 aGrey
.Convert(BmpConversion::N8BitGreys
);
1405 rDev
.DrawBitmap(aBelow
, aGrey
);
1407 aBelow
.Move(aGrey
.GetSizePixel().Width(),0);
1408 BitmapEx
aGreyMask(aSrc
.GetBitmap(),
1409 AlphaMask(aSrc
.GetMask()));
1410 rDev
.DrawBitmapEx(aBelow
, aGreyMask
);
1412 aLocation
.Move(aSrc
.GetSizePixel().Width()*6,0);
1413 if (aLocation
.X() > r
.Right())
1414 aLocation
= Point(0,aLocation
.Y()+aSrc
.GetSizePixel().Height()*3+4);
1417 // now go crazy with random foo
1418 doDrawIcons(rDev
, r
, true);
1422 doDrawIcons(rDev
, r
, false);
1427 struct FetchDrawBitmap
: public RegionRenderer
1429 RENDER_DETAILS(fetchdraw
,KEY_F
,50)
1430 virtual void RenderRegion(OutputDevice
&rDev
, tools::Rectangle r
,
1431 const RenderContext
&) override
1433 Bitmap
aBitmap(rDev
.GetBitmap(Point(0,0),rDev
.GetOutputSizePixel()));
1434 aBitmap
.Scale(r
.GetSize(), BmpScaleFlag::BestQuality
);
1435 rDev
.DrawBitmap(r
.TopLeft(), aBitmap
);
1439 void drawThumbs(vcl::RenderContext
& rDev
, tools::Rectangle aRect
, bool bVDev
)
1442 aCtx
.meStyle
= RENDER_THUMB
;
1443 aCtx
.mbVDev
= bVDev
;
1444 aCtx
.mpDemoRenderer
= this;
1445 aCtx
.maSize
= aRect
.GetSize();
1446 std::vector
<tools::Rectangle
> aRegions(partition(aRect
, mnSegmentsX
, mnSegmentsY
));
1447 DemoRenderer::clearRects(rDev
, aRegions
);
1448 for (size_t i
= 0; i
< maRenderers
.size(); i
++)
1450 RegionRenderer
* r
= maRenderers
[i
];
1452 rDev
.SetClipRegion( vcl::Region( aRegions
[i
] ) );
1455 if (getIterCount() > 0)
1459 double nStartTime
= getTimeNow();
1460 for (int j
= 0; j
< r
->getTestRepeatCount() * THUMB_REPEAT_FACTOR
; j
++)
1461 r
->RenderRegion(rDev
, aRegions
[i
], aCtx
);
1462 addTime(i
, (getTimeNow() - nStartTime
) / THUMB_REPEAT_FACTOR
);
1464 for (int j
= 0; j
< r
->getTestRepeatCount(); j
++)
1465 r
->RenderRegion(rDev
, aRegions
[i
], aCtx
);
1468 r
->RenderRegion(rDev
, aRegions
[i
], aCtx
);
1470 rDev
.SetClipRegion();
1474 void drawToDevice(vcl::RenderContext
& rDev
, Size aSize
, bool bVDev
)
1477 aCtx
.mbVDev
= bVDev
;
1478 aCtx
.mpDemoRenderer
= this;
1479 aCtx
.maSize
= aSize
;
1480 tools::Rectangle
aWholeWin(Point(0,0), rDev
.GetOutputSizePixel());
1482 drawBackground(rDev
, aWholeWin
);
1484 if (!bVDev
/* want everything in the vdev */ &&
1485 mnSelectedRenderer
>= 0 &&
1486 static_cast<sal_uInt32
>(mnSelectedRenderer
) < maRenderers
.size())
1488 aCtx
.meStyle
= RENDER_EXPANDED
;
1489 RegionRenderer
* r
= maRenderers
[mnSelectedRenderer
];
1491 if (getIterCount() > 0)
1493 double nStartTime
= getTimeNow();
1494 for (int i
= 0; i
< r
->getTestRepeatCount(); i
++)
1495 r
->RenderRegion(rDev
, aWholeWin
, aCtx
);
1496 addTime(mnSelectedRenderer
, getTimeNow() - nStartTime
);
1498 r
->RenderRegion(rDev
, aWholeWin
, aCtx
);
1501 drawThumbs(rDev
, aWholeWin
, bVDev
);
1503 std::vector
<VclPtr
<vcl::Window
> > maInvalidates
;
1504 void addInvalidate(vcl::Window
*pWindow
) { maInvalidates
.emplace_back(pWindow
); };
1505 void removeInvalidate(vcl::Window
*pWindow
)
1507 for (auto aIt
= maInvalidates
.begin(); aIt
!= maInvalidates
.end(); ++aIt
)
1509 if (*aIt
== pWindow
)
1511 maInvalidates
.erase(aIt
);
1518 for (auto const& invalidate
: maInvalidates
)
1519 invalidate
->Invalidate();
1523 #if FIXME_BOUNCE_BUTTON
1524 IMPL_LINK_NOARG(DemoRenderer
,BounceTimerCb
,Timer
*,void)
1526 mpButton
->Check(mnBounceX
>0);
1527 mpButton
->SetPressed(mnBounceY
>0);
1529 Point aCur
= mpButtonWin
->GetPosPixel();
1530 static const int nMovePix
= 10;
1531 aCur
.Move(mnBounceX
* nMovePix
, mnBounceX
* nMovePix
);
1532 Size aWinSize
= GetSizePixel();
1533 if (aCur
.X() <= 0 || aCur
.X() >= aWinSize
.Width())
1535 if (aCur
.Y() <= 0 || aCur
.Y() >= aWinSize
.Height())
1537 mpButtonWin
->SetPosPixel(aCur
);
1539 // All smoke and mirrors to test sub-region invalidation underneath
1540 Rectangle
aRect(aCur
, mpButtonWin
->GetSizePixel());
1545 void DemoRenderer::KeyInput(const KeyEvent
&rKEvt
)
1547 sal_uInt16 nCode
= rKEvt
.GetKeyCode().GetCode();
1549 // click to zoom out
1550 if (mnSelectedRenderer
>= 0)
1552 if (nCode
== KEY_ESCAPE
|| nCode
== KEY_BACKSPACE
)
1554 mnSelectedRenderer
= -1;
1561 for (size_t i
= 0; i
< maRenderers
.size(); i
++)
1563 if (nCode
== maRenderers
[i
]->getAccelerator())
1565 mnSelectedRenderer
= i
;
1573 bool DemoRenderer::MouseButtonDown(const MouseEvent
& rMEvt
)
1575 // click to zoom out
1576 if (mnSelectedRenderer
>= 0)
1578 mnSelectedRenderer
= -1;
1583 // click on a region to zoom into it
1584 std::vector
<tools::Rectangle
> aRegions(partition(GetSizePixel(), mnSegmentsX
, mnSegmentsY
));
1585 for (size_t i
= 0; i
< aRegions
.size(); i
++)
1587 if (aRegions
[i
].IsInside(rMEvt
.GetPosPixel()))
1589 mnSelectedRenderer
= i
;
1595 #if FIXME_BOUNCE_BUTTON
1596 // otherwise bounce floating windows
1599 mpButtonWin
= VclPtr
<FloatingWindow
>::Create(this);
1600 mpButton
= VclPtr
<PushButton
>::Create(mpButtonWin
);
1601 mpButton
->SetSymbol(SymbolType::HELP
);
1602 mpButton
->SetText("PushButton demo");
1603 mpButton
->SetPosSizePixel(Point(0,0), mpButton
->GetOptimalSize());
1605 mpButtonWin
->SetPosSizePixel(Point(0,0), mpButton
->GetOptimalSize());
1606 mpButtonWin
->Show();
1607 mnBounceX
= 1; mnBounceX
= 1;
1608 maBounce
.SetInvokeHandler(LINK(this,DemoRenderer
,BounceTimerCb
));
1609 maBounce
.SetTimeout(55);
1623 void DemoRenderer::InitRenderers()
1625 maRenderers
.push_back(new DrawLines
);
1626 maRenderers
.push_back(new DrawText
);
1627 maRenderers
.push_back(new DrawPoly
);
1628 maRenderers
.push_back(new DrawEllipse
);
1629 maRenderers
.push_back(new DrawCheckered
);
1630 maRenderers
.push_back(new DrawBitmapEx
);
1631 maRenderers
.push_back(new DrawBitmap
);
1632 maRenderers
.push_back(new DrawGradient
);
1633 maRenderers
.push_back(new DrawPolyPolygons
);
1634 maRenderers
.push_back(new DrawClipped
);
1635 maRenderers
.push_back(new DrawToVirtualDevice
);
1636 maRenderers
.push_back(new DrawXOR
);
1637 maRenderers
.push_back(new DrawIcons());
1638 maRenderers
.push_back(new FetchDrawBitmap
);
1641 OUString
DemoRenderer::getRendererList()
1643 OUStringBuffer aBuf
;
1644 for (size_t i
= 0; i
< maRenderers
.size(); i
++)
1646 aBuf
.append(maRenderers
[i
]->getName());
1649 return aBuf
.makeStringAndClear();
1652 double DemoRenderer::getAndResetBenchmark(const RenderStyle style
)
1654 double geomean
= 1.0;
1655 fprintf(stderr
, "Rendering: %s, Times (ms):\n", style
== RENDER_THUMB
? "THUMB": "EXPANDED");
1656 for (size_t i
= 0; i
< maRenderers
.size(); i
++)
1658 double avgtime
= maRenderers
[i
]->sumTime
/ maRenderers
[i
]->countTime
;
1660 fprintf(stderr
, "%s: %f (iteration: %d*%d*%d)\n",
1661 rtl::OUStringToOString(maRenderers
[i
]->getName(),
1662 RTL_TEXTENCODING_UTF8
).getStr(), avgtime
,
1663 maRenderers
[i
]->countTime
, maRenderers
[i
]->getTestRepeatCount(),
1664 (style
== RENDER_THUMB
) ? THUMB_REPEAT_FACTOR
: 1);
1665 maRenderers
[i
]->sumTime
= 0;
1666 maRenderers
[i
]->countTime
= 0;
1668 geomean
= pow(geomean
, 1.0/maRenderers
.size());
1669 fprintf(stderr
, "GEOMEAN_%s: %f\n", style
== RENDER_THUMB
? "THUMB": "EXPANDED", geomean
);
1673 void DemoRenderer::setIterCount(sal_Int32 i
)
1678 sal_Int32
DemoRenderer::getIterCount()
1683 void DemoRenderer::addTime(int i
, double t
)
1685 maRenderers
[i
]->sumTime
+= t
/ maRenderers
[i
]->getTestRepeatCount();
1686 maRenderers
[i
]->countTime
++;
1689 void DemoRenderer::selectRenderer(const OUString
&rName
)
1691 for (size_t i
= 0; i
< maRenderers
.size(); i
++)
1693 if (maRenderers
[i
]->getName() == rName
)
1695 mnSelectedRenderer
= i
;
1702 int DemoRenderer::selectNextRenderer()
1704 mnSelectedRenderer
++;
1705 if (mnSelectedRenderer
== static_cast<signed>(maRenderers
.size()))
1706 mnSelectedRenderer
= -1;
1708 return mnSelectedRenderer
;
1711 class DemoWin
: public WorkWindow
1713 DemoRenderer
&mrRenderer
;
1717 class RenderThread
: public salhelper::Thread
{
1721 RenderThread(DemoWin
&rWin
, sal_uInt32 nDelaySecs
)
1722 : Thread("vcldemo render thread")
1725 maDelay
.Seconds
= nDelaySecs
;
1726 maDelay
.Nanosec
= 0;
1729 virtual ~RenderThread() override
1733 virtual void execute() override
1735 osl_waitThread(&maDelay
);
1737 SolarMutexGuard aGuard
;
1738 fprintf (stderr
, "render from a different thread\n");
1742 rtl::Reference
<RenderThread
> mxThread
;
1745 DemoWin(DemoRenderer
&rRenderer
, bool bThreads
) :
1746 WorkWindow(nullptr, WB_APP
| WB_STDWORK
),
1747 mrRenderer(rRenderer
),
1748 testThreads(bThreads
)
1750 mrRenderer
.addInvalidate(this);
1751 underTesting
= false;
1753 virtual ~DemoWin() override
1757 virtual void dispose() override
1760 mrRenderer
.removeInvalidate(this);
1761 WorkWindow::dispose();
1763 virtual void MouseButtonDown(const MouseEvent
& rMEvt
) override
1765 mrRenderer
.SetSizePixel(GetSizePixel());
1766 if (!mrRenderer
.MouseButtonDown(rMEvt
))
1769 { // render this window asynchronously in a new thread
1770 sal_uInt32 nDelaySecs
= 0;
1771 if (rMEvt
.GetButtons() & MOUSE_RIGHT
)
1773 mxThread
= new RenderThread(*this, nDelaySecs
);
1776 { // spawn another window
1777 VclPtrInstance
<DemoWin
> pNewWin(mrRenderer
, testThreads
);
1778 pNewWin
->SetText("Another interactive VCL demo window");
1783 virtual void KeyInput(const KeyEvent
& rKEvt
) override
1785 mrRenderer
.SetSizePixel(GetSizePixel());
1786 mrRenderer
.KeyInput(rKEvt
);
1788 virtual void Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRect
) override
1790 mrRenderer
.SetSizePixel(GetSizePixel());
1791 fprintf(stderr
, "DemoWin::Paint(%ld,%ld,%ld,%ld)\n", rRect
.getX(), rRect
.getY(), rRect
.getWidth(), rRect
.getHeight());
1792 if (mrRenderer
.getIterCount() == 0)
1793 mrRenderer
.drawToDevice(rRenderContext
, GetSizePixel(), false);
1795 TestAndQuit(rRenderContext
);
1798 void TestAndQuit(vcl::RenderContext
& rRenderContext
)
1802 underTesting
= true;
1803 for (sal_Int32 i
= 0; i
< mrRenderer
.getIterCount(); i
++)
1805 while (mrRenderer
.selectNextRenderer() > -1)
1807 mrRenderer
.drawToDevice(rRenderContext
, GetSizePixel(), false);
1811 double expandedGEOMEAN
= mrRenderer
.getAndResetBenchmark(RENDER_EXPANDED
);
1813 for (sal_Int32 i
= 0; i
< mrRenderer
.getIterCount(); i
++)
1814 mrRenderer
.drawToDevice(rRenderContext
, GetSizePixel(), false);
1816 double thumbGEOMEAN
= mrRenderer
.getAndResetBenchmark(RENDER_THUMB
);
1818 fprintf(stderr
, "GEOMEAN_TOTAL: %f\n", pow(thumbGEOMEAN
* expandedGEOMEAN
, 0.5));
1819 Application::Quit();
1823 class DemoWidgets
: public WorkWindow
1825 VclPtr
<MenuBar
> mpBar
;
1826 VclPtr
<VclBox
> mpBox
;
1827 VclPtr
<ToolBox
> mpToolbox
;
1828 VclPtr
<PushButton
> mpButton
;
1829 VclPtr
<VclHBox
> mpHBox
;
1830 VclPtr
<CheckBox
> mpGLCheck
;
1831 VclPtr
<ComboBox
> mpGLCombo
;
1832 VclPtr
<PushButton
> mpGLButton
;
1834 DECL_LINK(GLTestClick
, Button
*, void);
1838 WorkWindow(nullptr, WB_APP
| WB_STDWORK
),
1839 mpBox(VclPtrInstance
<VclVBox
>(this, false, 3)),
1840 mpToolbox(VclPtrInstance
<ToolBox
>(mpBox
.get())),
1841 mpButton(VclPtrInstance
<PushButton
>(mpBox
.get())),
1842 mpHBox(VclPtrInstance
<VclHBox
>(mpBox
.get(), true, 3)),
1843 mpGLCheck(VclPtrInstance
<CheckBox
>(mpHBox
.get())),
1844 mpGLCombo(VclPtrInstance
<ComboBox
>(mpHBox
.get())),
1845 mpGLButton(VclPtrInstance
<PushButton
>(mpHBox
.get()))
1847 SetText("VCL widget demo");
1849 Wallpaper
aWallpaper(BitmapEx("sfx2/res/startcenter-logo.png"));
1850 aWallpaper
.SetStyle(WallpaperStyle::BottomRight
);
1851 aWallpaper
.SetColor(COL_RED
);
1853 mpBox
->SetBackground(aWallpaper
);
1856 Help::EnableBalloonHelp();
1857 mpToolbox
->SetHelpText("Help text");
1858 mpToolbox
->InsertItem(0, "Toolbar item");
1859 mpToolbox
->SetQuickHelpText(0, "This is a tooltip popup");
1860 mpToolbox
->InsertSeparator();
1863 mpButton
->SetText("Click me; go on");
1866 mpGLCheck
->SetText("Test in OGL zone");
1868 mpGLCombo
->InsertEntry("sleep 1 second");
1869 mpGLCombo
->InsertEntry("sleep 3 seconds");
1870 mpGLCombo
->InsertEntry("sleep 7 seconds");
1871 mpGLCombo
->SelectEntryPos(2);
1873 mpGLButton
->SetText("Execute test");
1874 mpGLButton
->SetClickHdl(LINK(this,DemoWidgets
,GLTestClick
));
1878 mpBar
= VclPtr
<MenuBar
>::Create();
1879 mpBar
->InsertItem(0,"File");
1880 VclPtrInstance
<PopupMenu
> pPopup
;
1881 pPopup
->InsertItem(0,"Item");
1882 mpBar
->SetPopupMenu(0, pPopup
);
1887 virtual ~DemoWidgets() override
{ disposeOnce(); }
1888 virtual void dispose() override
1890 mpGLButton
.disposeAndClear();
1891 mpGLCombo
.disposeAndClear();
1892 mpGLCheck
.disposeAndClear();
1893 mpHBox
.disposeAndClear();
1894 mpToolbox
.disposeAndClear();
1895 mpButton
.disposeAndClear();
1896 mpBox
.disposeAndClear();
1897 mpBar
.disposeAndClear();
1898 WorkWindow::dispose();
1900 virtual void Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
&) override
1902 tools::Rectangle
aWholeSize(Point(0, 0),GetOutputSizePixel());
1903 vcl::Region
aClip(aWholeSize
);
1904 tools::Rectangle
aExclude(tools::Rectangle(Point(50,50),Size(100,100)));
1905 aClip
.Exclude(aExclude
);
1907 Wallpaper
aWallpaper(COL_GREEN
);
1909 rRenderContext
.Push(PushFlags::CLIPREGION
);
1910 rRenderContext
.IntersectClipRegion(aClip
);
1911 rRenderContext
.DrawWallpaper(aWholeSize
, aWallpaper
);
1912 rRenderContext
.Pop();
1914 ScopedVclPtrInstance
< VirtualDevice
> pDev(*this);
1915 pDev
->EnableRTL(IsRTLEnabled());
1916 pDev
->SetOutputSizePixel(aExclude
.GetSize());
1918 tools::Rectangle
aSubRect(aWholeSize
);
1919 aSubRect
.Move(-aExclude
.Left(), -aExclude
.Top());
1920 pDev
->DrawWallpaper(aSubRect
, aWallpaper
);
1922 rRenderContext
.DrawOutDev(aExclude
.TopLeft(), aExclude
.GetSize(),
1923 Point( 0, 0 ), aExclude
.GetSize(), *pDev
.get() );
1927 class OpenGLZoneTest
{
1929 static void enter() { OpenGLZone::enter(); }
1930 static void leave() { OpenGLZone::leave(); }
1933 IMPL_LINK_NOARG(DemoWidgets
, GLTestClick
, Button
*, void)
1935 sal_Int32 nSelected
= mpGLCombo
->GetSelectedEntryPos();
1955 bool bEnterLeave
= mpGLCheck
->IsChecked();
1957 OpenGLZoneTest::enter();
1959 osl_waitThread(&aDelay
);
1962 OpenGLZoneTest::leave();
1965 class DemoPopup
: public FloatingWindow
1968 DemoPopup() : FloatingWindow( nullptr, WB_SYSTEMWINDOW
|WB_TOOLTIPWIN
)
1970 SetType( WindowType::HELPTEXTWINDOW
);
1972 SetOutputSizePixel( Size( 300, 30 ) );
1973 SetBackground(Wallpaper(COL_YELLOW
));
1975 Show( true, ShowFlags::NoActivate
);
1979 virtual void Paint(vcl::RenderContext
& /*rRenderContext*/, const tools::Rectangle
&) override
1981 // Interestingly in GL mode on Windows, this doesn't render.
1983 Size aSize
= GetOutputSizePixel();
1984 tools::Rectangle
aTextRect(Point(6, 6), aSize
);
1986 SetTextColor(COL_BLACK
);
1987 SetTextAlign(ALIGN_TOP
);
1988 DrawText(aTextRect
, "This is a standalone help text test",
1989 DrawTextFlags::MultiLine
|DrawTextFlags::WordBreak
|
1990 DrawTextFlags::Left
|DrawTextFlags::Top
);
1992 SetLineColor(COL_BLACK
);
1994 DrawRect( tools::Rectangle( Point(), aSize
) );
1995 aSize
.AdjustWidth( -2 );
1996 aSize
.AdjustHeight( -2 );
1997 Color
aColor( GetLineColor() );
1998 SetLineColor( COL_GRAY
);
1999 DrawRect( tools::Rectangle( Point( 1, 1 ), aSize
) );
2000 SetLineColor( aColor
);
2003 virtual void MouseButtonDown( const MouseEvent
& ) override
2005 Application::Quit();
2011 VclPtr
<WorkWindow
> mxWinA
;
2012 VclPtr
<WorkWindow
> mxWinB
;
2013 rtl::Reference
<OpenGLContext
> mpA
;
2014 rtl::Reference
<OpenGLContext
> mpB
;
2016 static OpenGLSalGraphicsImpl
*getImpl(const VclPtr
<OutputDevice
> &xOut
)
2018 SalGraphics
*pGraphics
= xOut
->GetGraphics();
2019 return dynamic_cast<OpenGLSalGraphicsImpl
*>(pGraphics
->GetImpl());
2023 mxWinA(VclPtr
<WorkWindow
>::Create(nullptr, WB_APP
| WB_STDWORK
)),
2024 mxWinB(VclPtr
<WorkWindow
>::Create(nullptr, WB_APP
| WB_STDWORK
))
2026 OpenGLSalGraphicsImpl
*pImplA
;
2027 OpenGLSalGraphicsImpl
*pImplB
;
2028 if (!OpenGLHelper::isVCLOpenGLEnabled())
2030 pImplA
= pImplB
= nullptr;
2031 fprintf (stderr
, "OpenGL is not enabled: try SAL_FORCEGL=1\n");
2035 pImplA
= getImpl(mxWinA
);
2036 pImplB
= getImpl(mxWinB
);
2037 assert (pImplA
&& pImplB
);
2038 mpA
= pImplA
->GetOpenGLContext();
2039 mpB
= pImplB
->GetOpenGLContext();
2041 assert (mpA
.is() && mpB
.is());
2042 assert (mpA
!= mpB
);
2046 mxWinB
.disposeAndClear();
2047 mxWinA
.disposeAndClear();
2050 void testCurrentFramebuffer()
2052 fprintf(stderr
,"test OpenGLContext's framebuffer association.\n");
2054 OpenGLFramebuffer
*pBuffer
;
2056 OpenGLTexture
aTexture(256,128);
2057 pBuffer
= mpA
->AcquireFramebuffer(aTexture
);
2059 assert (pBuffer
->IsFree()); (void)pBuffer
;
2061 assert (mpA
->mpCurrentFramebuffer
== nullptr);
2064 void testVirtualDevice()
2066 fprintf(stderr
, "test sharing OpenGLContexts with virtual-devices reference counting\n");
2067 VclPtrInstance
<WorkWindow
> xTempWin(nullptr, WB_STDWORK
);
2069 // forcibly make this context current by rendering
2070 xTempWin
->DrawPixel(Point(0, 0), COL_RED
);
2072 // get some other guys to leach off this context
2073 VclPtrInstance
<VirtualDevice
> xVDev
;
2074 rtl::Reference
<OpenGLContext
> pContext
= getImpl(xVDev
)->GetOpenGLContext();
2075 VclPtrInstance
<VirtualDevice
> xVDev2
;
2076 rtl::Reference
<OpenGLContext
> pContext2
= getImpl(xVDev
)->GetOpenGLContext();
2078 // sharing the same off-screen context.
2079 assert(pContext
== pContext2
);
2080 assert(pContext
== getImpl(xTempWin
)->GetOpenGLContext());
2081 assert(pContext
!= mpA
&& pContext
!= mpB
);
2082 (void)pContext
; (void)pContext2
;
2084 // Kill the parent we free-ride on ...
2085 xTempWin
.disposeAndClear();
2087 // This appears to continue working; fun.
2089 xVDev
->DrawPixel(aPt
, COL_GREEN
);
2090 assert(xVDev
->GetPixel(aPt
) == COL_GREEN
);
2091 xVDev
.disposeAndClear();
2093 // Switch context to see if we can switch back.
2094 mxWinA
->DrawPixel(aPt
, COL_WHITE
);
2096 // Now try switching back to this guy ...
2097 xVDev2
->DrawPixel(aPt
, COL_BLUE
);
2098 assert(xVDev2
->GetPixel(aPt
) == COL_BLUE
);
2099 xVDev2
.disposeAndClear();
2104 if (!OpenGLHelper::isVCLOpenGLEnabled())
2107 testCurrentFramebuffer();
2108 testVirtualDevice();
2115 void renderFonts(const std::vector
<OUString
> &aFontNames
)
2117 ScopedVclPtrInstance
<VirtualDevice
> xDevice
;
2118 Size
aSize(1024, 1024);
2119 xDevice
->SetOutputSizePixel(aSize
);
2121 for (auto & aFontName
: aFontNames
)
2123 vcl::Font
aFont(aFontName
, Size(0,96));
2125 aFont
.SetCOL_BLACK
);
2126 xDevice
->SetFont(aFont
);
2129 FontMetric aMetric
= xDevice
->GetFontMetric(aFont
);
2131 FontCharMapRef xMap
;
2132 if (xDevice
->GetFontCharMap(xMap
))
2134 ... iterate through glyphs
...
2138 bool GetGlyphBoundRects( const Point
& rOrigin
, const OUString
& rStr
, int nIndex
,
2139 int nLen
, int nBase
, MetricVector
& rVector
);
2141 include
/vcl
/outdev
.hxx
:typedef std::vector
< Rectangle
> MetricVector
;
2142 include
/vcl
/outdev
.hxx
: MetricVector
* pVector
= nullptr, OUString
* pDisplayText
= nullptr );
2143 include
/vcl
/outdev
.hxx
: MetricVector
* pVector
= nullptr, OUString
* pDisplayText
= nullptr,
2144 include
/vcl
/outdev
.hxx
: MetricVector
* pVector
, OUString
* pDisplayText
, vcl::ITextLayout
& _rLayout
);
2145 include
/vcl
/outdev
.hxx
: DrawTextFlags nStyle
= DrawTextFlags::Mnemonic
, MetricVector
* pVector
= nullp
2147 bool GetTextBoundRect( Rectangle
& rRect
,
2148 const OUString
& rStr
, sal_Int32 nBase
= 0, sal_Int32 nIndex
= 0, sal_Int32 nLen
= -1,
2149 sal_uLong nLayoutWidth
= 0, const long* pDXArray
= nullptr ) const;
2152 void DrawText( const Point
& rStartPt
, const OUString
& rStr
,
2153 sal_Int32 nIndex
= 0, sal_Int32 nLen
= -1,
2154 MetricVector
* pVector
= nullptr, OUString
* pDisplayText
= nullptr );
2156 void DrawText( const Rectangle
& rRect
,
2157 const OUString
& rStr
, DrawTextFlags nStyle
= DrawTextFlags::NONE
,
2158 MetricVector
* pVector
= nullptr, OUString
* pDisplayText
= nullptr,
2159 vcl::ITextLayout
* _pTextLayout
= nullptr );
2161 Rectangle
GetTextRect( const Rectangle
& rRect
,
2162 const OUString
& rStr
, DrawTextFlags nStyle
= DrawTextFlags::WordBreak
,
2163 TextRectInfo
* pInfo
= nullptr,
2164 const vcl::ITextLayout
* _pTextLayout
= nullptr ) const;
2172 class DemoApp
: public Application
2174 static int showHelp(DemoRenderer
&rRenderer
)
2176 fprintf(stderr
,"vcldemo - a VCL test app\n");
2177 fprintf(stderr
," --help - print this text\n");
2178 fprintf(stderr
," --show <renderer> - start with a given renderer, options are:\n");
2179 OUString
aRenderers(rRenderer
.getRendererList());
2180 fprintf(stderr
," %s\n",
2181 rtl::OUStringToOString(aRenderers
, RTL_TEXTENCODING_UTF8
).getStr());
2182 fprintf(stderr
," --test <iterCount> - create benchmark data\n");
2183 fprintf(stderr
," --widgets - launch the widget test.\n");
2184 fprintf(stderr
," --threads - render from multiple threads.\n");
2185 fprintf(stderr
," --gltest - run openGL regression tests.\n");
2186 fprintf(stderr
, "\n");
2193 virtual int Main() override
2197 bool bWidgets
= false, bThreads
= false;
2198 bool bPopup
= false, bGLTest
= false;
2199 DemoRenderer aRenderer
;
2200 std::vector
<OUString
> aFontNames
;
2202 for (sal_uInt16 i
= 0; i
< GetCommandLineParamCount(); ++i
)
2204 bool bLast
= i
== GetCommandLineParamCount() - 1;
2205 OUString aArg
= GetCommandLineParam(i
);
2206 if (aArg
== "--help" || aArg
== "-h")
2207 return showHelp(aRenderer
);
2208 if (aArg
== "--show")
2211 return showHelp(aRenderer
);
2213 aRenderer
.selectRenderer(GetCommandLineParam(++i
));
2215 else if (aArg
== "--test")
2218 return showHelp(aRenderer
);
2220 aRenderer
.setIterCount(GetCommandLineParam(++i
).toInt32());
2222 else if (aArg
== "--widgets")
2224 else if (aArg
== "--popup")
2226 else if (aArg
== "--gltest")
2228 else if (aArg
== "--threads")
2230 else if (aArg
== "--font" && !bLast
)
2231 aFontNames
.push_back(GetCommandLineParam(++i
));
2232 else if (aArg
.startsWith("--"))
2234 fprintf(stderr
,"Unknown argument '%s'\n",
2235 rtl::OUStringToOString(aArg
, RTL_TEXTENCODING_UTF8
).getStr());
2236 return showHelp(aRenderer
);
2240 ScopedVclPtrInstance
<DemoWin
> aMainWin(aRenderer
, bThreads
);
2241 VclPtr
<DemoWidgets
> xWidgets
;
2242 VclPtr
<DemoPopup
> xPopup
;
2244 aMainWin
->SetText("Interactive VCL demo #1");
2245 #if HAVE_FEATURE_OPENGL
2249 return aTests
.execute();
2254 xWidgets
= VclPtr
< DemoWidgets
>::Create ();
2256 xPopup
= VclPtrInstance
< DemoPopup
> ();
2257 else if (aFontNames
.size() > 0)
2258 renderFonts(aFontNames
);
2262 Application::Execute();
2264 xWidgets
.disposeAndClear();
2265 xPopup
.disposeAndClear();
2267 catch (const css::uno::Exception
& e
)
2269 SAL_WARN("vcl.app", "Fatal: " << e
);
2272 catch (const std::exception
& e
)
2274 SAL_WARN("vcl.app", "Fatal: " << e
.what());
2281 void Init() override
2285 uno::Reference
<uno::XComponentContext
> xComponentContext
2286 = ::cppu::defaultBootstrap_InitialComponentContext();
2287 uno::Reference
<lang::XMultiServiceFactory
> xMSF
;
2288 xMSF
.set(xComponentContext
->getServiceManager(), uno::UNO_QUERY
);
2290 Application::Abort("Bootstrap failure - no service manager");
2292 ::comphelper::setProcessServiceFactory(xMSF
);
2294 catch (const uno::Exception
&e
)
2296 Application::Abort("Bootstrap exception " + e
.Message
);
2299 void DeInit() override
2301 uno::Reference
< lang::XComponent
>(
2302 comphelper::getProcessComponentContext(),
2303 uno::UNO_QUERY_THROW
)-> dispose();
2304 ::comphelper::setProcessServiceFactory(nullptr);
2308 void vclmain::createApplication()
2310 static DemoApp aApp
;
2313 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */