blob: a683dd1ebd981b2affa815c50f1f71464466f668 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004 - 2005 University Of British Columbia and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* University Of British Columbia - initial API and implementation
*******************************************************************************/
/*
* Created on Dec 29, 2004
*/
package org.eclipse.mylar.ui.internal.views;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.Display;
public class HighlighterImageDescriptor extends ImageDescriptor {
private Image image;
public HighlighterImageDescriptor(Color fromColor, Color toColor) {
super();
ImageData band = createGradientBand(50, 20, false,
new RGB(fromColor.getRed(), fromColor.getGreen(), fromColor.getBlue()),
new RGB(toColor.getRed(), toColor.getGreen(), toColor.getBlue()),
4, 4, 4);
image = new Image(Display.getCurrent(), band);
}
@Override
public boolean equals(Object obj) {
return (obj != null) && this.equals(obj.getClass())
&& image.equals(((HighlighterImageDescriptor) obj).image);
}
@Override
public ImageData getImageData() {
return image.getImageData();
}
@Override
public int hashCode() {
return image.hashCode();
}
public Image getImage() {
return image;
}
// ----------- COPIED FROM ImageData ---------------
/**
* Creates an ImageData containing one band's worth of a gradient filled
* block. If <code>vertical</code> is true, the band must be tiled
* horizontally to fill a region, otherwise it must be tiled vertically.
*
* @param width the width of the region to be filled
* @param height the height of the region to be filled
* @param vertical if true sweeps from top to bottom, else
* sweeps from left to right
* @param fromRGB the color to start with
* @param toRGB the color to end with
* @param redBits the number of significant red bits, 0 for palette modes
* @param greenBits the number of significant green bits, 0 for palette modes
* @param blueBits the number of significant blue bits, 0 for palette modes
* @return the new ImageData
*/
static ImageData createGradientBand(
int width, int height, boolean vertical,
RGB fromRGB, RGB toRGB,
int redBits, int greenBits, int blueBits) {
/* Gradients are drawn as tiled bands */
final int bandWidth, bandHeight, bitmapDepth;
final byte[] bitmapData;
final PaletteData paletteData;
/* Select an algorithm depending on the depth of the screen */
if (redBits != 0 && greenBits != 0 && blueBits != 0) {
paletteData = new PaletteData(0x0000ff00, 0x00ff0000, 0xff000000);
bitmapDepth = 32;
if (redBits >= 8 && greenBits >= 8 && blueBits >= 8) {
/* Precise color */
final int steps;
if (vertical) {
bandWidth = 1;
bandHeight = height;
steps = bandHeight > 1 ? bandHeight - 1 : 1;
} else {
bandWidth = width;
bandHeight = 1;
steps = bandWidth > 1 ? bandWidth - 1 : 1;
}
final int bytesPerLine = bandWidth * 4;
bitmapData = new byte[bandHeight * bytesPerLine];
buildPreciseGradientChannel(fromRGB.blue, toRGB.blue, steps, bandWidth, bandHeight, vertical, bitmapData, 0, bytesPerLine);
buildPreciseGradientChannel(fromRGB.green, toRGB.green, steps, bandWidth, bandHeight, vertical, bitmapData, 1, bytesPerLine);
buildPreciseGradientChannel(fromRGB.red, toRGB.red, steps, bandWidth, bandHeight, vertical, bitmapData, 2, bytesPerLine);
} else {
/* Dithered color */
final int steps;
if (vertical) {
bandWidth = (width < 8) ? width : 8;
bandHeight = height;
steps = bandHeight > 1 ? bandHeight - 1 : 1;
} else {
bandWidth = width;
bandHeight = (height < 8) ? height : 8;
steps = bandWidth > 1 ? bandWidth - 1 : 1;
}
final int bytesPerLine = bandWidth * 4;
bitmapData = new byte[bandHeight * bytesPerLine];
buildDitheredGradientChannel(fromRGB.blue, toRGB.blue, steps, bandWidth, bandHeight, vertical, bitmapData, 0, bytesPerLine, blueBits);
buildDitheredGradientChannel(fromRGB.green, toRGB.green, steps, bandWidth, bandHeight, vertical, bitmapData, 1, bytesPerLine, greenBits);
buildDitheredGradientChannel(fromRGB.red, toRGB.red, steps, bandWidth, bandHeight, vertical, bitmapData, 2, bytesPerLine, redBits);
}
} else {
/* Dithered two tone */
paletteData = new PaletteData(new RGB[] { fromRGB, toRGB });
bitmapDepth = 8;
final int blendi;
if (vertical) {
bandWidth = (width < 8) ? width : 8;
bandHeight = height;
blendi = (bandHeight > 1) ? 0x1040000 / (bandHeight - 1) + 1 : 1;
} else {
bandWidth = width;
bandHeight = (height < 8) ? height : 8;
blendi = (bandWidth > 1) ? 0x1040000 / (bandWidth - 1) + 1 : 1;
}
final int bytesPerLine = (bandWidth + 3) & -4;
bitmapData = new byte[bandHeight * bytesPerLine];
if (vertical) {
for (int dy = 0, blend = 0, dp = 0; dy < bandHeight;
++dy, blend += blendi, dp += bytesPerLine) {
for (int dx = 0; dx < bandWidth; ++dx) {
bitmapData[dp + dx] = (blend + DITHER_MATRIX[dy & 7][dx]) <
0x1000000 ? (byte)0 : (byte)1;
}
}
} else {
for (int dx = 0, blend = 0; dx < bandWidth; ++dx, blend += blendi) {
for (int dy = 0, dptr = dx; dy < bandHeight; ++dy, dptr += bytesPerLine) {
bitmapData[dptr] = (blend + DITHER_MATRIX[dy][dx & 7]) <
0x1000000 ? (byte)0 : (byte)1;
}
}
}
}
return new ImageData(bandWidth, bandHeight, bitmapDepth, paletteData, 4, bitmapData);
}
/*
* Fill in dithered gradated values for a color channel
*/
static final void buildDitheredGradientChannel(int from, int to, int steps,
int bandWidth, int bandHeight, boolean vertical,
byte[] bitmapData, int dp, int bytesPerLine, int bits) {
final int mask = 0xff00 >>> bits;
int val = from << 16;
final int inc = ((to << 16) - val) / steps + 1;
if (vertical) {
for (int dy = 0; dy < bandHeight; ++dy, dp += bytesPerLine) {
for (int dx = 0, dptr = dp; dx < bandWidth; ++dx, dptr += 4) {
final int thresh = DITHER_MATRIX[dy & 7][dx] >>> bits;
int temp = val + thresh;
if (temp > 0xffffff) bitmapData[dptr] = -1;
else bitmapData[dptr] = (byte)((temp >>> 16) & mask);
}
val += inc;
}
} else {
for (int dx = 0; dx < bandWidth; ++dx, dp += 4) {
for (int dy = 0, dptr = dp; dy < bandHeight; ++dy, dptr += bytesPerLine) {
final int thresh = DITHER_MATRIX[dy][dx & 7] >>> bits;
int temp = val + thresh;
if (temp > 0xffffff) bitmapData[dptr] = -1;
else bitmapData[dptr] = (byte)((temp >>> 16) & mask);
}
val += inc;
}
}
}
/*
* Fill in gradated values for a color channel
*/
static final void buildPreciseGradientChannel(int from, int to, int steps,
int bandWidth, int bandHeight, boolean vertical,
byte[] bitmapData, int dp, int bytesPerLine) {
int val = from << 16;
final int inc = ((to << 16) - val) / steps + 1;
if (vertical) {
for (int dy = 0; dy < bandHeight; ++dy, dp += bytesPerLine) {
bitmapData[dp] = (byte)(val >>> 16);
val += inc;
}
} else {
for (int dx = 0; dx < bandWidth; ++dx, dp += 4) {
bitmapData[dp] = (byte)(val >>> 16);
val += inc;
}
}
}
/**
* Scaled 8x8 Bayer dither matrix.
*/
static final int[][] DITHER_MATRIX = {
{ 0xfc0000, 0x7c0000, 0xdc0000, 0x5c0000, 0xf40000, 0x740000, 0xd40000, 0x540000 },
{ 0x3c0000, 0xbc0000, 0x1c0000, 0x9c0000, 0x340000, 0xb40000, 0x140000, 0x940000 },
{ 0xcc0000, 0x4c0000, 0xec0000, 0x6c0000, 0xc40000, 0x440000, 0xe40000, 0x640000 },
{ 0x0c0000, 0x8c0000, 0x2c0000, 0xac0000, 0x040000, 0x840000, 0x240000, 0xa40000 },
{ 0xf00000, 0x700000, 0xd00000, 0x500000, 0xf80000, 0x780000, 0xd80000, 0x580000 },
{ 0x300000, 0xb00000, 0x100000, 0x900000, 0x380000, 0xb80000, 0x180000, 0x980000 },
{ 0xc00000, 0x400000, 0xe00000, 0x600000, 0xc80000, 0x480000, 0xe80000, 0x680000 },
{ 0x000000, 0x800000, 0x200000, 0xa00000, 0x080000, 0x880000, 0x280000, 0xa80000 }
};
}