alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (Underline.java)

This example Java source code file (Underline.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

awt, basicstroke, concurrenthashmap, default_thickness, font, generalpath, geometry, ignore_thickness, imgrayunderline, line2d, shape, standardunderline, threading, threads, underline, underline_list, underlines, use_thickness

The Underline.java Java example source code

/*
 * Copyright (c) 1998, 2006, Oracle and/or its affiliates. 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.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
/*
 *
 * (C) Copyright IBM Corp. 1998, All Rights Reserved
 */

package sun.font;

import java.awt.BasicStroke;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.Stroke;

import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;

import java.awt.font.TextAttribute;

import java.util.concurrent.ConcurrentHashMap;

/**
 * This class provides drawing and bounds-measurement of
 * underlines.  Additionally, it has a factory method for
 * obtaining underlines from values of underline attributes.
 */

abstract class Underline {

    /**
     * Draws the underline into g2d.  The thickness should be obtained
     * from a LineMetrics object.  Note that some underlines ignore the
     * thickness parameter.
     * The underline is drawn from (x1, y) to (x2, y).
     */
    abstract void drawUnderline(Graphics2D g2d,
                                float thickness,
                                float x1,
                                float x2,
                                float y);

    /**
     * Returns the bottom of the bounding rectangle for this underline.
     */
    abstract float getLowerDrawLimit(float thickness);

    /**
     * Returns a Shape representing the underline.  The thickness should be obtained
     * from a LineMetrics object.  Note that some underlines ignore the
     * thickness parameter.
     */
    abstract Shape getUnderlineShape(float thickness,
                                     float x1,
                                     float x2,
                                     float y);

     // Implementation of underline for standard and Input Method underlines.
     // These classes are private.

    // IM Underlines ignore thickness param, and instead use
    // DEFAULT_THICKNESS
    private static final float DEFAULT_THICKNESS = 1.0f;

    // StandardUnderline's constructor takes a boolean param indicating
    // whether to override the default thickness.  These values clarify
    // the semantics of the parameter.
    private static final boolean USE_THICKNESS = true;
    private static final boolean IGNORE_THICKNESS = false;

    // Implementation of standard underline and all input method underlines
    // except UNDERLINE_LOW_GRAY.
    private static final class StandardUnderline extends Underline {

        // the amount by which to move the underline
        private float shift;

        // the actual line thickness is this value times
        // the requested thickness
        private float thicknessMultiplier;

        // if non-null, underline is drawn with a BasicStroke
        // with this dash pattern
        private float[] dashPattern;

        // if false, all underlines are DEFAULT_THICKNESS thick
        // if true, use thickness param
        private boolean useThickness;

        // cached BasicStroke
        private BasicStroke cachedStroke;

        StandardUnderline(float shift,
                          float thicknessMultiplier,
                          float[] dashPattern,
                          boolean useThickness) {

            this.shift = shift;
            this.thicknessMultiplier = thicknessMultiplier;
            this.dashPattern = dashPattern;
            this.useThickness = useThickness;
            this.cachedStroke = null;
        }

        private BasicStroke createStroke(float lineThickness) {

            if (dashPattern == null) {
                return new BasicStroke(lineThickness,
                                       BasicStroke.CAP_BUTT,
                                       BasicStroke.JOIN_MITER);
            }
            else {
                return new BasicStroke(lineThickness,
                                       BasicStroke.CAP_BUTT,
                                       BasicStroke.JOIN_MITER,
                                       10.0f,
                                       dashPattern,
                                       0);
            }
        }

        private float getLineThickness(float thickness) {

            if (useThickness) {
                return thickness * thicknessMultiplier;
            }
            else {
                return DEFAULT_THICKNESS * thicknessMultiplier;
            }
        }

        private Stroke getStroke(float thickness) {

            float lineThickness = getLineThickness(thickness);
            BasicStroke stroke = cachedStroke;
            if (stroke == null ||
                    stroke.getLineWidth() != lineThickness) {

                stroke = createStroke(lineThickness);
                cachedStroke = stroke;
            }

            return stroke;
        }

        void drawUnderline(Graphics2D g2d,
                           float thickness,
                           float x1,
                           float x2,
                           float y) {


            Stroke saveStroke = g2d.getStroke();
            g2d.setStroke(getStroke(thickness));
            g2d.draw(new Line2D.Float(x1, y + shift, x2, y + shift));
            g2d.setStroke(saveStroke);
        }

        float getLowerDrawLimit(float thickness) {

            return shift + getLineThickness(thickness);
        }

        Shape getUnderlineShape(float thickness,
                                float x1,
                                float x2,
                                float y) {

            Stroke ulStroke = getStroke(thickness);
            Line2D line = new Line2D.Float(x1, y + shift, x2, y + shift);
            return ulStroke.createStrokedShape(line);
        }
    }

    // Implementation of UNDERLINE_LOW_GRAY.
    private static class IMGrayUnderline extends Underline {

        private BasicStroke stroke;

        IMGrayUnderline() {
            stroke = new BasicStroke(DEFAULT_THICKNESS,
                                     BasicStroke.CAP_BUTT,
                                     BasicStroke.JOIN_MITER,
                                     10.0f,
                                     new float[] {1, 1},
                                     0);
        }

        void drawUnderline(Graphics2D g2d,
                           float thickness,
                           float x1,
                           float x2,
                           float y) {

            Stroke saveStroke = g2d.getStroke();
            g2d.setStroke(stroke);

            Line2D.Float drawLine = new Line2D.Float(x1, y, x2, y);
            g2d.draw(drawLine);

            drawLine.y1 += DEFAULT_THICKNESS;
            drawLine.y2 += DEFAULT_THICKNESS;
            drawLine.x1 += DEFAULT_THICKNESS;

            g2d.draw(drawLine);

            g2d.setStroke(saveStroke);
        }

        float getLowerDrawLimit(float thickness) {

            return DEFAULT_THICKNESS * 2;
        }

        Shape getUnderlineShape(float thickness,
                                float x1,
                                float x2,
                                float y) {

            GeneralPath gp = new GeneralPath();

            Line2D.Float line = new Line2D.Float(x1, y, x2, y);
            gp.append(stroke.createStrokedShape(line), false);

            line.y1 += DEFAULT_THICKNESS;
            line.y2 += DEFAULT_THICKNESS;
            line.x1 += DEFAULT_THICKNESS;

            gp.append(stroke.createStrokedShape(line), false);

            return gp;
        }
    }

     // Keep a map of underlines, one for each type
     // of underline.  The Underline objects are Flyweights
     // (shared across multiple clients), so they should be immutable.
     // If this implementation changes then clone underline
     // instances in getUnderline before returning them.
    private static final ConcurrentHashMap<Object, Underline>
        UNDERLINES = new ConcurrentHashMap<Object, Underline>(6);
    private static final Underline[] UNDERLINE_LIST;

    static {
        Underline[] uls = new Underline[6];

        uls[0] = new StandardUnderline(0, 1, null, USE_THICKNESS);
        UNDERLINES.put(TextAttribute.UNDERLINE_ON, uls[0]);

        uls[1] = new StandardUnderline(1, 1, null, IGNORE_THICKNESS);
        UNDERLINES.put(TextAttribute.UNDERLINE_LOW_ONE_PIXEL, uls[1]);

        uls[2] = new StandardUnderline(1, 2, null, IGNORE_THICKNESS);
        UNDERLINES.put(TextAttribute.UNDERLINE_LOW_TWO_PIXEL, uls[2]);

        uls[3] = new StandardUnderline(1, 1, new float[] { 1, 1 }, IGNORE_THICKNESS);
        UNDERLINES.put(TextAttribute.UNDERLINE_LOW_DOTTED, uls[3]);

        uls[4] = new IMGrayUnderline();
        UNDERLINES.put(TextAttribute.UNDERLINE_LOW_GRAY, uls[4]);

        uls[5] = new StandardUnderline(1, 1, new float[] { 4, 4 }, IGNORE_THICKNESS);
        UNDERLINES.put(TextAttribute.UNDERLINE_LOW_DASHED, uls[5]);

        UNDERLINE_LIST = uls;
    }

    /**
     * Return the Underline for the given value of
     * TextAttribute.INPUT_METHOD_UNDERLINE or
     * TextAttribute.UNDERLINE.
     * If value is not an input method underline value or
     * TextAttribute.UNDERLINE_ON, null is returned.
     */
    static Underline getUnderline(Object value) {

        if (value == null) {
            return null;
        }

        return (Underline) UNDERLINES.get(value);
    }

    static Underline getUnderline(int index) {
        return index < 0 ? null : UNDERLINE_LIST[index];
    }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java Underline.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.