This page is a work in progress as I track down the problem. Please add comments if you have anything that might be helpful.
The problem appears to be with Java applets that use double buffering (performing all drawing operations to an off-screen image and then displaying that image).
Certain applets (it seems to be large sized ones) are displaying twice, one on top of the other, and the top copy is the correct size but it showing a corrupted image formed from random parts of images that were already in the browser's memory.
Browsers affected:
Firefox
Safari
Chrome
Opera
Safari
Chrome
Opera
The same applet runs fine in all browsers on Windows XP and Debian Squeeze.
OSX versions known to be affected:
Mac OS 10.7.5
Mac OS 10.8.2
Mac OS 10.8.2
Java versions exhibiting graphics corruption:
Java 7 update 10
Java 7 update 11
Java 7 update 13
Java 7 update 11
Java 7 update 13
Update 28/12/2012: The following code reproduces the corruption:
package com.chrisnewland.applet;
import java.applet.*;
import java.awt.*;
import java.awt.image.BufferedImage;
public class SimpleApplet extends Applet implements Runnable
{
private int width;
private int height;
private BufferedImage bufferImage;
private Graphics2D bufferGraphics;
private boolean running = false;
private boolean nextImageReady = false;
@Override
public void init()
{
setSize(800, 2000);
width = this.getSize().width;
height = this.getSize().height;
GraphicsEnvironment env = GraphicsEnvironment
.getLocalGraphicsEnvironment();
GraphicsDevice device = env.getDefaultScreenDevice();
GraphicsConfiguration config = device.getDefaultConfiguration();
bufferImage = config.createCompatibleImage(width, height);
bufferGraphics = (Graphics2D) bufferImage.getGraphics();
}
@Override
public void start()
{
running = true;
new Thread(this).start();
}
@Override
public void stop()
{
running = false;
}
@Override
public void update(Graphics g)
{
if (!nextImageReady)
{
return;
}
g.drawImage(bufferImage, 0, 0, null);
nextImageReady = false;
try
{
Thread.sleep(20);
}
catch (InterruptedException ie)
{
}
}
@Override
public void paint(Graphics g)
{
update(g);
}
@Override
public void run()
{
int x = 0;
try
{
while (running)
{
if (!nextImageReady)
{
bufferGraphics.setColor(Color.white);
bufferGraphics.fillRect(0, 0, width, height);
bufferGraphics.setColor(Color.black);
bufferGraphics.fillRect(x, height / 4, 200, 200);
x += 4;
if (x > width)
{
x = 0;
}
repaint();
nextImageReady = true;
}
else
{
Thread.sleep(1);
}
}
}
catch (Exception ie)
{
ie.printStackTrace();
}
}
}
import java.applet.*;
import java.awt.*;
import java.awt.image.BufferedImage;
public class SimpleApplet extends Applet implements Runnable
{
private int width;
private int height;
private BufferedImage bufferImage;
private Graphics2D bufferGraphics;
private boolean running = false;
private boolean nextImageReady = false;
@Override
public void init()
{
setSize(800, 2000);
width = this.getSize().width;
height = this.getSize().height;
GraphicsEnvironment env = GraphicsEnvironment
.getLocalGraphicsEnvironment();
GraphicsDevice device = env.getDefaultScreenDevice();
GraphicsConfiguration config = device.getDefaultConfiguration();
bufferImage = config.createCompatibleImage(width, height);
bufferGraphics = (Graphics2D) bufferImage.getGraphics();
}
@Override
public void start()
{
running = true;
new Thread(this).start();
}
@Override
public void stop()
{
running = false;
}
@Override
public void update(Graphics g)
{
if (!nextImageReady)
{
return;
}
g.drawImage(bufferImage, 0, 0, null);
nextImageReady = false;
try
{
Thread.sleep(20);
}
catch (InterruptedException ie)
{
}
}
@Override
public void paint(Graphics g)
{
update(g);
}
@Override
public void run()
{
int x = 0;
try
{
while (running)
{
if (!nextImageReady)
{
bufferGraphics.setColor(Color.white);
bufferGraphics.fillRect(0, 0, width, height);
bufferGraphics.setColor(Color.black);
bufferGraphics.fillRect(x, height / 4, 200, 200);
x += 4;
if (x > width)
{
x = 0;
}
repaint();
nextImageReady = true;
}
else
{
Thread.sleep(1);
}
}
}
catch (Exception ie)
{
ie.printStackTrace();
}
}
}
I've been experimenting with this issue. It seems that the error occurs, as you say, with large applets, but only where the applet tag's width/height exceeds the visible area of the browser window. If the applet tag's width/height are sized so that it fits entirely in the browser window, the problem doesn't occur. It doesn't seem to matter what you set the applet's size to inside the init() method.