gt:       Stroke stroke = new BasicStroke(3.0f);
context: /*
   * Copyright 2000-2008 Sun Microsystems, Inc.  All Rights Reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.
   *
   * This code is distributed in the hope that it will be useful, but WITHOUT
   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   * version 2 for more details (a copy is included in the LICENSE file that
   * accompanied this code).
   *
   * You should have received a copy of the GNU General Public License version
   * 2 along with this work; if not, write to the Free Software Foundation,
   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   *
   * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   * CA 95054 USA or visit www.sun.com if you need additional information or
   * have any questions.
   *
   */
  
  package sun.jvm.hotspot.ui;
  
  import java.math.*;
  import java.awt.*;
  import java.awt.font.*;
  import java.awt.geom.*;
  import java.awt.event.*;
  import java.io.*;
  import javax.swing.*;
  import javax.swing.event.*;
  import java.util.*;
  
  import sun.jvm.hotspot.debugger.*;
  import sun.jvm.hotspot.debugger.dummy.*;
  import sun.jvm.hotspot.utilities.*;
  
  /** A subclass of JPanel which displays a hex dump of memory along
      with annotations describing the significance of various
      pieces. This can be used to implement either a stack or heap
      inspector. */
  
  public class AnnotatedMemoryPanel extends JPanel {
    private boolean is64Bit;
    private Debugger debugger;
    private long    addressSize;
    private HighPrecisionJScrollBar scrollBar;
    private Font font;
    private int bytesPerLine;
    private int paintCount;
    private String unmappedAddrString;
    // Type of this is an IntervalTree indexed by Interval<Address> and
    // with user data of type Annotation
    private IntervalTree annotations =
      new IntervalTree(new Comparator() {
          public int compare(Object o1, Object o2) {
            Address a1 = (Address) o1;
            Address a2 = (Address) o2;
  
            if ((a1 == null) && (a2 == null)) {
              return 0;
            } else if (a1 == null) {
              return -1;
            } else if (a2 == null) {
              return 1;
            }
  
            if (a1.equals(a2)) {
              return 0;
            } else if (a1.lessThan(a2)) {
              return -1;
            }
            return 1;
          }
        });
    // Keep track of the last start address at which we painted, so we
    // can scroll annotations
    private Address lastStartAddr;
    // This contains the list of currently-visible IntervalNodes, in
    // sorted order by their low endpoint, in the form of a
    // List<Annotation>. These annotations have already been laid out.
    private java.util.List visibleAnnotations;
    // Darker colors than defaults for better readability
    private static Color[] colors = {
      new Color(0.0f, 0.0f, 0.6f), // blue
      new Color(0.6f, 0.0f, 0.6f), // magenta
      new Color(0.0f, 0.8f, 0.0f), // green
      new Color(0.8f, 0.3f, 0.0f), // orange
      new Color(0.0f, 0.6f, 0.8f), // cyan
      new Color(0.2f, 0.2f, 0.2f), // dark gray
    };
  
    /** Default is 32-bit mode */
    public AnnotatedMemoryPanel(Debugger debugger) {
      this(debugger, false);
    }
  
    public AnnotatedMemoryPanel(Debugger debugger, boolean is64Bit, Address addrValue, Address addrLow, Address addrHigh) {
      super();
      init(debugger, is64Bit, addressToBigInt(addrValue), addressToBigInt(addrLow), addressToBigInt(addrHigh));
    }
  
    public AnnotatedMemoryPanel(Debugger debugger, boolean is64Bit ) {
      super();
      init(debugger, is64Bit, defaultMemoryLocation(is64Bit), defaultMemoryLow(is64Bit), defaultMemoryHigh(is64Bit));
    }
  
    static class AnnoX {
      int     lineX;
      Address highBound;
  
      public AnnoX(int lineX, Address highBound) {
        this.lineX = lineX;
        this.highBound = highBound;
      }
    }
  
    public synchronized void paintComponent(Graphics g) {
      //    System.err.println("AnnotatedMemoryPanel.paintComponent() " + ++paintCount);
      super.paintComponent(g);
  
      // Clone the Graphics so we don't screw up its state for Swing
      // drawing (as this code otherwise does)
      g = g.create();
  
      g.setFont(font);
      g.setColor(Color.black);
      Rectangle rect = new Rectangle();
      getBounds(rect);
      String firstAddressString = null;
      int lineHeight;
      int addrWidth;
      {
        Rectangle2D bounds = GraphicsUtilities.getStringBounds(unmappedAddrString, g);
        lineHeight = (int) bounds.getHeight();
        addrWidth  = (int) bounds.getWidth();
      }
      int addrX = (int) (0.25 * addrWidth);
      int dataX = (int) (addrX + (1.5 * addrWidth));
      int lineStartX = dataX + addrWidth + 5;
      int annoStartX = (int) (lineStartX + (0.75 * addrWidth));
  
      int numLines = rect.height / lineHeight;
  
      BigInteger startVal  = scrollBar.getValueHP();
      BigInteger perLine = new BigInteger(Integer.toString((int) addressSize));
      // lineCount and maxLines are both 1 less than expected
      BigInteger lineCount = new BigInteger(Integer.toString((int) (numLines - 1)));
      BigInteger maxLines = scrollBar.getMaximumHP().subtract(scrollBar.getMinimumHP()).divide(perLine);
      if (lineCount.compareTo(maxLines) > 0) {
        lineCount = maxLines;
      }
      BigInteger offsetVal = lineCount.multiply(perLine);
      BigInteger endVal    = startVal.add(offsetVal);
      if (endVal.compareTo(scrollBar.getMaximumHP()) > 0) {
        startVal = scrollBar.getMaximumHP().subtract(offsetVal);
        endVal   = scrollBar.getMaximumHP();
        // Sure seems like this call will cause us to immediately redraw...
        scrollBar.setValueHP(startVal);
      }
      scrollBar.setVisibleAmountHP(offsetVal.add(perLine));
      scrollBar.setBlockIncrementHP(offsetVal);
  
      Address startAddr = bigIntToAddress(startVal);
      Address endAddr   = bigIntToAddress(endVal);
  
      // Scroll last-known annotations
      int scrollOffset = 0;
      if (lastStartAddr != null) {
        scrollOffset = (int) lastStartAddr.minus(startAddr);
      } else {
        if (startAddr != null) {
          scrollOffset = (int) (-1 * startAddr.minus(lastStartAddr));
        }
      }
      scrollOffset = scrollOffset * lineHeight / (int) addressSize;
      scrollAnnotations(scrollOffset);
      lastStartAddr = startAddr;
  
      int curY = lineHeight;
      Address curAddr = startAddr;
      for (int i = 0; i < numLines; i++) {
        String s = bigIntToHexString(startVal);
        g.drawString(s, addrX, curY);
        try {
          s = addressToString(startAddr.getAddressAt(i * addressSize));
        }
        catch (UnmappedAddressException e) {
          s = unmappedAddrString;
        }
        g.drawString(s, dataX, curY);
        curY += lineHeight;
        startVal = startVal.add(perLine);
      }
  
      // Query for visible annotations (little slop to ensure we get the
      // top and bottom)
      // FIXME: it would be nice to have a more static layout; that is,
      // if something scrolls off the bottom of the screen, other
      // annotations still visible shouldn't change position
      java.util.List va =
        annotations.findAllNodesIntersecting(new Interval(startAddr.addOffsetTo(-addressSize),
                                                          endAddr.addOffsetTo(2 * addressSize)));
  
      // Render them
      int curLineX = lineStartX;
      int curTextX = annoStartX;
      int curColorIdx = 0;
      if (g instanceof Graphics2D) {
  