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

fillRect appears to execute asynchronously in Java 2 applets

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Duplicate
    • Icon: P4 P4
    • None
    • 1.2.2
    • client-libs
    • 2d
    • x86
    • windows_98



      Name: sl110371 Date: 06/28/2000


      java version "1.2.2"
      Classic VM (build JDK-1.2.2-001, native threads, symcjit)
      --- AND ALSO ---
      java version "1.3.0rc2"
      Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0rc2-Y)
      Java HotSpot(TM) Client VM (build 1.3.0rc2-Y, mixed mode)


      I am a highly experienced software engineer (30 years) and I have developed
      portions of shipping products in Java for the past three years. The recent
      availability of Netscape 6 Preview Release 1 motivated me to re-test my Java
      applets under Java 2. I encountered a severe problem, so I downloaded the "pure
      Sun" Java 2 SDK v1.3 (RC 2) and also Java 2 SDK v1.2.2 (production). I was able
      to reproduce the problem consistently under "appletviewer" in BOTH 1.2.2 and 1.3
      (as well as Netscape 6 PR1, which ships with the pre-release 1.3 JRE).

      This problem does NOT occur under JDK v1.1 (I have been using 1.1.5 for several
      years). It also does NOT occur under Netscape Communicator (through version
      4.7) or Microsoft Internet Explorer (through version 5.01).

      The problem is that whenever I redraw a character cell in the applet's "update"
      method, I get "random" results -- most of the time, it draws okay, but about 10%
      of the time I get a "blank cell". The typical code sequence is:

      g.setColor(Color.white);
      g.fillRect(x, y, cell_width, cell_height);
      g.setColor(Color.black);
      g.drawChars(array, 0, 1, x, y + cell_base);

      What appears to be happening is that the "fillRect" method is being executed
      asynchronously, under a separate thread -- which may or may not finish before
      the "drawChars" is executed! The result is that about 10% of the time, on
      random character cells, the "fillRect" is performed AFTER the "drawChars" and
      "wipes out" the character that was just drawn. (This also happens if
      "clearRect" is used instead of "fillRect" and/or if "drawString" is used instead
      of "drawChars".)

      I was able to confirm this theory by commenting out the call to the "fillRect"
      method. In that case, it works correctly 100% of the time under Java 2.
      Unfortunately, that is not a workable solution because susequent updates to the
      same character cell are then written on top of the earlier character, creating a
      big mess!

      It is also possible to "work around" the problem by eliminating the use of the
      "update" method and doing all of the text drawing in the applet's "paint"
      method, without using any calls to "fillRect" (relying instead on the fact that
      the "paint" method always clears the entire background). That trick works okay
      for the simple test case I am including here, but it will not work for the
      shipping applets that I produced over the last few years -- because many of them
      need to fill the background of the cell with colors that are DIFFERENT from the
      applet's normal background color. (And that trick has negative performance
      implications as well.)

      The test case is a simple applet that draws all 256 pages of a Unicode font, one
      page at a time. The keys to control this applet are not shown "on screen".
      They are as follows:

      right arrow = next Unicode page
      left arrow = previous Unicode page
      up arrow = larger font
      down arrow = smaller font
      scroll lock = toggles between "Courier" and "Monospaced" fonts

      Following are the HTML file and the Java source code necessary to reproduce this
      problem:

      <HTML>
      <HEAD>
      <TITLE>Font Test</TITLE>
      </HEAD>
      <BODY>
      <CENTER>
      <H3>Font Test</H3>
      </CENTER>

      <CENTER>
      <APPLET CODE="fonts.class" WIDTH=728 HEIGHT=466>
      </APPLET>
      </CENTER>

      </BODY>
      </HTML>

      import java.applet.Applet;
      import java.awt.Color;
      import java.awt.Font;
      import java.awt.Graphics;
      import java.awt.event.*;

      public class fonts extends Applet implements FocusListener, KeyListener
        {
        Font screen_font;
        int width, height;
        int cell_width, cell_height, cell_base;
        int left_margin, top_margin;
        int x, y;
        int font_test_page, font_test_size = 16; boolean font_test_type;
        boolean have_focus, want_focus;
        boolean focus_when_stopped = true;

        public void init()
          {
      //
      javax.swing.RepaintManager.currentManager(this).setDoubleBufferingEnabled(false)
      ;
          setBackground(Color.white);
          width = getSize().width;
          height = getSize().height;
          cell_width = width/32;
          left_margin = (width - 32*cell_width)/2;
          cell_height = height/18;
          top_margin = (height - 18*cell_height)/2;
          this.addFocusListener(this);
          this.addKeyListener(this);
          }

        public void start()
          {
      // System.out.println("Applet started");
          want_focus = focus_when_stopped;
          }

        public void stop()
          {
      // System.out.println("Applet stopped");
          focus_when_stopped = have_focus;
          }

        public void paint(Graphics g)
          {
          if (screen_font == null)
            {
            int sf_cell_width = width/48;
            int fs = 13;
            screen_font = new Font("Courier", Font.PLAIN, 13);
            int cw = g.getFontMetrics(screen_font).charWidth('0');
            if (cw < sf_cell_width)
              {
              for (fs = 14; fs <= 96; fs++)
                {
                screen_font = new Font("Courier", Font.PLAIN, fs);
                cw = g.getFontMetrics(screen_font).charWidth('0');
                if (cw == sf_cell_width)
                  break;
                else if (cw > sf_cell_width)
                  {
                  screen_font = new Font("Courier", Font.PLAIN, fs - 1);
                  cw = g.getFontMetrics(screen_font).charWidth('0');
                  break;
                  }
                }
              }
            else if (cw > sf_cell_width)
              {
              for (fs = 12; fs >= 1; fs--)
                {
                screen_font = new Font("Courier", Font.PLAIN, fs);
                cw = g.getFontMetrics(screen_font).charWidth('0');
                if (cw <= sf_cell_width)
                  break;
                }
              }
            int ds = g.getFontMetrics(screen_font).getDescent();
            cell_base = cell_height - 1 - ds;
      // System.out.println("width: " + width + "; height: " + height
      // + "; sf_cell_width: " + sf_cell_width + "; cell_height: " +
      cell_height
      // + "; font size: " + fs + "; actual cell width: " + cw
      // + "; descent: " + ds);
      // System.out.println("screen_font: " + screen_font);
            }

          if (want_focus)
            {
            want_focus = false;
            requestFocus();
            }

          font_test(g);
          }

        public void update(Graphics g)
          {
          font_test(g);
          }

        void font_test(Graphics g)
          {
      //
      javax.swing.RepaintManager.currentManager(this).setDoubleBufferingEnabled(false)
      ;
          g.setFont(screen_font);
          y = top_margin;
          g.setColor(Color.white);
          g.fillRect(left_margin, y, 32*cell_width, 2*cell_height);
          g.setColor(Color.black);
          g.drawString(" Unicode Page " + font_test_page
              + (font_test_type ? " [Monospaced" : " [Courier")
              + ", size " + font_test_size + "]",
              left_margin, y + cell_base + 8);
          y += 2*cell_height;
      // Font test_font = new Font("ZapfDingbats", Font.PLAIN, font_test_size);
          Font test_font = new Font(font_test_type ? "Monospaced" : "Courier",
              Font.PLAIN, font_test_size);
          if (test_font == null)
            {
            System.out.println("Test font is null!");
            System.exit(0);
            }
          else
            {
      // int fw = g.getFontMetrics(test_font).charWidth('0');
      // System.out.println("test_font: " + test_font + "; cell width: " + fw);
            g.setFont(test_font);
            char[] array = new char[1];
            for (int i = 0; i < 16; i++)
              {
              x = left_margin;
              for (int j = 0; j < 16; j++)
                {
                g.setColor(Color.white);
                g.fillRect(x, y, 2*cell_width, cell_height);
                g.setColor(Color.black);
                array[0] = (char)(256*font_test_page + 16*j + i);
                g.drawChars(array, 0, 1, x + cell_width/2, y + cell_base + 2);
                x += 2*cell_width;
                }
              y += cell_height;
              }
            }
          }

        public void focusGained(FocusEvent e)
          {
      // System.out.println("Focus gained: " + e);
          have_focus = true;
          }

        public void focusLost(FocusEvent e)
          {
      // System.out.println("Focus lost: " + e);
          have_focus = false;
          }

        public void keyPressed(KeyEvent e)
          {
          int key = e.getKeyCode();

          switch (key)
            {
            case KeyEvent.VK_SHIFT:
            case KeyEvent.VK_CONTROL:
            case KeyEvent.VK_ALT:
              return;
            }

          int modifiers = e.getModifiers();

          switch (key)
            {
            case KeyEvent.VK_UP:
              if (++font_test_size == 49)
                font_test_size = 1;
              repaint();
              break;
            case KeyEvent.VK_DOWN:
              if (--font_test_size == 0)
                font_test_size = 48;
              repaint();
              break;
            case KeyEvent.VK_LEFT:
              if (--font_test_page == -1)
                font_test_page = 255;
              repaint();
              break;
            case KeyEvent.VK_RIGHT:
              if (++font_test_page == 256)
                font_test_page = 0;
              repaint();
              break;
            case KeyEvent.VK_SCROLL_LOCK:
              font_test_type ^= true;
              repaint();
              break;
            default:
              break;
            }
          }

        public void keyTyped(KeyEvent e)
          {
          }

        public void keyReleased(KeyEvent e)
          {
          }
        }
      (Review ID: 103420)
      ======================================================================

            Unassigned Unassigned
            duke J. Duke
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: