| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
package javax.swing.text.html;  | 
 | 
 | 
 | 
import java.awt.Color;  | 
 | 
import java.awt.Component;  | 
 | 
import java.awt.Graphics;  | 
 | 
import java.awt.Graphics2D;  | 
 | 
import java.awt.Insets;  | 
 | 
import java.awt.Polygon;  | 
 | 
import java.awt.Rectangle;  | 
 | 
import java.awt.Shape;  | 
 | 
import java.util.HashMap;  | 
 | 
import java.util.Map;  | 
 | 
import javax.swing.border.AbstractBorder;  | 
 | 
import javax.swing.text.AttributeSet;  | 
 | 
import javax.swing.text.View;  | 
 | 
import javax.swing.text.html.CSS.Attribute;  | 
 | 
import javax.swing.text.html.CSS.BorderStyle;  | 
 | 
import javax.swing.text.html.CSS.BorderWidthValue;  | 
 | 
import javax.swing.text.html.CSS.ColorValue;  | 
 | 
import javax.swing.text.html.CSS.CssValue;  | 
 | 
import javax.swing.text.html.CSS.LengthValue;  | 
 | 
import javax.swing.text.html.CSS.Value;  | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
class CSSBorder extends AbstractBorder { | 
 | 
 | 
 | 
      | 
 | 
    final static int COLOR = 0, STYLE = 1, WIDTH = 2;  | 
 | 
 | 
 | 
      | 
 | 
    final static int TOP = 0, RIGHT = 1, BOTTOM = 2, LEFT = 3;  | 
 | 
 | 
 | 
      | 
 | 
    final static Attribute[][] ATTRIBUTES = { | 
 | 
        { Attribute.BORDER_TOP_COLOR, Attribute.BORDER_RIGHT_COLOR, | 
 | 
          Attribute.BORDER_BOTTOM_COLOR, Attribute.BORDER_LEFT_COLOR, },  | 
 | 
        { Attribute.BORDER_TOP_STYLE, Attribute.BORDER_RIGHT_STYLE, | 
 | 
          Attribute.BORDER_BOTTOM_STYLE, Attribute.BORDER_LEFT_STYLE, },  | 
 | 
        { Attribute.BORDER_TOP_WIDTH, Attribute.BORDER_RIGHT_WIDTH, | 
 | 
          Attribute.BORDER_BOTTOM_WIDTH, Attribute.BORDER_LEFT_WIDTH, },  | 
 | 
    };  | 
 | 
 | 
 | 
      | 
 | 
    final static CssValue PARSERS[] = { | 
 | 
        new ColorValue(), new BorderStyle(), new BorderWidthValue(null, 0),  | 
 | 
    };  | 
 | 
 | 
 | 
      | 
 | 
    final static Object[] DEFAULTS = { | 
 | 
        Attribute.BORDER_COLOR,   | 
 | 
        PARSERS[1].parseCssValue(Attribute.BORDER_STYLE.getDefaultValue()),  | 
 | 
        PARSERS[2].parseCssValue(Attribute.BORDER_WIDTH.getDefaultValue()),  | 
 | 
    };  | 
 | 
 | 
 | 
      | 
 | 
    final AttributeSet attrs;  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    CSSBorder(AttributeSet attrs) { | 
 | 
        this.attrs = attrs;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private Color getBorderColor(int side) { | 
 | 
        Object o = attrs.getAttribute(ATTRIBUTES[COLOR][side]);  | 
 | 
        ColorValue cv;  | 
 | 
        if (o instanceof ColorValue) { | 
 | 
            cv = (ColorValue) o;  | 
 | 
        } else { | 
 | 
            // Marker for the default value.  Use 'color' property value as the  | 
 | 
              | 
 | 
            cv = (ColorValue) attrs.getAttribute(Attribute.COLOR);  | 
 | 
            if (cv == null) { | 
 | 
                cv = (ColorValue) PARSERS[COLOR].parseCssValue(  | 
 | 
                                            Attribute.COLOR.getDefaultValue());  | 
 | 
            }  | 
 | 
        }  | 
 | 
        return cv.getValue();  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private int getBorderWidth(int side) { | 
 | 
        int width = 0;  | 
 | 
        BorderStyle bs = (BorderStyle) attrs.getAttribute(  | 
 | 
                                                    ATTRIBUTES[STYLE][side]);  | 
 | 
        if ((bs != null) && (bs.getValue() != Value.NONE)) { | 
 | 
            // The 'border-style' value of "none" forces the computed value  | 
 | 
              | 
 | 
            LengthValue bw = (LengthValue) attrs.getAttribute(  | 
 | 
                                                    ATTRIBUTES[WIDTH][side]);  | 
 | 
            if (bw == null) { | 
 | 
                bw = (LengthValue) DEFAULTS[WIDTH];  | 
 | 
            }  | 
 | 
            width = (int) bw.getValue(true);  | 
 | 
        }  | 
 | 
        return width;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private int[] getWidths() { | 
 | 
        int[] widths = new int[4];  | 
 | 
        for (int i = 0; i < widths.length; i++) { | 
 | 
            widths[i] = getBorderWidth(i);  | 
 | 
        }  | 
 | 
        return widths;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private Value getBorderStyle(int side) { | 
 | 
        BorderStyle style =  | 
 | 
                    (BorderStyle) attrs.getAttribute(ATTRIBUTES[STYLE][side]);  | 
 | 
        if (style == null) { | 
 | 
            style = (BorderStyle) DEFAULTS[STYLE];  | 
 | 
        }  | 
 | 
        return style.getValue();  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private Polygon getBorderShape(int side) { | 
 | 
        Polygon shape = null;  | 
 | 
        int[] widths = getWidths();  | 
 | 
        if (widths[side] != 0) { | 
 | 
            shape = new Polygon(new int[4], new int[4], 0);  | 
 | 
            shape.addPoint(0, 0);  | 
 | 
            shape.addPoint(-widths[(side + 3) % 4], -widths[side]);  | 
 | 
            shape.addPoint(widths[(side + 1) % 4], -widths[side]);  | 
 | 
            shape.addPoint(0, 0);  | 
 | 
        }  | 
 | 
        return shape;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private BorderPainter getBorderPainter(int side) { | 
 | 
        Value style = getBorderStyle(side);  | 
 | 
        return borderPainters.get(style);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    static Color getAdjustedColor(Color c, double factor) { | 
 | 
        double f = 1 - Math.min(Math.abs(factor), 1);  | 
 | 
        double inc = (factor > 0 ? 255 * (1 - f) : 0);  | 
 | 
        return new Color((int) (c.getRed() * f + inc),  | 
 | 
                         (int) (c.getGreen() * f + inc),  | 
 | 
                         (int) (c.getBlue() * f + inc));  | 
 | 
    }  | 
 | 
 | 
 | 
 | 
 | 
    /* The javax.swing.border.Border methods.  */  | 
 | 
 | 
 | 
    public Insets getBorderInsets(Component c, Insets insets) { | 
 | 
        int[] widths = getWidths();  | 
 | 
        insets.set(widths[TOP], widths[LEFT], widths[BOTTOM], widths[RIGHT]);  | 
 | 
        return insets;  | 
 | 
    }  | 
 | 
 | 
 | 
    public void paintBorder(Component c, Graphics g,  | 
 | 
                                        int x, int y, int width, int height) { | 
 | 
        if (!(g instanceof Graphics2D)) { | 
 | 
            return;  | 
 | 
        }  | 
 | 
 | 
 | 
        Graphics2D g2 = (Graphics2D) g.create();  | 
 | 
 | 
 | 
        int[] widths = getWidths();  | 
 | 
 | 
 | 
          | 
 | 
        int intX = x + widths[LEFT];  | 
 | 
        int intY = y + widths[TOP];  | 
 | 
        int intWidth = width - (widths[RIGHT] + widths[LEFT]);  | 
 | 
        int intHeight = height - (widths[TOP] + widths[BOTTOM]);  | 
 | 
 | 
 | 
          | 
 | 
        int[][] intCorners = { | 
 | 
            { intX, intY }, | 
 | 
            { intX + intWidth, intY }, | 
 | 
            { intX + intWidth, intY + intHeight }, | 
 | 
            { intX, intY + intHeight, }, | 
 | 
        };  | 
 | 
 | 
 | 
          | 
 | 
        for (int i = 0; i < 4; i++) { | 
 | 
            Value style = getBorderStyle(i);  | 
 | 
            Polygon shape = getBorderShape(i);  | 
 | 
            if ((style != Value.NONE) && (shape != null)) { | 
 | 
                int sideLength = (i % 2 == 0 ? intWidth : intHeight);  | 
 | 
 | 
 | 
                  | 
 | 
                shape.xpoints[2] += sideLength;  | 
 | 
                shape.xpoints[3] += sideLength;  | 
 | 
                Color color = getBorderColor(i);  | 
 | 
                BorderPainter painter = getBorderPainter(i);  | 
 | 
 | 
 | 
                double angle = i * Math.PI / 2;  | 
 | 
                g2.setClip(g.getClip());   | 
 | 
                g2.translate(intCorners[i][0], intCorners[i][1]);  | 
 | 
                g2.rotate(angle);  | 
 | 
                g2.clip(shape);  | 
 | 
                painter.paint(shape, g2, color, i);  | 
 | 
                g2.rotate(-angle);  | 
 | 
                g2.translate(-intCorners[i][0], -intCorners[i][1]);  | 
 | 
            }  | 
 | 
        }  | 
 | 
        g2.dispose();  | 
 | 
    }  | 
 | 
 | 
 | 
 | 
 | 
    /* Border painters.  */  | 
 | 
 | 
 | 
    interface BorderPainter { | 
 | 
          | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
         */  | 
 | 
        void paint(Polygon shape, Graphics g, Color color, int side);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    static class NullPainter implements BorderPainter { | 
 | 
        public void paint(Polygon shape, Graphics g, Color color, int side) { | 
 | 
            // Do nothing.  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    static class SolidPainter implements BorderPainter { | 
 | 
        public void paint(Polygon shape, Graphics g, Color color, int side) { | 
 | 
            g.setColor(color);  | 
 | 
            g.fillPolygon(shape);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    abstract static class StrokePainter implements BorderPainter { | 
 | 
          | 
 | 
 | 
 | 
         */  | 
 | 
        void paintStrokes(Rectangle r, Graphics g, int axis,  | 
 | 
                                int[] lengthPattern, Color[] colorPattern) { | 
 | 
            boolean xAxis = (axis == View.X_AXIS);  | 
 | 
            int start = 0;  | 
 | 
            int end = (xAxis ? r.width : r.height);  | 
 | 
            while (start < end) { | 
 | 
                for (int i = 0; i < lengthPattern.length; i++) { | 
 | 
                    if (start >= end) { | 
 | 
                        break;  | 
 | 
                    }  | 
 | 
                    int length = lengthPattern[i];  | 
 | 
                    Color c = colorPattern[i];  | 
 | 
                    if (c != null) { | 
 | 
                        int x = r.x + (xAxis ? start : 0);  | 
 | 
                        int y = r.y + (xAxis ? 0 : start);  | 
 | 
                        int width = xAxis ? length : r.width;  | 
 | 
                        int height = xAxis ? r.height : length;  | 
 | 
                        g.setColor(c);  | 
 | 
                        g.fillRect(x, y, width, height);  | 
 | 
                    }  | 
 | 
                    start += length;  | 
 | 
                }  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    static class DoublePainter extends StrokePainter { | 
 | 
        public void paint(Polygon shape, Graphics g, Color color, int side) { | 
 | 
            Rectangle r = shape.getBounds();  | 
 | 
            int length = Math.max(r.height / 3, 1);  | 
 | 
            int[] lengthPattern = { length, length }; | 
 | 
            Color[] colorPattern = { color, null }; | 
 | 
            paintStrokes(r, g, View.Y_AXIS, lengthPattern, colorPattern);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    static class DottedDashedPainter extends StrokePainter { | 
 | 
        final int factor;  | 
 | 
 | 
 | 
        DottedDashedPainter(int factor) { | 
 | 
            this.factor = factor;  | 
 | 
        }  | 
 | 
 | 
 | 
        public void paint(Polygon shape, Graphics g, Color color, int side) { | 
 | 
            Rectangle r = shape.getBounds();  | 
 | 
            int length = r.height * factor;  | 
 | 
            int[] lengthPattern = { length, length }; | 
 | 
            Color[] colorPattern = { color, null }; | 
 | 
            paintStrokes(r, g, View.X_AXIS, lengthPattern, colorPattern);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    abstract static class ShadowLightPainter extends StrokePainter { | 
 | 
          | 
 | 
 | 
 | 
         */  | 
 | 
        static Color getShadowColor(Color c) { | 
 | 
            return CSSBorder.getAdjustedColor(c, -0.3);  | 
 | 
        }  | 
 | 
 | 
 | 
          | 
 | 
 | 
 | 
         */  | 
 | 
        static Color getLightColor(Color c) { | 
 | 
            return CSSBorder.getAdjustedColor(c, 0.7);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    static class GrooveRidgePainter extends ShadowLightPainter { | 
 | 
        final Value type;  | 
 | 
 | 
 | 
        GrooveRidgePainter(Value type) { | 
 | 
            this.type = type;  | 
 | 
        }  | 
 | 
 | 
 | 
        public void paint(Polygon shape, Graphics g, Color color, int side) { | 
 | 
            Rectangle r = shape.getBounds();  | 
 | 
            int length = Math.max(r.height / 2, 1);  | 
 | 
            int[] lengthPattern = { length, length }; | 
 | 
            Color[] colorPattern =  | 
 | 
                             ((side + 1) % 4 < 2) == (type == Value.GROOVE) ?  | 
 | 
                new Color[] { getShadowColor(color), getLightColor(color) } : | 
 | 
                new Color[] { getLightColor(color), getShadowColor(color) }; | 
 | 
            paintStrokes(r, g, View.Y_AXIS, lengthPattern, colorPattern);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    static class InsetOutsetPainter extends ShadowLightPainter { | 
 | 
        Value type;  | 
 | 
 | 
 | 
        InsetOutsetPainter(Value type) { | 
 | 
            this.type = type;  | 
 | 
        }  | 
 | 
 | 
 | 
        public void paint(Polygon shape, Graphics g, Color color, int side) { | 
 | 
            g.setColor(((side + 1) % 4 < 2) == (type == Value.INSET) ?  | 
 | 
                                getShadowColor(color) : getLightColor(color));  | 
 | 
            g.fillPolygon(shape);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    static void registerBorderPainter(Value style, BorderPainter painter) { | 
 | 
        borderPainters.put(style, painter);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    static Map<Value, BorderPainter> borderPainters =  | 
 | 
                                        new HashMap<Value, BorderPainter>();  | 
 | 
 | 
 | 
      | 
 | 
    static { | 
 | 
        registerBorderPainter(Value.NONE, new NullPainter());  | 
 | 
        registerBorderPainter(Value.HIDDEN, new NullPainter());  | 
 | 
        registerBorderPainter(Value.SOLID, new SolidPainter());  | 
 | 
        registerBorderPainter(Value.DOUBLE, new DoublePainter());  | 
 | 
        registerBorderPainter(Value.DOTTED, new DottedDashedPainter(1));  | 
 | 
        registerBorderPainter(Value.DASHED, new DottedDashedPainter(3));  | 
 | 
        registerBorderPainter(Value.GROOVE, new GrooveRidgePainter(Value.GROOVE));  | 
 | 
        registerBorderPainter(Value.RIDGE, new GrooveRidgePainter(Value.RIDGE));  | 
 | 
        registerBorderPainter(Value.INSET, new InsetOutsetPainter(Value.INSET));  | 
 | 
        registerBorderPainter(Value.OUTSET, new InsetOutsetPainter(Value.OUTSET));  | 
 | 
    }  | 
 | 
}  |