src/java.desktop/share/native/libsplashscreen/splashscreen_gfx_impl.h
changeset 47216 71c04702a3d5
parent 25859 3317bb8137f4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/share/native/libsplashscreen/splashscreen_gfx_impl.h	Tue Sep 12 19:03:39 2017 +0200
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c) 2005, 2010, 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.
+ */
+
+#ifndef SPLASHSCREEN_GFX_IMPL_H
+#define SPLASHSCREEN_GFX_IMPL_H
+
+#include "splashscreen_gfx.h"
+
+/* here come some very simple macros */
+
+/* advance a pointer p by sizeof(type)*n bytes */
+#define INCPN(type,p,n) ((p) = (type*)(p)+(n))
+
+/* advance a pointer by sizeof(type) */
+#define INCP(type,p) INCPN(type,(p),1)
+
+/* store a typed value to pointed location */
+#define PUT(type,p,v) (*(type*)(p) = (type)(v))
+
+/* load a typed value from pointed location */
+#define GET(type,p) (*(type*)p)
+
+/* same as cond<0?-1:0 */
+enum
+{
+    IFNEG_SHIFT_BITS = sizeof(int) * 8 - 1
+};
+
+#define IFNEG(cond) ((int)(cond)>>IFNEG_SHIFT_BITS)
+
+/* same as cond<0?n1:n2 */
+#define IFNEGPOS(cond,n1,n2) ((IFNEG(cond)&(n1))|((~IFNEG(cond))&(n2)))
+
+/* value shifted left by n bits, negative n is allowed */
+#define LSHIFT(value,n) IFNEGPOS((n),(value)>>-(n),(value)<<(n))
+
+/* value shifted right by n bits, negative n is allowed */
+#define RSHIFT(value,n) IFNEGPOS(n,(value)<<-(n),(value)>>(n))
+
+/* converts a single i'th component to the specific format defined by format->shift[i] and format->mask[i] */
+#define CONVCOMP(quad,format,i) \
+    (LSHIFT((quad),(format)->shift[i])&(format)->mask[i])
+
+/* extracts the component defined by format->shift[i] and format->mask[i] from a specific-format value */
+#define UNCONVCOMP(value,format,i) \
+    (RSHIFT((value)&(format)->mask[i],(format)->shift[i]))
+
+/*  dithers the color using the dither matrices and colormap from format
+    indices to dither matrices are passed as arguments */
+INLINE unsigned
+ditherColor(rgbquad_t value, ImageFormat * format, int row, int col)
+{
+    int blue = QUAD_BLUE(value);
+    int green = QUAD_GREEN(value);
+    int red = QUAD_RED(value);
+
+    blue = format->dithers[0].colorTable[blue +
+        format->dithers[0].matrix[col & DITHER_MASK][row & DITHER_MASK]];
+    green = format->dithers[1].colorTable[green +
+        format->dithers[1].matrix[col & DITHER_MASK][row & DITHER_MASK]];
+    red = format->dithers[2].colorTable[red +
+        format->dithers[2].matrix[col & DITHER_MASK][row & DITHER_MASK]];
+    return red + green + blue;
+}
+
+/*      blend (lerp between) two rgb quads
+        src and dst alpha is ignored
+        the algorithm: src*alpha+dst*(1-alpha)=(src-dst)*alpha+dst, rb and g are done separately
+*/
+INLINE rgbquad_t
+blendRGB(rgbquad_t dst, rgbquad_t src, rgbquad_t alpha)
+{
+    const rgbquad_t a = alpha;
+    const rgbquad_t a1 = 0xFF - alpha;
+
+    return MAKE_QUAD(
+        (rgbquad_t)((QUAD_RED(src) * a + QUAD_RED(dst) * a1) / 0xFF),
+        (rgbquad_t)((QUAD_GREEN(src) * a + QUAD_GREEN(dst) * a1) / 0xFF),
+        (rgbquad_t)((QUAD_BLUE(src) * a + QUAD_BLUE(dst) * a1) / 0xFF),
+        0);
+}
+
+/*      scales rgb quad by alpha. basically similar to what's above. src alpha is retained.
+        used for premultiplying alpha
+
+        btw: braindead MSVC6 generates _three_ mul instructions for this function */
+
+INLINE rgbquad_t
+premultiplyRGBA(rgbquad_t src)
+{
+    rgbquad_t srb = src & 0xFF00FF;
+    rgbquad_t sg = src & 0xFF00;
+    rgbquad_t alpha = src >> QUAD_ALPHA_SHIFT;
+
+    alpha += 1;
+
+    srb *= alpha;
+    sg *= alpha;
+    srb >>= 8;
+    sg >>= 8;
+
+    return (src & 0xFF000000) | (srb & 0xFF00FF) | (sg & 0xFF00);
+}
+
+/*      The functions below are inherently ineffective, but the performance seems to be
+        more or less adequate for the case of splash screens. They can be optimized later
+        if needed. The idea of optimization is to provide inlineable form of putRGBADither and
+        getRGBA at least for certain most frequently used visuals. Something like this is
+        done in Java 2D ("loops"). This would be possible with C++ templates, but making it
+        clean for C would require ugly preprocessor tricks. Leaving it out for later.
+*/
+
+/*      convert a single pixel color value from rgbquad according to visual format
+        and place it to pointed location
+        ordered dithering used when necessary */
+INLINE void
+putRGBADither(rgbquad_t value, void *ptr, ImageFormat * format,
+        int row, int col)
+{
+    if (format->premultiplied) {
+        value = premultiplyRGBA(value);
+    }
+    if (format->dithers) {
+        value = format->colorIndex[ditherColor(value, format, row, col)];
+    }
+    else {
+        value = CONVCOMP(value, format, 0) | CONVCOMP(value, format, 1) |
+            CONVCOMP(value, format, 2) | CONVCOMP(value, format, 3);
+    }
+    switch (format->byteOrder) {
+    case BYTE_ORDER_LSBFIRST:
+        switch (format->depthBytes) {   /* lack of *break*'s is intentional */
+        case 4:
+            PUT(byte_t, ptr, value & 0xff);
+            value >>= 8;
+            INCP(byte_t, ptr);
+        case 3:
+            PUT(byte_t, ptr, value & 0xff);
+            value >>= 8;
+            INCP(byte_t, ptr);
+        case 2:
+            PUT(byte_t, ptr, value & 0xff);
+            value >>= 8;
+            INCP(byte_t, ptr);
+        case 1:
+            PUT(byte_t, ptr, value & 0xff);
+        }
+        break;
+    case BYTE_ORDER_MSBFIRST:
+        switch (format->depthBytes) {   /* lack of *break*'s is intentional */
+        case 4:
+            PUT(byte_t, ptr, (value >> 24) & 0xff);
+            INCP(byte_t, ptr);
+        case 3:
+            PUT(byte_t, ptr, (value >> 16) & 0xff);
+            INCP(byte_t, ptr);
+        case 2:
+            PUT(byte_t, ptr, (value >> 8) & 0xff);
+            INCP(byte_t, ptr);
+        case 1:
+            PUT(byte_t, ptr, value & 0xff);
+        }
+        break;
+    case BYTE_ORDER_NATIVE:
+        switch (format->depthBytes) {
+        case 4:
+            PUT(rgbquad_t, ptr, value);
+            break;
+        case 3:                /* not supported, LSB or MSB should always be specified */
+            PUT(byte_t, ptr, 0xff); /* Put a stub value */
+            INCP(byte_t, ptr);
+            PUT(byte_t, ptr, 0xff);
+            INCP(byte_t, ptr);
+            PUT(byte_t, ptr, 0xff);
+            break;
+        case 2:
+            PUT(word_t, ptr, value);
+            break;
+        case 1:
+            PUT(byte_t, ptr, value);
+            break;
+        }
+    }
+}
+
+/* load a single pixel color value and un-convert it to rgbquad according to visual format */
+INLINE rgbquad_t
+getRGBA(void *ptr, ImageFormat * format)
+{
+    /*
+       FIXME: color is not un-alpha-premultiplied on get
+       this is not required by current code, but it makes the implementation inconsistent
+       i.e. put(get) will not work right for alpha-premultiplied images */
+
+    /* get the value basing on depth and byte order */
+    rgbquad_t value = 0;
+
+    switch (format->byteOrder) {
+    case BYTE_ORDER_LSBFIRST:
+        switch (format->depthBytes) {
+        case 4:
+            value |= GET(byte_t, ptr);
+            value <<= 8;
+            INCP(byte_t, ptr);
+        case 3:
+            value |= GET(byte_t, ptr);
+            value <<= 8;
+            INCP(byte_t, ptr);
+        case 2:
+            value |= GET(byte_t, ptr);
+            value <<= 8;
+            INCP(byte_t, ptr);
+        case 1:
+            value |= GET(byte_t, ptr);
+        }
+        break;
+    case BYTE_ORDER_MSBFIRST:
+        switch (format->depthBytes) {   /* lack of *break*'s is intentional */
+        case 4:
+            value |= (GET(byte_t, ptr) << 24);
+            INCP(byte_t, ptr);
+        case 3:
+            value |= (GET(byte_t, ptr) << 16);
+            INCP(byte_t, ptr);
+        case 2:
+            value |= (GET(byte_t, ptr) << 8);
+            INCP(byte_t, ptr);
+        case 1:
+            value |= GET(byte_t, ptr);
+        }
+        break;
+    case BYTE_ORDER_NATIVE:
+        switch (format->depthBytes) {
+        case 4:
+            value = GET(rgbquad_t, ptr);
+            break;
+        case 3:                /* not supported, LSB or MSB should always be specified */
+            value = 0xFFFFFFFF; /*return a stub value */
+            break;
+        case 2:
+            value = (rgbquad_t) GET(word_t, ptr);
+            break;
+        case 1:
+            value = (rgbquad_t) GET(byte_t, ptr);
+            break;
+        }
+        break;
+    }
+    /* now un-convert the value */
+    if (format->colorMap) {
+        if (value == format->transparentColor)
+            return 0;
+        else
+            return format->colorMap[value];
+    }
+    else {
+        return UNCONVCOMP(value, format, 0) | UNCONVCOMP(value, format, 1) |
+            UNCONVCOMP(value, format, 2) | UNCONVCOMP(value, format, 3) |
+            format->fixedBits;
+    }
+}
+
+/* fill the line with the specified color according to visual format */
+INLINE void
+fillLine(rgbquad_t color, void *pDst, int incDst, int n,
+        ImageFormat * dstFormat, int row, int col)
+{
+    int i;
+
+    for (i = 0; i < n; ++i) {
+        putRGBADither(color, pDst, dstFormat, row, col++);
+        INCPN(byte_t, pDst, incDst);
+    }
+}
+
+/* find the shift for specified mask, also verify the mask is valid */
+INLINE int
+getMaskShift(rgbquad_t mask, int *pShift, int *pnumBits)
+{
+    int shift = 0, numBits = 0;
+
+    /* check the mask is not empty */
+    if (!mask)
+        return 0;
+    /* calculate the shift */
+    while ((mask & 1) == 0) {
+        ++shift;
+        mask >>= 1;
+    }
+    /* check the mask is contigious */
+    if ((mask & (mask + 1)) != 0)
+        return 0;
+    /* calculate the number of bits */
+    do {
+        ++numBits;
+        mask >>= 1;
+    } while ((mask & 1) != 0);
+    *pShift = shift;
+    *pnumBits = numBits;
+    return 1;
+}
+
+#endif