1 /*
   2  * Copyright (c) 2003, 2018, 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 
  26 package sun.awt.X11;
  27 
  28 import java.awt.*;
  29 import java.io.*;
  30 import sun.security.action.GetPropertyAction;
  31 import java.security.AccessController;
  32 
  33 /**
  34   *
  35   *  This class contains code that is need to mimic the
  36   *  Motif Color selection and color defaults code.
  37   *
  38   *  Portions of this code have been ported to java from
  39   *  Motif sources (Color.c) (ColorP.h) etc.
  40   *
  41   *  Author: Bino George
  42   *
  43   */
  44 
  45 class MotifColorUtilities {
  46 
  47 
  48     static final float XmRED_LUMINOSITY=0.30f;
  49     static final float XmGREEN_LUMINOSITY=0.59f;
  50     static final float XmBLUE_LUMINOSITY=0.11f;
  51     static final int XmINTENSITY_FACTOR=75;
  52     static final int XmLIGHT_FACTOR=0;
  53     static final int XmLUMINOSITY_FACTOR=25;
  54 
  55     static final int XmMAX_SHORT=65535;
  56 
  57 
  58     static final int XmCOLOR_PERCENTILE=(XmMAX_SHORT / 100);
  59 
  60     static final int XmDEFAULT_DARK_THRESHOLD=20;
  61     static final int XmDEFAULT_LIGHT_THRESHOLD=93;
  62     static final int XmDEFAULT_FOREGROUND_THRESHOLD=70;
  63 
  64     static final int BLACK = 0xFF000000;
  65     static final int WHITE = 0xFFFFFFFF;
  66     static final int MOTIF_WINDOW_COLOR= 0xFFDFDFDF;
  67 
  68     static final int DEFAULT_COLOR =  0xFFC4C4C4;
  69 
  70     static final int  XmCOLOR_LITE_THRESHOLD = XmDEFAULT_LIGHT_THRESHOLD * XmCOLOR_PERCENTILE;
  71     static final int  XmCOLOR_DARK_THRESHOLD = XmDEFAULT_DARK_THRESHOLD * XmCOLOR_PERCENTILE;
  72     static final int  XmFOREGROUND_THRESHOLD = XmDEFAULT_FOREGROUND_THRESHOLD * XmCOLOR_PERCENTILE;
  73 
  74     /* LITE color model
  75        percent to interpolate RGB towards black for SEL, BS, TS */
  76 
  77     static final int XmCOLOR_LITE_SEL_FACTOR = 15;
  78     static final int XmCOLOR_LITE_BS_FACTOR =  40;
  79     static final int XmCOLOR_LITE_TS_FACTOR =  20;
  80 
  81     /* DARK color model
  82        percent to interpolate RGB towards white for SEL, BS, TS */
  83 
  84     static final int XmCOLOR_DARK_SEL_FACTOR=  15;
  85     static final int XmCOLOR_DARK_BS_FACTOR =  30;
  86     static final int XmCOLOR_DARK_TS_FACTOR =  50;
  87 
  88     /* STD color model
  89        percent to interpolate RGB towards black for SEL, BS
  90        percent to interpolate RGB towards white for TS
  91        HI values used for high brightness (within STD)
  92        LO values used for low brightness (within STD)
  93        Interpolate factors between HI & LO values based on brightness */
  94 
  95     static final int XmCOLOR_HI_SEL_FACTOR = 15;
  96     static final int XmCOLOR_HI_BS_FACTOR =  40;
  97     static final int XmCOLOR_HI_TS_FACTOR =  60;
  98 
  99     static final int XmCOLOR_LO_SEL_FACTOR=  15;
 100     static final int XmCOLOR_LO_BS_FACTOR =  60;
 101     static final int XmCOLOR_LO_TS_FACTOR =  50;
 102 
 103     static int brightness( int red, int green, int blue )
 104     {
 105         float brightness;
 106         float intensity;
 107         float light;
 108         float luminosity, maxprimary, minprimary;
 109 
 110         // To mimix Motif logic, we need to convert to 16 bit color values.
 111 
 112         red = red << 8;
 113         green = green << 8;
 114         blue = blue << 8;
 115 
 116 
 117         intensity = (red + green + blue) / 3;
 118 
 119 
 120         /*
 121          * The casting nonsense below is to try to control the point at
 122          * the truncation occurs.
 123          */
 124 
 125         luminosity = (int) ((XmRED_LUMINOSITY * (float) red)
 126                 + (XmGREEN_LUMINOSITY * (float) green)
 127                 + (XmBLUE_LUMINOSITY * (float) blue));
 128 
 129         maxprimary = ( (red > green) ?
 130                 ( (red > blue) ? red : blue ) :
 131                 ( (green > blue) ? green : blue ) );
 132 
 133         minprimary = ( (red < green) ?
 134                 ( (red < blue) ? red : blue ) :
 135                 ( (green < blue) ? green : blue ) );
 136 
 137         light = (minprimary + maxprimary) / 2;
 138 
 139         brightness = ( (intensity * XmINTENSITY_FACTOR) +
 140                 (light * XmLIGHT_FACTOR) +
 141                 (luminosity * XmLUMINOSITY_FACTOR) ) / 100;
 142         return Math.round(brightness);
 143     }
 144 
 145     static int calculateForegroundFromBackground(int r, int g, int b) {
 146 
 147         int foreground = WHITE;
 148         int  brightness = brightness(r,g,b);
 149 
 150         if (brightness >  XmFOREGROUND_THRESHOLD) {
 151             foreground = BLACK;
 152         }
 153         else foreground = WHITE;
 154 
 155         return foreground;
 156     }
 157 
 158     static int calculateTopShadowFromBackground(int r, int g, int b) {
 159 
 160         float color_value,f;
 161 
 162         int br = r << 8;
 163         int bg = g << 8;
 164         int bb = b << 8;
 165 
 166         int brightness = brightness(r,g,b);
 167 
 168         float red;
 169         float green;
 170         float blue;
 171 
 172         if (brightness < XmCOLOR_DARK_THRESHOLD) {
 173             // dark background
 174 
 175             color_value = br;
 176             color_value += XmCOLOR_DARK_TS_FACTOR *
 177                 (XmMAX_SHORT - color_value) / 100;
 178             red = color_value;
 179 
 180             color_value = bg;
 181             color_value += XmCOLOR_DARK_TS_FACTOR *
 182                 (XmMAX_SHORT - color_value) / 100;
 183             green = color_value;
 184 
 185             color_value = bb;
 186             color_value += XmCOLOR_DARK_TS_FACTOR *
 187                 (XmMAX_SHORT - color_value) / 100;
 188             blue = color_value;
 189         }
 190         else if (brightness > XmCOLOR_LITE_THRESHOLD) {
 191             // lite background
 192 
 193             color_value = br;
 194             color_value -= (color_value * XmCOLOR_LITE_TS_FACTOR) / 100;
 195             red = color_value;
 196 
 197             color_value = bg;
 198             color_value -= (color_value * XmCOLOR_LITE_TS_FACTOR) / 100;
 199             green = color_value;
 200 
 201             color_value = bb;
 202             color_value -= (color_value * XmCOLOR_LITE_TS_FACTOR) / 100;
 203             blue = color_value;
 204 
 205         }
 206         else {
 207             // medium
 208             f = XmCOLOR_LO_TS_FACTOR + (brightness
 209                     * ( XmCOLOR_HI_TS_FACTOR - XmCOLOR_LO_TS_FACTOR )
 210                     / XmMAX_SHORT);
 211 
 212             color_value = br;
 213             color_value += f * ( XmMAX_SHORT - color_value ) / 100;
 214             red = color_value;
 215 
 216             color_value = bg;
 217             color_value += f * ( XmMAX_SHORT - color_value ) / 100;
 218             green = color_value;
 219 
 220             color_value = bb;
 221             color_value += f * ( XmMAX_SHORT - color_value ) / 100;
 222             blue = color_value;
 223 
 224 
 225         }
 226 
 227 
 228         int ired = ((int)red) >> 8;
 229         int igreen = ((int)green) >> 8;
 230         int iblue = ((int)blue) >> 8;
 231 
 232         int ret = 0xff000000 | ired <<16 | igreen<<8 | iblue;
 233 
 234         return ret;
 235     }
 236 
 237 
 238     static int calculateBottomShadowFromBackground(int r, int g, int b) {
 239 
 240         float color_value,f;
 241 
 242         int br = r << 8;
 243         int bg = g << 8;
 244         int bb = b << 8;
 245 
 246         int brightness = brightness(r,g,b);
 247 
 248         float red;
 249         float green;
 250         float blue;
 251 
 252         if (brightness < XmCOLOR_DARK_THRESHOLD) {
 253             // dark background
 254             color_value = br;
 255             color_value += XmCOLOR_DARK_BS_FACTOR *
 256                 (XmMAX_SHORT - color_value) / 100;
 257             red = color_value;
 258 
 259             color_value = bg;
 260             color_value += XmCOLOR_DARK_BS_FACTOR *
 261                 (XmMAX_SHORT - color_value) / 100;
 262             green = color_value;
 263 
 264             color_value = bb;
 265             color_value += XmCOLOR_DARK_BS_FACTOR *
 266                 (XmMAX_SHORT - color_value) / 100;
 267             blue = color_value;
 268 
 269         }
 270         else if (brightness > XmCOLOR_LITE_THRESHOLD) {
 271             // lite background
 272             color_value = br;
 273             color_value -= (color_value * XmCOLOR_LITE_BS_FACTOR) / 100;
 274             red = color_value;
 275 
 276             color_value = bg;
 277             color_value -= (color_value * XmCOLOR_LITE_BS_FACTOR) / 100;
 278             green = color_value;
 279 
 280             color_value = bb;
 281             color_value -= (color_value * XmCOLOR_LITE_BS_FACTOR) / 100;
 282             blue = color_value;
 283 
 284         }
 285         else {
 286             // medium
 287             f = XmCOLOR_LO_BS_FACTOR + (brightness
 288                     * ( XmCOLOR_HI_BS_FACTOR - XmCOLOR_LO_BS_FACTOR )
 289                     / XmMAX_SHORT);
 290 
 291             color_value = br;
 292             color_value -= (color_value * f) / 100;
 293             red = color_value;
 294 
 295             color_value = bg;
 296             color_value -= (color_value * f) / 100;
 297             green = color_value;
 298 
 299             color_value = bb;
 300             color_value -= (color_value * f) / 100;
 301             blue = color_value;
 302         }
 303 
 304 
 305         int ired = ((int)red) >> 8;
 306         int igreen = ((int)green) >> 8;
 307         int iblue = ((int)blue) >> 8;
 308 
 309         int ret = 0xff000000 | ired <<16 | igreen<<8 | iblue;
 310 
 311         return ret;
 312     }
 313 
 314     static int calculateSelectFromBackground(int r, int g, int b) {
 315 
 316         float color_value,f;
 317 
 318         int br = r << 8;
 319         int bg = g << 8;
 320         int bb = b << 8;
 321 
 322         int brightness = brightness(r,g,b);
 323 
 324         float red;
 325         float green;
 326         float blue;
 327 
 328         if (brightness < XmCOLOR_DARK_THRESHOLD) {
 329             // dark background
 330             color_value = br;
 331             color_value += XmCOLOR_DARK_SEL_FACTOR *
 332                 (XmMAX_SHORT - color_value) / 100;
 333             red = color_value;
 334 
 335             color_value = bg;
 336             color_value += XmCOLOR_DARK_SEL_FACTOR *
 337                 (XmMAX_SHORT - color_value) / 100;
 338             green = color_value;
 339 
 340             color_value = bb;
 341             color_value += XmCOLOR_DARK_SEL_FACTOR *
 342                 (XmMAX_SHORT - color_value) / 100;
 343             blue = color_value;
 344 
 345         }
 346         else if (brightness > XmCOLOR_LITE_THRESHOLD) {
 347             // lite background
 348             color_value = br;
 349             color_value -= (color_value * XmCOLOR_LITE_SEL_FACTOR) / 100;
 350             red = color_value;
 351 
 352             color_value = bg;
 353             color_value -= (color_value * XmCOLOR_LITE_SEL_FACTOR) / 100;
 354             green = color_value;
 355 
 356             color_value = bb;
 357             color_value -= (color_value * XmCOLOR_LITE_SEL_FACTOR) / 100;
 358             blue = color_value;
 359 
 360         }
 361         else {
 362             // medium
 363             f = XmCOLOR_LO_SEL_FACTOR + (brightness
 364                     * ( XmCOLOR_HI_SEL_FACTOR - XmCOLOR_LO_SEL_FACTOR )
 365                     / XmMAX_SHORT);
 366 
 367             color_value = br;
 368             color_value -= (color_value * f) / 100;
 369             red = color_value;
 370 
 371             color_value = bg;
 372             color_value -= (color_value * f) / 100;
 373             green = color_value;
 374 
 375             color_value = bb;
 376             color_value -= (color_value * f) / 100;
 377             blue = color_value;
 378         }
 379 
 380 
 381         int ired = ((int)red) >> 8;
 382         int igreen = ((int)green) >> 8;
 383         int iblue = ((int)blue) >> 8;
 384 
 385         int ret = 0xff000000 | ired <<16 | igreen<<8 | iblue;
 386 
 387         return ret;
 388     }
 389 
 390    static void loadSystemColorsForCDE(int[] systemColors) throws Exception  {
 391         // System.out.println("loadSystemColorsForCDE");
 392         XAtom resourceManager = XAtom.get("RESOURCE_MANAGER");
 393 
 394         String resourceString = resourceManager.getProperty(XToolkit.getDefaultRootWindow());
 395 
 396         int index = resourceString.indexOf("ColorPalette:");
 397         int len = resourceString.length();
 398         while ( (index < len) && (resourceString.charAt(index) != ':')) index++;
 399         index++; // skip :
 400         if (resourceString.charAt(index) == '\t') index++; // skip \t
 401 
 402         String paletteFile = resourceString.substring(index,resourceString.indexOf("\n",index));
 403 
 404         //System.out.println("Palette File = " + paletteFile);
 405 
 406         // Check if palette is a user palette.
 407 
 408         String  paletteFilePath = System.getProperty("user.home") + "/.dt/palettes/" + paletteFile;
 409 
 410         File pFile = new File(paletteFilePath);
 411         if (!pFile.exists())
 412         {
 413             // Must be a system palette
 414             paletteFilePath = "/usr/dt/palettes/" + paletteFile;
 415             pFile = new File(paletteFilePath);
 416             if (!pFile.exists())
 417             {
 418                 throw new FileNotFoundException("Could not open : "+ paletteFilePath);
 419             }
 420         }
 421         BufferedReader bfr = new BufferedReader(new FileReader(pFile));
 422 
 423         int[] colors = new int[8];
 424         int r,g,b;
 425         String temp,color;
 426 
 427         for (int i=0;i<8;i++) {
 428             temp = bfr.readLine();
 429             color = temp.substring(1,temp.length());
 430             r = Integer.valueOf(color.substring(0,4),16).intValue() >> 8;
 431             g = Integer.valueOf(color.substring(4,8),16).intValue() >> 8;
 432             b = Integer.valueOf(color.substring(8,12),16).intValue() >> 8;
 433             colors[i] = 0xff000000 | r<<16 | g<<8 | b;
 434             //  System.out.println("color["+i+"]="+Integer.toHexString(colors[i]) + "r = " +r + "g="+g+"b="+b);
 435         }
 436 
 437         systemColors[SystemColor.ACTIVE_CAPTION] = colors[0];
 438         systemColors[SystemColor.ACTIVE_CAPTION_BORDER] = colors[0];
 439 
 440         systemColors[SystemColor.INACTIVE_CAPTION] = colors[1];
 441         systemColors[SystemColor.INACTIVE_CAPTION_BORDER] = colors[1];
 442 
 443         systemColors[SystemColor.WINDOW] = colors[1];
 444 
 445         systemColors[SystemColor.WINDOW_BORDER] = colors[1];
 446         systemColors[SystemColor.MENU] = colors[1];
 447 
 448         systemColors[SystemColor.TEXT] = colors[3];
 449 
 450         systemColors[SystemColor.SCROLLBAR] = colors[1];
 451         systemColors[SystemColor.CONTROL] = colors[1];
 452 
 453         int activeFore;
 454         int inactiveFore;
 455         int textFore;
 456 
 457 
 458         r = (colors[0] & 0x00FF0000) >> 16;
 459         g = (colors[0] & 0x0000FF00) >> 8;
 460         b = (colors[0] & 0x000000FF);
 461 
 462         activeFore = MotifColorUtilities.calculateForegroundFromBackground(r,g,b);
 463 
 464         r = (colors[1] & 0x00FF0000) >> 16;
 465         g = (colors[1] & 0x0000FF00) >> 8;
 466         b = (colors[1] & 0x000000FF);
 467 
 468         inactiveFore = MotifColorUtilities.calculateForegroundFromBackground(r,g,b);
 469 
 470         int top_shadow = MotifColorUtilities.calculateTopShadowFromBackground(r,g,b);
 471         int bottom_shadow = MotifColorUtilities.calculateBottomShadowFromBackground(r,g,b);
 472 
 473 
 474         r = (colors[3] & 0x00FF0000) >> 16;
 475         g = (colors[3] & 0x0000FF00) >> 8;
 476         b = (colors[3] & 0x000000FF);
 477 
 478         textFore = MotifColorUtilities.calculateForegroundFromBackground(r,g,b);
 479 
 480 
 481         systemColors[SystemColor.ACTIVE_CAPTION_TEXT] = activeFore;
 482         systemColors[SystemColor.INACTIVE_CAPTION_TEXT] = inactiveFore;
 483         systemColors[SystemColor.WINDOW_TEXT] = inactiveFore;
 484         systemColors[SystemColor.MENU_TEXT] = inactiveFore;
 485         systemColors[SystemColor.TEXT_TEXT] = textFore;
 486         systemColors[SystemColor.TEXT_HIGHLIGHT] = MotifColorUtilities.BLACK;
 487         systemColors[SystemColor.TEXT_HIGHLIGHT_TEXT] = MotifColorUtilities.DEFAULT_COLOR;
 488         systemColors[SystemColor.CONTROL_TEXT] = inactiveFore;
 489         Color tmp = new Color(top_shadow);
 490         systemColors[SystemColor.CONTROL_HIGHLIGHT] =  top_shadow;
 491         systemColors[SystemColor.CONTROL_LT_HIGHLIGHT] =  tmp.brighter().getRGB();
 492 
 493         tmp = new Color(bottom_shadow);
 494         systemColors[SystemColor.CONTROL_SHADOW] =  bottom_shadow;
 495         systemColors[SystemColor.CONTROL_DK_SHADOW] = tmp.darker().getRGB();
 496 
 497     }
 498 
 499     static void loadMotifDefaultColors(int[] systemColors) {
 500         //fix for 5092883. WINDOW should be light gray and TEXT should be WHITE to look similar to Motif
 501         systemColors[SystemColor.WINDOW] = MotifColorUtilities.MOTIF_WINDOW_COLOR;
 502         systemColors[SystemColor.TEXT] = MotifColorUtilities.WHITE;
 503         systemColors[SystemColor.WINDOW_TEXT] = MotifColorUtilities.BLACK;
 504         systemColors[SystemColor.MENU_TEXT] = MotifColorUtilities.BLACK;
 505         systemColors[SystemColor.ACTIVE_CAPTION_TEXT] = MotifColorUtilities.BLACK;
 506         systemColors[SystemColor.INACTIVE_CAPTION_TEXT] = MotifColorUtilities.BLACK;
 507         systemColors[SystemColor.TEXT_TEXT] = MotifColorUtilities.BLACK;
 508         systemColors[SystemColor.TEXT_HIGHLIGHT] = MotifColorUtilities.BLACK;
 509         systemColors[SystemColor.TEXT_HIGHLIGHT_TEXT] = MotifColorUtilities.DEFAULT_COLOR;
 510         systemColors[SystemColor.CONTROL_TEXT] = MotifColorUtilities.BLACK;
 511         systemColors[SystemColor.WINDOW_BORDER] = MotifColorUtilities.DEFAULT_COLOR;
 512         systemColors[SystemColor.MENU] = MotifColorUtilities.DEFAULT_COLOR;
 513         systemColors[SystemColor.SCROLLBAR] = MotifColorUtilities.DEFAULT_COLOR;
 514         systemColors[SystemColor.CONTROL] = MotifColorUtilities.MOTIF_WINDOW_COLOR;
 515 
 516         int r = (MotifColorUtilities.DEFAULT_COLOR & 0x00FF0000) >> 16;
 517         int g = (MotifColorUtilities.DEFAULT_COLOR & 0x0000FF00) >> 8;
 518         int b = (MotifColorUtilities.DEFAULT_COLOR & 0x000000FF);
 519 
 520 
 521         int top_shadow = MotifColorUtilities.calculateTopShadowFromBackground(r,g,b);
 522         int bottom_shadow = MotifColorUtilities.calculateBottomShadowFromBackground(r,g,b);
 523 
 524         Color tmp = new Color(top_shadow);
 525         systemColors[SystemColor.CONTROL_HIGHLIGHT] =  top_shadow;
 526         systemColors[SystemColor.CONTROL_LT_HIGHLIGHT] =  tmp.brighter().getRGB();
 527 
 528         tmp = new Color(bottom_shadow);
 529         systemColors[SystemColor.CONTROL_SHADOW] =  bottom_shadow;
 530         systemColors[SystemColor.CONTROL_DK_SHADOW] = tmp.darker().getRGB();
 531 
 532     }
 533 
 534 
 535     static void loadSystemColors(int[] systemColors) {
 536         if ("Linux".equals(AccessController.doPrivileged(new GetPropertyAction("os.name")))) { // Load motif default colors on Linux.
 537             loadMotifDefaultColors(systemColors);
 538         }
 539         else
 540         {
 541             try {
 542                 loadSystemColorsForCDE(systemColors);
 543             }
 544             catch (Exception e) // Failure to load CDE colors.
 545             {
 546                 loadMotifDefaultColors(systemColors);
 547             }
 548         }
 549     }
 550 }