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