1 /*
   2  * Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package com.sun.java.swing.plaf.gtk;
  26 
  27 import javax.swing.plaf.synth.ColorType;
  28 import java.awt.Color;
  29 import javax.swing.plaf.ColorUIResource;
  30 
  31 /**
  32  * @author Scott Violet
  33  */
  34 public class GTKColorType extends ColorType {
  35     // GTK allows you to specify the foreground and background in a
  36     // gtkrc, the rest (dark, mid, light) are calculated from these
  37     // values.
  38     public static final ColorType LIGHT = new GTKColorType("Light");
  39     public static final ColorType DARK = new GTKColorType("Dark");
  40     public static final ColorType MID = new GTKColorType("Mid");
  41     public static final ColorType BLACK = new GTKColorType("Black");
  42     public static final ColorType WHITE = new GTKColorType("White");
  43 
  44     public static final int MAX_COUNT;
  45 
  46     private static final float[] HLS_COLORS = new float[3];
  47     private static final Object HLS_COLOR_LOCK = new Object();
  48 
  49     static {
  50         MAX_COUNT = WHITE.getID() + 1;
  51     }
  52 
  53     private static int hlsToRGB(float h, float l, float s) {
  54         float m2 = (l <= .5f) ? (l * (1 + s)) : (l + s - l * s);
  55         float m1 = 2.0f * l - m2;
  56         float r, g, b;
  57 
  58         if (s == 0.0) {
  59             if (h == 0.0) {
  60                 r = g = b = l;
  61             }
  62             else {
  63                 r = g = b = 0;
  64             }
  65         }
  66         else {
  67             r = hlsValue(m1, m2, h + 120);
  68             g = hlsValue(m1, m2, h);
  69             b = hlsValue(m1, m2, h - 120);
  70         }
  71         return (((int)(r * 255)) << 16) | (((int)(g * 255.0)) << 8) |
  72                ((int)(b * 255));
  73     }
  74 
  75     private static float hlsValue(float n1, float n2, float h) {
  76         if (h > 360) {
  77             h -= 360;
  78         }
  79         else if (h < 0) {
  80             h += 360;
  81         }
  82         if (h < 60) {
  83             return n1 + (n2 - n1) * h / 60.0f;
  84         }
  85         else if (h < 180) {
  86             return n2;
  87         }
  88         else if (h < 240) {
  89             return n1 + (n2 - n1) * (240.0f - h) / 60.0f;
  90         }
  91         return n1;
  92     }
  93 
  94     /**
  95      * Converts from RGB color space to HLS colorspace.
  96      */
  97     private static float[] rgbToHLS(int rgb, float[] hls) {
  98         float r = ((rgb & 0xFF0000) >> 16) / 255.0f;
  99         float g = ((rgb & 0xFF00) >> 8) / 255.0f;
 100         float b = (rgb & 0xFF) / 255.0f;
 101 
 102         /* calculate lightness */
 103         float max = Math.max(Math.max(r, g), b);
 104         float min = Math.min(Math.min(r, g), b);
 105         float l = (max + min) / 2.0f;
 106         float s = 0;
 107         float h = 0;
 108 
 109         if (max != min) {
 110             float delta = max - min;
 111             s = (l <= .5f) ? (delta / (max + min)) : (delta / (2.0f - max -min));
 112             if (r == max) {
 113                 h = (g - b) / delta;
 114             }
 115             else if (g == max) {
 116                 h = 2.0f + (b - r) / delta;
 117             }
 118             else {
 119                 h = 4.0f + (r - g) / delta;
 120             }
 121             h *= 60.0f;
 122             if (h < 0) {
 123                 h += 360.0f;
 124             }
 125         }
 126         if (hls == null) {
 127             hls = new float[3];
 128         }
 129         hls[0] = h;
 130         hls[1] = l;
 131         hls[2] = s;
 132         return hls;
 133     }
 134 
 135     /**
 136      * Creates and returns a new color derived from the passed in color.
 137      * The transformation is done in the HLS color space using the specified
 138      * arguments to scale.
 139      *
 140      * @param color Color to alter
 141      * @param hFactory Amount to scale the hue
 142      * @param lFactor Amount to scale the lightness
 143      * @param sFactory Amount to sacle saturation
 144      * @return newly created color
 145      */
 146     static Color adjustColor(Color color, float hFactor, float lFactor,
 147                              float sFactor) {
 148         float h;
 149         float l;
 150         float s;
 151 
 152         synchronized(HLS_COLOR_LOCK) {
 153             float[] hls = rgbToHLS(color.getRGB(), HLS_COLORS);
 154             h = hls[0];
 155             l = hls[1];
 156             s = hls[2];
 157         }
 158         h = Math.min(360, hFactor * h);
 159         l = Math.min(1, lFactor * l);
 160         s = Math.min(1, sFactor * s);
 161         return new ColorUIResource(hlsToRGB(h, l, s));
 162     }
 163 
 164     protected GTKColorType(String name) {
 165         super(name);
 166     }
 167 }