Hi there,
I've discovered an issue with the Canvas implementation
when it comes to clipping
Unfortunately the only practical way to reset the clip of a
HTML5 2D canvas context is to save/restore its state - however
this does not only affect its clipping state but all other
properties.
The current implementation of GCOperationWriter doesn't take
this into account and therefore causes incorrect behaviour
when clipping is used.
E.g. the following code should fill two blue rectangles -
instead a yellow and a blue one is filled:
gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_YELLOW));
gc.setClipping(0, 0, 300, 300);
gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_BLUE));
gc.fillRectangle(10, 10, 20, 20);
gc.setClipping(1, 1, 300, 300);
gc.fillRectangle(30, 30, 20, 20);
The issue can be resolved by remembering the state that has
been changed since the last GC.save() call - so that it can
set up again properly after GC.restore() has to be called to
get rid of the clip.
Please find below the suggested fix (ECA is signed).
Best regards, Clemens
---
rap_untouched/org.eclipse.rap/bundles/org.eclipse.rap.rwt/widgetkits/org/eclipse/swt/internal/widgets/canvaskit/GCOperationWriter.java
2017-02-16 02:18:46.739449633 +0100
+++
org.eclipse.rap/bundles/org.eclipse.rap.rwt/widgetkits/org/eclipse/swt/internal/widgets/canvaskit/GCOperationWriter.java
2017-02-16 01:50:44.164810648 +0100
@@ -50,9 +50,11 @@
private int lineWidth;
private RGB foreground;
private RGB background;
+ private JsonArray[] currProperties;
GCOperationWriter( Control control ) {
this.control = control;
+ currProperties = new JsonArray[8];
}
void initialize() {
@@ -367,14 +369,25 @@
String msg = "Unsupported operation id: " +
operation.id;
throw new RuntimeException( msg );
}
- operations.add( new JsonArray().add( name ).add( value ) );
+
+ JsonArray jsonPropArray = new JsonArray().add( name ).add(
value );
+ currProperties[
operation.id] = jsonPropArray;
+ operations.add( jsonPropArray );
}
private void setClipping( SetClipping operation ) {
if( operation.isReset() ) {
addClientOperation( "restore" );
+
+ for(int i=0; i < currProperties.length; i++) {
+ if(currProperties[i] != null) {
+ operations.add( currProperties[i] );
+ }
+ }
} else {
addClientOperation( "save" );
+ currProperties = new JsonArray[currProperties.length];
+
if( operation.isRectangular() ) {
Rectangle rect = operation.rectangle;
addClientOperation( "beginPath" );
@@ -387,7 +400,8 @@
}
private void setTransform( SetTransform operation ) {
- addClientOperation( "setTransform", operation.elements );
+ currProperties[7] = addClientOperation( "setTransform",
+ operation.elements );
}
private void renderPath( byte[] types, float[] points ) {
@@ -426,20 +440,22 @@
}
}
- private void addClientOperation( String name, float... args )
{
+ private JsonArray addClientOperation( String name, float...
args ) {
JsonArray operation = new JsonArray().add( name );
for( int i = 0; i < args.length; i++ ) {
operation.add( args[ i ] );
}
operations.add( operation );
+ return operation;
}
- private void addClientOperation( String name, String argText,
float... args ) {
+ private JsonArray addClientOperation( String name, String
argText, float... args ) {
JsonArray operation = new JsonArray().add( name ).add(
argText );
for( int i = 0; i < args.length; i++ ) {
operation.add( args[ i ] );
}
operations.add( operation );
+ return operation;
}
private float getOffset( boolean fill ) {