xref: /trunk/main/canvas/workben/canvasdemo.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 
29 // MARKER(update_precomp.py): autogen include statement, do not remove
30 #include "precompiled_canvas.hxx"
31 // This code strongly inspired by Miguel / Federico's Gnome Canvas demo code.
32 
33 #include <comphelper/processfactory.hxx>
34 #include <comphelper/regpathhelper.hxx>
35 #include <cppuhelper/servicefactory.hxx>
36 #include <cppuhelper/bootstrap.hxx>
37 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
38 #include <com/sun/star/lang/XInitialization.hpp>
39 #include <com/sun/star/registry/XSimpleRegistry.hpp>
40 
41 #include <ucbhelper/contentbroker.hxx>
42 #include <ucbhelper/configurationkeys.hxx>
43 
44 #include <basegfx/polygon/b2dpolygon.hxx>
45 #include <basegfx/polygon/b2dpolygontools.hxx>
46 #include <basegfx/tools/canvastools.hxx>
47 
48 #include <vcl/window.hxx>
49 #include <vcl/virdev.hxx>
50 #include <vcl/svapp.hxx>
51 #include <vcl/msgbox.hxx>
52 #include <vcl/unowrap.hxx>
53 #include <vcl/canvastools.hxx>
54 
55 #include <rtl/bootstrap.hxx>
56 
57 #include <com/sun/star/rendering/XCanvas.hpp>
58 #include <com/sun/star/rendering/FillRule.hpp>
59 #include <com/sun/star/rendering/ViewState.hpp>
60 #include <com/sun/star/rendering/RenderState.hpp>
61 #include <com/sun/star/rendering/PathCapType.hpp>
62 #include <com/sun/star/rendering/PathJoinType.hpp>
63 #include <com/sun/star/rendering/XSpriteCanvas.hpp>
64 #include <com/sun/star/rendering/XGraphicDevice.hpp>
65 #include <com/sun/star/rendering/CompositeOperation.hpp>
66 #include <com/sun/star/rendering/XBitmap.hpp>
67 
68 #include <stdio.h>
69 #include <unistd.h>
70 
71 
72 // never import whole leaf namespaces, since this will result in
73 // absolutely weird effects during (Koenig) name lookup
74 using namespace ::com::sun::star;
75 
76 
77 class DemoApp : public Application
78 {
79 public:
80     virtual void Main();
81     virtual USHORT  Exception( USHORT nError );
82 };
83 
84 static void PrintHelp()
85 {
86     fprintf( stdout, "canvasdemo - Exercise the new canvas impl\n" );
87 }
88 
89 class TestWindow : public Dialog
90 {
91     public:
92         TestWindow() : Dialog( (Window *) NULL )
93         {
94             SetText( rtl::OUString::createFromAscii( "Canvas test" ) );
95             SetSizePixel( Size( 600, 450 ) );
96             EnablePaint( true );
97             Show();
98         }
99         virtual ~TestWindow() {}
100         virtual void MouseButtonUp( const MouseEvent& /*rMEvt*/ )
101         {
102             //TODO: do something cool
103             EndDialog();
104         }
105         virtual void Paint( const Rectangle& rRect );
106 };
107 
108 class DemoRenderer
109 {
110     public:
111         Size maSize;
112         Size maBox;
113         rendering::ViewState   maViewState;
114         rendering::RenderState maRenderState;
115         uno::Sequence< double > maColorBlack;
116         uno::Sequence< double > maColorWhite;
117         uno::Sequence< double > maColorRed;
118         uno::Reference< rendering::XCanvas > mxCanvas;
119         uno::Reference< rendering::XCanvasFont > mxDefaultFont;
120         uno::Reference< rendering::XGraphicDevice > mxDevice;
121 
122         DemoRenderer( uno::Reference< rendering::XGraphicDevice > xDevice,
123                       uno::Reference< rendering::XCanvas > xCanvas,
124                       Size aSize ) :
125             maSize(aSize),
126             maBox(),
127             maViewState(),
128             maRenderState(),
129             maColorBlack( vcl::unotools::colorToStdColorSpaceSequence( Color(COL_BLACK)) ),
130             maColorWhite( vcl::unotools::colorToStdColorSpaceSequence( Color(COL_WHITE)) ),
131             maColorRed( vcl::unotools::colorToStdColorSpaceSequence( Color(COL_RED)) ),
132             mxCanvas(xCanvas),
133             mxDefaultFont(),
134             mxDevice( xDevice )
135         {
136             // Geometry init
137             geometry::AffineMatrix2D aUnit( 1,0, 0,
138                                             0,1, 0 );
139             maViewState.AffineTransform = aUnit;
140             maRenderState.AffineTransform = aUnit;
141             maRenderState.DeviceColor = maColorBlack;
142 
143             //I can't figure out what the compsiteoperation stuff does
144             //it doesn't seem to do anything in either VCL or cairocanvas
145             //I was hoping that CLEAR would clear the canvas before we paint,
146             //but nothing changes
147             maRenderState.CompositeOperation = rendering::CompositeOperation::OVER;
148 
149             maBox.Width() = aSize.Width() / 3;
150             maBox.Height() = aSize.Height() / 3;
151 
152             lang::Locale aLocale;
153             rendering::FontInfo aFontInfo;
154             aFontInfo.FamilyName = ::rtl::OUString::createFromAscii( "Swiss" );
155             aFontInfo.StyleName = ::rtl::OUString::createFromAscii( "SansSerif" );
156             geometry::Matrix2D aFontMatrix( 1, 0,
157                                             0, 1 );
158             rendering::FontRequest aFontRequest( aFontInfo, 12.0, 0.0, aLocale );
159             uno::Sequence< beans::PropertyValue > aExtraFontProperties;
160             mxDefaultFont = xCanvas->createFont( aFontRequest, aExtraFontProperties, aFontMatrix );
161             if( !mxDefaultFont.is() )
162                 fprintf( stderr, "Failed to create font\n" );
163         }
164 
165         void drawGrid()
166         {
167             double d, dIncr = maSize.Width() / 3;
168             for ( d = 0; d <= maSize.Width(); d += dIncr )
169                 mxCanvas->drawLine( geometry::RealPoint2D( d, 0 ),
170                                     geometry::RealPoint2D( d, maSize.Height() ),
171                                     maViewState, maRenderState );
172             dIncr = maSize.Height() / 3;
173             for ( d = 0; d <= maSize.Height(); d += dIncr )
174                 mxCanvas->drawLine( geometry::RealPoint2D( 0, d ),
175                                     geometry::RealPoint2D( maSize.Width(), d ),
176                                     maViewState, maRenderState );
177         }
178 
179         void drawStringAt( ::rtl::OString aString, double x, double y )
180         {
181             rendering::StringContext aText;
182             aText.Text = ::rtl::OStringToOUString( aString, RTL_TEXTENCODING_UTF8 );
183             aText.StartPosition = 0;
184             aText.Length = aString.getLength();
185             rendering::RenderState aRenderState( maRenderState );
186             aRenderState.AffineTransform.m02 += x;
187             aRenderState.AffineTransform.m12 += y;
188 
189             mxCanvas->drawText( aText, mxDefaultFont, maViewState, aRenderState, 0);
190         }
191 
192         void drawRect( Rectangle rRect, uno::Sequence< double > &aColor, int /*nWidth*/ )
193         {
194             uno::Sequence< geometry::RealPoint2D > aPoints(4);
195             uno::Reference< rendering::XLinePolyPolygon2D > xPoly;
196 
197             aPoints[0] = geometry::RealPoint2D( rRect.Left(),  rRect.Top() );
198             aPoints[1] = geometry::RealPoint2D( rRect.Left(),  rRect.Bottom() );
199             aPoints[2] = geometry::RealPoint2D( rRect.Right(), rRect.Bottom() );
200             aPoints[3] = geometry::RealPoint2D( rRect.Right(), rRect.Top() );
201 
202             uno::Sequence< uno::Sequence< geometry::RealPoint2D > > aPolys(1);
203             aPolys[0] = aPoints;
204             xPoly = mxDevice->createCompatibleLinePolyPolygon( aPolys );
205             xPoly->setClosed( 0, true );
206             uno::Reference< rendering::XPolyPolygon2D> xPP( xPoly, uno::UNO_QUERY );
207 
208             rendering::RenderState aRenderState( maRenderState );
209             aRenderState.DeviceColor = aColor;
210             mxCanvas->drawPolyPolygon( xPP, maViewState, aRenderState );
211         }
212 
213         void translate( double x, double y)
214         {
215             maRenderState.AffineTransform.m02 += x;
216             maRenderState.AffineTransform.m12 += y;
217         }
218 
219         void drawPolishDiamond( double center_x, double center_y)
220         {
221             const int    VERTICES = 10;
222             const double RADIUS = 60.0;
223             int i, j;
224             double a;
225 
226             rendering::RenderState maOldRenderState = maRenderState; // push
227             translate( center_x, center_y );
228 
229             for (i = 0; i < VERTICES; i++)
230             {
231                 a = 2.0 * M_PI * i / VERTICES;
232                 geometry::RealPoint2D aSrc( RADIUS * cos (a), RADIUS * sin (a) );
233 
234                 for (j = i + 1; j < VERTICES; j++)
235                 {
236                     a = 2.0 * M_PI * j / VERTICES;
237 
238 //                  FIXME: set cap_style to 'ROUND'
239                     mxCanvas->drawLine( aSrc,
240                                         geometry::RealPoint2D( RADIUS * cos (a),
241                                                                RADIUS * sin (a) ),
242                                         maViewState, maRenderState );
243                 }
244             }
245 
246             maRenderState = maOldRenderState; // pop
247         }
248 
249         void drawHilbert( double anchor_x, double anchor_y )
250         {
251             const double SCALE=7.0;
252             const char hilbert[] = "urdrrulurulldluuruluurdrurddldrrruluurdrurddldrddlulldrdldrrurd";
253             int nLength = sizeof( hilbert ) / sizeof (hilbert [0]);
254 
255             uno::Sequence< geometry::RealPoint2D > aPoints( nLength );
256             uno::Reference< rendering::XLinePolyPolygon2D > xPoly;
257 
258             aPoints[0] = geometry::RealPoint2D( anchor_x, anchor_y );
259             for (int i = 0; i < nLength; i++ )
260             {
261                 switch( hilbert[i] )
262                 {
263                     case 'u':
264                         aPoints[i+1] = geometry::RealPoint2D( aPoints[i].X,
265                                                             aPoints[i].Y - SCALE );
266                         break;
267                     case 'd':
268                         aPoints[i+1] = geometry::RealPoint2D( aPoints[i].X,
269                                                             aPoints[i].Y + SCALE );
270                         break;
271                     case 'l':
272                         aPoints[i+1] = geometry::RealPoint2D( aPoints[i].X - SCALE,
273                                                             aPoints[i].Y );
274                         break;
275                     case 'r':
276                         aPoints[i+1] = geometry::RealPoint2D( aPoints[i].X + SCALE,
277                                                             aPoints[i].Y );
278                         break;
279                 }
280             }
281 
282             uno::Sequence< uno::Sequence< geometry::RealPoint2D > > aPolys(1);
283             aPolys[0] = aPoints;
284 
285             xPoly = mxDevice->createCompatibleLinePolyPolygon( aPolys );
286             xPoly->setClosed( 0, false );
287             uno::Reference< rendering::XPolyPolygon2D> xPP( xPoly, uno::UNO_QUERY );
288 
289             rendering::RenderState aRenderState( maRenderState );
290             aRenderState.DeviceColor = maColorRed;
291 //          aRenderState.DeviceColor[3] = 0.5;
292             rendering::StrokeAttributes aStrokeAttrs;
293             aStrokeAttrs.StrokeWidth = 4.0;
294             aStrokeAttrs.MiterLimit = 2.0; // ?
295             aStrokeAttrs.StartCapType = rendering::PathCapType::BUTT;
296             aStrokeAttrs.EndCapType = rendering::PathCapType::BUTT;
297             aStrokeAttrs.JoinType = rendering::PathJoinType::MITER;
298             //fprintf( stderr, "FIXME: stroking a PolyPolygon doesn't show up\n" );
299             //yes it does
300             mxCanvas->strokePolyPolygon( xPP, maViewState, aRenderState, aStrokeAttrs );
301             // FIXME: do this instead:
302             //mxCanvas->drawPolyPolygon( xPP, maViewState, aRenderState );
303         }
304 
305         void drawTitle( rtl::OString aTitle )
306         {
307             // FIXME: text anchoring to be done
308             double nStringWidth = aTitle.getLength() * 8.0;
309             drawStringAt ( aTitle, (maBox.Width() - nStringWidth) / 2, 15 );
310         }
311 
312         void drawRectangles()
313         {
314             rendering::RenderState maOldRenderState = maRenderState; // push
315 
316             drawTitle( ::rtl::OString( "Rectangles" ) );
317 
318             drawRect( Rectangle( 20, 30, 70, 60 ), maColorRed, 8 );
319             // color mediumseagreen, stipple fill, outline black
320             drawRect( Rectangle( 90, 40, 180, 100 ), maColorBlack, 4 );
321             // color steelblue, filled, no outline
322             drawRect( Rectangle( 10, 80, 80, 140 ), maColorBlack, 1 );
323 
324             maRenderState = maOldRenderState; // pop
325         }
326 
327         void drawEllipses()
328         {
329             rendering::RenderState maOldRenderState = maRenderState; // push
330             translate( maBox.Width(), 0.0 );
331 
332             drawTitle( ::rtl::OString( "Ellipses" ) );
333 
334             const basegfx::B2DPoint aCenter( maBox.Width()*.5,
335                                              maBox.Height()*.5 );
336             const basegfx::B2DPoint aRadii( maBox.Width()*.3,
337                                             maBox.Height()*.3 );
338             const basegfx::B2DPolygon& rEllipse(
339                 basegfx::tools::createPolygonFromEllipse( aCenter,
340                                                           aRadii.getX(),
341                                                           aRadii.getY() ));
342 
343             uno::Reference< rendering::XPolyPolygon2D > xPoly(
344                 basegfx::unotools::xPolyPolygonFromB2DPolygon(mxDevice,
345                                                               rEllipse) );
346 
347             rendering::StrokeAttributes aStrokeAttrs;
348             aStrokeAttrs.StrokeWidth = 4.0;
349             aStrokeAttrs.MiterLimit = 2.0; // ?
350             aStrokeAttrs.StartCapType = rendering::PathCapType::BUTT;
351             aStrokeAttrs.EndCapType = rendering::PathCapType::BUTT;
352             aStrokeAttrs.JoinType = rendering::PathJoinType::MITER;
353             mxCanvas->strokePolyPolygon( xPoly, maViewState, maRenderState, aStrokeAttrs );
354 
355             maRenderState = maOldRenderState; // pop
356         }
357 
358         void drawText()
359         {
360             rendering::RenderState maOldRenderState = maRenderState; // push
361             translate( maBox.Width() * 2.0, 0.0 );
362 
363             drawTitle( ::rtl::OString( "Text" ) );
364 
365             translate( 0.0,
366                        maBox.Height() * .5 );
367             drawTitle( ::rtl::OString( "This is lame" ) );
368 
369             maRenderState = maOldRenderState; // pop
370         }
371 
372         void drawImages()
373         {
374             rendering::RenderState maOldRenderState = maRenderState; // push
375             translate( 0.0, maBox.Height() );
376 
377             drawTitle( ::rtl::OString( "Images" ) );
378 
379             uno::Reference< rendering::XBitmap > xBitmap(mxCanvas, uno::UNO_QUERY);
380 
381             if( !xBitmap.is() )
382                 return;
383 
384             translate( maBox.Width()*0.1, maBox.Height()*0.2 );
385             maRenderState.AffineTransform.m00 *= 4.0/15;
386             maRenderState.AffineTransform.m11 *= 3.0/15;
387 
388             mxCanvas->drawBitmap(xBitmap, maViewState, maRenderState);
389 
390             // uno::Reference< rendering::XBitmap > xBitmap2( xBitmap->getScaledBitmap(geometry::RealSize2D(48, 48), false) );
391             // mxCanvas->drawBitmap(xBitmap2, maViewState, maRenderState); //yes, but where?
392             //cairo-canvas says:
393             //called CanvasHelper::getScaledBitmap, we return NULL, TODO
394             //Exception 'BitmapEx vclcanvas::tools::bitmapExFromXBitmap(const com::sun::star::uno::Reference<com::sun::star::rendering::XBitmap>&),
395             //bitmapExFromXBitmap(): could not extract BitmapEx' thrown
396             //
397             //vcl-canvas says:
398             //Exception 'BitmapEx vclcanvas::tools::bitmapExFromXBitmap(const com::sun::star::uno::Reference<com::sun::star::rendering::XBitmap>&),
399             //bitmapExFromXBitmap(): could not extract bitmap' thrown
400             //  Thorsten says that this is a bug, and Thorsten never lies.
401 
402             maRenderState = maOldRenderState; // pop
403         }
404 
405         void drawLines()
406         {
407             rendering::RenderState maOldRenderState = maRenderState; // push
408             translate( maBox.Width(), maBox.Height() );
409 
410             drawTitle( ::rtl::OString( "Lines" ) );
411 
412             drawPolishDiamond( 70.0, 80.0 );
413             drawHilbert( 140.0, 140.0 );
414 
415             maRenderState = maOldRenderState; // pop
416         }
417 
418         void drawCurves()
419         {
420             rendering::RenderState maOldRenderState = maRenderState; // push
421             translate( maBox.Width() * 2.0, maBox.Height() );
422 
423             drawTitle( ::rtl::OString( "Curves" ) );
424 
425             translate( maBox.Width() * .5, maBox.Height() * .5 );
426 
427             const double r= 30.0;
428             const int num_curves = 3;
429 
430             //hacky hack hack
431             uno::Sequence< geometry::RealBezierSegment2D > aBeziers (num_curves);
432             uno::Reference< rendering::XBezierPolyPolygon2D > xPoly;
433 
434             for (int i= 0; i < num_curves; i++)
435                 aBeziers[i]= geometry::RealBezierSegment2D( r * cos(i*2*M_PI/num_curves), //Px
436                                                             r * sin(i*2*M_PI/num_curves), //py
437                                                             r * 2 * cos((i*2*M_PI + 2*M_PI)/num_curves),  //C1x
438                                                             r * 2 * sin((i*2*M_PI + 2*M_PI)/num_curves),  //C1y
439                                                             r * 2 * cos((i*2*M_PI + 2*M_PI)/num_curves),  //C2x
440                                                             r * 2 * sin((i*2*M_PI + 2*M_PI)/num_curves)); //C2y
441             uno::Sequence< uno::Sequence< geometry::RealBezierSegment2D > > aPolys(1);
442             aPolys[0] = aBeziers;
443             xPoly = mxDevice->createCompatibleBezierPolyPolygon(aPolys);
444             xPoly->setClosed( 0, true );
445             //uno::Reference< rendering::XBezierPolyPolygon2D> xPP( xPoly, uno::UNO_QUERY );
446             //compiles, but totally screws up.  I think it is interpretting the bezier as a line
447             uno::Reference< rendering::XPolyPolygon2D> xPP( xPoly, uno::UNO_QUERY );
448 
449             rendering::StrokeAttributes aStrokeAttrs;
450             aStrokeAttrs.StrokeWidth = 4.0;
451             aStrokeAttrs.MiterLimit = 2.0; // ?
452             aStrokeAttrs.StartCapType = rendering::PathCapType::BUTT;
453             aStrokeAttrs.EndCapType = rendering::PathCapType::BUTT;
454             aStrokeAttrs.JoinType = rendering::PathJoinType::MITER;
455             mxCanvas->strokePolyPolygon( xPP, maViewState, maRenderState, aStrokeAttrs );
456             //you can't draw a BezierPolyPolygon2D with this, even though it is derived from it
457             //mxCanvas->drawPolyPolygon( xPP, maViewState, maRenderState );
458 
459             maRenderState = maOldRenderState; // pop
460         }
461 
462     double gimmerand()
463         {
464             return (double)(rand()) / RAND_MAX * 100 + 50;
465         }
466 
467         void drawArcs()
468         {
469             rendering::RenderState maOldRenderState = maRenderState; // push
470             translate( 0.0, maBox.Height() * 2.0 );
471 
472             drawTitle( ::rtl::OString( "Arcs" ) );
473 
474 
475             //begin hacks
476             //This stuff doesn't belong here, but probably in curves
477             //This stuff doesn't work in VCL b/c vcl doesn't do beziers
478             //Hah!  Everytime the window redraws, we do this
479             double ax;
480             double ay;
481             double bx;
482             double by;
483             bx= gimmerand();
484             by= gimmerand();
485 
486             for (int i= 0; i < 1; i++)
487             {
488                 //point a= point b;
489                 ax= bx;
490                 ay= by;
491                 //point b= rand;
492                 bx= gimmerand();
493                 by= gimmerand();
494                 double c1x= gimmerand();
495                 double c1y= gimmerand();
496                 double c2x= gimmerand();
497                 double c2y= gimmerand();
498                 maRenderState.DeviceColor = maColorRed;
499                 mxCanvas->drawLine(geometry::RealPoint2D(ax, ay), geometry::RealPoint2D(c1x, c1y), maViewState, maRenderState);
500                 mxCanvas->drawLine(geometry::RealPoint2D(c1x, c1y), geometry::RealPoint2D(c2x, c2y), maViewState, maRenderState);
501                 mxCanvas->drawLine(geometry::RealPoint2D(bx, by), geometry::RealPoint2D(c2x, c2y), maViewState, maRenderState);
502                 //draw from a to b
503                 geometry::RealBezierSegment2D aBezierSegment(
504                     ax, //Px
505                     ay, //Py
506                     c1x,
507                     c1x,
508                     c2x,
509                     c2y
510                     );
511                 geometry::RealPoint2D aEndPoint(bx, by);
512                 maRenderState.DeviceColor = maColorBlack;
513                 mxCanvas->drawBezier(
514                     aBezierSegment,
515                     aEndPoint,
516                     maViewState, maRenderState );
517             }
518             maRenderState = maOldRenderState; // pop
519         }
520 
521 
522     void drawRegularPolygon(double centerx, double centery, int sides, double r)
523         {
524             //hacky hack hack
525             uno::Sequence< geometry::RealPoint2D > aPoints (sides);
526             uno::Reference< rendering::XLinePolyPolygon2D > xPoly;
527 
528             for (int i= 0; i < sides; i++)
529             {
530                 aPoints[i]= geometry::RealPoint2D( centerx + r * cos(i*2 * M_PI/sides),
531                                                    centery + r * sin(i*2 * M_PI/sides));
532             }
533             uno::Sequence< uno::Sequence< geometry::RealPoint2D > > aPolys(1);
534             aPolys[0] = aPoints;
535             xPoly = mxDevice->createCompatibleLinePolyPolygon( aPolys );
536             xPoly->setClosed( 0, true );
537             rendering::RenderState aRenderState( maRenderState );
538             aRenderState.DeviceColor = maColorRed;
539             uno::Reference< rendering::XPolyPolygon2D> xPP( xPoly, uno::UNO_QUERY );
540             mxCanvas->drawPolyPolygon( xPP, maViewState, aRenderState);
541             mxCanvas->fillPolyPolygon( xPP,
542                                        maViewState,
543                                        aRenderState );
544         }
545 
546         void drawPolygons()
547         {
548             rendering::RenderState maOldRenderState = maRenderState; // push
549             translate( maBox.Width() * 1.0, maBox.Height() * 2.0 );
550 
551             drawTitle( ::rtl::OString( "Polgyons" ) );
552 
553             int sides= 3;
554             for (int i= 1; i <= 4; i++)
555             {
556                 drawRegularPolygon(35*i, 35, sides, 15);
557                 sides++;
558             }
559 
560             maRenderState = maOldRenderState; // pop
561         }
562 
563         void drawWidgets() // FIXME: prolly makes no sense
564         {
565             rendering::RenderState maOldRenderState = maRenderState; // push
566             translate( maBox.Width() * 2.0, maBox.Height() * 2.0 );
567 
568             drawTitle( ::rtl::OString( "Widgets" ) );
569 
570             maRenderState = maOldRenderState; // pop
571         }
572 };
573 
574 
575 void TestWindow::Paint( const Rectangle& /*rRect*/ )
576 {
577     try
578     {
579         const Size aVDevSize(300,300);
580         VirtualDevice aVDev(*this);
581         aVDev.SetOutputSizePixel(aVDevSize);
582         uno::Reference< rendering::XCanvas > xVDevCanvas( aVDev.GetCanvas(),
583                                                           uno::UNO_QUERY_THROW );
584         uno::Reference< rendering::XGraphicDevice > xVDevDevice( xVDevCanvas->getDevice(),
585                                                                  uno::UNO_QUERY_THROW );
586         DemoRenderer aVDevRenderer( xVDevDevice, xVDevCanvas, aVDevSize);
587         xVDevCanvas->clear();
588         aVDevRenderer.drawGrid();
589         aVDevRenderer.drawRectangles();
590         aVDevRenderer.drawEllipses();
591         aVDevRenderer.drawText();
592         aVDevRenderer.drawLines();
593         aVDevRenderer.drawCurves();
594         aVDevRenderer.drawArcs();
595         aVDevRenderer.drawPolygons();
596 
597         uno::Reference< rendering::XCanvas > xCanvas( GetSpriteCanvas(),
598                                                           uno::UNO_QUERY_THROW );
599         uno::Reference< rendering::XGraphicDevice > xDevice( xCanvas->getDevice(),
600                                                              uno::UNO_QUERY_THROW );
601 
602         DemoRenderer aRenderer( xDevice, xCanvas, GetSizePixel() );
603         xCanvas->clear();
604         aRenderer.drawGrid();
605         aRenderer.drawRectangles();
606         aRenderer.drawEllipses();
607         aRenderer.drawText();
608         aRenderer.drawLines();
609         aRenderer.drawCurves();
610         aRenderer.drawArcs();
611         aRenderer.drawPolygons();
612         aRenderer.drawWidgets();
613         aRenderer.drawImages();
614 
615         // check whether virdev actually contained something
616         uno::Reference< rendering::XBitmap > xBitmap(xVDevCanvas, uno::UNO_QUERY);
617         if( !xBitmap.is() )
618             return;
619 
620         aRenderer.maRenderState.AffineTransform.m02 += 100;
621         aRenderer.maRenderState.AffineTransform.m12 += 100;
622         xCanvas->drawBitmap(xBitmap, aRenderer.maViewState, aRenderer.maRenderState);
623 
624         uno::Reference< rendering::XSpriteCanvas > xSpriteCanvas( xCanvas,
625                                                                   uno::UNO_QUERY );
626         if( xSpriteCanvas.is() )
627             xSpriteCanvas->updateScreen( sal_True ); // without
628                                                      // updateScreen(),
629                                                      // nothing is
630                                                      // visible
631     }
632     catch (const uno::Exception &e)
633     {
634         fprintf( stderr, "Exception '%s' thrown\n" ,
635                  (const sal_Char *) ::rtl::OUStringToOString( e.Message, RTL_TEXTENCODING_UTF8 ) );
636     }
637 }
638 
639 USHORT DemoApp::Exception( USHORT nError )
640 {
641     switch( nError & EXC_MAJORTYPE )
642     {
643         case EXC_RSCNOTLOADED:
644             Abort( String::CreateFromAscii( "Error: could not load language resources.\nPlease check your installation.\n" ) );
645             break;
646     }
647     return 0;
648 }
649 
650 void DemoApp::Main()
651 {
652     bool bHelp = false;
653 
654     for( USHORT i = 0; i < GetCommandLineParamCount(); i++ )
655     {
656         ::rtl::OUString aParam = GetCommandLineParam( i );
657 
658         if( aParam.equalsAscii( "--help" ) ||
659             aParam.equalsAscii( "-h" ) )
660                 bHelp = true;
661     }
662 
663     if( bHelp )
664     {
665         PrintHelp();
666         return;
667     }
668 
669     //-------------------------------------------------
670     // create the global service-manager
671     //-------------------------------------------------
672     uno::Reference< lang::XMultiServiceFactory > xFactory;
673     try
674     {
675         uno::Reference< uno::XComponentContext > xCtx = ::cppu::defaultBootstrap_InitialComponentContext();
676         xFactory = uno::Reference< lang::XMultiServiceFactory >(  xCtx->getServiceManager(),
677                                                                   uno::UNO_QUERY );
678         if( xFactory.is() )
679             ::comphelper::setProcessServiceFactory( xFactory );
680     }
681     catch( uno::Exception& )
682     {
683     }
684 
685     if( !xFactory.is() )
686     {
687         fprintf( stderr, "Could not bootstrap UNO, installation must be in disorder. Exiting.\n" );
688         exit( 1 );
689     }
690 
691     // Create UCB.
692     uno::Sequence< uno::Any > aArgs( 2 );
693     aArgs[ 0 ] <<= rtl::OUString::createFromAscii( UCB_CONFIGURATION_KEY1_LOCAL );
694     aArgs[ 1 ] <<= rtl::OUString::createFromAscii( UCB_CONFIGURATION_KEY2_OFFICE );
695     ::ucbhelper::ContentBroker::initialize( xFactory, aArgs );
696 
697     InitVCL( xFactory );
698     TestWindow pWindow;
699     pWindow.Execute();
700     DeInitVCL();
701 
702     // clean up UCB
703     ::ucbhelper::ContentBroker::deinitialize();
704 }
705 
706 DemoApp aDemoApp;
707 
708 // TODO
709 //   - bouncing clip-rectangle mode - bounce a clip-rect around the window ...
710 //   - complete all of pre-existing canvas bits
711 //   - affine transform tweakage ...
712 
713