Loading tools/layoutlib/bridge/src/android/graphics/GradientShader.java 0 → 100644 +197 −0 Original line number Diff line number Diff line /* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.graphics; /** * Base class for Gradient shader. This is not a standard android class and is just used * as a base class for the re-implemented gradient classes. * * It also provides a base class to handle common code between the different shaders' * implementations of {@link java.awt.Paint}. * * @see LinearGradient * @see RadialGradient * @see SweepGradient */ public abstract class GradientShader extends Shader { protected final int[] mColors; protected final float[] mPositions; /** * Creates the base shader and do some basic test on the parameters. * * @param colors The colors to be distributed along the gradient line * @param positions May be null. The relative positions [0..1] of each * corresponding color in the colors array. If this is null, the * the colors are distributed evenly along the gradient line. */ protected GradientShader(int colors[], float positions[]) { if (colors.length < 2) { throw new IllegalArgumentException("needs >= 2 number of colors"); } if (positions != null && colors.length != positions.length) { throw new IllegalArgumentException("color and position arrays must be of equal length"); } if (positions == null) { float spacing = 1.f / (colors.length - 1); positions = new float[colors.length]; positions[0] = 0.f; positions[colors.length-1] = 1.f; for (int i = 1; i < colors.length - 1 ; i++) { positions[i] = spacing * i; } } mColors = colors; mPositions = positions; } /** * Base class for (Java) Gradient Paints. This handles computing the gradient colors based * on the color and position lists, as well as the {@link TileMode} * */ protected abstract static class GradientPaint implements java.awt.Paint { private final static int GRADIENT_SIZE = 100; private final int[] mColors; private final float[] mPositions; private final TileMode mTileMode; private int[] mGradient; protected GradientPaint(int[] colors, float[] positions, TileMode tileMode) { mColors = colors; mPositions = positions; mTileMode = tileMode; } public int getTransparency() { return java.awt.Paint.TRANSLUCENT; } /** * Pre-computes the colors for the gradient. This must be called once before any call * to {@link #getGradientColor(float)} */ protected synchronized void precomputeGradientColors() { 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] = computeColor(mColors[prevPos], mColors[nextPos], percent); } } } /** * 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. */ protected int getGradientColor(float pos) { if (pos < 0.f) { switch (mTileMode) { 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 (mTileMode) { 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]; } /** * Returns the color between c1, and c2, based on the percent of the distance * between c1 and c2. */ private int computeColor(int c1, int c2, float percent) { int a = computeChannel((c1 >> 24) & 0xFF, (c2 >> 24) & 0xFF, percent); int r = computeChannel((c1 >> 16) & 0xFF, (c2 >> 16) & 0xFF, percent); int g = computeChannel((c1 >> 8) & 0xFF, (c2 >> 8) & 0xFF, percent); int b = computeChannel((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 computeChannel(int c1, int c2, float percent) { return c1 + (int)((percent * (c2-c1)) + .5); } } } tools/layoutlib/bridge/src/android/graphics/LinearGradient.java +31 −171 Original line number Diff line number Diff line Loading @@ -16,19 +16,9 @@ package android.graphics; 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.BufferedImage; import java.awt.image.ColorModel; import java.awt.image.Raster; public class LinearGradient extends GradientShader { public class LinearGradient extends Shader { private Paint mJavaPaint; private java.awt.Paint mJavaPaint; /** * Create a shader that draws a linear gradient along a line. Loading @@ -45,24 +35,8 @@ public class LinearGradient extends Shader { */ public LinearGradient(float x0, float y0, float x1, float y1, int colors[], float positions[], TileMode tile) { if (colors.length < 2) { throw new IllegalArgumentException("needs >= 2 number of colors"); } if (positions != null && colors.length != positions.length) { throw new IllegalArgumentException("color and position arrays must be of equal length"); } if (positions == null) { float spacing = 1.f / (colors.length - 1); positions = new float[colors.length]; positions[0] = 0.f; positions[colors.length-1] = 1.f; for (int i = 1; i < colors.length - 1 ; i++) { positions[i] = spacing * i; } } mJavaPaint = new MultiPointLinearGradientPaint(x0, y0, x1, y1, colors, positions, tile); super(colors, positions); mJavaPaint = new LinearGradientPaint(x0, y0, x1, y1, mColors, mPositions, tile); } /** Loading @@ -84,117 +58,62 @@ public class LinearGradient extends Shader { // ---------- Custom Methods @Override public Paint getJavaPaint() { java.awt.Paint getJavaPaint() { return mJavaPaint; } private static class MultiPointLinearGradientPaint implements Paint { private final static int GRADIENT_SIZE = 100; /** * Linear Gradient (Java) Paint able to handle more than 2 points, as * {@link java.awt.GradientPaint} only supports 2 points and does not support Android's tile * modes. */ private static class LinearGradientPaint extends GradientPaint { 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[], public LinearGradientPaint(float x0, float y0, float x1, float y1, int colors[], float positions[], TileMode tile) { super(colors, positions, 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 java.awt.PaintContext createContext( java.awt.image.ColorModel colorModel, java.awt.Rectangle deviceBounds, java.awt.geom.Rectangle2D userBounds, java.awt.geom.AffineTransform xform, java.awt.RenderingHints hints) { precomputeGradientColors(); return new LinearGradientPaintContext(colorModel); } 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]); private class LinearGradientPaintContext implements java.awt.PaintContext { mGradient[i] = getColor(mColors[prevPos], mColors[nextPos], percent); } } } private final java.awt.image.ColorModel mColorModel; /** * 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; public LinearGradientPaintContext(java.awt.image.ColorModel colorModel) { mColorModel = colorModel; // 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() { public java.awt.image.ColorModel getColorModel() { return mColorModel; } public Raster getRaster(int x, int y, int w, int h) { BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); public java.awt.image.Raster getRaster(int x, int y, int w, int h) { java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h, java.awt.image.BufferedImage.TYPE_INT_ARGB); int[] data = new int[w*h]; Loading Loading @@ -236,7 +155,7 @@ public class LinearGradient extends Shader { private int getColor(float absPos, float refPos, float refSize) { float pos = (absPos - refPos) / refSize; return getIndexFromPos(pos); return getGradientColor(pos); } /** Loading @@ -248,66 +167,7 @@ public class LinearGradient extends Shader { // 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]; return getGradientColor(pos); } } } tools/layoutlib/bridge/src/android/graphics/RadialGradient.java +110 −48 Original line number Diff line number Diff line Loading @@ -16,55 +16,117 @@ package android.graphics; import java.awt.Paint; public class RadialGradient extends Shader { /** Create a shader that draws a radial gradient given the center and radius. @param x The x-coordinate of the center of the radius @param y The y-coordinate of the center of the radius @param radius Must be positive. The radius of the circle for this gradient @param colors The colors to be distributed between the center and edge of the circle @param positions May be NULL. The relative position of each corresponding color in the colors array. If this is NULL, the the colors are distributed evenly between the center and edge of the circle. @param tile The Shader tiling mode public class RadialGradient extends GradientShader { private RadialGradientPaint mPaint; /** * Create a shader that draws a radial gradient given the center and radius. * * @param x The x-coordinate of the center of the radius * @param y The y-coordinate of the center of the radius * @param radius Must be positive. The radius of the circle for this * gradient * @param colors The colors to be distributed between the center and edge of * the circle * @param positions May be NULL. The relative position of each corresponding * color in the colors array. If this is NULL, the the colors are * distributed evenly between the center and edge of the circle. * @param tile The Shader tiling mode */ public RadialGradient(float x, float y, float radius, int colors[], float positions[], TileMode tile) { public RadialGradient(float x, float y, float radius, int colors[], float positions[], TileMode tile) { super(colors, positions); if (radius <= 0) { throw new IllegalArgumentException("radius must be > 0"); } if (colors.length < 2) { throw new IllegalArgumentException("needs >= 2 number of colors"); mPaint = new RadialGradientPaint(x, y, radius, mColors, mPositions, tile); } if (positions != null && colors.length != positions.length) { throw new IllegalArgumentException("color and position arrays must be of equal length"); /** * Create a shader that draws a radial gradient given the center and radius. * * @param x The x-coordinate of the center of the radius * @param y The y-coordinate of the center of the radius * @param radius Must be positive. The radius of the circle for this * gradient * @param color0 The color at the center of the circle. * @param color1 The color at the edge of the circle. * @param tile The Shader tiling mode */ public RadialGradient(float x, float y, float radius, int color0, int color1, TileMode tile) { this(x, y, radius, new int[] { color0, color1 }, null /* positions */, tile); } // FIXME Implement shader @Override java.awt.Paint getJavaPaint() { return mPaint; } /** Create a shader that draws a radial gradient given the center and radius. @param x The x-coordinate of the center of the radius @param y The y-coordinate of the center of the radius @param radius Must be positive. The radius of the circle for this gradient @param color0 The color at the center of the circle. @param color1 The color at the edge of the circle. @param tile The Shader tiling mode */ public RadialGradient(float x, float y, float radius, int color0, int color1, TileMode tile) { if (radius <= 0) { throw new IllegalArgumentException("radius must be > 0"); private static class RadialGradientPaint extends GradientPaint { private final float mX; private final float mY; private final float mRadius; public RadialGradientPaint(float x, float y, float radius, int[] colors, float[] positions, TileMode mode) { super(colors, positions, mode); mX = x; mY = y; mRadius = radius; } // FIXME Implement shader public java.awt.PaintContext createContext( java.awt.image.ColorModel colorModel, java.awt.Rectangle deviceBounds, java.awt.geom.Rectangle2D userBounds, java.awt.geom.AffineTransform xform, java.awt.RenderingHints hints) { precomputeGradientColors(); return new RadialGradientPaintContext(colorModel); } @Override Paint getJavaPaint() { // TODO Auto-generated method stub return null; private class RadialGradientPaintContext implements java.awt.PaintContext { private final java.awt.image.ColorModel mColorModel; public RadialGradientPaintContext(java.awt.image.ColorModel colorModel) { mColorModel = colorModel; } public void dispose() { } public java.awt.image.ColorModel getColorModel() { return mColorModel; } public java.awt.image.Raster getRaster(int x, int y, int w, int h) { java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h, java.awt.image.BufferedImage.TYPE_INT_ARGB); int[] data = new int[w*h]; // compute distance from each point to the center, and figure out the distance from // it. int index = 0; for (int iy = 0 ; iy < h ; iy++) { for (int ix = 0 ; ix < w ; ix++) { float _x = x + ix - mX; float _y = y + iy - mY; float distance = (float) Math.sqrt(_x * _x + _y * _y); data[index++] = getGradientColor(distance / mRadius); } } image.setRGB(0 /*startX*/, 0 /*startY*/, w, h, data, 0 /*offset*/, w /*scansize*/); return image.getRaster(); } } } } Loading
tools/layoutlib/bridge/src/android/graphics/GradientShader.java 0 → 100644 +197 −0 Original line number Diff line number Diff line /* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.graphics; /** * Base class for Gradient shader. This is not a standard android class and is just used * as a base class for the re-implemented gradient classes. * * It also provides a base class to handle common code between the different shaders' * implementations of {@link java.awt.Paint}. * * @see LinearGradient * @see RadialGradient * @see SweepGradient */ public abstract class GradientShader extends Shader { protected final int[] mColors; protected final float[] mPositions; /** * Creates the base shader and do some basic test on the parameters. * * @param colors The colors to be distributed along the gradient line * @param positions May be null. The relative positions [0..1] of each * corresponding color in the colors array. If this is null, the * the colors are distributed evenly along the gradient line. */ protected GradientShader(int colors[], float positions[]) { if (colors.length < 2) { throw new IllegalArgumentException("needs >= 2 number of colors"); } if (positions != null && colors.length != positions.length) { throw new IllegalArgumentException("color and position arrays must be of equal length"); } if (positions == null) { float spacing = 1.f / (colors.length - 1); positions = new float[colors.length]; positions[0] = 0.f; positions[colors.length-1] = 1.f; for (int i = 1; i < colors.length - 1 ; i++) { positions[i] = spacing * i; } } mColors = colors; mPositions = positions; } /** * Base class for (Java) Gradient Paints. This handles computing the gradient colors based * on the color and position lists, as well as the {@link TileMode} * */ protected abstract static class GradientPaint implements java.awt.Paint { private final static int GRADIENT_SIZE = 100; private final int[] mColors; private final float[] mPositions; private final TileMode mTileMode; private int[] mGradient; protected GradientPaint(int[] colors, float[] positions, TileMode tileMode) { mColors = colors; mPositions = positions; mTileMode = tileMode; } public int getTransparency() { return java.awt.Paint.TRANSLUCENT; } /** * Pre-computes the colors for the gradient. This must be called once before any call * to {@link #getGradientColor(float)} */ protected synchronized void precomputeGradientColors() { 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] = computeColor(mColors[prevPos], mColors[nextPos], percent); } } } /** * 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. */ protected int getGradientColor(float pos) { if (pos < 0.f) { switch (mTileMode) { 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 (mTileMode) { 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]; } /** * Returns the color between c1, and c2, based on the percent of the distance * between c1 and c2. */ private int computeColor(int c1, int c2, float percent) { int a = computeChannel((c1 >> 24) & 0xFF, (c2 >> 24) & 0xFF, percent); int r = computeChannel((c1 >> 16) & 0xFF, (c2 >> 16) & 0xFF, percent); int g = computeChannel((c1 >> 8) & 0xFF, (c2 >> 8) & 0xFF, percent); int b = computeChannel((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 computeChannel(int c1, int c2, float percent) { return c1 + (int)((percent * (c2-c1)) + .5); } } }
tools/layoutlib/bridge/src/android/graphics/LinearGradient.java +31 −171 Original line number Diff line number Diff line Loading @@ -16,19 +16,9 @@ package android.graphics; 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.BufferedImage; import java.awt.image.ColorModel; import java.awt.image.Raster; public class LinearGradient extends GradientShader { public class LinearGradient extends Shader { private Paint mJavaPaint; private java.awt.Paint mJavaPaint; /** * Create a shader that draws a linear gradient along a line. Loading @@ -45,24 +35,8 @@ public class LinearGradient extends Shader { */ public LinearGradient(float x0, float y0, float x1, float y1, int colors[], float positions[], TileMode tile) { if (colors.length < 2) { throw new IllegalArgumentException("needs >= 2 number of colors"); } if (positions != null && colors.length != positions.length) { throw new IllegalArgumentException("color and position arrays must be of equal length"); } if (positions == null) { float spacing = 1.f / (colors.length - 1); positions = new float[colors.length]; positions[0] = 0.f; positions[colors.length-1] = 1.f; for (int i = 1; i < colors.length - 1 ; i++) { positions[i] = spacing * i; } } mJavaPaint = new MultiPointLinearGradientPaint(x0, y0, x1, y1, colors, positions, tile); super(colors, positions); mJavaPaint = new LinearGradientPaint(x0, y0, x1, y1, mColors, mPositions, tile); } /** Loading @@ -84,117 +58,62 @@ public class LinearGradient extends Shader { // ---------- Custom Methods @Override public Paint getJavaPaint() { java.awt.Paint getJavaPaint() { return mJavaPaint; } private static class MultiPointLinearGradientPaint implements Paint { private final static int GRADIENT_SIZE = 100; /** * Linear Gradient (Java) Paint able to handle more than 2 points, as * {@link java.awt.GradientPaint} only supports 2 points and does not support Android's tile * modes. */ private static class LinearGradientPaint extends GradientPaint { 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[], public LinearGradientPaint(float x0, float y0, float x1, float y1, int colors[], float positions[], TileMode tile) { super(colors, positions, 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 java.awt.PaintContext createContext( java.awt.image.ColorModel colorModel, java.awt.Rectangle deviceBounds, java.awt.geom.Rectangle2D userBounds, java.awt.geom.AffineTransform xform, java.awt.RenderingHints hints) { precomputeGradientColors(); return new LinearGradientPaintContext(colorModel); } 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]); private class LinearGradientPaintContext implements java.awt.PaintContext { mGradient[i] = getColor(mColors[prevPos], mColors[nextPos], percent); } } } private final java.awt.image.ColorModel mColorModel; /** * 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; public LinearGradientPaintContext(java.awt.image.ColorModel colorModel) { mColorModel = colorModel; // 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() { public java.awt.image.ColorModel getColorModel() { return mColorModel; } public Raster getRaster(int x, int y, int w, int h) { BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); public java.awt.image.Raster getRaster(int x, int y, int w, int h) { java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h, java.awt.image.BufferedImage.TYPE_INT_ARGB); int[] data = new int[w*h]; Loading Loading @@ -236,7 +155,7 @@ public class LinearGradient extends Shader { private int getColor(float absPos, float refPos, float refSize) { float pos = (absPos - refPos) / refSize; return getIndexFromPos(pos); return getGradientColor(pos); } /** Loading @@ -248,66 +167,7 @@ public class LinearGradient extends Shader { // 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]; return getGradientColor(pos); } } }
tools/layoutlib/bridge/src/android/graphics/RadialGradient.java +110 −48 Original line number Diff line number Diff line Loading @@ -16,55 +16,117 @@ package android.graphics; import java.awt.Paint; public class RadialGradient extends Shader { /** Create a shader that draws a radial gradient given the center and radius. @param x The x-coordinate of the center of the radius @param y The y-coordinate of the center of the radius @param radius Must be positive. The radius of the circle for this gradient @param colors The colors to be distributed between the center and edge of the circle @param positions May be NULL. The relative position of each corresponding color in the colors array. If this is NULL, the the colors are distributed evenly between the center and edge of the circle. @param tile The Shader tiling mode public class RadialGradient extends GradientShader { private RadialGradientPaint mPaint; /** * Create a shader that draws a radial gradient given the center and radius. * * @param x The x-coordinate of the center of the radius * @param y The y-coordinate of the center of the radius * @param radius Must be positive. The radius of the circle for this * gradient * @param colors The colors to be distributed between the center and edge of * the circle * @param positions May be NULL. The relative position of each corresponding * color in the colors array. If this is NULL, the the colors are * distributed evenly between the center and edge of the circle. * @param tile The Shader tiling mode */ public RadialGradient(float x, float y, float radius, int colors[], float positions[], TileMode tile) { public RadialGradient(float x, float y, float radius, int colors[], float positions[], TileMode tile) { super(colors, positions); if (radius <= 0) { throw new IllegalArgumentException("radius must be > 0"); } if (colors.length < 2) { throw new IllegalArgumentException("needs >= 2 number of colors"); mPaint = new RadialGradientPaint(x, y, radius, mColors, mPositions, tile); } if (positions != null && colors.length != positions.length) { throw new IllegalArgumentException("color and position arrays must be of equal length"); /** * Create a shader that draws a radial gradient given the center and radius. * * @param x The x-coordinate of the center of the radius * @param y The y-coordinate of the center of the radius * @param radius Must be positive. The radius of the circle for this * gradient * @param color0 The color at the center of the circle. * @param color1 The color at the edge of the circle. * @param tile The Shader tiling mode */ public RadialGradient(float x, float y, float radius, int color0, int color1, TileMode tile) { this(x, y, radius, new int[] { color0, color1 }, null /* positions */, tile); } // FIXME Implement shader @Override java.awt.Paint getJavaPaint() { return mPaint; } /** Create a shader that draws a radial gradient given the center and radius. @param x The x-coordinate of the center of the radius @param y The y-coordinate of the center of the radius @param radius Must be positive. The radius of the circle for this gradient @param color0 The color at the center of the circle. @param color1 The color at the edge of the circle. @param tile The Shader tiling mode */ public RadialGradient(float x, float y, float radius, int color0, int color1, TileMode tile) { if (radius <= 0) { throw new IllegalArgumentException("radius must be > 0"); private static class RadialGradientPaint extends GradientPaint { private final float mX; private final float mY; private final float mRadius; public RadialGradientPaint(float x, float y, float radius, int[] colors, float[] positions, TileMode mode) { super(colors, positions, mode); mX = x; mY = y; mRadius = radius; } // FIXME Implement shader public java.awt.PaintContext createContext( java.awt.image.ColorModel colorModel, java.awt.Rectangle deviceBounds, java.awt.geom.Rectangle2D userBounds, java.awt.geom.AffineTransform xform, java.awt.RenderingHints hints) { precomputeGradientColors(); return new RadialGradientPaintContext(colorModel); } @Override Paint getJavaPaint() { // TODO Auto-generated method stub return null; private class RadialGradientPaintContext implements java.awt.PaintContext { private final java.awt.image.ColorModel mColorModel; public RadialGradientPaintContext(java.awt.image.ColorModel colorModel) { mColorModel = colorModel; } public void dispose() { } public java.awt.image.ColorModel getColorModel() { return mColorModel; } public java.awt.image.Raster getRaster(int x, int y, int w, int h) { java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h, java.awt.image.BufferedImage.TYPE_INT_ARGB); int[] data = new int[w*h]; // compute distance from each point to the center, and figure out the distance from // it. int index = 0; for (int iy = 0 ; iy < h ; iy++) { for (int ix = 0 ; ix < w ; ix++) { float _x = x + ix - mX; float _y = y + iy - mY; float distance = (float) Math.sqrt(_x * _x + _y * _y); data[index++] = getGradientColor(distance / mRadius); } } image.setRGB(0 /*startX*/, 0 /*startY*/, w, h, data, 0 /*offset*/, w /*scansize*/); return image.getRaster(); } } } }