LayoutLib: Fix gradient rendering.
- fully support canvas transform - fully support shader local transform - fix repeat/mirror issue in the negative values. Change-Id: Ib2aa7ade1c2702da4364cbda9a5a3ae72c1d3174
This commit is contained in:
@ -119,20 +119,23 @@ public abstract class Gradient_Delegate extends Shader_Delegate {
|
|||||||
pos = 0.f;
|
pos = 0.f;
|
||||||
break;
|
break;
|
||||||
case REPEAT:
|
case REPEAT:
|
||||||
// remove the integer part to stay in the [0,1] range
|
// remove the integer part to stay in the [0,1] range.
|
||||||
// careful: this is a negative value, so use ceil instead of floor
|
// we also need to invert the value from [-1,0] to [0, 1]
|
||||||
pos = pos - (float)Math.ceil(pos);
|
pos = pos - (float)Math.floor(pos);
|
||||||
break;
|
break;
|
||||||
case MIRROR:
|
case MIRROR:
|
||||||
|
// this is the same as the positive side, just make the value positive
|
||||||
|
// first.
|
||||||
|
pos = Math.abs(pos);
|
||||||
|
|
||||||
// get the integer and the decimal part
|
// get the integer and the decimal part
|
||||||
// careful: this is a negative value, so use ceil instead of floor
|
int intPart = (int)Math.floor(pos);
|
||||||
int intPart = (int)Math.ceil(pos);
|
|
||||||
pos = pos - intPart;
|
pos = pos - intPart;
|
||||||
// 0 -> -1 : mirrored order
|
// 0 -> 1 : normal order
|
||||||
// -1 -> -2: normal order
|
// 1 -> 2: mirrored
|
||||||
// etc..
|
// etc..
|
||||||
// this means if the intpart is even we invert
|
// this means if the intpart is odd we invert
|
||||||
if ((intPart % 2) == 0) {
|
if ((intPart % 2) == 1) {
|
||||||
pos = 1.f - pos;
|
pos = 1.f - pos;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -16,11 +16,14 @@
|
|||||||
|
|
||||||
package android.graphics;
|
package android.graphics;
|
||||||
|
|
||||||
|
import com.android.layoutlib.bridge.Bridge;
|
||||||
import com.android.layoutlib.bridge.impl.DelegateManager;
|
import com.android.layoutlib.bridge.impl.DelegateManager;
|
||||||
|
|
||||||
import android.graphics.Shader.TileMode;
|
import android.graphics.Shader.TileMode;
|
||||||
|
|
||||||
import java.awt.Paint;
|
import java.awt.Paint;
|
||||||
|
import java.awt.geom.AffineTransform;
|
||||||
|
import java.awt.geom.NoninvertibleTransformException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delegate implementing the native methods of android.graphics.LinearGradient
|
* Delegate implementing the native methods of android.graphics.LinearGradient
|
||||||
@ -115,7 +118,7 @@ public class LinearGradient_Delegate extends Gradient_Delegate {
|
|||||||
* {@link java.awt.GradientPaint} only supports 2 points and does not support Android's tile
|
* {@link java.awt.GradientPaint} only supports 2 points and does not support Android's tile
|
||||||
* modes.
|
* modes.
|
||||||
*/
|
*/
|
||||||
private static class LinearGradientPaint extends GradientPaint {
|
private class LinearGradientPaint extends GradientPaint {
|
||||||
|
|
||||||
private final float mX0;
|
private final float mX0;
|
||||||
private final float mY0;
|
private final float mY0;
|
||||||
@ -126,11 +129,11 @@ public class LinearGradient_Delegate extends Gradient_Delegate {
|
|||||||
public LinearGradientPaint(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) {
|
float positions[], TileMode tile) {
|
||||||
super(colors, positions, tile);
|
super(colors, positions, tile);
|
||||||
mX0 = x0;
|
mX0 = x0;
|
||||||
mY0 = y0;
|
mY0 = y0;
|
||||||
mDx = x1 - x0;
|
mDx = x1 - x0;
|
||||||
mDy = y1 - y0;
|
mDy = y1 - y0;
|
||||||
mDSize2 = mDx * mDx + mDy * mDy;
|
mDSize2 = mDx * mDx + mDy * mDy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public java.awt.PaintContext createContext(
|
public java.awt.PaintContext createContext(
|
||||||
@ -140,16 +143,37 @@ public class LinearGradient_Delegate extends Gradient_Delegate {
|
|||||||
java.awt.geom.AffineTransform xform,
|
java.awt.geom.AffineTransform xform,
|
||||||
java.awt.RenderingHints hints) {
|
java.awt.RenderingHints hints) {
|
||||||
precomputeGradientColors();
|
precomputeGradientColors();
|
||||||
return new LinearGradientPaintContext(colorModel);
|
|
||||||
|
AffineTransform canvasMatrix;
|
||||||
|
try {
|
||||||
|
canvasMatrix = xform.createInverse();
|
||||||
|
} catch (NoninvertibleTransformException e) {
|
||||||
|
Bridge.getLog().error(null, "Unable to inverse matrix in LinearGradient", e);
|
||||||
|
canvasMatrix = new AffineTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
AffineTransform localMatrix = getLocalMatrix();
|
||||||
|
try {
|
||||||
|
localMatrix = localMatrix.createInverse();
|
||||||
|
} catch (NoninvertibleTransformException e) {
|
||||||
|
Bridge.getLog().error(null, "Unable to inverse matrix in LinearGradient", e);
|
||||||
|
localMatrix = new AffineTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new LinearGradientPaintContext(canvasMatrix, localMatrix, colorModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class LinearGradientPaintContext implements java.awt.PaintContext {
|
private class LinearGradientPaintContext implements java.awt.PaintContext {
|
||||||
|
|
||||||
|
private final AffineTransform mCanvasMatrix;
|
||||||
|
private final AffineTransform mLocalMatrix;
|
||||||
private final java.awt.image.ColorModel mColorModel;
|
private final java.awt.image.ColorModel mColorModel;
|
||||||
|
|
||||||
public LinearGradientPaintContext(java.awt.image.ColorModel colorModel) {
|
public LinearGradientPaintContext(AffineTransform canvasMatrix,
|
||||||
|
AffineTransform localMatrix, java.awt.image.ColorModel colorModel) {
|
||||||
|
mCanvasMatrix = canvasMatrix;
|
||||||
|
mLocalMatrix = localMatrix;
|
||||||
mColorModel = colorModel;
|
mColorModel = colorModel;
|
||||||
// FIXME: so far all this is always the same rect gotten in getRaster with an identity matrix?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
@ -165,31 +189,22 @@ public class LinearGradient_Delegate extends Gradient_Delegate {
|
|||||||
|
|
||||||
int[] data = new int[w*h];
|
int[] data = new int[w*h];
|
||||||
|
|
||||||
if (mDx == 0) { // vertical gradient
|
int index = 0;
|
||||||
// compute first column and copy to all other columns
|
float[] pt1 = new float[2];
|
||||||
int index = 0;
|
float[] pt2 = new float[2];
|
||||||
for (int iy = 0 ; iy < h ; iy++) {
|
for (int iy = 0 ; iy < h ; iy++) {
|
||||||
int color = getColor(iy + y, mY0, mDy);
|
|
||||||
for (int ix = 0 ; ix < w ; ix++) {
|
|
||||||
data[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++) {
|
for (int ix = 0 ; ix < w ; ix++) {
|
||||||
line[ix] = getColor(ix + x, mX0, mDx);
|
// handle the canvas transform
|
||||||
}
|
pt1[0] = x + ix;
|
||||||
|
pt1[1] = y + iy;
|
||||||
|
mCanvasMatrix.transform(pt1, 0, pt2, 0, 1);
|
||||||
|
|
||||||
for (int iy = 0 ; iy < h ; iy++) {
|
// handle the local matrix.
|
||||||
System.arraycopy(line, 0, data, iy*w, line.length);
|
pt1[0] = pt2[0];
|
||||||
}
|
pt1[1] = pt2[1];
|
||||||
} else {
|
mLocalMatrix.transform(pt1, 0, pt2, 0, 1);
|
||||||
int index = 0;
|
|
||||||
for (int iy = 0 ; iy < h ; iy++) {
|
data[index++] = getColor(pt2[0], pt2[1]);
|
||||||
for (int ix = 0 ; ix < w ; ix++) {
|
|
||||||
data[index++] = getColor(ix + x, iy + y);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,13 +214,6 @@ public class LinearGradient_Delegate extends Gradient_Delegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns a color for the easy vertical/horizontal mode */
|
|
||||||
private int getColor(float absPos, float refPos, float refSize) {
|
|
||||||
float pos = (absPos - refPos) / refSize;
|
|
||||||
|
|
||||||
return getGradientColor(pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a color for an arbitrary point.
|
* Returns a color for an arbitrary point.
|
||||||
*/
|
*/
|
||||||
|
@ -471,7 +471,7 @@ public final class Matrix_Delegate {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
d.preTransform(getRotate(degrees, px, py));
|
d.postTransform(getRotate(degrees, px, py));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,11 +16,14 @@
|
|||||||
|
|
||||||
package android.graphics;
|
package android.graphics;
|
||||||
|
|
||||||
|
import com.android.layoutlib.bridge.Bridge;
|
||||||
import com.android.layoutlib.bridge.impl.DelegateManager;
|
import com.android.layoutlib.bridge.impl.DelegateManager;
|
||||||
|
|
||||||
import android.graphics.Shader.TileMode;
|
import android.graphics.Shader.TileMode;
|
||||||
|
|
||||||
import java.awt.Paint;
|
import java.awt.Paint;
|
||||||
|
import java.awt.geom.AffineTransform;
|
||||||
|
import java.awt.geom.NoninvertibleTransformException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delegate implementing the native methods of android.graphics.RadialGradient
|
* Delegate implementing the native methods of android.graphics.RadialGradient
|
||||||
@ -105,18 +108,17 @@ public class RadialGradient_Delegate extends Gradient_Delegate {
|
|||||||
private RadialGradient_Delegate(float x, float y, float radius, int colors[], float positions[],
|
private RadialGradient_Delegate(float x, float y, float radius, int colors[], float positions[],
|
||||||
TileMode tile) {
|
TileMode tile) {
|
||||||
super(colors, positions);
|
super(colors, positions);
|
||||||
|
|
||||||
mJavaPaint = new RadialGradientPaint(x, y, radius, mColors, mPositions, tile);
|
mJavaPaint = new RadialGradientPaint(x, y, radius, mColors, mPositions, tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class RadialGradientPaint extends GradientPaint {
|
private class RadialGradientPaint extends GradientPaint {
|
||||||
|
|
||||||
private final float mX;
|
private final float mX;
|
||||||
private final float mY;
|
private final float mY;
|
||||||
private final float mRadius;
|
private final float mRadius;
|
||||||
|
|
||||||
public RadialGradientPaint(float x, float y, float radius, int[] colors, float[] positions,
|
public RadialGradientPaint(float x, float y, float radius,
|
||||||
TileMode mode) {
|
int[] colors, float[] positions, TileMode mode) {
|
||||||
super(colors, positions, mode);
|
super(colors, positions, mode);
|
||||||
mX = x;
|
mX = x;
|
||||||
mY = y;
|
mY = y;
|
||||||
@ -130,14 +132,36 @@ public class RadialGradient_Delegate extends Gradient_Delegate {
|
|||||||
java.awt.geom.AffineTransform xform,
|
java.awt.geom.AffineTransform xform,
|
||||||
java.awt.RenderingHints hints) {
|
java.awt.RenderingHints hints) {
|
||||||
precomputeGradientColors();
|
precomputeGradientColors();
|
||||||
return new RadialGradientPaintContext(colorModel);
|
|
||||||
|
AffineTransform canvasMatrix;
|
||||||
|
try {
|
||||||
|
canvasMatrix = xform.createInverse();
|
||||||
|
} catch (NoninvertibleTransformException e) {
|
||||||
|
Bridge.getLog().error(null, "Unable to inverse matrix in RadialGradient", e);
|
||||||
|
canvasMatrix = new AffineTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
AffineTransform localMatrix = getLocalMatrix();
|
||||||
|
try {
|
||||||
|
localMatrix = localMatrix.createInverse();
|
||||||
|
} catch (NoninvertibleTransformException e) {
|
||||||
|
Bridge.getLog().error(null, "Unable to inverse matrix in RadialGradient", e);
|
||||||
|
localMatrix = new AffineTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new RadialGradientPaintContext(canvasMatrix, localMatrix, colorModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class RadialGradientPaintContext implements java.awt.PaintContext {
|
private class RadialGradientPaintContext implements java.awt.PaintContext {
|
||||||
|
|
||||||
|
private final AffineTransform mCanvasMatrix;
|
||||||
|
private final AffineTransform mLocalMatrix;
|
||||||
private final java.awt.image.ColorModel mColorModel;
|
private final java.awt.image.ColorModel mColorModel;
|
||||||
|
|
||||||
public RadialGradientPaintContext(java.awt.image.ColorModel colorModel) {
|
public RadialGradientPaintContext(AffineTransform canvasMatrix,
|
||||||
|
AffineTransform localMatrix, java.awt.image.ColorModel colorModel) {
|
||||||
|
mCanvasMatrix = canvasMatrix;
|
||||||
|
mLocalMatrix = localMatrix;
|
||||||
mColorModel = colorModel;
|
mColorModel = colorModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,10 +181,22 @@ public class RadialGradient_Delegate extends Gradient_Delegate {
|
|||||||
// compute distance from each point to the center, and figure out the distance from
|
// compute distance from each point to the center, and figure out the distance from
|
||||||
// it.
|
// it.
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
float[] pt1 = new float[2];
|
||||||
|
float[] pt2 = new float[2];
|
||||||
for (int iy = 0 ; iy < h ; iy++) {
|
for (int iy = 0 ; iy < h ; iy++) {
|
||||||
for (int ix = 0 ; ix < w ; ix++) {
|
for (int ix = 0 ; ix < w ; ix++) {
|
||||||
float _x = x + ix - mX;
|
// handle the canvas transform
|
||||||
float _y = y + iy - mY;
|
pt1[0] = x + ix;
|
||||||
|
pt1[1] = y + iy;
|
||||||
|
mCanvasMatrix.transform(pt1, 0, pt2, 0, 1);
|
||||||
|
|
||||||
|
// handle the local matrix
|
||||||
|
pt1[0] = pt2[0] - mX;
|
||||||
|
pt1[1] = pt2[1] - mY;
|
||||||
|
mLocalMatrix.transform(pt1, 0, pt2, 0, 1);
|
||||||
|
|
||||||
|
float _x = pt2[0];
|
||||||
|
float _y = pt2[1];
|
||||||
float distance = (float) Math.sqrt(_x * _x + _y * _y);
|
float distance = (float) Math.sqrt(_x * _x + _y * _y);
|
||||||
|
|
||||||
data[index++] = getGradientColor(distance / mRadius);
|
data[index++] = getGradientColor(distance / mRadius);
|
||||||
|
@ -18,6 +18,8 @@ package android.graphics;
|
|||||||
|
|
||||||
import com.android.layoutlib.bridge.impl.DelegateManager;
|
import com.android.layoutlib.bridge.impl.DelegateManager;
|
||||||
|
|
||||||
|
import java.awt.geom.AffineTransform;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delegate implementing the native methods of android.graphics.Shader
|
* Delegate implementing the native methods of android.graphics.Shader
|
||||||
*
|
*
|
||||||
@ -109,4 +111,19 @@ public abstract class Shader_Delegate {
|
|||||||
|
|
||||||
// ---- Private delegate/helper methods ----
|
// ---- Private delegate/helper methods ----
|
||||||
|
|
||||||
|
protected AffineTransform getLocalMatrix() {
|
||||||
|
Matrix_Delegate localMatrixDelegate = null;
|
||||||
|
if (mLocalMatrix > 0) {
|
||||||
|
localMatrixDelegate = Matrix_Delegate.getDelegate(mLocalMatrix);
|
||||||
|
if (localMatrixDelegate == null) {
|
||||||
|
assert false;
|
||||||
|
return new AffineTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
return localMatrixDelegate.getAffineTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new AffineTransform();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -16,9 +16,12 @@
|
|||||||
|
|
||||||
package android.graphics;
|
package android.graphics;
|
||||||
|
|
||||||
|
import com.android.layoutlib.bridge.Bridge;
|
||||||
import com.android.layoutlib.bridge.impl.DelegateManager;
|
import com.android.layoutlib.bridge.impl.DelegateManager;
|
||||||
|
|
||||||
import java.awt.Paint;
|
import java.awt.Paint;
|
||||||
|
import java.awt.geom.AffineTransform;
|
||||||
|
import java.awt.geom.NoninvertibleTransformException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delegate implementing the native methods of android.graphics.SweepGradient
|
* Delegate implementing the native methods of android.graphics.SweepGradient
|
||||||
@ -90,16 +93,16 @@ public class SweepGradient_Delegate extends Gradient_Delegate {
|
|||||||
private SweepGradient_Delegate(float cx, float cy,
|
private SweepGradient_Delegate(float cx, float cy,
|
||||||
int colors[], float positions[]) {
|
int colors[], float positions[]) {
|
||||||
super(colors, positions);
|
super(colors, positions);
|
||||||
|
|
||||||
mJavaPaint = new SweepGradientPaint(cx, cy, mColors, mPositions);
|
mJavaPaint = new SweepGradientPaint(cx, cy, mColors, mPositions);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class SweepGradientPaint extends GradientPaint {
|
private class SweepGradientPaint extends GradientPaint {
|
||||||
|
|
||||||
private final float mCx;
|
private final float mCx;
|
||||||
private final float mCy;
|
private final float mCy;
|
||||||
|
|
||||||
public SweepGradientPaint(float cx, float cy, int[] colors, float[] positions) {
|
public SweepGradientPaint(float cx, float cy, int[] colors,
|
||||||
|
float[] positions) {
|
||||||
super(colors, positions, null /*tileMode*/);
|
super(colors, positions, null /*tileMode*/);
|
||||||
mCx = cx;
|
mCx = cx;
|
||||||
mCy = cy;
|
mCy = cy;
|
||||||
@ -112,14 +115,36 @@ public class SweepGradient_Delegate extends Gradient_Delegate {
|
|||||||
java.awt.geom.AffineTransform xform,
|
java.awt.geom.AffineTransform xform,
|
||||||
java.awt.RenderingHints hints) {
|
java.awt.RenderingHints hints) {
|
||||||
precomputeGradientColors();
|
precomputeGradientColors();
|
||||||
return new SweepGradientPaintContext(colorModel);
|
|
||||||
|
AffineTransform canvasMatrix;
|
||||||
|
try {
|
||||||
|
canvasMatrix = xform.createInverse();
|
||||||
|
} catch (NoninvertibleTransformException e) {
|
||||||
|
Bridge.getLog().error(null, "Unable to inverse matrix in SweepGradient", e);
|
||||||
|
canvasMatrix = new AffineTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
AffineTransform localMatrix = getLocalMatrix();
|
||||||
|
try {
|
||||||
|
localMatrix = localMatrix.createInverse();
|
||||||
|
} catch (NoninvertibleTransformException e) {
|
||||||
|
Bridge.getLog().error(null, "Unable to inverse matrix in SweepGradient", e);
|
||||||
|
localMatrix = new AffineTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new SweepGradientPaintContext(canvasMatrix, localMatrix, colorModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SweepGradientPaintContext implements java.awt.PaintContext {
|
private class SweepGradientPaintContext implements java.awt.PaintContext {
|
||||||
|
|
||||||
|
private final AffineTransform mCanvasMatrix;
|
||||||
|
private final AffineTransform mLocalMatrix;
|
||||||
private final java.awt.image.ColorModel mColorModel;
|
private final java.awt.image.ColorModel mColorModel;
|
||||||
|
|
||||||
public SweepGradientPaintContext(java.awt.image.ColorModel colorModel) {
|
public SweepGradientPaintContext(AffineTransform canvasMatrix,
|
||||||
|
AffineTransform localMatrix, java.awt.image.ColorModel colorModel) {
|
||||||
|
mCanvasMatrix = canvasMatrix;
|
||||||
|
mLocalMatrix = localMatrix;
|
||||||
mColorModel = colorModel;
|
mColorModel = colorModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,10 +164,23 @@ public class SweepGradient_Delegate extends Gradient_Delegate {
|
|||||||
// compute angle from each point to the center, and figure out the distance from
|
// compute angle from each point to the center, and figure out the distance from
|
||||||
// it.
|
// it.
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
float[] pt1 = new float[2];
|
||||||
|
float[] pt2 = new float[2];
|
||||||
for (int iy = 0 ; iy < h ; iy++) {
|
for (int iy = 0 ; iy < h ; iy++) {
|
||||||
for (int ix = 0 ; ix < w ; ix++) {
|
for (int ix = 0 ; ix < w ; ix++) {
|
||||||
float dx = x + ix - mCx;
|
// handle the canvas transform
|
||||||
float dy = y + iy - mCy;
|
pt1[0] = x + ix;
|
||||||
|
pt1[1] = y + iy;
|
||||||
|
mCanvasMatrix.transform(pt1, 0, pt2, 0, 1);
|
||||||
|
|
||||||
|
// handle the local matrix
|
||||||
|
pt1[0] = pt2[0] - mCx;
|
||||||
|
pt1[1] = pt2[1] - mCy;
|
||||||
|
mLocalMatrix.transform(pt1, 0, pt2, 0, 1);
|
||||||
|
|
||||||
|
float dx = pt2[0];
|
||||||
|
float dy = pt2[1];
|
||||||
|
|
||||||
float angle;
|
float angle;
|
||||||
if (dx == 0) {
|
if (dx == 0) {
|
||||||
angle = (float) (dy < 0 ? 3 * Math.PI / 2 : Math.PI / 2);
|
angle = (float) (dy < 0 ? 3 * Math.PI / 2 : Math.PI / 2);
|
||||||
|
Reference in New Issue
Block a user