Loading tools/layoutlib/bridge/src/android/graphics/LinearGradient.java +243 −6 Original line number Diff line number Diff line Loading @@ -19,10 +19,20 @@ package android.graphics; import java.awt.GradientPaint; import java.awt.Color; import java.awt.Paint; import java.awt.PaintContext; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import java.awt.image.ColorModel; import java.awt.image.DataBuffer; import java.awt.image.Raster; import java.awt.image.SampleModel; import java.awt.image.WritableRaster; public class LinearGradient extends Shader { private GradientPaint mGradientPaint; private Paint mJavaPaint; /** * Create a shader that draws a linear gradient along a line. Loading @@ -46,12 +56,13 @@ public class LinearGradient extends Shader { throw new IllegalArgumentException("color and position arrays must be of equal length"); } // FIXME implement multi color linear gradient if (colors.length == 2) { if (colors.length == 2) { // for 2 colors: use the Java implementation // The hasAlpha flag in Color() is only used to enforce alpha to 0xFF if false. // If true the alpha is read from the int. mGradientPaint = new GradientPaint(x0, y0, new Color(colors[0], true /* hasalpha */), mJavaPaint = new GradientPaint(x0, y0, new Color(colors[0], true /* hasalpha */), x1, y1, new Color(colors[1], true /* hasalpha */), tile != TileMode.CLAMP); } else { mJavaPaint = new MultiPointLinearGradientPaint(x0, y0, x1, y1, colors, positions, tile); } } Loading @@ -70,7 +81,7 @@ public class LinearGradient extends Shader { TileMode tile) { // The hasAlpha flag in Color() is only used to enforce alpha to 0xFF if false. // If true the alpha is read from the int. mGradientPaint = new GradientPaint(x0, y0, new Color(color0, true /* hasalpha */), x1, y1, mJavaPaint = new GradientPaint(x0, y0, new Color(color0, true /* hasalpha */), x1, y1, new Color(color1, true /* hasalpha */), tile != TileMode.CLAMP); } Loading @@ -78,6 +89,232 @@ public class LinearGradient extends Shader { @Override public Paint getJavaPaint() { return mGradientPaint; return mJavaPaint; } private static class MultiPointLinearGradientPaint implements Paint { private final static int GRADIENT_SIZE = 100; private final float mX0; private final float mY0; private final float mDx; private final float mDy; private final float mDSize2; private final int[] mColors; private final float[] mPositions; private final TileMode mTile; private int[] mGradient; public MultiPointLinearGradientPaint(float x0, float y0, float x1, float y1, int colors[], float positions[], TileMode tile) { mX0 = x0; mY0 = y0; mDx = x1 - x0; mDy = y1 - y0; mDSize2 = mDx * mDx + mDy * mDy; mColors = colors; mPositions = positions; mTile = tile; } public PaintContext createContext(ColorModel cm, Rectangle deviceBounds, Rectangle2D userBounds, AffineTransform xform, RenderingHints hints) { prepareColors(); return new MultiPointLinearGradientPaintContext(cm, deviceBounds, userBounds, xform, hints); } public int getTransparency() { return TRANSLUCENT; } private synchronized void prepareColors() { if (mGradient == null) { // actually create an array with an extra size, so that we can really go // from 0 to SIZE (100%), or currentPos in the loop below will never equal 1.0 mGradient = new int[GRADIENT_SIZE+1]; int prevPos = 0; int nextPos = 1; for (int i = 0 ; i <= GRADIENT_SIZE ; i++) { // compute current position float currentPos = (float)i/GRADIENT_SIZE; while (currentPos > mPositions[nextPos]) { prevPos = nextPos++; } float percent = (currentPos - mPositions[prevPos]) / (mPositions[nextPos] - mPositions[prevPos]); mGradient[i] = getColor(mColors[prevPos], mColors[nextPos], percent); } } } /** * Returns the color between c1, and c2, based on the percent of the distance * between c1 and c2. */ private int getColor(int c1, int c2, float percent) { int a = getChannel((c1 >> 24) & 0xFF, (c2 >> 24) & 0xFF, percent); int r = getChannel((c1 >> 16) & 0xFF, (c2 >> 16) & 0xFF, percent); int g = getChannel((c1 >> 8) & 0xFF, (c2 >> 8) & 0xFF, percent); int b = getChannel((c1 ) & 0xFF, (c2 ) & 0xFF, percent); return a << 24 | r << 16 | g << 8 | b; } /** * Returns the channel value between 2 values based on the percent of the distance between * the 2 values.. */ private int getChannel(int c1, int c2, float percent) { return c1 + (int)((percent * (c2-c1)) + .5); } private class MultiPointLinearGradientPaintContext implements PaintContext { private ColorModel mColorModel; private final Rectangle mDeviceBounds; private final Rectangle2D mUserBounds; private final AffineTransform mXform; private final RenderingHints mHints; public MultiPointLinearGradientPaintContext(ColorModel cm, Rectangle deviceBounds, Rectangle2D userBounds, AffineTransform xform, RenderingHints hints) { mColorModel = cm; // FIXME: so far all this is always the same rect gotten in getRaster with an indentity matrix? mDeviceBounds = deviceBounds; mUserBounds = userBounds; mXform = xform; mHints = hints; } public void dispose() { } public ColorModel getColorModel() { return mColorModel; } public Raster getRaster(int x, int y, int w, int h) { SampleModel sampleModel = mColorModel.createCompatibleSampleModel(w, h); WritableRaster raster = Raster.createWritableRaster(sampleModel, new java.awt.Point(x, y)); DataBuffer data = raster.getDataBuffer(); if (mDx == 0) { // vertical gradient // compute first column and copy to all other columns int index = 0; for (int iy = 0 ; iy < h ; iy++) { int color = getColor(iy + y, mY0, mDy); for (int ix = 0 ; ix < w ; ix++) { data.setElem(index++, color); } } } else if (mDy == 0) { // horizontal // compute first line in a tmp array and copy to all lines int[] line = new int[w]; for (int ix = 0 ; ix < w ; ix++) { line[ix] = getColor(ix + x, mX0, mDx); } int index = 0; for (int iy = 0 ; iy < h ; iy++) { for (int ix = 0 ; ix < w ; ix++) { data.setElem(index++, line[ix]); } } } else { int index = 0; for (int iy = 0 ; iy < h ; iy++) { for (int ix = 0 ; ix < w ; ix++) { data.setElem(index++, getColor(ix + x, iy + y)); } } } return raster; } } /** Returns a color for the easy vertical/horizontal mode */ private int getColor(float absPos, float refPos, float refSize) { float pos = (absPos - refPos) / refSize; return getIndexFromPos(pos); } /** * Returns a color for an arbitrary point. */ private int getColor(float x, float y) { // find the x position on the gradient vector. float _x = (mDx*mDy*(y-mY0) + mDy*mDy*mX0 + mDx*mDx*x) / mDSize2; // from it get the position relative to the vector float pos = (float) ((_x - mX0) / mDx); return getIndexFromPos(pos); } /** * Returns the color based on the position in the gradient. * <var>pos</var> can be anything, even < 0 or > > 1, as the gradient * will use {@link TileMode} value to convert it into a [0,1] value. */ private int getIndexFromPos(float pos) { if (pos < 0.f) { switch (mTile) { case CLAMP: pos = 0.f; break; case REPEAT: // remove the integer part to stay in the [0,1] range // careful: this is a negative value, so use ceil instead of floor pos = pos - (float)Math.ceil(pos); break; case MIRROR: // get the integer and the decimal part // careful: this is a negative value, so use ceil instead of floor int intPart = (int)Math.ceil(pos); pos = pos - intPart; // 0 -> -1 : mirrored order // -1 -> -2: normal order // etc.. // this means if the intpart is even we invert if ((intPart % 2) == 0) { pos = 1.f - pos; } break; } } else if (pos > 1f) { switch (mTile) { case CLAMP: pos = 1.f; break; case REPEAT: // remove the integer part to stay in the [0,1] range pos = pos - (float)Math.floor(pos); break; case MIRROR: // get the integer and the decimal part int intPart = (int)Math.floor(pos); pos = pos - intPart; // 0 -> 1 : normal order // 1 -> 2: mirrored // etc.. // this means if the intpart is odd we invert if ((intPart % 2) == 1) { pos = 1.f - pos; } break; } } int index = (int)((pos * GRADIENT_SIZE) + .5); return mGradient[index]; } } } Loading
tools/layoutlib/bridge/src/android/graphics/LinearGradient.java +243 −6 Original line number Diff line number Diff line Loading @@ -19,10 +19,20 @@ package android.graphics; import java.awt.GradientPaint; import java.awt.Color; import java.awt.Paint; import java.awt.PaintContext; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import java.awt.image.ColorModel; import java.awt.image.DataBuffer; import java.awt.image.Raster; import java.awt.image.SampleModel; import java.awt.image.WritableRaster; public class LinearGradient extends Shader { private GradientPaint mGradientPaint; private Paint mJavaPaint; /** * Create a shader that draws a linear gradient along a line. Loading @@ -46,12 +56,13 @@ public class LinearGradient extends Shader { throw new IllegalArgumentException("color and position arrays must be of equal length"); } // FIXME implement multi color linear gradient if (colors.length == 2) { if (colors.length == 2) { // for 2 colors: use the Java implementation // The hasAlpha flag in Color() is only used to enforce alpha to 0xFF if false. // If true the alpha is read from the int. mGradientPaint = new GradientPaint(x0, y0, new Color(colors[0], true /* hasalpha */), mJavaPaint = new GradientPaint(x0, y0, new Color(colors[0], true /* hasalpha */), x1, y1, new Color(colors[1], true /* hasalpha */), tile != TileMode.CLAMP); } else { mJavaPaint = new MultiPointLinearGradientPaint(x0, y0, x1, y1, colors, positions, tile); } } Loading @@ -70,7 +81,7 @@ public class LinearGradient extends Shader { TileMode tile) { // The hasAlpha flag in Color() is only used to enforce alpha to 0xFF if false. // If true the alpha is read from the int. mGradientPaint = new GradientPaint(x0, y0, new Color(color0, true /* hasalpha */), x1, y1, mJavaPaint = new GradientPaint(x0, y0, new Color(color0, true /* hasalpha */), x1, y1, new Color(color1, true /* hasalpha */), tile != TileMode.CLAMP); } Loading @@ -78,6 +89,232 @@ public class LinearGradient extends Shader { @Override public Paint getJavaPaint() { return mGradientPaint; return mJavaPaint; } private static class MultiPointLinearGradientPaint implements Paint { private final static int GRADIENT_SIZE = 100; private final float mX0; private final float mY0; private final float mDx; private final float mDy; private final float mDSize2; private final int[] mColors; private final float[] mPositions; private final TileMode mTile; private int[] mGradient; public MultiPointLinearGradientPaint(float x0, float y0, float x1, float y1, int colors[], float positions[], TileMode tile) { mX0 = x0; mY0 = y0; mDx = x1 - x0; mDy = y1 - y0; mDSize2 = mDx * mDx + mDy * mDy; mColors = colors; mPositions = positions; mTile = tile; } public PaintContext createContext(ColorModel cm, Rectangle deviceBounds, Rectangle2D userBounds, AffineTransform xform, RenderingHints hints) { prepareColors(); return new MultiPointLinearGradientPaintContext(cm, deviceBounds, userBounds, xform, hints); } public int getTransparency() { return TRANSLUCENT; } private synchronized void prepareColors() { if (mGradient == null) { // actually create an array with an extra size, so that we can really go // from 0 to SIZE (100%), or currentPos in the loop below will never equal 1.0 mGradient = new int[GRADIENT_SIZE+1]; int prevPos = 0; int nextPos = 1; for (int i = 0 ; i <= GRADIENT_SIZE ; i++) { // compute current position float currentPos = (float)i/GRADIENT_SIZE; while (currentPos > mPositions[nextPos]) { prevPos = nextPos++; } float percent = (currentPos - mPositions[prevPos]) / (mPositions[nextPos] - mPositions[prevPos]); mGradient[i] = getColor(mColors[prevPos], mColors[nextPos], percent); } } } /** * Returns the color between c1, and c2, based on the percent of the distance * between c1 and c2. */ private int getColor(int c1, int c2, float percent) { int a = getChannel((c1 >> 24) & 0xFF, (c2 >> 24) & 0xFF, percent); int r = getChannel((c1 >> 16) & 0xFF, (c2 >> 16) & 0xFF, percent); int g = getChannel((c1 >> 8) & 0xFF, (c2 >> 8) & 0xFF, percent); int b = getChannel((c1 ) & 0xFF, (c2 ) & 0xFF, percent); return a << 24 | r << 16 | g << 8 | b; } /** * Returns the channel value between 2 values based on the percent of the distance between * the 2 values.. */ private int getChannel(int c1, int c2, float percent) { return c1 + (int)((percent * (c2-c1)) + .5); } private class MultiPointLinearGradientPaintContext implements PaintContext { private ColorModel mColorModel; private final Rectangle mDeviceBounds; private final Rectangle2D mUserBounds; private final AffineTransform mXform; private final RenderingHints mHints; public MultiPointLinearGradientPaintContext(ColorModel cm, Rectangle deviceBounds, Rectangle2D userBounds, AffineTransform xform, RenderingHints hints) { mColorModel = cm; // FIXME: so far all this is always the same rect gotten in getRaster with an indentity matrix? mDeviceBounds = deviceBounds; mUserBounds = userBounds; mXform = xform; mHints = hints; } public void dispose() { } public ColorModel getColorModel() { return mColorModel; } public Raster getRaster(int x, int y, int w, int h) { SampleModel sampleModel = mColorModel.createCompatibleSampleModel(w, h); WritableRaster raster = Raster.createWritableRaster(sampleModel, new java.awt.Point(x, y)); DataBuffer data = raster.getDataBuffer(); if (mDx == 0) { // vertical gradient // compute first column and copy to all other columns int index = 0; for (int iy = 0 ; iy < h ; iy++) { int color = getColor(iy + y, mY0, mDy); for (int ix = 0 ; ix < w ; ix++) { data.setElem(index++, color); } } } else if (mDy == 0) { // horizontal // compute first line in a tmp array and copy to all lines int[] line = new int[w]; for (int ix = 0 ; ix < w ; ix++) { line[ix] = getColor(ix + x, mX0, mDx); } int index = 0; for (int iy = 0 ; iy < h ; iy++) { for (int ix = 0 ; ix < w ; ix++) { data.setElem(index++, line[ix]); } } } else { int index = 0; for (int iy = 0 ; iy < h ; iy++) { for (int ix = 0 ; ix < w ; ix++) { data.setElem(index++, getColor(ix + x, iy + y)); } } } return raster; } } /** Returns a color for the easy vertical/horizontal mode */ private int getColor(float absPos, float refPos, float refSize) { float pos = (absPos - refPos) / refSize; return getIndexFromPos(pos); } /** * Returns a color for an arbitrary point. */ private int getColor(float x, float y) { // find the x position on the gradient vector. float _x = (mDx*mDy*(y-mY0) + mDy*mDy*mX0 + mDx*mDx*x) / mDSize2; // from it get the position relative to the vector float pos = (float) ((_x - mX0) / mDx); return getIndexFromPos(pos); } /** * Returns the color based on the position in the gradient. * <var>pos</var> can be anything, even < 0 or > > 1, as the gradient * will use {@link TileMode} value to convert it into a [0,1] value. */ private int getIndexFromPos(float pos) { if (pos < 0.f) { switch (mTile) { case CLAMP: pos = 0.f; break; case REPEAT: // remove the integer part to stay in the [0,1] range // careful: this is a negative value, so use ceil instead of floor pos = pos - (float)Math.ceil(pos); break; case MIRROR: // get the integer and the decimal part // careful: this is a negative value, so use ceil instead of floor int intPart = (int)Math.ceil(pos); pos = pos - intPart; // 0 -> -1 : mirrored order // -1 -> -2: normal order // etc.. // this means if the intpart is even we invert if ((intPart % 2) == 0) { pos = 1.f - pos; } break; } } else if (pos > 1f) { switch (mTile) { case CLAMP: pos = 1.f; break; case REPEAT: // remove the integer part to stay in the [0,1] range pos = pos - (float)Math.floor(pos); break; case MIRROR: // get the integer and the decimal part int intPart = (int)Math.floor(pos); pos = pos - intPart; // 0 -> 1 : normal order // 1 -> 2: mirrored // etc.. // this means if the intpart is odd we invert if ((intPart % 2) == 1) { pos = 1.f - pos; } break; } } int index = (int)((pos * GRADIENT_SIZE) + .5); return mGradient[index]; } } }