merge the formfield patch from ooo-build
[ooovba.git] / canvas / source / java / CanvasUtils.java
blob35f8dc2c470e4e3b71b5d601e6d886eb99361e80
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: CanvasUtils.java,v $
10 * $Revision: 1.7 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // UNO
32 import com.sun.star.uno.UnoRuntime;
34 // Canvas
35 import com.sun.star.rendering.*;
36 import com.sun.star.geometry.*;
38 // Java AWT
39 import java.awt.*;
40 import java.awt.geom.*;
42 public class CanvasUtils
45 // Canvas utilities
46 // ================
48 public static java.awt.geom.AffineTransform makeTransform( AffineMatrix2D ooTransform )
50 return new AffineTransform( ooTransform.m00,
51 ooTransform.m10,
52 ooTransform.m01,
53 ooTransform.m11,
54 ooTransform.m02,
55 ooTransform.m12 );
58 public static AffineMatrix2D makeAffineMatrix2D( java.awt.geom.AffineTransform transform )
60 double[] matrix = new double[6];
61 transform.getMatrix( matrix );
63 return new AffineMatrix2D( matrix[0], matrix[2], matrix[4],
64 matrix[1], matrix[3], matrix[5] );
67 public static void initGraphics( Graphics2D graphics )
69 if( graphics != null )
71 java.awt.RenderingHints hints = new java.awt.RenderingHints(null);
72 boolean hq = true;
74 if( hq )
76 hints.add( new java.awt.RenderingHints( java.awt.RenderingHints.KEY_FRACTIONALMETRICS,
77 java.awt.RenderingHints.VALUE_FRACTIONALMETRICS_ON ) );
78 // hints.add( new java.awt.RenderingHints( java.awt.RenderingHints.KEY_ALPHA_INTERPOLATION,
79 // java.awt.RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY) );
80 hints.add( new java.awt.RenderingHints( java.awt.RenderingHints.KEY_ALPHA_INTERPOLATION,
81 java.awt.RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED) );
82 // hints.add( new java.awt.RenderingHints( java.awt.RenderingHints.KEY_INTERPOLATION,
83 // java.awt.RenderingHints.VALUE_INTERPOLATION_BICUBIC) );
84 hints.add( new java.awt.RenderingHints( java.awt.RenderingHints.KEY_INTERPOLATION,
85 java.awt.RenderingHints.VALUE_INTERPOLATION_BILINEAR) );
86 // hints.add( new java.awt.RenderingHints( java.awt.RenderingHints.KEY_RENDERING,
87 // java.awt.RenderingHints.VALUE_RENDER_QUALITY) );
88 hints.add( new java.awt.RenderingHints( java.awt.RenderingHints.KEY_RENDERING,
89 java.awt.RenderingHints.VALUE_RENDER_SPEED) );
90 // hints.add( new java.awt.RenderingHints( java.awt.RenderingHints.KEY_STROKE_CONTROL,
91 // java.awt.RenderingHints.VALUE_STROKE_NORMALIZE) );
92 hints.add( new java.awt.RenderingHints( java.awt.RenderingHints.KEY_STROKE_CONTROL,
93 java.awt.RenderingHints.VALUE_STROKE_DEFAULT) );
94 hints.add( new java.awt.RenderingHints( java.awt.RenderingHints.KEY_ANTIALIASING,
95 java.awt.RenderingHints.VALUE_ANTIALIAS_ON) );
97 else
99 hints.add( new java.awt.RenderingHints( java.awt.RenderingHints.KEY_ALPHA_INTERPOLATION,
100 java.awt.RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED) );
101 hints.add( new java.awt.RenderingHints( java.awt.RenderingHints.KEY_INTERPOLATION,
102 java.awt.RenderingHints.VALUE_INTERPOLATION_BILINEAR) );
103 hints.add( new java.awt.RenderingHints( java.awt.RenderingHints.KEY_RENDERING,
104 java.awt.RenderingHints.VALUE_RENDER_SPEED) );
105 hints.add( new java.awt.RenderingHints( java.awt.RenderingHints.KEY_STROKE_CONTROL,
106 java.awt.RenderingHints.VALUE_STROKE_DEFAULT) );
107 hints.add( new java.awt.RenderingHints( java.awt.RenderingHints.KEY_ANTIALIASING,
108 java.awt.RenderingHints.VALUE_ANTIALIAS_OFF) );
111 // the least common denominator standard
112 hints.add( new java.awt.RenderingHints( java.awt.RenderingHints.KEY_FRACTIONALMETRICS,
113 java.awt.RenderingHints.VALUE_FRACTIONALMETRICS_ON) );
114 hints.add( new java.awt.RenderingHints( java.awt.RenderingHints.KEY_TEXT_ANTIALIASING,
115 java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_ON) );
117 graphics.setRenderingHints( hints );
121 //----------------------------------------------------------------------------------
123 public static java.awt.geom.GeneralPath makeGenPathFromBezierPoints( RealBezierSegment2D [][] points )
125 java.awt.geom.GeneralPath path = new java.awt.geom.GeneralPath();
127 // extract every polygon into GeneralPath object
128 for( int i=0; i<points.length; ++i )
130 if( points[i].length > 0 )
131 path.moveTo((float) points[i][0].Px, (float) points[i][0].Py);
133 for( int j=1; j<points[i].length; ++j )
135 CanvasUtils.printLog( "makeGenPathFromBezierPoints: point added." );
136 path.curveTo((float)(points[i][j-1].C1x), (float)(points[i][j-1].C1y),
137 (float)(points[i][j-1].C2x), (float)(points[i][j-1].C2y),
138 (float) points[i][j].Px, (float) points[i][j].Py );
141 // TODO: closePath?
144 return path;
147 public static java.awt.geom.GeneralPath makeGenPathFromBezierPoly( com.sun.star.rendering.XBezierPolyPolygon2D poly )
151 com.sun.star.geometry.RealBezierSegment2D [][] points = poly.getBezierSegments(0,-1,0,-1);
153 return makeGenPathFromBezierPoints( points );
155 catch( com.sun.star.lang.IndexOutOfBoundsException e )
159 return new java.awt.geom.GeneralPath();
162 public static java.awt.geom.GeneralPath makeGenPathFromLinePoints( RealPoint2D [][] points )
164 java.awt.geom.GeneralPath path = new java.awt.geom.GeneralPath();
166 // extract every polygon into GeneralPath object
167 for( int i=0; i<points.length; ++i )
169 if( points[i].length > 0 )
170 path.moveTo((float) points[i][0].X, (float) points[i][0].Y);
172 for( int j=1; j<points[i].length; ++j )
174 CanvasUtils.printLog( "makeGenPathFromLinePoints: point (" +
175 points[i][j].X + "," + points[i][j].Y + ") added." );
176 path.lineTo((float) points[i][j].X, (float) points[i][j].Y );
179 // TODO: closePath?
182 return path;
185 public static java.awt.geom.GeneralPath makeGenPathFromLinePoly( com.sun.star.rendering.XLinePolyPolygon2D poly )
189 com.sun.star.geometry.RealPoint2D [][] points = poly.getPoints(0,-1,0,-1);
191 return makeGenPathFromLinePoints( points );
193 catch( com.sun.star.lang.IndexOutOfBoundsException e )
197 return new java.awt.geom.GeneralPath();
200 public static java.awt.geom.GeneralPath makeGeneralPath( com.sun.star.rendering.XPolyPolygon2D poly )
202 if( poly instanceof BezierPolyPolygon )
204 CanvasUtils.printLog( "makeGeneralPath: bezier impl used." );
205 return ((BezierPolyPolygon)poly).getJavaPath();
208 if( poly instanceof LinePolyPolygon )
210 CanvasUtils.printLog( "makeGeneralPath: line impl used." );
211 return ((LinePolyPolygon)poly).getJavaPath();
214 XBezierPolyPolygon2D bezierPoly = (XBezierPolyPolygon2D) UnoRuntime.queryInterface(XBezierPolyPolygon2D.class, poly);
216 if( bezierPoly != null )
218 // extract polygon data. Prefer bezier interface, because
219 // that's the more high-level data.
220 return makeGenPathFromBezierPoly( bezierPoly );
223 XLinePolyPolygon2D linePoly = (XLinePolyPolygon2D) UnoRuntime.queryInterface(XLinePolyPolygon2D.class, poly);
225 if( linePoly != null )
227 // extract polygon data. Fallback to line polygon, if no
228 // curves are available.
229 return makeGenPathFromLinePoly( linePoly );
232 // Only opaque general interface. No chance to get to the
233 // data. Empty path, then
234 CanvasUtils.printLog( "makeGeneralPath: Cannot access polygon data, given interface has class" + poly.getClass().getName() );
235 return new GeneralPath();
238 public static java.awt.image.BufferedImage getBufferedImage( com.sun.star.rendering.XBitmap bitmap )
240 if( bitmap instanceof CanvasBitmap )
242 CanvasUtils.printLog( "getBufferedImage: CanvasBitmap impl used." );
243 return ((CanvasBitmap)bitmap).getBufferedImage();
246 XIntegerBitmap integerBitmap = (XIntegerBitmap) UnoRuntime.queryInterface(XIntegerBitmap.class, bitmap);
248 if( integerBitmap != null )
250 // extract bitmap data. TODO.
251 return null;
254 // check other types. TODO.
255 return null;
258 public static byte [] int2byte( int [] input )
260 byte [] output = new byte[4*input.length];
262 int i, j;
263 for( i=0, j=0; i<input.length; ++i )
265 output[j] = (byte)(input[i] & 255);
266 output[j+1] = (byte)((input[i]/256) & 255);
267 output[j+2] = (byte)((input[i]/256/256) & 255);
268 output[j+3] = (byte)((input[i]/256/256/256) & 255);
269 j += 4;
272 return output;
275 public static int [] byte2int( byte [] input )
277 int [] output = new int[(input.length+3)/4];
279 int i, j;
280 for( i=0,j=0; j<output.length; ++j )
282 output[j] = input[i] + (input[i+1] + (input[i+2] + input[i+3]*256)*256)*256;
283 i += 4;
286 return output;
289 public static int javaRuleFromCompositeOp( byte compositeOp )
291 // TODO: Finish mapping of Canvas and Java compositing magics
292 int rule = java.awt.AlphaComposite.SRC_OVER;
293 switch( compositeOp )
295 case com.sun.star.rendering.CompositeOperation.CLEAR:
296 CanvasUtils.printLog( "javaRuleFromCompositeOp: clear selected" );
297 rule = java.awt.AlphaComposite.CLEAR;
298 break;
300 case com.sun.star.rendering.CompositeOperation.SOURCE:
301 CanvasUtils.printLog( "javaRuleFromCompositeOp: src selected" );
302 rule = java.awt.AlphaComposite.SRC;
303 break;
305 case com.sun.star.rendering.CompositeOperation.DESTINATION:
306 CanvasUtils.printLog( "javaRuleFromCompositeOp: dst selected" );
307 rule = java.awt.AlphaComposite.DST;
308 break;
310 case com.sun.star.rendering.CompositeOperation.OVER:
311 CanvasUtils.printLog( "javaRuleFromCompositeOp: over selected" );
312 rule = java.awt.AlphaComposite.SRC_OVER;
313 break;
315 case com.sun.star.rendering.CompositeOperation.UNDER:
316 CanvasUtils.printLog( "javaRuleFromCompositeOp: under selected" );
317 rule = java.awt.AlphaComposite.DST_OVER;
318 break;
320 case com.sun.star.rendering.CompositeOperation.INSIDE:
321 CanvasUtils.printLog( "javaRuleFromCompositeOp: inside selected" );
322 rule = java.awt.AlphaComposite.CLEAR;
323 break;
325 case com.sun.star.rendering.CompositeOperation.INSIDE_REVERSE:
326 CanvasUtils.printLog( "javaRuleFromCompositeOp: inReverse selected" );
327 rule = java.awt.AlphaComposite.CLEAR;
328 break;
330 case com.sun.star.rendering.CompositeOperation.OUTSIDE:
331 CanvasUtils.printLog( "javaRuleFromCompositeOp: outside selected" );
332 rule = java.awt.AlphaComposite.CLEAR;
333 break;
335 case com.sun.star.rendering.CompositeOperation.OUTSIDE_REVERSE:
336 CanvasUtils.printLog( "javaRuleFromCompositeOp: outReverse selected" );
337 rule = java.awt.AlphaComposite.CLEAR;
338 break;
340 case com.sun.star.rendering.CompositeOperation.XOR:
341 CanvasUtils.printLog( "javaRuleFromCompositeOp: xor selected" );
342 rule = java.awt.AlphaComposite.CLEAR;
343 break;
345 case com.sun.star.rendering.CompositeOperation.ADD:
346 CanvasUtils.printLog( "javaRuleFromCompositeOp: add selected" );
347 rule = java.awt.AlphaComposite.CLEAR;
348 break;
350 case com.sun.star.rendering.CompositeOperation.SATURATE:
351 CanvasUtils.printLog( "javaRuleFromCompositeOp: saturate selected" );
352 rule = java.awt.AlphaComposite.CLEAR;
353 break;
355 default:
356 CanvasUtils.printLog( "javaRuleFromCompositeOp: Unexpected compositing rule" );
357 break;
360 return rule;
363 public static java.awt.AlphaComposite makeAlphaComposite( byte compositeOp )
365 return java.awt.AlphaComposite.getInstance( javaRuleFromCompositeOp( compositeOp ) );
368 public static java.awt.AlphaComposite makeAlphaCompositeAlpha( byte compositeOp, double alpha )
370 return java.awt.AlphaComposite.getInstance( javaRuleFromCompositeOp( compositeOp ), (float)alpha );
373 // when given to setupGraphicsState, makes that method to also
374 // setup the Paint with the color specified in the render state.
375 public static final byte alsoSetupPaint=0;
377 // when given to setupGraphicsState, makes that method to _not_
378 // setup the Paint with the color specified in the render state.
379 public static final byte dontSetupPaint=1;
381 public static java.awt.geom.AffineTransform ViewConcatRenderTransform( ViewState viewState,
382 RenderState renderState )
384 // calculate overall affine transform
385 AffineTransform transform = makeTransform( viewState.AffineTransform );
386 transform.concatenate( makeTransform( renderState.AffineTransform ) );
388 printTransform( transform, "ViewConcatRenderTransform" );
390 return transform;
393 public static void setupGraphicsState( java.awt.Graphics2D graphics,
394 ViewState viewState,
395 RenderState renderState,
396 byte paintTouchMode )
398 // calculate overall affine transform
399 graphics.setTransform( ViewConcatRenderTransform(viewState, renderState ) );
401 // setup overall clip polyPolygon
402 if( viewState.Clip != null )
404 Area clipArea = new Area( makeGeneralPath( viewState.Clip ) );
406 if( renderState.Clip != null )
407 clipArea.intersect( new Area( makeGeneralPath( renderState.Clip ) ) );
409 graphics.setClip( clipArea );
411 else if( renderState.Clip != null )
413 Area clipArea = new Area( makeGeneralPath( renderState.Clip ) );
414 graphics.setClip( clipArea );
416 else
418 // TODO: HACK! Use true visible area here!
419 graphics.setClip( new java.awt.Rectangle(-1000000,-1000000,2000000,2000000) );
422 // setup current output color
423 // TODO: Complete color handling here
424 if( paintTouchMode == alsoSetupPaint )
426 switch( renderState.DeviceColor.length )
428 case 3:
429 CanvasUtils.printLog( "setupGraphicsState: Color(" +
430 renderState.DeviceColor[0] + "," +
431 renderState.DeviceColor[1] + "," +
432 renderState.DeviceColor[2] + ") set." );
433 graphics.setColor( new Color( (float)renderState.DeviceColor[0],
434 (float)renderState.DeviceColor[1],
435 (float)renderState.DeviceColor[2] ) );
436 break;
438 case 4:
439 CanvasUtils.printLog( "setupGraphicsState: Color(" +
440 renderState.DeviceColor[0] + "," +
441 renderState.DeviceColor[1] + "," +
442 renderState.DeviceColor[2] + "," +
443 renderState.DeviceColor[3] + ") set." );
444 graphics.setColor( new Color( (float)renderState.DeviceColor[0],
445 (float)renderState.DeviceColor[1],
446 (float)renderState.DeviceColor[2],
447 (float)renderState.DeviceColor[3] ) );
448 break;
450 default:
451 CanvasUtils.printLog( "setupGraphicsState: unexpected number of " +
452 renderState.DeviceColor.length + " color components!" );
453 break;
457 // setup current composite mode
458 graphics.setComposite( makeAlphaComposite( renderState.CompositeOperation ) );
461 public static void applyStrokeAttributes( java.awt.Graphics2D graphics,
462 StrokeAttributes attributes )
464 int cap = java.awt.BasicStroke.CAP_BUTT;
466 if( attributes.StartCapType != attributes.EndCapType )
467 CanvasUtils.printLog( "applyStrokeAttributes: different start and end caps are not yet supported!" );
469 if( attributes.LineArray.length != 0 )
470 CanvasUtils.printLog( "applyStrokeAttributes: multi-strokes are not yet supported!" );
472 if( attributes.StartCapType == PathCapType.BUTT )
473 cap = java.awt.BasicStroke.CAP_BUTT;
474 else if( attributes.StartCapType == PathCapType.ROUND )
475 cap = java.awt.BasicStroke.CAP_ROUND;
476 else if( attributes.StartCapType == PathCapType.SQUARE )
477 cap = java.awt.BasicStroke.CAP_SQUARE;
479 int join = java.awt.BasicStroke.JOIN_MITER;
481 if( attributes.JoinType == PathJoinType.MITER )
482 cap = java.awt.BasicStroke.JOIN_MITER;
483 else if( attributes.JoinType == PathJoinType.ROUND )
484 cap = java.awt.BasicStroke.JOIN_ROUND;
485 else if( attributes.JoinType == PathJoinType.BEVEL )
486 cap = java.awt.BasicStroke.JOIN_BEVEL;
487 else
488 CanvasUtils.printLog( "applyStrokeAttributes: current join type not yet supported!" );
490 float [] dashArray = null;
492 if( attributes.DashArray.length != 0 )
494 dashArray = new float [attributes.DashArray.length];
496 for( int i=0; i<attributes.DashArray.length; ++i )
497 dashArray[i] = (float)attributes.DashArray[i];
500 graphics.setStroke( new java.awt.BasicStroke( (float)attributes.StrokeWidth,
501 cap,
502 join,
503 (float)attributes.MiterLimit,
504 dashArray,
505 0) );
508 public static void setupGraphicsFont( java.awt.Graphics2D graphics,
509 ViewState viewState,
510 RenderState renderState,
511 com.sun.star.rendering.XCanvasFont xFont )
513 if( xFont instanceof CanvasFont )
515 CanvasUtils.printLog( "setupGraphicsFont: font impl used." );
516 graphics.setFont( ((CanvasFont)xFont).getFont() );
518 else
520 CanvasUtils.printLog( "setupGraphicsFont: creating Java font anew." );
521 CanvasFont canvasFont;
522 canvasFont = new CanvasFont( xFont.getFontRequest(), null );
523 graphics.setFont( canvasFont.getFont() );
527 static java.awt.geom.Rectangle2D.Double calcTransformedRectBounds( java.awt.geom.Rectangle2D.Double aRect,
528 AffineTransform aTransform )
530 // transform rect by given transformation
531 java.awt.geom.Point2D.Double aPointTopLeft = new java.awt.geom.Point2D.Double(aRect.x, aRect.y);
532 aTransform.transform(aPointTopLeft, aPointTopLeft);
534 java.awt.geom.Point2D.Double aPointTopRight = new java.awt.geom.Point2D.Double(aRect.x + aRect.width,
535 aRect.y);
536 aTransform.transform(aPointTopRight, aPointTopRight);
538 java.awt.geom.Point2D.Double aPointBottomLeft = new java.awt.geom.Point2D.Double(aRect.x,
539 aRect.y + aRect.height);
540 aTransform.transform(aPointBottomLeft, aPointBottomLeft);
542 java.awt.geom.Point2D.Double aPointBottomRight = new java.awt.geom.Point2D.Double(aRect.x + aRect.width,
543 aRect.y + aRect.height);
544 aTransform.transform(aPointBottomRight, aPointBottomRight);
546 // calc bounding rect of those four points
547 java.awt.geom.Point2D.Double aResTopLeft = new java.awt.geom.Point2D.Double( Math.min(aPointTopLeft.x,
548 Math.min(aPointTopRight.x,
549 Math.min(aPointBottomLeft.x,aPointBottomRight.x))),
550 Math.min(aPointTopLeft.y,
551 Math.min(aPointTopRight.y,
552 Math.min(aPointBottomLeft.y,aPointBottomRight.y))) );
554 java.awt.geom.Point2D.Double aResBottomRight = new java.awt.geom.Point2D.Double( Math.max(aPointTopLeft.x,
555 Math.max(aPointTopRight.x,
556 Math.max(aPointBottomLeft.x,aPointBottomRight.x))),
557 Math.max(aPointTopLeft.y,
558 Math.max(aPointTopRight.y,
559 Math.max(aPointBottomLeft.y,aPointBottomRight.y))) );
560 return new java.awt.geom.Rectangle2D.Double( aResTopLeft.x, aResTopLeft.y,
561 aResBottomRight.x - aResTopLeft.x,
562 aResBottomRight.y - aResTopLeft.y );
565 // Create a corrected view transformation out of the give one,
566 // which ensures that the rectangle given by (0,0) and
567 // attributes.untransformedSize is mapped with its left,top corner
568 // to (0,0) again. This is required to properly render sprite
569 // animations to buffer bitmaps.
570 public static ViewState createAnimationViewState( ViewState inputViewState,
571 AnimationAttributes attributes )
573 // TODO: Properly respect clip here. Might have to be transformed, too.
575 AffineTransform aViewTransform = makeTransform( inputViewState.AffineTransform );
577 // transform Rect(0,0,attributes.untransformedSize) by
578 // viewTransform
579 java.awt.geom.Rectangle2D.Double aTransformedRect =
580 calcTransformedRectBounds( new java.awt.geom.Rectangle2D.Double(0.0, 0.0,
581 attributes.UntransformedSize.Width,
582 attributes.UntransformedSize.Height),
583 aViewTransform );
585 printTransform( aViewTransform, "createAnimationViewState" );
587 CanvasUtils.printLog( "createAnimationViewState: transformed origin is: (" + aTransformedRect.x + ", " + aTransformedRect.y + ")" );
589 // now move resulting left,top point of bounds to (0,0)
590 AffineTransform animationViewTransform = new AffineTransform();
591 animationViewTransform.translate( -aTransformedRect.x, -aTransformedRect.y );
592 animationViewTransform.concatenate( aViewTransform );
594 printTransform( animationViewTransform, "createAnimationViewState" );
596 return new ViewState( makeAffineMatrix2D( animationViewTransform ), inputViewState.Clip );
599 public static void postRenderImageTreatment( Image buffer )
601 // TODO: This is specific to Sun's JREs 1.4 and upwards. Make this more portable
602 buffer.flush(); // as long as we force images to VRAM,
603 // we need to flush them afterwards, to
604 // avoid eating up all VRAM.
607 public static void printTransform( AffineTransform transform,
608 String stringPrefix )
610 CanvasUtils.printLog( stringPrefix + ": Transform is" );
611 double [] matrix = new double[6];
612 transform.getMatrix(matrix);
613 int i;
614 for( i=0; i<6; ++i )
615 System.err.print( matrix[i] + ", " );
616 CanvasUtils.printLog( "" );
619 public static void preCondition( boolean bCondition,
620 String methodName )
622 if( !bCondition )
623 printLog("Precondition violated: " + methodName);
626 public static void printLog( String s )
628 System.err.println( s );