Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8094962

NullPointerException when chaining DropShadow Effect to Reflection Effect

    Details

      Description

      I've written an AnimPlasma application that animates a colorful plasma image on JavaFX's canvas. The source code appears below (and an explanation of the problem follows):

      import javafx.animation.PauseTransition;

      import javafx.application.Application;

      import javafx.event.ActionEvent;
      import javafx.event.EventHandler;

      import javafx.geometry.VPos;

      import javafx.scene.Group;
      import javafx.scene.Scene;

      import javafx.scene.canvas.Canvas;
      import javafx.scene.canvas.GraphicsContext;

      import javafx.scene.effect.DropShadow;
      import javafx.scene.effect.Reflection;

      import javafx.scene.paint.Color;
      import javafx.scene.paint.CycleMethod;
      import javafx.scene.paint.LinearGradient;
      import javafx.scene.paint.Stop;

      import javafx.scene.text.Font;
      import javafx.scene.text.Text;

      import javafx.stage.Stage;

      import javafx.util.Duration;

      public class AnimPlasma extends Application
      {
         private int[] palette;
         private byte[][] plasma;
         private int[] colors;

         private GraphicsContext gc;

         @Override
         public void start(final Stage primaryStage)
         {
            primaryStage.setTitle("Animated Plasma");
            primaryStage.setWidth(600);
            primaryStage.setHeight(600);

            final Group group = new Group();

            Text text = new Text();
            text.setText("Animated Plasma");
            text.setFill(Color.YELLOW);
            text.setFont(new Font("Arial BOLD", 24.0));
            text.setEffect(new DropShadow());
            text.xProperty().bind(primaryStage.widthProperty()
                            .subtract(text.layoutBoundsProperty().getValue().getWidth())
                            .divide(2));
            text.setY(30.0);
            text.setTextOrigin(VPos.TOP);
            group.getChildren().add(text);

            Canvas canvas = new Canvas(400, 400);
            canvas.setTranslateX(100);
            canvas.setTranslateY(100);
            gc = canvas.getGraphicsContext2D();
            group.getChildren().add(canvas);
      /*
      DropShadow ds = new DropShadow();
      ds.setInput(new Reflection());
      group.setEffect(ds);
      */
            Reflection r = new Reflection();
            r.setInput(new DropShadow()); // This line leads to NullPointerException.
            group.setEffect(r);

            LinearGradient lg = new LinearGradient(0.0, 0.0, 0.0, 1.0, true,
                                                   CycleMethod.NO_CYCLE,
                                                   new Stop(0, Color.BLUE),
                                                   new Stop(1.0, Color.BLUEVIOLET));
            Scene scene = new Scene(group, lg);
            primaryStage.setScene(scene);

            primaryStage.setResizable(false);
            primaryStage.show();

            setup(canvas);

            final PauseTransition pt = new PauseTransition(Duration.millis(30));
            pt.setCycleCount(1);
            pt.setOnFinished(new EventHandler<ActionEvent>()
                             {
                                @Override
                                public void handle(ActionEvent ae)
                                {
                                   update(canvas);
                                   pt.play();
                                }
                             });
            pt.play();
         }

         void setup(Canvas canvas)
         {
            palette = new int[256];
            for (int i = 0; i < palette.length; i++)
            {
                Color color = Color.hsb(i/255.0*360, 1.0, 1.0);
                int red = (int) (color.getRed()*255);
                int grn = (int) (color.getGreen()*255);
                int blu = (int) (color.getBlue()*255);
                palette[i] = (red << 16)|(grn << 8)|blu;
            }

            plasma = new byte[(int) canvas.getHeight()][];
            for (int i = 0; i < plasma.length; i++)
                plasma[i] = new byte[(int) canvas.getWidth()];

            colors = new int[(int) (canvas.getWidth()*canvas.getHeight())];
         }

         void update(Canvas canvas)
         {
            int width = (int) canvas.getWidth();
            int height = (int) canvas.getHeight();
            for (int row = 0; row < height; row++)
                for (int col = 0; col < width; col++)
                    plasma[row][col] =
                           (byte) ((128.0+128.0*Math.cos(row/8.0)+
                                  128.0+128.0*Math.cos(col/8.0))/2);

            int shift = (int) System.currentTimeMillis()/5;
            int base = 0;
            for (int row = 0; row < height; row++)
            {
                for (int col = 0; col < width; col++)
                {
                    colors[base+col] = palette[(plasma[row][col]+shift)&255];
                    int r = (colors[base+col]>>16)&255;
                    int g = (colors[base+col]>>8)&255;
                    int b = colors[base+col]&255;
                    gc.setFill(Color.rgb(r, g, b));
                    gc.fillRect(row, col, 1, 1);
                }
               
                base += width;
            }
         }

         public static void main(String[] args)
         {
            launch(args);
         }
      }

      In the following code sequence, r.setInput(new DropShadow()); leads to repeated runtime error messages:

      Reflection r = new Reflection();
      r.setInput(new DropShadow()); // This line leads to NullPointerException.
      group.setEffect(r);

      The error message appears below:

      java.lang.NullPointerException
      at com.sun.scenario.effect.FilterEffect.getBounds(FilterEffect.java:67)
      at com.sun.scenario.effect.BoxShadow.getBounds(BoxShadow.java:367)
      at com.sun.scenario.effect.Offset.getBounds(Offset.java:145)
      at com.sun.scenario.effect.FilterEffect.getBounds(FilterEffect.java:72)
      at com.sun.scenario.effect.DelegateEffect.getBounds(DelegateEffect.java:60)
      at com.sun.scenario.effect.Effect.getBounds(Effect.java:325)
      at com.sun.scenario.effect.Reflection.getDirtyRegions(Reflection.java:271)
      at com.sun.javafx.sg.prism.NGNode.applyEffect(NGNode.java:2471)
      at com.sun.javafx.sg.prism.NGNode.accumulateGroupDirtyRegion(NGNode.java:1209)
      at com.sun.javafx.sg.prism.NGNode.accumulateDirtyRegions(NGNode.java:1033)
      at com.sun.javafx.tk.quantum.ViewPainter.paintImpl(ViewPainter.java:236)
      at com.sun.javafx.tk.quantum.PresentingPainter.run(PresentingPainter.java:89)
      at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
      at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
      at com.sun.javafx.tk.RenderJob.run(RenderJob.java:58)
      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
      at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:129)
      at java.lang.Thread.run(Thread.java:744)

      When I comment out r.setInput(new DropShadow());, everything works fine except that there is no drop shadow. Interestingly, if I replace the three-line code sequence with the following code sequence:

      DropShadow ds = new DropShadow();
      ds.setInput(new Reflection());
      group.setEffect(ds);

      there is no problem.

      Jeff

        Attachments

          Activity

            People

            • Assignee:
              msladecek Martin Sládeček
              Reporter:
              duke J. Duke (Inactive)
            • Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:
                Imported: