From d9c64369cf9be6568af2d79c35fb470cc261730d Mon Sep 17 00:00:00 2001 From: Xavier Ducrohet Date: Tue, 14 Dec 2010 14:40:41 -0800 Subject: LayoutLib: Fix gradient rendering. - fully support canvas transform - fully support shader local transform - fix repeat/mirror issue in the negative values. Change-Id: Ib2aa7ade1c2702da4364cbda9a5a3ae72c1d3174 --- .../src/android/graphics/Gradient_Delegate.java | 21 +++--- .../android/graphics/LinearGradient_Delegate.java | 86 ++++++++++++---------- .../src/android/graphics/Matrix_Delegate.java | 2 +- .../android/graphics/RadialGradient_Delegate.java | 52 +++++++++++-- .../src/android/graphics/Shader_Delegate.java | 17 +++++ .../android/graphics/SweepGradient_Delegate.java | 52 +++++++++++-- 6 files changed, 166 insertions(+), 64 deletions(-) (limited to 'tools') diff --git a/tools/layoutlib/bridge/src/android/graphics/Gradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Gradient_Delegate.java index 042d557..bc4ccd2 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Gradient_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Gradient_Delegate.java @@ -119,20 +119,23 @@ public abstract class Gradient_Delegate extends Shader_Delegate { 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); + // remove the integer part to stay in the [0,1] range. + // we also need to invert the value from [-1,0] to [0, 1] + pos = pos - (float)Math.floor(pos); break; 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 - // careful: this is a negative value, so use ceil instead of floor - int intPart = (int)Math.ceil(pos); + int intPart = (int)Math.floor(pos); pos = pos - intPart; - // 0 -> -1 : mirrored order - // -1 -> -2: normal order + // 0 -> 1 : normal order + // 1 -> 2: mirrored // etc.. - // this means if the intpart is even we invert - if ((intPart % 2) == 0) { + // this means if the intpart is odd we invert + if ((intPart % 2) == 1) { pos = 1.f - pos; } break; diff --git a/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java index 7573dc1..862b4544 100644 --- a/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java @@ -16,11 +16,14 @@ package android.graphics; +import com.android.layoutlib.bridge.Bridge; import com.android.layoutlib.bridge.impl.DelegateManager; import android.graphics.Shader.TileMode; import java.awt.Paint; +import java.awt.geom.AffineTransform; +import java.awt.geom.NoninvertibleTransformException; /** * 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 * modes. */ - private static class LinearGradientPaint extends GradientPaint { + private class LinearGradientPaint extends GradientPaint { private final float mX0; 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[], float positions[], TileMode tile) { super(colors, positions, tile); - mX0 = x0; - mY0 = y0; - mDx = x1 - x0; - mDy = y1 - y0; - mDSize2 = mDx * mDx + mDy * mDy; + mX0 = x0; + mY0 = y0; + mDx = x1 - x0; + mDy = y1 - y0; + mDSize2 = mDx * mDx + mDy * mDy; } public java.awt.PaintContext createContext( @@ -140,16 +143,37 @@ public class LinearGradient_Delegate extends Gradient_Delegate { java.awt.geom.AffineTransform xform, java.awt.RenderingHints hints) { 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 final AffineTransform mCanvasMatrix; + private final AffineTransform mLocalMatrix; 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; - // FIXME: so far all this is always the same rect gotten in getRaster with an identity matrix? } public void dispose() { @@ -165,31 +189,22 @@ public class LinearGradient_Delegate extends Gradient_Delegate { int[] data = new int[w*h]; - 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[index++] = color; - } - } - } else if (mDy == 0) { // horizontal - // compute first line in a tmp array and copy to all lines - int[] line = new int[w]; + int index = 0; + float[] pt1 = new float[2]; + float[] pt2 = new float[2]; + for (int iy = 0 ; iy < h ; iy++) { 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++) { - System.arraycopy(line, 0, data, iy*w, line.length); - } - } else { - int index = 0; - for (int iy = 0 ; iy < h ; iy++) { - for (int ix = 0 ; ix < w ; ix++) { - data[index++] = getColor(ix + x, iy + y); - } + // handle the local matrix. + pt1[0] = pt2[0]; + pt1[1] = pt2[1]; + mLocalMatrix.transform(pt1, 0, pt2, 0, 1); + + data[index++] = getColor(pt2[0], pt2[1]); } } @@ -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. */ diff --git a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java index bef8c8c..6b43544 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java @@ -471,7 +471,7 @@ public final class Matrix_Delegate { return false; } - d.preTransform(getRotate(degrees, px, py)); + d.postTransform(getRotate(degrees, px, py)); return true; } diff --git a/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java index c36ce53..eebf378 100644 --- a/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java @@ -16,11 +16,14 @@ package android.graphics; +import com.android.layoutlib.bridge.Bridge; import com.android.layoutlib.bridge.impl.DelegateManager; import android.graphics.Shader.TileMode; import java.awt.Paint; +import java.awt.geom.AffineTransform; +import java.awt.geom.NoninvertibleTransformException; /** * 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[], TileMode tile) { super(colors, positions); - 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 mY; private final float mRadius; - public RadialGradientPaint(float x, float y, float radius, int[] colors, float[] positions, - TileMode mode) { + public RadialGradientPaint(float x, float y, float radius, + int[] colors, float[] positions, TileMode mode) { super(colors, positions, mode); mX = x; mY = y; @@ -130,14 +132,36 @@ public class RadialGradient_Delegate extends Gradient_Delegate { java.awt.geom.AffineTransform xform, java.awt.RenderingHints hints) { 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 final AffineTransform mCanvasMatrix; + private final AffineTransform mLocalMatrix; 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; } @@ -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 // it. int index = 0; + float[] pt1 = new float[2]; + float[] pt2 = new float[2]; for (int iy = 0 ; iy < h ; iy++) { for (int ix = 0 ; ix < w ; ix++) { - float _x = x + ix - mX; - float _y = y + iy - mY; + // handle the canvas transform + 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); data[index++] = getGradientColor(distance / mRadius); diff --git a/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java index 646ac80..7bf1443 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java @@ -18,6 +18,8 @@ package android.graphics; import com.android.layoutlib.bridge.impl.DelegateManager; +import java.awt.geom.AffineTransform; + /** * Delegate implementing the native methods of android.graphics.Shader * @@ -109,4 +111,19 @@ public abstract class Shader_Delegate { // ---- 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(); + } + } diff --git a/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java index 358c3c7..97c3cfd 100644 --- a/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java @@ -16,9 +16,12 @@ package android.graphics; +import com.android.layoutlib.bridge.Bridge; import com.android.layoutlib.bridge.impl.DelegateManager; import java.awt.Paint; +import java.awt.geom.AffineTransform; +import java.awt.geom.NoninvertibleTransformException; /** * 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, int colors[], float positions[]) { super(colors, positions); - 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 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*/); mCx = cx; mCy = cy; @@ -112,14 +115,36 @@ public class SweepGradient_Delegate extends Gradient_Delegate { java.awt.geom.AffineTransform xform, java.awt.RenderingHints hints) { 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 final AffineTransform mCanvasMatrix; + private final AffineTransform mLocalMatrix; 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; } @@ -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 // it. int index = 0; + float[] pt1 = new float[2]; + float[] pt2 = new float[2]; for (int iy = 0 ; iy < h ; iy++) { for (int ix = 0 ; ix < w ; ix++) { - float dx = x + ix - mCx; - float dy = y + iy - mCy; + // handle the canvas transform + 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; if (dx == 0) { angle = (float) (dy < 0 ? 3 * Math.PI / 2 : Math.PI / 2); -- cgit v1.1