Path: blob/master/src/java.desktop/share/native/libsplashscreen/splashscreen_gfx_impl.h
41149 views
/*1* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#ifndef SPLASHSCREEN_GFX_IMPL_H26#define SPLASHSCREEN_GFX_IMPL_H2728#include "splashscreen_gfx.h"2930/* here come some very simple macros */3132/* advance a pointer p by sizeof(type)*n bytes */33#define INCPN(type,p,n) ((p) = (type*)(p)+(n))3435/* advance a pointer by sizeof(type) */36#define INCP(type,p) INCPN(type,(p),1)3738/* store a typed value to pointed location */39#define PUT(type,p,v) (*(type*)(p) = (type)(v))4041/* load a typed value from pointed location */42#define GET(type,p) (*(type*)p)4344/* same as cond<0?-1:0 */45enum46{47IFNEG_SHIFT_BITS = sizeof(int) * 8 - 148};4950#define IFNEG(cond) ((int)(cond)>>IFNEG_SHIFT_BITS)5152/* same as cond<0?n1:n2 */53#define IFNEGPOS(cond,n1,n2) ((IFNEG(cond)&(n1))|((~IFNEG(cond))&(n2)))5455/* value shifted left by n bits, negative n is allowed */56#define LSHIFT(value,n) IFNEGPOS((n),(value)>>-(n),(value)<<(n))5758/* value shifted right by n bits, negative n is allowed */59#define RSHIFT(value,n) IFNEGPOS(n,(value)<<-(n),(value)>>(n))6061/* converts a single i'th component to the specific format defined by format->shift[i] and format->mask[i] */62#define CONVCOMP(quad,format,i) \63(LSHIFT((quad),(format)->shift[i])&(format)->mask[i])6465/* extracts the component defined by format->shift[i] and format->mask[i] from a specific-format value */66#define UNCONVCOMP(value,format,i) \67(RSHIFT((value)&(format)->mask[i],(format)->shift[i]))6869/* dithers the color using the dither matrices and colormap from format70indices to dither matrices are passed as arguments */71INLINE unsigned72ditherColor(rgbquad_t value, ImageFormat * format, int row, int col)73{74int blue = QUAD_BLUE(value);75int green = QUAD_GREEN(value);76int red = QUAD_RED(value);7778blue = format->dithers[0].colorTable[blue +79format->dithers[0].matrix[col & DITHER_MASK][row & DITHER_MASK]];80green = format->dithers[1].colorTable[green +81format->dithers[1].matrix[col & DITHER_MASK][row & DITHER_MASK]];82red = format->dithers[2].colorTable[red +83format->dithers[2].matrix[col & DITHER_MASK][row & DITHER_MASK]];84return red + green + blue;85}8687/* blend (lerp between) two rgb quads88src and dst alpha is ignored89the algorithm: src*alpha+dst*(1-alpha)=(src-dst)*alpha+dst, rb and g are done separately90*/91INLINE rgbquad_t92blendRGB(rgbquad_t dst, rgbquad_t src, rgbquad_t alpha)93{94const rgbquad_t a = alpha;95const rgbquad_t a1 = 0xFF - alpha;9697return MAKE_QUAD(98(rgbquad_t)((QUAD_RED(src) * a + QUAD_RED(dst) * a1) / 0xFF),99(rgbquad_t)((QUAD_GREEN(src) * a + QUAD_GREEN(dst) * a1) / 0xFF),100(rgbquad_t)((QUAD_BLUE(src) * a + QUAD_BLUE(dst) * a1) / 0xFF),1010);102}103104/* scales rgb quad by alpha. basically similar to what's above. src alpha is retained.105used for premultiplying alpha106107btw: braindead MSVC6 generates _three_ mul instructions for this function */108109INLINE rgbquad_t110premultiplyRGBA(rgbquad_t src)111{112rgbquad_t srb = src & 0xFF00FF;113rgbquad_t sg = src & 0xFF00;114rgbquad_t alpha = src >> QUAD_ALPHA_SHIFT;115116alpha += 1;117118srb *= alpha;119sg *= alpha;120srb >>= 8;121sg >>= 8;122123return (src & 0xFF000000) | (srb & 0xFF00FF) | (sg & 0xFF00);124}125126/* The functions below are inherently ineffective, but the performance seems to be127more or less adequate for the case of splash screens. They can be optimized later128if needed. The idea of optimization is to provide inlineable form of putRGBADither and129getRGBA at least for certain most frequently used visuals. Something like this is130done in Java 2D ("loops"). This would be possible with C++ templates, but making it131clean for C would require ugly preprocessor tricks. Leaving it out for later.132*/133134/* convert a single pixel color value from rgbquad according to visual format135and place it to pointed location136ordered dithering used when necessary */137INLINE void138putRGBADither(rgbquad_t value, void *ptr, ImageFormat * format,139int row, int col)140{141if (format->premultiplied) {142value = premultiplyRGBA(value);143}144if (format->dithers) {145value = format->colorIndex[ditherColor(value, format, row, col)];146}147else {148value = CONVCOMP(value, format, 0) | CONVCOMP(value, format, 1) |149CONVCOMP(value, format, 2) | CONVCOMP(value, format, 3);150}151switch (format->byteOrder) {152case BYTE_ORDER_LSBFIRST:153switch (format->depthBytes) { /* lack of *break*'s is intentional */154case 4:155PUT(byte_t, ptr, value & 0xff);156value >>= 8;157INCP(byte_t, ptr);158case 3:159PUT(byte_t, ptr, value & 0xff);160value >>= 8;161INCP(byte_t, ptr);162case 2:163PUT(byte_t, ptr, value & 0xff);164value >>= 8;165INCP(byte_t, ptr);166case 1:167PUT(byte_t, ptr, value & 0xff);168}169break;170case BYTE_ORDER_MSBFIRST:171switch (format->depthBytes) { /* lack of *break*'s is intentional */172case 4:173PUT(byte_t, ptr, (value >> 24) & 0xff);174INCP(byte_t, ptr);175case 3:176PUT(byte_t, ptr, (value >> 16) & 0xff);177INCP(byte_t, ptr);178case 2:179PUT(byte_t, ptr, (value >> 8) & 0xff);180INCP(byte_t, ptr);181case 1:182PUT(byte_t, ptr, value & 0xff);183}184break;185case BYTE_ORDER_NATIVE:186switch (format->depthBytes) {187case 4:188PUT(rgbquad_t, ptr, value);189break;190case 3: /* not supported, LSB or MSB should always be specified */191PUT(byte_t, ptr, 0xff); /* Put a stub value */192INCP(byte_t, ptr);193PUT(byte_t, ptr, 0xff);194INCP(byte_t, ptr);195PUT(byte_t, ptr, 0xff);196break;197case 2:198PUT(word_t, ptr, value);199break;200case 1:201PUT(byte_t, ptr, value);202break;203}204}205}206207/* load a single pixel color value and un-convert it to rgbquad according to visual format */208INLINE rgbquad_t209getRGBA(void *ptr, ImageFormat * format)210{211/*212FIXME: color is not un-alpha-premultiplied on get213this is not required by current code, but it makes the implementation inconsistent214i.e. put(get) will not work right for alpha-premultiplied images */215216/* get the value basing on depth and byte order */217rgbquad_t value = 0;218219switch (format->byteOrder) {220case BYTE_ORDER_LSBFIRST:221switch (format->depthBytes) {222case 4:223value |= GET(byte_t, ptr);224value <<= 8;225INCP(byte_t, ptr);226case 3:227value |= GET(byte_t, ptr);228value <<= 8;229INCP(byte_t, ptr);230case 2:231value |= GET(byte_t, ptr);232value <<= 8;233INCP(byte_t, ptr);234case 1:235value |= GET(byte_t, ptr);236}237break;238case BYTE_ORDER_MSBFIRST:239switch (format->depthBytes) { /* lack of *break*'s is intentional */240case 4:241value |= (GET(byte_t, ptr) << 24);242INCP(byte_t, ptr);243case 3:244value |= (GET(byte_t, ptr) << 16);245INCP(byte_t, ptr);246case 2:247value |= (GET(byte_t, ptr) << 8);248INCP(byte_t, ptr);249case 1:250value |= GET(byte_t, ptr);251}252break;253case BYTE_ORDER_NATIVE:254switch (format->depthBytes) {255case 4:256value = GET(rgbquad_t, ptr);257break;258case 3: /* not supported, LSB or MSB should always be specified */259value = 0xFFFFFFFF; /*return a stub value */260break;261case 2:262value = (rgbquad_t) GET(word_t, ptr);263break;264case 1:265value = (rgbquad_t) GET(byte_t, ptr);266break;267}268break;269}270/* now un-convert the value */271if (format->colorMap) {272if (value == format->transparentColor)273return 0;274else275return format->colorMap[value];276}277else {278return UNCONVCOMP(value, format, 0) | UNCONVCOMP(value, format, 1) |279UNCONVCOMP(value, format, 2) | UNCONVCOMP(value, format, 3) |280format->fixedBits;281}282}283284/* fill the line with the specified color according to visual format */285INLINE void286fillLine(rgbquad_t color, void *pDst, int incDst, int n,287ImageFormat * dstFormat, int row, int col)288{289int i;290291for (i = 0; i < n; ++i) {292putRGBADither(color, pDst, dstFormat, row, col++);293INCPN(byte_t, pDst, incDst);294}295}296297/* find the shift for specified mask, also verify the mask is valid */298INLINE int299getMaskShift(rgbquad_t mask, int *pShift, int *pnumBits)300{301int shift = 0, numBits = 0;302303/* check the mask is not empty */304if (!mask)305return 0;306/* calculate the shift */307while ((mask & 1) == 0) {308++shift;309mask >>= 1;310}311/* check the mask is contigious */312if ((mask & (mask + 1)) != 0)313return 0;314/* calculate the number of bits */315do {316++numBits;317mask >>= 1;318} while ((mask & 1) != 0);319*pShift = shift;320*pnumBits = numBits;321return 1;322}323324#endif325326327