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

Java example source code file (Decoration.java)

This example Java source code file (Decoration.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

area, awt, color, coremetrics, decoration, decorationimpl, font, geometry, graphics2d, object, paint, plain, rectangle2d, shape, stringbuffer, stroke, underline, util

The Decoration.java Java example source code

/*
 * 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. 1999-2003, All Rights Reserved
 *
 */

package sun.font;

import java.util.Map;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;

import java.awt.font.TextAttribute;

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

import static sun.font.AttributeValues.*;
import static sun.font.EAttribute.*;

/**
 * This class handles underlining, strikethrough, and foreground and
 * background styles on text.  Clients simply acquire instances
 * of this class and hand them off to ExtendedTextLabels or GraphicComponents.
 */
public class Decoration {

    /**
     * This interface is implemented by clients that use Decoration.
     * Unfortunately, interface methods have to public;  ideally these
     * would be package-private.
     */
    public interface Label {
        CoreMetrics getCoreMetrics();
        Rectangle2D getLogicalBounds();

        void handleDraw(Graphics2D g2d, float x, float y);
        Rectangle2D handleGetCharVisualBounds(int index);
        Rectangle2D handleGetVisualBounds();
        Shape handleGetOutline(float x, float y);
    }

    private Decoration() {
    }

    /**
     * Return a Decoration which does nothing.
     */
    public static Decoration getPlainDecoration() {

        return PLAIN;
    }

    private static final int VALUES_MASK =
        AttributeValues.getMask(EFOREGROUND, EBACKGROUND, ESWAP_COLORS,
                                ESTRIKETHROUGH, EUNDERLINE, EINPUT_METHOD_HIGHLIGHT,
                                EINPUT_METHOD_UNDERLINE);

    public static Decoration getDecoration(AttributeValues values) {
        if (values == null || !values.anyDefined(VALUES_MASK)) {
            return PLAIN;
        }

        values = values.applyIMHighlight();

        return new DecorationImpl(values.getForeground(),
                                  values.getBackground(),
                                  values.getSwapColors(),
                                  values.getStrikethrough(),
                                  Underline.getUnderline(values.getUnderline()),
                                  Underline.getUnderline(values.getInputMethodUnderline()));
    }

    /**
     * Return a Decoration appropriate for the the given Map.
     * @param attributes the Map used to determine the Decoration
     */
    public static Decoration getDecoration(Map attributes) {
        if (attributes == null) {
            return PLAIN;
        }
        return getDecoration(AttributeValues.fromMap(attributes));
    }

    public void drawTextAndDecorations(Label label,
                                Graphics2D g2d,
                                float x,
                                float y) {

        label.handleDraw(g2d, x, y);
    }

    public Rectangle2D getVisualBounds(Label label) {

        return label.handleGetVisualBounds();
    }

    public Rectangle2D getCharVisualBounds(Label label, int index) {

        return label.handleGetCharVisualBounds(index);
    }

    Shape getOutline(Label label,
                     float x,
                     float y) {

        return label.handleGetOutline(x, y);
    }

    private static final Decoration PLAIN = new Decoration();

    private static final class DecorationImpl extends Decoration {

        private Paint fgPaint = null;
        private Paint bgPaint = null;
        private boolean swapColors = false;
        private boolean strikethrough = false;
        private Underline stdUnderline = null; // underline from TextAttribute.UNDERLINE_ON
        private Underline imUnderline = null; // input method underline

        DecorationImpl(Paint foreground,
                       Paint background,
                       boolean swapColors,
                       boolean strikethrough,
                       Underline stdUnderline,
                       Underline imUnderline) {

            fgPaint = (Paint) foreground;
            bgPaint = (Paint) background;

            this.swapColors = swapColors;
            this.strikethrough = strikethrough;

            this.stdUnderline = stdUnderline;
            this.imUnderline = imUnderline;
        }

        private static boolean areEqual(Object lhs, Object rhs) {

            if (lhs == null) {
                return rhs == null;
            }
            else {
                return lhs.equals(rhs);
            }
        }

        public boolean equals(Object rhs) {

            if (rhs == this) {
                return true;
            }
            if (rhs == null) {
                return false;
            }

            DecorationImpl other = null;
            try {
                other = (DecorationImpl) rhs;
            }
            catch(ClassCastException e) {
                return false;
            }

            if (!(swapColors == other.swapColors &&
                        strikethrough == other.strikethrough)) {
                return false;
            }

            if (!areEqual(stdUnderline, other.stdUnderline)) {
                return false;
            }
            if (!areEqual(fgPaint, other.fgPaint)) {
                return false;
            }
            if (!areEqual(bgPaint, other.bgPaint)) {
                return false;
            }
            return areEqual(imUnderline, other.imUnderline);
        }

        public int hashCode() {

            int hc = 1;
            if (strikethrough) {
                hc |= 2;
            }
            if (swapColors) {
                hc |= 4;
            }
            if (stdUnderline != null) {
                hc += stdUnderline.hashCode();
            }
            return hc;
        }

        /**
        * Return the bottom of the Rectangle which encloses pixels
        * drawn by underlines.
        */
        private float getUnderlineMaxY(CoreMetrics cm) {

            float maxY = 0;
            if (stdUnderline != null) {

                float ulBottom = cm.underlineOffset;
                ulBottom += stdUnderline.getLowerDrawLimit(cm.underlineThickness);
                maxY = Math.max(maxY, ulBottom);
            }

            if (imUnderline != null) {

                float ulBottom = cm.underlineOffset;
                ulBottom += imUnderline.getLowerDrawLimit(cm.underlineThickness);
                maxY = Math.max(maxY, ulBottom);
            }

            return maxY;
        }

        private void drawTextAndEmbellishments(Label label,
                                               Graphics2D g2d,
                                               float x,
                                               float y) {

            label.handleDraw(g2d, x, y);

            if (!strikethrough && stdUnderline == null && imUnderline == null) {
                return;
            }

            float x1 = x;
            float x2 = x1 + (float)label.getLogicalBounds().getWidth();

            CoreMetrics cm = label.getCoreMetrics();
            if (strikethrough) {
                Stroke savedStroke = g2d.getStroke();
                g2d.setStroke(new BasicStroke(cm.strikethroughThickness,
                                              BasicStroke.CAP_BUTT,
                                              BasicStroke.JOIN_MITER));
                float strikeY = y + cm.strikethroughOffset;
                g2d.draw(new Line2D.Float(x1, strikeY, x2, strikeY));
                g2d.setStroke(savedStroke);
            }

            float ulOffset = cm.underlineOffset;
            float ulThickness = cm.underlineThickness;

            if (stdUnderline != null) {
                stdUnderline.drawUnderline(g2d, ulThickness, x1, x2, y + ulOffset);
            }

            if (imUnderline != null) {
                imUnderline.drawUnderline(g2d, ulThickness, x1, x2, y + ulOffset);
            }
        }

        public void drawTextAndDecorations(Label label,
                                    Graphics2D g2d,
                                    float x,
                                    float y) {

            if (fgPaint == null && bgPaint == null && swapColors == false) {
                drawTextAndEmbellishments(label, g2d, x, y);
            }
            else {
                Paint savedPaint = g2d.getPaint();
                Paint foreground, background;

                if (swapColors) {
                    background = fgPaint==null? savedPaint : fgPaint;
                    if (bgPaint == null) {
                        if (background instanceof Color) {
                            Color bg = (Color)background;
                            // 30/59/11 is standard weights, tweaked a bit
                            int brightness = 33 * bg.getRed()
                                + 53 * bg.getGreen()
                                + 14 * bg.getBlue();
                            foreground = brightness > 18500 ? Color.BLACK : Color.WHITE;
                        } else {
                            foreground = Color.WHITE;
                        }
                    } else {
                        foreground = bgPaint;
                    }
                }
                else {
                    foreground = fgPaint==null? savedPaint : fgPaint;
                    background = bgPaint;
                }

                if (background != null) {

                    Rectangle2D bgArea = label.getLogicalBounds();
                    bgArea = new Rectangle2D.Float(x + (float)bgArea.getX(),
                                                y + (float)bgArea.getY(),
                                                (float)bgArea.getWidth(),
                                                (float)bgArea.getHeight());

                    g2d.setPaint(background);
                    g2d.fill(bgArea);
                }

                g2d.setPaint(foreground);
                drawTextAndEmbellishments(label, g2d, x, y);
                g2d.setPaint(savedPaint);
            }
        }

        public Rectangle2D getVisualBounds(Label label) {

            Rectangle2D visBounds = label.handleGetVisualBounds();

            if (swapColors || bgPaint != null || strikethrough
                        || stdUnderline != null || imUnderline != null) {

                float minX = 0;
                Rectangle2D lb = label.getLogicalBounds();

                float minY = 0, maxY = 0;

                if (swapColors || bgPaint != null) {

                    minY = (float)lb.getY();
                    maxY = minY + (float)lb.getHeight();
                }

                maxY = Math.max(maxY, getUnderlineMaxY(label.getCoreMetrics()));

                Rectangle2D ab = new Rectangle2D.Float(minX, minY, (float)lb.getWidth(), maxY-minY);
                visBounds.add(ab);
            }

            return visBounds;
        }

        Shape getOutline(Label label,
                         float x,
                         float y) {

            if (!strikethrough && stdUnderline == null && imUnderline == null) {
                return label.handleGetOutline(x, y);
            }

            CoreMetrics cm = label.getCoreMetrics();

            // NOTE:  The performace of the following code may
            // be very poor.
            float ulThickness = cm.underlineThickness;
            float ulOffset = cm.underlineOffset;

            Rectangle2D lb = label.getLogicalBounds();
            float x1 = x;
            float x2 = x1 + (float)lb.getWidth();

            Area area = null;

            if (stdUnderline != null) {
                Shape ul = stdUnderline.getUnderlineShape(ulThickness,
                                                          x1, x2, y+ulOffset);
                area = new Area(ul);
            }

            if (strikethrough) {
                Stroke stStroke = new BasicStroke(cm.strikethroughThickness,
                                                  BasicStroke.CAP_BUTT,
                                                  BasicStroke.JOIN_MITER);
                float shiftY = y + cm.strikethroughOffset;
                Line2D line = new Line2D.Float(x1, shiftY, x2, shiftY);
                Area slArea = new Area(stStroke.createStrokedShape(line));
                if(area == null) {
                    area = slArea;
                } else {
                    area.add(slArea);
                }
            }

            if (imUnderline != null) {
                Shape ul = imUnderline.getUnderlineShape(ulThickness,
                                                         x1, x2, y+ulOffset);
                Area ulArea = new Area(ul);
                if (area == null) {
                    area = ulArea;
                }
                else {
                    area.add(ulArea);
                }
            }

            // area won't be null here, since at least one underline exists.
            area.add(new Area(label.handleGetOutline(x, y)));

            return new GeneralPath(area);
        }


        public String toString() {
            StringBuffer buf = new StringBuffer();
            buf.append(super.toString());
            buf.append("[");
            if (fgPaint != null) buf.append("fgPaint: " + fgPaint);
            if (bgPaint != null) buf.append(" bgPaint: " + bgPaint);
            if (swapColors) buf.append(" swapColors: true");
            if (strikethrough) buf.append(" strikethrough: true");
            if (stdUnderline != null) buf.append(" stdUnderline: " + stdUnderline);
            if (imUnderline != null) buf.append(" imUnderline: " + imUnderline);
            buf.append("]");
            return buf.toString();
        }
    }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java Decoration.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.