diff --git a/tools/layoutlib/bridge/src/android/graphics/BaseCanvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BaseCanvas_Delegate.java new file mode 100644 index 0000000000000..df858067ba045 --- /dev/null +++ b/tools/layoutlib/bridge/src/android/graphics/BaseCanvas_Delegate.java @@ -0,0 +1,727 @@ +/* + * Copyright (C) 2016 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; + +import com.android.ide.common.rendering.api.LayoutLog; +import com.android.layoutlib.bridge.Bridge; +import com.android.layoutlib.bridge.impl.DelegateManager; +import com.android.layoutlib.bridge.impl.GcSnapshot; +import com.android.layoutlib.bridge.impl.PorterDuffUtility; +import com.android.ninepatch.NinePatchChunk; +import com.android.tools.layoutlib.annotations.LayoutlibDelegate; + +import android.text.TextUtils; + +import java.awt.*; +import java.awt.geom.AffineTransform; +import java.awt.geom.Arc2D; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; + +public class BaseCanvas_Delegate { + // ---- delegate manager ---- + protected static DelegateManager sManager = + new DelegateManager<>(BaseCanvas_Delegate.class); + + // ---- delegate helper data ---- + private final static boolean[] sBoolOut = new boolean[1]; + + + // ---- delegate data ---- + protected Bitmap_Delegate mBitmap; + protected GcSnapshot mSnapshot; + + // ---- Public Helper methods ---- + + protected BaseCanvas_Delegate(Bitmap_Delegate bitmap) { + mSnapshot = GcSnapshot.createDefaultSnapshot(mBitmap = bitmap); + } + + protected BaseCanvas_Delegate() { + mSnapshot = GcSnapshot.createDefaultSnapshot(null /*image*/); + } + + /** + * Disposes of the {@link Graphics2D} stack. + */ + protected void dispose() { + mSnapshot.dispose(); + } + + /** + * Returns the current {@link Graphics2D} used to draw. + */ + public GcSnapshot getSnapshot() { + return mSnapshot; + } + + // ---- native methods ---- + + @LayoutlibDelegate + /*package*/ static void nDrawBitmap(long nativeCanvas, Bitmap bitmap, float left, float top, + long nativePaintOrZero, int canvasDensity, int screenDensity, int bitmapDensity) { + // get the delegate from the native int. + Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap); + if (bitmapDelegate == null) { + return; + } + + BufferedImage image = bitmapDelegate.getImage(); + float right = left + image.getWidth(); + float bottom = top + image.getHeight(); + + drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero, + 0, 0, image.getWidth(), image.getHeight(), + (int)left, (int)top, (int)right, (int)bottom); + } + + @LayoutlibDelegate + /*package*/ static void nDrawBitmap(long nativeCanvas, Bitmap bitmap, float srcLeft, float srcTop, + float srcRight, float srcBottom, float dstLeft, float dstTop, float dstRight, + float dstBottom, long nativePaintOrZero, int screenDensity, int bitmapDensity) { + // get the delegate from the native int. + Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap); + if (bitmapDelegate == null) { + return; + } + + drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero, (int) srcLeft, (int) srcTop, + (int) srcRight, (int) srcBottom, (int) dstLeft, (int) dstTop, (int) dstRight, + (int) dstBottom); + } + + @LayoutlibDelegate + /*package*/ static void nDrawBitmap(long nativeCanvas, int[] colors, int offset, int stride, + final float x, final float y, int width, int height, boolean hasAlpha, + long nativePaintOrZero) { + // create a temp BufferedImage containing the content. + final BufferedImage image = new BufferedImage(width, height, + hasAlpha ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB); + image.setRGB(0, 0, width, height, colors, offset, stride); + + draw(nativeCanvas, nativePaintOrZero, true /*compositeOnly*/, false /*forceSrcMode*/, + (graphics, paint) -> { + if (paint != null && paint.isFilterBitmap()) { + graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BILINEAR); + } + + graphics.drawImage(image, (int) x, (int) y, null); + }); + } + + @LayoutlibDelegate + /*package*/ static void nDrawColor(long nativeCanvas, final int color, final int mode) { + // get the delegate from the native int. + BaseCanvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); + if (canvasDelegate == null) { + return; + } + + final int w = canvasDelegate.mBitmap.getImage().getWidth(); + final int h = canvasDelegate.mBitmap.getImage().getHeight(); + draw(nativeCanvas, (graphics, paint) -> { + // reset its transform just in case + graphics.setTransform(new AffineTransform()); + + // set the color + graphics.setColor(new java.awt.Color(color, true /*alpha*/)); + + Composite composite = PorterDuffUtility.getComposite( + PorterDuffUtility.getPorterDuffMode(mode), 0xFF); + if (composite != null) { + graphics.setComposite(composite); + } + + graphics.fillRect(0, 0, w, h); + }); + } + + @LayoutlibDelegate + /*package*/ static void nDrawPaint(long nativeCanvas, long paint) { + // FIXME + Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, + "Canvas.drawPaint is not supported.", null, null /*data*/); + } + + @LayoutlibDelegate + /*package*/ static void nDrawPoint(long nativeCanvas, float x, float y, + long nativePaint) { + // FIXME + Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, + "Canvas.drawPoint is not supported.", null, null /*data*/); + } + + @LayoutlibDelegate + /*package*/ static void nDrawPoints(long nativeCanvas, float[] pts, int offset, int count, + long nativePaint) { + // FIXME + Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, + "Canvas.drawPoint is not supported.", null, null /*data*/); + } + + @LayoutlibDelegate + /*package*/ static void nDrawLine(long nativeCanvas, + final float startX, final float startY, final float stopX, final float stopY, + long paint) { + draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/, + (graphics, paintDelegate) -> graphics.drawLine((int)startX, (int)startY, (int)stopX, (int)stopY)); + } + + @LayoutlibDelegate + /*package*/ static void nDrawLines(long nativeCanvas, + final float[] pts, final int offset, final int count, + long nativePaint) { + draw(nativeCanvas, nativePaint, false /*compositeOnly*/, + false /*forceSrcMode*/, (graphics, paintDelegate) -> { + for (int i = 0; i < count; i += 4) { + graphics.drawLine((int) pts[i + offset], (int) pts[i + offset + 1], + (int) pts[i + offset + 2], (int) pts[i + offset + 3]); + } + }); + } + + @LayoutlibDelegate + /*package*/ static void nDrawRect(long nativeCanvas, + final float left, final float top, final float right, final float bottom, long paint) { + + draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/, + (graphics, paintDelegate) -> { + int style = paintDelegate.getStyle(); + + // draw + if (style == Paint.Style.FILL.nativeInt || + style == Paint.Style.FILL_AND_STROKE.nativeInt) { + graphics.fillRect((int)left, (int)top, + (int)(right-left), (int)(bottom-top)); + } + + if (style == Paint.Style.STROKE.nativeInt || + style == Paint.Style.FILL_AND_STROKE.nativeInt) { + graphics.drawRect((int)left, (int)top, + (int)(right-left), (int)(bottom-top)); + } + }); + } + + @LayoutlibDelegate + /*package*/ static void nDrawOval(long nativeCanvas, final float left, + final float top, final float right, final float bottom, long paint) { + if (right > left && bottom > top) { + draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/, + (graphics, paintDelegate) -> { + int style = paintDelegate.getStyle(); + + // draw + if (style == Paint.Style.FILL.nativeInt || + style == Paint.Style.FILL_AND_STROKE.nativeInt) { + graphics.fillOval((int)left, (int)top, + (int)(right - left), (int)(bottom - top)); + } + + if (style == Paint.Style.STROKE.nativeInt || + style == Paint.Style.FILL_AND_STROKE.nativeInt) { + graphics.drawOval((int)left, (int)top, + (int)(right - left), (int)(bottom - top)); + } + }); + } + } + + @LayoutlibDelegate + /*package*/ static void nDrawCircle(long nativeCanvas, + float cx, float cy, float radius, long paint) { + nDrawOval(nativeCanvas, + cx - radius, cy - radius, cx + radius, cy + radius, + paint); + } + + @LayoutlibDelegate + /*package*/ static void nDrawArc(long nativeCanvas, + final float left, final float top, final float right, final float bottom, + final float startAngle, final float sweep, + final boolean useCenter, long paint) { + if (right > left && bottom > top) { + draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/, + (graphics, paintDelegate) -> { + int style = paintDelegate.getStyle(); + + Arc2D.Float arc = new Arc2D.Float( + left, top, right - left, bottom - top, + -startAngle, -sweep, + useCenter ? Arc2D.PIE : Arc2D.OPEN); + + // draw + if (style == Paint.Style.FILL.nativeInt || + style == Paint.Style.FILL_AND_STROKE.nativeInt) { + graphics.fill(arc); + } + + if (style == Paint.Style.STROKE.nativeInt || + style == Paint.Style.FILL_AND_STROKE.nativeInt) { + graphics.draw(arc); + } + }); + } + } + + @LayoutlibDelegate + /*package*/ static void nDrawRoundRect(long nativeCanvas, + final float left, final float top, final float right, final float bottom, + final float rx, final float ry, long paint) { + draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/, + (graphics, paintDelegate) -> { + int style = paintDelegate.getStyle(); + + // draw + if (style == Paint.Style.FILL.nativeInt || + style == Paint.Style.FILL_AND_STROKE.nativeInt) { + graphics.fillRoundRect( + (int)left, (int)top, + (int)(right - left), (int)(bottom - top), + 2 * (int)rx, 2 * (int)ry); + } + + if (style == Paint.Style.STROKE.nativeInt || + style == Paint.Style.FILL_AND_STROKE.nativeInt) { + graphics.drawRoundRect( + (int)left, (int)top, + (int)(right - left), (int)(bottom - top), + 2 * (int)rx, 2 * (int)ry); + } + }); + } + + @LayoutlibDelegate + public static void nDrawPath(long nativeCanvas, long path, long paint) { + final Path_Delegate pathDelegate = Path_Delegate.getDelegate(path); + if (pathDelegate == null) { + return; + } + + draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/, + (graphics, paintDelegate) -> { + Shape shape = pathDelegate.getJavaShape(); + Rectangle2D bounds = shape.getBounds2D(); + if (bounds.isEmpty()) { + // Apple JRE 1.6 doesn't like drawing empty shapes. + // http://b.android.com/178278 + + if (pathDelegate.isEmpty()) { + // This means that the path doesn't have any lines or curves so + // nothing to draw. + return; + } + + // The stroke width is not consider for the size of the bounds so, + // for example, a horizontal line, would be considered as an empty + // rectangle. + // If the strokeWidth is not 0, we use it to consider the size of the + // path as well. + float strokeWidth = paintDelegate.getStrokeWidth(); + if (strokeWidth <= 0.0f) { + return; + } + bounds.setRect(bounds.getX(), bounds.getY(), + Math.max(strokeWidth, bounds.getWidth()), + Math.max(strokeWidth, bounds.getHeight())); + } + + int style = paintDelegate.getStyle(); + + if (style == Paint.Style.FILL.nativeInt || + style == Paint.Style.FILL_AND_STROKE.nativeInt) { + graphics.fill(shape); + } + + if (style == Paint.Style.STROKE.nativeInt || + style == Paint.Style.FILL_AND_STROKE.nativeInt) { + graphics.draw(shape); + } + }); + } + + @LayoutlibDelegate + /*package*/ static void nDrawRegion(long nativeCanvas, long nativeRegion, + long nativePaint) { + // FIXME + Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, + "Some canvas paths may not be drawn", null, null); + } + + @LayoutlibDelegate + /*package*/ static void nDrawNinePatch(long nativeCanvas, long nativeBitmap, long ninePatch, + final float dstLeft, final float dstTop, final float dstRight, final float dstBottom, + long nativePaintOrZero, final int screenDensity, final int bitmapDensity) { + + // get the delegate from the native int. + final Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(nativeBitmap); + if (bitmapDelegate == null) { + return; + } + + byte[] c = NinePatch_Delegate.getChunk(ninePatch); + if (c == null) { + // not a 9-patch? + BufferedImage image = bitmapDelegate.getImage(); + drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero, 0, 0, image.getWidth(), + image.getHeight(), (int) dstLeft, (int) dstTop, (int) dstRight, + (int) dstBottom); + return; + } + + final NinePatchChunk chunkObject = NinePatch_Delegate.getChunk(c); + assert chunkObject != null; + if (chunkObject == null) { + return; + } + + Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); + if (canvasDelegate == null) { + return; + } + + // this one can be null + Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nativePaintOrZero); + + canvasDelegate.getSnapshot().draw(new GcSnapshot.Drawable() { + @Override + public void draw(Graphics2D graphics, Paint_Delegate paint) { + chunkObject.draw(bitmapDelegate.getImage(), graphics, (int) dstLeft, (int) dstTop, + (int) (dstRight - dstLeft), (int) (dstBottom - dstTop), screenDensity, + bitmapDensity); + } + }, paintDelegate, true, false); + + } + + @LayoutlibDelegate + /*package*/ static void nDrawBitmapMatrix(long nCanvas, Bitmap bitmap, + long nMatrix, long nPaint) { + // get the delegate from the native int. + BaseCanvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas); + if (canvasDelegate == null) { + return; + } + + // get the delegate from the native int, which can be null + Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nPaint); + + // get the delegate from the native int. + Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap); + if (bitmapDelegate == null) { + return; + } + + final BufferedImage image = getImageToDraw(bitmapDelegate, paintDelegate, sBoolOut); + + Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix); + if (matrixDelegate == null) { + return; + } + + final AffineTransform mtx = matrixDelegate.getAffineTransform(); + + canvasDelegate.getSnapshot().draw((graphics, paint) -> { + if (paint != null && paint.isFilterBitmap()) { + graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BILINEAR); + } + + //FIXME add support for canvas, screen and bitmap densities. + graphics.drawImage(image, mtx, null); + }, paintDelegate, true /*compositeOnly*/, false /*forceSrcMode*/); + } + + @LayoutlibDelegate + /*package*/ static void nDrawBitmapMesh(long nCanvas, Bitmap bitmap, + int meshWidth, int meshHeight, float[] verts, int vertOffset, int[] colors, + int colorOffset, long nPaint) { + // FIXME + Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, + "Canvas.drawBitmapMesh is not supported.", null, null /*data*/); + } + + @LayoutlibDelegate + /*package*/ static void nDrawVertices(long nCanvas, int mode, int n, + float[] verts, int vertOffset, + float[] texs, int texOffset, + int[] colors, int colorOffset, + short[] indices, int indexOffset, + int indexCount, long nPaint) { + // FIXME + Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, + "Canvas.drawVertices is not supported.", null, null /*data*/); + } + + @LayoutlibDelegate + /*package*/ static void nDrawText(long nativeCanvas, char[] text, int index, int count, + float startX, float startY, int flags, long paint, long typeface) { + drawText(nativeCanvas, text, index, count, startX, startY, (flags & 1) != 0, + paint, typeface); + } + + @LayoutlibDelegate + /*package*/ static void nDrawText(long nativeCanvas, String text, + int start, int end, float x, float y, final int flags, long paint, + long typeface) { + int count = end - start; + char[] buffer = TemporaryBuffer.obtain(count); + TextUtils.getChars(text, start, end, buffer, 0); + + nDrawText(nativeCanvas, buffer, 0, count, x, y, flags, paint, typeface); + } + + @LayoutlibDelegate + /*package*/ static void nDrawTextRun(long nativeCanvas, String text, + int start, int end, int contextStart, int contextEnd, + float x, float y, boolean isRtl, long paint, long typeface) { + int count = end - start; + char[] buffer = TemporaryBuffer.obtain(count); + TextUtils.getChars(text, start, end, buffer, 0); + + drawText(nativeCanvas, buffer, 0, count, x, y, isRtl, paint, typeface); + } + + @LayoutlibDelegate + /*package*/ static void nDrawTextRun(long nativeCanvas, char[] text, + int start, int count, int contextStart, int contextCount, + float x, float y, boolean isRtl, long paint, long typeface) { + drawText(nativeCanvas, text, start, count, x, y, isRtl, paint, typeface); + } + + @LayoutlibDelegate + /*package*/ static void nDrawTextOnPath(long nativeCanvas, + char[] text, int index, + int count, long path, + float hOffset, + float vOffset, int bidiFlags, + long paint, long typeface) { + // FIXME + Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, + "Canvas.drawTextOnPath is not supported.", null, null /*data*/); + } + + @LayoutlibDelegate + /*package*/ static void nDrawTextOnPath(long nativeCanvas, + String text, long path, + float hOffset, + float vOffset, + int bidiFlags, long paint, + long typeface) { + // FIXME + Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, + "Canvas.drawTextOnPath is not supported.", null, null /*data*/); + } + + // ---- Private delegate/helper methods ---- + + /** + * Executes a {@link GcSnapshot.Drawable} with a given canvas and paint. + *

Note that the drawable may actually be executed several times if there are + * layers involved (see {@link #saveLayer(RectF, Paint_Delegate, int)}. + */ + private static void draw(long nCanvas, long nPaint, boolean compositeOnly, boolean forceSrcMode, + GcSnapshot.Drawable drawable) { + // get the delegate from the native int. + BaseCanvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas); + if (canvasDelegate == null) { + return; + } + + // get the paint which can be null if nPaint is 0; + Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nPaint); + + canvasDelegate.getSnapshot().draw(drawable, paintDelegate, compositeOnly, forceSrcMode); + } + + /** + * Executes a {@link GcSnapshot.Drawable} with a given canvas. No paint object will be provided + * to {@link GcSnapshot.Drawable#draw(Graphics2D, Paint_Delegate)}. + *

Note that the drawable may actually be executed several times if there are + * layers involved (see {@link #saveLayer(RectF, Paint_Delegate, int)}. + */ + private static void draw(long nCanvas, GcSnapshot.Drawable drawable) { + // get the delegate from the native int. + BaseCanvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas); + if (canvasDelegate == null) { + return; + } + + canvasDelegate.mSnapshot.draw(drawable); + } + + private static void drawText(long nativeCanvas, final char[] text, final int index, + final int count, final float startX, final float startY, final boolean isRtl, + long paint, final long typeface) { + + draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/, + (graphics, paintDelegate) -> { + // WARNING: the logic in this method is similar to Paint_Delegate.measureText. + // Any change to this method should be reflected in Paint.measureText + + // assert that the typeface passed is actually the one stored in paint. + assert (typeface == paintDelegate.mNativeTypeface); + + // Paint.TextAlign indicates how the text is positioned relative to X. + // LEFT is the default and there's nothing to do. + float x = startX; + int limit = index + count; + if (paintDelegate.getTextAlign() != Paint.Align.LEFT.nativeInt) { + RectF bounds = + paintDelegate.measureText(text, index, count, null, 0, isRtl); + float m = bounds.right - bounds.left; + if (paintDelegate.getTextAlign() == Paint.Align.CENTER.nativeInt) { + x -= m / 2; + } else if (paintDelegate.getTextAlign() == Paint.Align.RIGHT.nativeInt) { + x -= m; + } + } + + new BidiRenderer(graphics, paintDelegate, text).setRenderLocation(x, + startY).renderText(index, limit, isRtl, null, 0, true); + }); + } + + private static void drawBitmap(long nativeCanvas, Bitmap_Delegate bitmap, + long nativePaintOrZero, final int sleft, final int stop, final int sright, + final int sbottom, final int dleft, final int dtop, final int dright, + final int dbottom) { + // get the delegate from the native int. + BaseCanvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); + if (canvasDelegate == null) { + return; + } + + // get the paint, which could be null if the int is 0 + Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nativePaintOrZero); + + final BufferedImage image = getImageToDraw(bitmap, paintDelegate, sBoolOut); + + draw(nativeCanvas, nativePaintOrZero, true /*compositeOnly*/, sBoolOut[0], + (graphics, paint) -> { + if (paint != null && paint.isFilterBitmap()) { + graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BILINEAR); + } + + //FIXME add support for canvas, screen and bitmap densities. + graphics.drawImage(image, dleft, dtop, dright, dbottom, sleft, stop, sright, + sbottom, null); + }); + } + + /** + * Returns a BufferedImage ready for drawing, based on the bitmap and paint delegate. + * The image returns, through a 1-size boolean array, whether the drawing code should + * use a SRC composite no matter what the paint says. + * + * @param bitmap the bitmap + * @param paint the paint that will be used to draw + * @param forceSrcMode whether the composite will have to be SRC + * @return the image to draw + */ + private static BufferedImage getImageToDraw(Bitmap_Delegate bitmap, Paint_Delegate paint, + boolean[] forceSrcMode) { + BufferedImage image = bitmap.getImage(); + forceSrcMode[0] = false; + + // if the bitmap config is alpha_8, then we erase all color value from it + // before drawing it. + if (bitmap.getConfig() == Bitmap.Config.ALPHA_8) { + fixAlpha8Bitmap(image); + } else if (!bitmap.hasAlpha()) { + // hasAlpha is merely a rendering hint. There can in fact be alpha values + // in the bitmap but it should be ignored at drawing time. + // There is two ways to do this: + // - override the composite to be SRC. This can only be used if the composite + // was going to be SRC or SRC_OVER in the first place + // - Create a different bitmap to draw in which all the alpha channel values is set + // to 0xFF. + if (paint != null) { + PorterDuff.Mode mode = PorterDuff.intToMode(paint.getPorterDuffMode()); + + forceSrcMode[0] = mode == PorterDuff.Mode.SRC_OVER || mode == PorterDuff.Mode.SRC; + } + + // if we can't force SRC mode, then create a temp bitmap of TYPE_RGB + if (!forceSrcMode[0]) { + image = Bitmap_Delegate.createCopy(image, BufferedImage.TYPE_INT_RGB, 0xFF); + } + } + + return image; + } + + private static void fixAlpha8Bitmap(final BufferedImage image) { + int w = image.getWidth(); + int h = image.getHeight(); + int[] argb = new int[w * h]; + image.getRGB(0, 0, image.getWidth(), image.getHeight(), argb, 0, image.getWidth()); + + final int length = argb.length; + for (int i = 0 ; i < length; i++) { + argb[i] &= 0xFF000000; + } + image.setRGB(0, 0, w, h, argb, 0, w); + } + + protected int save(int saveFlags) { + // get the current save count + int count = mSnapshot.size(); + + mSnapshot = mSnapshot.save(saveFlags); + + // return the old save count + return count; + } + + protected int saveLayerAlpha(RectF rect, int alpha, int saveFlags) { + Paint_Delegate paint = new Paint_Delegate(); + paint.setAlpha(alpha); + return saveLayer(rect, paint, saveFlags); + } + + protected int saveLayer(RectF rect, Paint_Delegate paint, int saveFlags) { + // get the current save count + int count = mSnapshot.size(); + + mSnapshot = mSnapshot.saveLayer(rect, paint, saveFlags); + + // return the old save count + return count; + } + + /** + * Restores the {@link GcSnapshot} to saveCount + * @param saveCount the saveCount + */ + protected void restoreTo(int saveCount) { + mSnapshot = mSnapshot.restoreTo(saveCount); + } + + /** + * Restores the top {@link GcSnapshot} + */ + protected void restore() { + mSnapshot = mSnapshot.restore(); + } + + protected boolean clipRect(float left, float top, float right, float bottom, int regionOp) { + return mSnapshot.clipRect(left, top, right, bottom, regionOp); + } +} diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java index 94152cd73ca20..43a0ff5a23dcb 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java @@ -55,40 +55,27 @@ import libcore.util.NativeAllocationRegistry_Delegate; * @see DelegateManager * */ -public final class Canvas_Delegate { +public final class Canvas_Delegate extends BaseCanvas_Delegate { // ---- delegate manager ---- - private static final DelegateManager sManager = - new DelegateManager(Canvas_Delegate.class); private static long sFinalizer = -1; - - // ---- delegate helper data ---- - - private final static boolean[] sBoolOut = new boolean[1]; - - - // ---- delegate data ---- - private Bitmap_Delegate mBitmap; - private GcSnapshot mSnapshot; - private DrawFilter_Delegate mDrawFilter = null; - // ---- Public Helper methods ---- /** * Returns the native delegate associated to a given {@link Canvas} object. */ public static Canvas_Delegate getDelegate(Canvas canvas) { - return sManager.getDelegate(canvas.getNativeCanvasWrapper()); + return (Canvas_Delegate) sManager.getDelegate(canvas.getNativeCanvasWrapper()); } /** * Returns the native delegate associated to a given an int referencing a {@link Canvas} object. */ public static Canvas_Delegate getDelegate(long native_canvas) { - return sManager.getDelegate(native_canvas); + return (Canvas_Delegate) sManager.getDelegate(native_canvas); } /** @@ -143,7 +130,7 @@ public final class Canvas_Delegate { @LayoutlibDelegate public static void nSetBitmap(long canvas, Bitmap bitmap) { - Canvas_Delegate canvasDelegate = sManager.getDelegate(canvas); + Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(canvas); Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap); if (canvasDelegate == null || bitmapDelegate==null) { return; @@ -155,7 +142,7 @@ public final class Canvas_Delegate { @LayoutlibDelegate public static boolean nIsOpaque(long nativeCanvas) { // get the delegate from the native int. - Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); + Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); if (canvasDelegate == null) { return false; } @@ -169,7 +156,7 @@ public final class Canvas_Delegate { @LayoutlibDelegate public static int nGetWidth(long nativeCanvas) { // get the delegate from the native int. - Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); + Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); if (canvasDelegate == null) { return 0; } @@ -180,7 +167,7 @@ public final class Canvas_Delegate { @LayoutlibDelegate public static int nGetHeight(long nativeCanvas) { // get the delegate from the native int. - Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); + Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); if (canvasDelegate == null) { return 0; } @@ -191,7 +178,7 @@ public final class Canvas_Delegate { @LayoutlibDelegate public static int nSave(long nativeCanvas, int saveFlags) { // get the delegate from the native int. - Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); + Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); if (canvasDelegate == null) { return 0; } @@ -204,7 +191,7 @@ public final class Canvas_Delegate { float t, float r, float b, long paint, int layerFlags) { // get the delegate from the native int. - Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); + Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); if (canvasDelegate == null) { return 0; } @@ -223,7 +210,7 @@ public final class Canvas_Delegate { float t, float r, float b, int alpha, int layerFlags) { // get the delegate from the native int. - Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); + Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); if (canvasDelegate == null) { return 0; } @@ -235,7 +222,7 @@ public final class Canvas_Delegate { public static void nRestore(long nativeCanvas, boolean throwOnUnderflow) { // FIXME: implement throwOnUnderflow. // get the delegate from the native int. - Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); + Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); if (canvasDelegate == null) { return; } @@ -248,7 +235,7 @@ public final class Canvas_Delegate { boolean throwOnUnderflow) { // FIXME: implement throwOnUnderflow. // get the delegate from the native int. - Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); + Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); if (canvasDelegate == null) { return; } @@ -259,7 +246,7 @@ public final class Canvas_Delegate { @LayoutlibDelegate public static int nGetSaveCount(long nativeCanvas) { // get the delegate from the native int. - Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); + Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); if (canvasDelegate == null) { return 0; } @@ -270,7 +257,7 @@ public final class Canvas_Delegate { @LayoutlibDelegate public static void nTranslate(long nativeCanvas, float dx, float dy) { // get the delegate from the native int. - Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); + Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); if (canvasDelegate == null) { return; } @@ -281,7 +268,7 @@ public final class Canvas_Delegate { @LayoutlibDelegate public static void nScale(long nativeCanvas, float sx, float sy) { // get the delegate from the native int. - Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); + Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); if (canvasDelegate == null) { return; } @@ -292,7 +279,7 @@ public final class Canvas_Delegate { @LayoutlibDelegate public static void nRotate(long nativeCanvas, float degrees) { // get the delegate from the native int. - Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); + Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); if (canvasDelegate == null) { return; } @@ -303,7 +290,7 @@ public final class Canvas_Delegate { @LayoutlibDelegate public static void nSkew(long nativeCanvas, float kx, float ky) { // get the delegate from the native int. - Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); + Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); if (canvasDelegate == null) { return; } @@ -327,7 +314,7 @@ public final class Canvas_Delegate { @LayoutlibDelegate public static void nConcat(long nCanvas, long nMatrix) { // get the delegate from the native int. - Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas); + Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nCanvas); if (canvasDelegate == null) { return; } @@ -355,7 +342,7 @@ public final class Canvas_Delegate { @LayoutlibDelegate public static void nSetMatrix(long nCanvas, long nMatrix) { // get the delegate from the native int. - Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas); + Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nCanvas); if (canvasDelegate == null) { return; } @@ -388,7 +375,7 @@ public final class Canvas_Delegate { float right, float bottom, int regionOp) { // get the delegate from the native int. - Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas); + Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nCanvas); if (canvasDelegate == null) { return false; } @@ -400,7 +387,7 @@ public final class Canvas_Delegate { public static boolean nClipPath(long nativeCanvas, long nativePath, int regionOp) { - Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); + Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); if (canvasDelegate == null) { return true; } @@ -417,7 +404,7 @@ public final class Canvas_Delegate { public static boolean nClipRegion(long nativeCanvas, long nativeRegion, int regionOp) { - Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); + Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); if (canvasDelegate == null) { return true; } @@ -432,7 +419,7 @@ public final class Canvas_Delegate { @LayoutlibDelegate public static void nSetDrawFilter(long nativeCanvas, long nativeFilter) { - Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); + Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); if (canvasDelegate == null) { return; } @@ -449,7 +436,7 @@ public final class Canvas_Delegate { public static boolean nGetClipBounds(long nativeCanvas, Rect bounds) { // get the delegate from the native int. - Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); + Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); if (canvasDelegate == null) { return false; } @@ -469,7 +456,7 @@ public final class Canvas_Delegate { @LayoutlibDelegate public static void nGetCTM(long canvas, long matrix) { // get the delegate from the native int. - Canvas_Delegate canvasDelegate = sManager.getDelegate(canvas); + Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(canvas); if (canvasDelegate == null) { return; } @@ -498,509 +485,11 @@ public final class Canvas_Delegate { } @LayoutlibDelegate - public static void nDrawColor(long nativeCanvas, final int color, final int mode) { - // get the delegate from the native int. - Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); - if (canvasDelegate == null) { - return; - } - - final int w = canvasDelegate.mBitmap.getImage().getWidth(); - final int h = canvasDelegate.mBitmap.getImage().getHeight(); - draw(nativeCanvas, new GcSnapshot.Drawable() { - - @Override - public void draw(Graphics2D graphics, Paint_Delegate paint) { - // reset its transform just in case - graphics.setTransform(new AffineTransform()); - - // set the color - graphics.setColor(new Color(color, true /*alpha*/)); - - Composite composite = PorterDuffUtility.getComposite( - PorterDuffUtility.getPorterDuffMode(mode), 0xFF); - if (composite != null) { - graphics.setComposite(composite); - } - - graphics.fillRect(0, 0, w, h); - } - }); - } - - @LayoutlibDelegate - public static void nDrawPaint(long nativeCanvas, long paint) { - // FIXME - Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, - "Canvas.drawPaint is not supported.", null, null /*data*/); - } - - @LayoutlibDelegate - public static void nDrawPoint(long nativeCanvas, float x, float y, - long nativePaint) { - // FIXME - Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, - "Canvas.drawPoint is not supported.", null, null /*data*/); - } - - @LayoutlibDelegate - public static void nDrawPoints(long nativeCanvas, float[] pts, int offset, int count, - long nativePaint) { - // FIXME - Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, - "Canvas.drawPoint is not supported.", null, null /*data*/); - } - - @LayoutlibDelegate - public static void nDrawLine(long nativeCanvas, - final float startX, final float startY, final float stopX, final float stopY, - long paint) { - draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/, - new GcSnapshot.Drawable() { - @Override - public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) { - graphics.drawLine((int)startX, (int)startY, (int)stopX, (int)stopY); - } - }); - } - - @LayoutlibDelegate - public static void nDrawLines(long nativeCanvas, - final float[] pts, final int offset, final int count, - long nativePaint) { - draw(nativeCanvas, nativePaint, false /*compositeOnly*/, - false /*forceSrcMode*/, new GcSnapshot.Drawable() { - @Override - public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) { - for (int i = 0; i < count; i += 4) { - graphics.drawLine((int) pts[i + offset], (int) pts[i + offset + 1], - (int) pts[i + offset + 2], (int) pts[i + offset + 3]); - } - } - }); - } - - @LayoutlibDelegate - public static void nDrawRect(long nativeCanvas, - final float left, final float top, final float right, final float bottom, long paint) { - - draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/, - new GcSnapshot.Drawable() { - @Override - public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) { - int style = paintDelegate.getStyle(); - - // draw - if (style == Paint.Style.FILL.nativeInt || - style == Paint.Style.FILL_AND_STROKE.nativeInt) { - graphics.fillRect((int)left, (int)top, - (int)(right-left), (int)(bottom-top)); - } - - if (style == Paint.Style.STROKE.nativeInt || - style == Paint.Style.FILL_AND_STROKE.nativeInt) { - graphics.drawRect((int)left, (int)top, - (int)(right-left), (int)(bottom-top)); - } - } - }); - } - - @LayoutlibDelegate - public static void nDrawOval(long nativeCanvas, final float left, - final float top, final float right, final float bottom, long paint) { - if (right > left && bottom > top) { - draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/, - new GcSnapshot.Drawable() { - @Override - public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) { - int style = paintDelegate.getStyle(); - - // draw - if (style == Paint.Style.FILL.nativeInt || - style == Paint.Style.FILL_AND_STROKE.nativeInt) { - graphics.fillOval((int)left, (int)top, - (int)(right - left), (int)(bottom - top)); - } - - if (style == Paint.Style.STROKE.nativeInt || - style == Paint.Style.FILL_AND_STROKE.nativeInt) { - graphics.drawOval((int)left, (int)top, - (int)(right - left), (int)(bottom - top)); - } - } - }); - } - } - - @LayoutlibDelegate - public static void nDrawCircle(long nativeCanvas, - float cx, float cy, float radius, long paint) { - nDrawOval(nativeCanvas, - cx - radius, cy - radius, cx + radius, cy + radius, - paint); - } - - @LayoutlibDelegate - public static void nDrawArc(long nativeCanvas, - final float left, final float top, final float right, final float bottom, - final float startAngle, final float sweep, - final boolean useCenter, long paint) { - if (right > left && bottom > top) { - draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/, - new GcSnapshot.Drawable() { - @Override - public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) { - int style = paintDelegate.getStyle(); - - Arc2D.Float arc = new Arc2D.Float( - left, top, right - left, bottom - top, - -startAngle, -sweep, - useCenter ? Arc2D.PIE : Arc2D.OPEN); - - // draw - if (style == Paint.Style.FILL.nativeInt || - style == Paint.Style.FILL_AND_STROKE.nativeInt) { - graphics.fill(arc); - } - - if (style == Paint.Style.STROKE.nativeInt || - style == Paint.Style.FILL_AND_STROKE.nativeInt) { - graphics.draw(arc); - } - } - }); - } - } - - @LayoutlibDelegate - public static void nDrawRoundRect(long nativeCanvas, - final float left, final float top, final float right, final float bottom, - final float rx, final float ry, long paint) { - draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/, - new GcSnapshot.Drawable() { - @Override - public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) { - int style = paintDelegate.getStyle(); - - // draw - if (style == Paint.Style.FILL.nativeInt || - style == Paint.Style.FILL_AND_STROKE.nativeInt) { - graphics.fillRoundRect( - (int)left, (int)top, - (int)(right - left), (int)(bottom - top), - 2 * (int)rx, 2 * (int)ry); - } - - if (style == Paint.Style.STROKE.nativeInt || - style == Paint.Style.FILL_AND_STROKE.nativeInt) { - graphics.drawRoundRect( - (int)left, (int)top, - (int)(right - left), (int)(bottom - top), - 2 * (int)rx, 2 * (int)ry); - } - } - }); - } - - @LayoutlibDelegate - public static void nDrawPath(long nativeCanvas, long path, long paint) { - final Path_Delegate pathDelegate = Path_Delegate.getDelegate(path); - if (pathDelegate == null) { - return; - } - - draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/, - new GcSnapshot.Drawable() { - @Override - public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) { - Shape shape = pathDelegate.getJavaShape(); - Rectangle2D bounds = shape.getBounds2D(); - if (bounds.isEmpty()) { - // Apple JRE 1.6 doesn't like drawing empty shapes. - // http://b.android.com/178278 - - if (pathDelegate.isEmpty()) { - // This means that the path doesn't have any lines or curves so - // nothing to draw. - return; - } - - // The stroke width is not consider for the size of the bounds so, - // for example, a horizontal line, would be considered as an empty - // rectangle. - // If the strokeWidth is not 0, we use it to consider the size of the - // path as well. - float strokeWidth = paintDelegate.getStrokeWidth(); - if (strokeWidth <= 0.0f) { - return; - } - bounds.setRect(bounds.getX(), bounds.getY(), - Math.max(strokeWidth, bounds.getWidth()), - Math.max(strokeWidth, bounds.getHeight())); - } - - int style = paintDelegate.getStyle(); - - if (style == Paint.Style.FILL.nativeInt || - style == Paint.Style.FILL_AND_STROKE.nativeInt) { - graphics.fill(shape); - } - - if (style == Paint.Style.STROKE.nativeInt || - style == Paint.Style.FILL_AND_STROKE.nativeInt) { - graphics.draw(shape); - } - } - }); - } - - @LayoutlibDelegate - public static void nDrawRegion(long nativeCanvas, long nativeRegion, - long nativePaint) { - // FIXME - Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, - "Some canvas paths may not be drawn", null, null); - } - - @LayoutlibDelegate - public static void nDrawNinePatch(Canvas thisCanvas, long nativeCanvas, - long nativeBitmap, long ninePatch, final float dstLeft, final float dstTop, - final float dstRight, final float dstBottom, long nativePaintOrZero, - final int screenDensity, final int bitmapDensity) { - - // get the delegate from the native int. - final Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(nativeBitmap); - if (bitmapDelegate == null) { - return; - } - - byte[] c = NinePatch_Delegate.getChunk(ninePatch); - if (c == null) { - // not a 9-patch? - BufferedImage image = bitmapDelegate.getImage(); - drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero, 0, 0, image.getWidth(), - image.getHeight(), (int) dstLeft, (int) dstTop, (int) dstRight, - (int) dstBottom); - return; - } - - final NinePatchChunk chunkObject = NinePatch_Delegate.getChunk(c); - assert chunkObject != null; - if (chunkObject == null) { - return; - } - - Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas); - if (canvasDelegate == null) { - return; - } - - // this one can be null - Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nativePaintOrZero); - - canvasDelegate.getSnapshot().draw(new GcSnapshot.Drawable() { - @Override - public void draw(Graphics2D graphics, Paint_Delegate paint) { - chunkObject.draw(bitmapDelegate.getImage(), graphics, (int) dstLeft, (int) dstTop, - (int) (dstRight - dstLeft), (int) (dstBottom - dstTop), screenDensity, - bitmapDensity); - } - }, paintDelegate, true, false); - - } - - @LayoutlibDelegate - public static void nDrawBitmap(Canvas thisCanvas, long nativeCanvas, Bitmap bitmap, - float left, float top, - long nativePaintOrZero, - int canvasDensity, - int screenDensity, - int bitmapDensity) { - // get the delegate from the native int. - Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap); - if (bitmapDelegate == null) { - return; - } - - BufferedImage image = bitmapDelegate.getImage(); - float right = left + image.getWidth(); - float bottom = top + image.getHeight(); - - drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero, - 0, 0, image.getWidth(), image.getHeight(), - (int)left, (int)top, (int)right, (int)bottom); - } - - @LayoutlibDelegate - public static void nDrawBitmap(Canvas thisCanvas, long nativeCanvas, Bitmap bitmap, - float srcLeft, float srcTop, float srcRight, float srcBottom, - float dstLeft, float dstTop, float dstRight, float dstBottom, - long nativePaintOrZero, int screenDensity, int bitmapDensity) { - // get the delegate from the native int. - Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap); - if (bitmapDelegate == null) { - return; - } - - drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero, - (int)srcLeft, (int)srcTop, (int)srcRight, (int)srcBottom, - (int)dstLeft, (int)dstTop, (int)dstRight, (int)dstBottom); - } - - @LayoutlibDelegate - public static void nDrawBitmap(long nativeCanvas, int[] colors, - int offset, int stride, final float x, - final float y, int width, int height, - boolean hasAlpha, - long nativePaintOrZero) { - // create a temp BufferedImage containing the content. - final BufferedImage image = new BufferedImage(width, height, - hasAlpha ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB); - image.setRGB(0, 0, width, height, colors, offset, stride); - - draw(nativeCanvas, nativePaintOrZero, true /*compositeOnly*/, false /*forceSrcMode*/, - new GcSnapshot.Drawable() { - @Override - public void draw(Graphics2D graphics, Paint_Delegate paint) { - if (paint != null && paint.isFilterBitmap()) { - graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, - RenderingHints.VALUE_INTERPOLATION_BILINEAR); - } - - graphics.drawImage(image, (int) x, (int) y, null); - } - }); - } - - @LayoutlibDelegate - public static void nativeDrawBitmapMatrix(long nCanvas, Bitmap bitmap, - long nMatrix, long nPaint) { - // get the delegate from the native int. - Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas); - if (canvasDelegate == null) { - return; - } - - // get the delegate from the native int, which can be null - Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nPaint); - - // get the delegate from the native int. - Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap); - if (bitmapDelegate == null) { - return; - } - - final BufferedImage image = getImageToDraw(bitmapDelegate, paintDelegate, sBoolOut); - - Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix); - if (matrixDelegate == null) { - return; - } - - final AffineTransform mtx = matrixDelegate.getAffineTransform(); - - canvasDelegate.getSnapshot().draw(new GcSnapshot.Drawable() { - @Override - public void draw(Graphics2D graphics, Paint_Delegate paint) { - if (paint != null && paint.isFilterBitmap()) { - graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, - RenderingHints.VALUE_INTERPOLATION_BILINEAR); - } - - //FIXME add support for canvas, screen and bitmap densities. - graphics.drawImage(image, mtx, null); - } - }, paintDelegate, true /*compositeOnly*/, false /*forceSrcMode*/); - } - - @LayoutlibDelegate - public static void nativeDrawBitmapMesh(long nCanvas, Bitmap bitmap, - int meshWidth, int meshHeight, float[] verts, int vertOffset, int[] colors, - int colorOffset, long nPaint) { - // FIXME - Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, - "Canvas.drawBitmapMesh is not supported.", null, null /*data*/); - } - - @LayoutlibDelegate - public static void nativeDrawVertices(long nCanvas, int mode, int n, - float[] verts, int vertOffset, - float[] texs, int texOffset, - int[] colors, int colorOffset, - short[] indices, int indexOffset, - int indexCount, long nPaint) { - // FIXME - Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, - "Canvas.drawVertices is not supported.", null, null /*data*/); - } - - @LayoutlibDelegate - public static void nDrawText(long nativeCanvas, char[] text, int index, int count, - float startX, float startY, int flags, long paint, long typeface) { - drawText(nativeCanvas, text, index, count, startX, startY, (flags & 1) != 0, - paint, typeface); - } - - @LayoutlibDelegate - public static void nDrawText(long nativeCanvas, String text, - int start, int end, float x, float y, final int flags, long paint, - long typeface) { - int count = end - start; - char[] buffer = TemporaryBuffer.obtain(count); - TextUtils.getChars(text, start, end, buffer, 0); - - nDrawText(nativeCanvas, buffer, 0, count, x, y, flags, paint, typeface); - } - - @LayoutlibDelegate - public static void nDrawTextRun(long nativeCanvas, String text, - int start, int end, int contextStart, int contextEnd, - float x, float y, boolean isRtl, long paint, long typeface) { - int count = end - start; - char[] buffer = TemporaryBuffer.obtain(count); - TextUtils.getChars(text, start, end, buffer, 0); - - drawText(nativeCanvas, buffer, 0, count, x, y, isRtl, paint, typeface); - } - - @LayoutlibDelegate - public static void nDrawTextRun(long nativeCanvas, char[] text, - int start, int count, int contextStart, int contextCount, - float x, float y, boolean isRtl, long paint, long typeface) { - drawText(nativeCanvas, text, start, count, x, y, isRtl, paint, typeface); - } - - @LayoutlibDelegate - public static void nDrawTextOnPath(long nativeCanvas, - char[] text, int index, - int count, long path, - float hOffset, - float vOffset, int bidiFlags, - long paint, long typeface) { - // FIXME - Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, - "Canvas.drawTextOnPath is not supported.", null, null /*data*/); - } - - @LayoutlibDelegate - public static void nDrawTextOnPath(long nativeCanvas, - String text, long path, - float hOffset, - float vOffset, - int bidiFlags, long paint, - long typeface) { - // FIXME - Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, - "Canvas.drawTextOnPath is not supported.", null, null /*data*/); - } - - @LayoutlibDelegate - /*package*/ static long getNativeFinalizer() { + /*package*/ static long nGetNativeFinalizer() { synchronized (Canvas_Delegate.class) { if (sFinalizer == -1) { sFinalizer = NativeAllocationRegistry_Delegate.createFinalizer(nativePtr -> { - Canvas_Delegate delegate = sManager.getDelegate(nativePtr); + Canvas_Delegate delegate = Canvas_Delegate.getDelegate(nativePtr); if (delegate != null) { delegate.dispose(); } @@ -1011,230 +500,12 @@ public final class Canvas_Delegate { return sFinalizer; } - // ---- Private delegate/helper methods ---- - - /** - * Executes a {@link GcSnapshot.Drawable} with a given canvas and paint. - *

Note that the drawable may actually be executed several times if there are - * layers involved (see {@link #saveLayer(RectF, Paint_Delegate, int)}. - */ - private static void draw(long nCanvas, long nPaint, boolean compositeOnly, boolean forceSrcMode, - GcSnapshot.Drawable drawable) { - // get the delegate from the native int. - Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas); - if (canvasDelegate == null) { - return; - } - - // get the paint which can be null if nPaint is 0; - Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nPaint); - - canvasDelegate.getSnapshot().draw(drawable, paintDelegate, compositeOnly, forceSrcMode); - } - - /** - * Executes a {@link GcSnapshot.Drawable} with a given canvas. No paint object will be provided - * to {@link GcSnapshot.Drawable#draw(Graphics2D, Paint_Delegate)}. - *

Note that the drawable may actually be executed several times if there are - * layers involved (see {@link #saveLayer(RectF, Paint_Delegate, int)}. - */ - private static void draw(long nCanvas, GcSnapshot.Drawable drawable) { - // get the delegate from the native int. - Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas); - if (canvasDelegate == null) { - return; - } - - canvasDelegate.mSnapshot.draw(drawable); - } - - private static void drawText(long nativeCanvas, final char[] text, final int index, - final int count, final float startX, final float startY, final boolean isRtl, - long paint, final long typeface) { - - draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/, - new GcSnapshot.Drawable() { - @Override - public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) { - // WARNING: the logic in this method is similar to Paint_Delegate.measureText. - // Any change to this method should be reflected in Paint.measureText - - // assert that the typeface passed is actually the one stored in paint. - assert (typeface == paintDelegate.mNativeTypeface); - - // Paint.TextAlign indicates how the text is positioned relative to X. - // LEFT is the default and there's nothing to do. - float x = startX; - int limit = index + count; - if (paintDelegate.getTextAlign() != Paint.Align.LEFT.nativeInt) { - RectF bounds = paintDelegate.measureText(text, index, count, null, 0, - isRtl); - float m = bounds.right - bounds.left; - if (paintDelegate.getTextAlign() == Paint.Align.CENTER.nativeInt) { - x -= m / 2; - } else if (paintDelegate.getTextAlign() == Paint.Align.RIGHT.nativeInt) { - x -= m; - } - } - - new BidiRenderer(graphics, paintDelegate, text).setRenderLocation(x, startY) - .renderText(index, limit, isRtl, null, 0, true); - } - }); - } - private Canvas_Delegate(Bitmap_Delegate bitmap) { - mSnapshot = GcSnapshot.createDefaultSnapshot(mBitmap = bitmap); + super(bitmap); } private Canvas_Delegate() { - mSnapshot = GcSnapshot.createDefaultSnapshot(null /*image*/); - } - - /** - * Disposes of the {@link Graphics2D} stack. - */ - private void dispose() { - mSnapshot.dispose(); - } - - private int save(int saveFlags) { - // get the current save count - int count = mSnapshot.size(); - - mSnapshot = mSnapshot.save(saveFlags); - - // return the old save count - return count; - } - - private int saveLayerAlpha(RectF rect, int alpha, int saveFlags) { - Paint_Delegate paint = new Paint_Delegate(); - paint.setAlpha(alpha); - return saveLayer(rect, paint, saveFlags); - } - - private int saveLayer(RectF rect, Paint_Delegate paint, int saveFlags) { - // get the current save count - int count = mSnapshot.size(); - - mSnapshot = mSnapshot.saveLayer(rect, paint, saveFlags); - - // return the old save count - return count; - } - - /** - * Restores the {@link GcSnapshot} to saveCount - * @param saveCount the saveCount - */ - private void restoreTo(int saveCount) { - mSnapshot = mSnapshot.restoreTo(saveCount); - } - - /** - * Restores the top {@link GcSnapshot} - */ - private void restore() { - mSnapshot = mSnapshot.restore(); - } - - private boolean clipRect(float left, float top, float right, float bottom, int regionOp) { - return mSnapshot.clipRect(left, top, right, bottom, regionOp); - } - - private static void drawBitmap( - long nativeCanvas, - Bitmap_Delegate bitmap, - long nativePaintOrZero, - final int sleft, final int stop, final int sright, final int sbottom, - final int dleft, final int dtop, final int dright, final int dbottom) { - // get the delegate from the native int. - Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); - if (canvasDelegate == null) { - return; - } - - // get the paint, which could be null if the int is 0 - Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nativePaintOrZero); - - final BufferedImage image = getImageToDraw(bitmap, paintDelegate, sBoolOut); - - draw(nativeCanvas, nativePaintOrZero, true /*compositeOnly*/, sBoolOut[0], - new GcSnapshot.Drawable() { - @Override - public void draw(Graphics2D graphics, Paint_Delegate paint) { - if (paint != null && paint.isFilterBitmap()) { - graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, - RenderingHints.VALUE_INTERPOLATION_BILINEAR); - } - - //FIXME add support for canvas, screen and bitmap densities. - graphics.drawImage(image, dleft, dtop, dright, dbottom, - sleft, stop, sright, sbottom, null); - } - }); - } - - - /** - * Returns a BufferedImage ready for drawing, based on the bitmap and paint delegate. - * The image returns, through a 1-size boolean array, whether the drawing code should - * use a SRC composite no matter what the paint says. - * - * @param bitmap the bitmap - * @param paint the paint that will be used to draw - * @param forceSrcMode whether the composite will have to be SRC - * @return the image to draw - */ - private static BufferedImage getImageToDraw(Bitmap_Delegate bitmap, Paint_Delegate paint, - boolean[] forceSrcMode) { - BufferedImage image = bitmap.getImage(); - forceSrcMode[0] = false; - - // if the bitmap config is alpha_8, then we erase all color value from it - // before drawing it. - if (bitmap.getConfig() == Bitmap.Config.ALPHA_8) { - fixAlpha8Bitmap(image); - } else if (!bitmap.hasAlpha()) { - // hasAlpha is merely a rendering hint. There can in fact be alpha values - // in the bitmap but it should be ignored at drawing time. - // There is two ways to do this: - // - override the composite to be SRC. This can only be used if the composite - // was going to be SRC or SRC_OVER in the first place - // - Create a different bitmap to draw in which all the alpha channel values is set - // to 0xFF. - if (paint != null) { - Xfermode_Delegate xfermodeDelegate = paint.getXfermode(); - if (xfermodeDelegate instanceof PorterDuffXfermode_Delegate) { - PorterDuff.Mode mode = - ((PorterDuffXfermode_Delegate)xfermodeDelegate).getMode(); - - forceSrcMode[0] = mode == PorterDuff.Mode.SRC_OVER || - mode == PorterDuff.Mode.SRC; - } - } - - // if we can't force SRC mode, then create a temp bitmap of TYPE_RGB - if (!forceSrcMode[0]) { - image = Bitmap_Delegate.createCopy(image, BufferedImage.TYPE_INT_RGB, 0xFF); - } - } - - return image; - } - - private static void fixAlpha8Bitmap(final BufferedImage image) { - int w = image.getWidth(); - int h = image.getHeight(); - int[] argb = new int[w * h]; - image.getRGB(0, 0, image.getWidth(), image.getHeight(), argb, 0, image.getWidth()); - - final int length = argb.length; - for (int i = 0 ; i < length; i++) { - argb[i] &= 0xFF000000; - } - image.setRGB(0, 0, w, h, argb, 0, w); + super(); } } diff --git a/tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java index 59ddcc6a6ca81..a459734e805ff 100644 --- a/tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java @@ -63,16 +63,8 @@ public class ComposeShader_Delegate extends Shader_Delegate { // ---- native methods ---- @LayoutlibDelegate - /*package*/ static long nativeCreate1(long native_shaderA, long native_shaderB, - long native_mode) { - // FIXME not supported yet. - ComposeShader_Delegate newDelegate = new ComposeShader_Delegate(); - return sManager.addNewDelegate(newDelegate); - } - - @LayoutlibDelegate - /*package*/ static long nativeCreate2(long native_shaderA, long native_shaderB, - int porterDuffMode) { + /*package*/ static long nativeCreate(long native_shaderA, long native_shaderB, + int native_mode) { // FIXME not supported yet. ComposeShader_Delegate newDelegate = new ComposeShader_Delegate(); return sManager.addNewDelegate(newDelegate); diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java index 0bbe33dc58df0..e68d8b3e9f937 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java @@ -90,10 +90,11 @@ public class Paint_Delegate { private int mHintingMode = Paint.HINTING_ON; private int mHyphenEdit; private float mLetterSpacing; // not used in actual text rendering. + private float mWordSpacing; // not used in actual text rendering. // Variant of the font. A paint's variant can only be compact or elegant. private FontVariant mFontVariant = FontVariant.COMPACT; - private Xfermode_Delegate mXfermode; + private int mPorterDuffMode = Xfermode.DEFAULT; private ColorFilter_Delegate mColorFilter; private Shader_Delegate mShader; private PathEffect_Delegate mPathEffect; @@ -206,12 +207,10 @@ public class Paint_Delegate { } /** - * Returns the {@link Xfermode} delegate or null if none have been set - * - * @return the delegate or null. + * Returns the {@link PorterDuff.Mode} as an int */ - public Xfermode_Delegate getXfermode() { - return mXfermode; + public int getPorterDuffMode() { + return mPorterDuffMode; } /** @@ -841,16 +840,12 @@ public class Paint_Delegate { } @LayoutlibDelegate - /*package*/ static long nSetXfermode(long native_object, long xfermode) { - // get the delegate from the native int. + /*package*/ static void nSetXfermode(long native_object, int xfermode) { Paint_Delegate delegate = sManager.getDelegate(native_object); if (delegate == null) { - return xfermode; + return; } - - delegate.mXfermode = Xfermode_Delegate.getDelegate(xfermode); - - return xfermode; + delegate.mPorterDuffMode = xfermode; } @LayoutlibDelegate @@ -998,7 +993,7 @@ public class Paint_Delegate { } @LayoutlibDelegate - /*package*/ static int nGetTextRunCursor(long native_object, char[] text, + /*package*/ static int nGetTextRunCursor(Paint paint, long native_object, char[] text, int contextStart, int contextLength, int flags, int offset, int cursorOpt) { // FIXME Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, @@ -1007,7 +1002,7 @@ public class Paint_Delegate { } @LayoutlibDelegate - /*package*/ static int nGetTextRunCursor(long native_object, String text, + /*package*/ static int nGetTextRunCursor(Paint paint, long native_object, String text, int contextStart, int contextEnd, int flags, int offset, int cursorOpt) { // FIXME Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, @@ -1085,6 +1080,26 @@ public class Paint_Delegate { delegate.mLetterSpacing = letterSpacing; } + @LayoutlibDelegate + /*package*/ static float nGetWordSpacing(long nativePaint) { + Paint_Delegate delegate = sManager.getDelegate(nativePaint); + if (delegate == null) { + return 0; + } + return delegate.mWordSpacing; + } + + @LayoutlibDelegate + /*package*/ static void nSetWordSpacing(long nativePaint, float wordSpacing) { + Bridge.getLog().fidelityWarning(LayoutLog.TAG_TEXT_RENDERING, + "Paint.setWordSpacing() not supported.", null, null); + Paint_Delegate delegate = sManager.getDelegate(nativePaint); + if (delegate == null) { + return; + } + delegate.mWordSpacing = wordSpacing; + } + @LayoutlibDelegate /*package*/ static void nSetFontFeatureSettings(long nativePaint, String settings) { Bridge.getLog().fidelityWarning(LayoutLog.TAG_TEXT_RENDERING, @@ -1215,7 +1230,7 @@ public class Paint_Delegate { mStrokeWidth = paint.mStrokeWidth; mStrokeMiter = paint.mStrokeMiter; - mXfermode = paint.mXfermode; + mPorterDuffMode = paint.mPorterDuffMode; mColorFilter = paint.mColorFilter; mShader = paint.mShader; mPathEffect = paint.mPathEffect; @@ -1242,7 +1257,7 @@ public class Paint_Delegate { mTextSize = 20.f; mTextScaleX = 1.f; mTextSkewX = 0.f; - mXfermode = null; + mPorterDuffMode = Xfermode.DEFAULT; mColorFilter = null; mShader = null; mPathEffect = null; diff --git a/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java deleted file mode 100644 index 8825f84995c8d..0000000000000 --- a/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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; - -import com.android.layoutlib.bridge.impl.DelegateManager; -import com.android.layoutlib.bridge.impl.PorterDuffUtility; -import com.android.tools.layoutlib.annotations.LayoutlibDelegate; - -import android.graphics.PorterDuff.Mode; - -import java.awt.Composite; - -import static com.android.layoutlib.bridge.impl.PorterDuffUtility.getPorterDuffMode; - -/** - * Delegate implementing the native methods of android.graphics.PorterDuffXfermode - * - * Through the layoutlib_create tool, the original native methods of PorterDuffXfermode have been - * replaced by calls to methods of the same name in this delegate class. - * - * This class behaves like the original native implementation, but in Java, keeping previously - * native data into its own objects and mapping them to int that are sent back and forth between - * it and the original PorterDuffXfermode class. - * - * Because this extends {@link Xfermode_Delegate}, there's no need to use a - * {@link DelegateManager}, as all the PathEffect classes will be added to the manager owned by - * {@link Xfermode_Delegate}. - * - */ -public class PorterDuffXfermode_Delegate extends Xfermode_Delegate { - - // ---- delegate data ---- - - private final Mode mMode; - - // ---- Public Helper methods ---- - - public Mode getMode() { - return mMode; - } - - @Override - public Composite getComposite(int alpha) { - return PorterDuffUtility.getComposite(mMode, alpha); - } - - @Override - public boolean isSupported() { - return true; - } - - @Override - public String getSupportMessage() { - // no message since isSupported returns true; - return null; - } - - - // ---- native methods ---- - - @LayoutlibDelegate - /*package*/ static long nativeCreateXfermode(int mode) { - PorterDuffXfermode_Delegate newDelegate = new PorterDuffXfermode_Delegate(mode); - return sManager.addNewDelegate(newDelegate); - } - - // ---- Private delegate/helper methods ---- - - private PorterDuffXfermode_Delegate(int mode) { - mMode = getPorterDuffMode(mode); - } - -} diff --git a/tools/layoutlib/bridge/src/android/graphics/Xfermode_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Xfermode_Delegate.java deleted file mode 100644 index 94a6d76fe8dc2..0000000000000 --- a/tools/layoutlib/bridge/src/android/graphics/Xfermode_Delegate.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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; - -import com.android.layoutlib.bridge.impl.DelegateManager; -import com.android.tools.layoutlib.annotations.LayoutlibDelegate; - -import java.awt.Composite; - -/** - * Delegate implementing the native methods of android.graphics.Xfermode - * - * Through the layoutlib_create tool, the original native methods of Xfermode have been replaced - * by calls to methods of the same name in this delegate class. - * - * This class behaves like the original native implementation, but in Java, keeping previously - * native data into its own objects and mapping them to int that are sent back and forth between - * it and the original Xfermode class. - * - * This also serve as a base class for all Xfermode delegate classes. - * - * @see DelegateManager - * - */ -public abstract class Xfermode_Delegate { - - // ---- delegate manager ---- - protected static final DelegateManager sManager = - new DelegateManager(Xfermode_Delegate.class); - - // ---- delegate helper data ---- - - // ---- delegate data ---- - - // ---- Public Helper methods ---- - - public static Xfermode_Delegate getDelegate(long native_instance) { - return sManager.getDelegate(native_instance); - } - - public abstract Composite getComposite(int alpha); - public abstract boolean isSupported(); - public abstract String getSupportMessage(); - - - // ---- native methods ---- - - @LayoutlibDelegate - /*package*/ static void finalizer(long native_instance) { - sManager.removeJavaReferenceFor(native_instance); - } - - // ---- Private delegate/helper methods ---- - -} diff --git a/tools/layoutlib/bridge/src/android/graphics/drawable/AnimatedVectorDrawable_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/drawable/AnimatedVectorDrawable_Delegate.java index 200fe3b1d1923..ad2c5647eef27 100644 --- a/tools/layoutlib/bridge/src/android/graphics/drawable/AnimatedVectorDrawable_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/drawable/AnimatedVectorDrawable_Delegate.java @@ -57,9 +57,14 @@ public class AnimatedVectorDrawable_Delegate { return sAnimatorSets.addNewDelegate(new AnimatorSetHolder()); } + @LayoutlibDelegate + /*package*/ static void nSetVectorDrawableTarget(long animatorPtr, long vectorDrawablePtr) { + // TODO: implement + } @LayoutlibDelegate /*package*/ static void nAddAnimator(long setPtr, long propertyValuesHolder, - long nativeInterpolator, long startDelay, long duration, int repeatCount) { + long nativeInterpolator, long startDelay, long duration, int repeatCount, + int repeatMode) { PropertySetter holder = sHolders.getDelegate(propertyValuesHolder); if (holder == null || holder.getValues() == null) { return; @@ -72,6 +77,7 @@ public class AnimatedVectorDrawable_Delegate { animator.setStartDelay(startDelay); animator.setDuration(duration); animator.setRepeatCount(repeatCount); + animator.setRepeatMode(repeatMode); animator.setTarget(holder); animator.setPropertyName(holder.getValues().getPropertyName()); @@ -136,6 +142,14 @@ public class AnimatedVectorDrawable_Delegate { setter.setValues(data); } + @LayoutlibDelegate + /*package*/ static void nSetPropertyHolderData(long nativePtr, int[] data, int length) { + PropertySetter setter = sHolders.getDelegate(nativePtr); + assert setter != null; + + setter.setValues(data); + } + @LayoutlibDelegate /*package*/ static void nStart(long animatorSetPtr, VectorDrawableAnimatorRT set, int id) { AnimatorSetHolder animatorSet = sAnimatorSets.getDelegate(animatorSetPtr); diff --git a/tools/layoutlib/bridge/src/android/graphics/drawable/AnimatedVectorDrawable_VectorDrawableAnimatorRT_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/drawable/AnimatedVectorDrawable_VectorDrawableAnimatorRT_Delegate.java index 3d78931a152cf..fc848d9af956b 100644 --- a/tools/layoutlib/bridge/src/android/graphics/drawable/AnimatedVectorDrawable_VectorDrawableAnimatorRT_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/drawable/AnimatedVectorDrawable_VectorDrawableAnimatorRT_Delegate.java @@ -18,6 +18,7 @@ package android.graphics.drawable; import com.android.tools.layoutlib.annotations.LayoutlibDelegate; +import android.graphics.Canvas; import android.graphics.drawable.AnimatedVectorDrawable.VectorDrawableAnimatorRT; public class AnimatedVectorDrawable_VectorDrawableAnimatorRT_Delegate { @@ -25,4 +26,9 @@ public class AnimatedVectorDrawable_VectorDrawableAnimatorRT_Delegate { /*package*/ static boolean useLastSeenTarget(VectorDrawableAnimatorRT thisDrawableAnimator) { return true; } + + @LayoutlibDelegate + /*package*/ static void onDraw(VectorDrawableAnimatorRT thisDrawableAnimator, Canvas canvas) { + // Do not attempt to record as we are not using a DisplayListCanvas + } } diff --git a/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java index 99042638102a9..cee679a1d4696 100644 --- a/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java @@ -23,6 +23,7 @@ import android.annotation.NonNull; import android.content.res.Resources; import android.content.res.Resources.Theme; import android.content.res.TypedArray; +import android.graphics.BaseCanvas_Delegate; import android.graphics.Canvas_Delegate; import android.graphics.Color; import android.graphics.Matrix; @@ -1197,7 +1198,7 @@ public class VectorDrawable_Delegate { fillPaintDelegate.setColorFilter(filterPtr); fillPaintDelegate.setShader(fullPath.mFillGradient); Path_Delegate.native_setFillType(mRenderPath.mNativePath, fullPath.mFillType); - Canvas_Delegate.nDrawPath(canvasPtr, mRenderPath.mNativePath, fillPaint + BaseCanvas_Delegate.nDrawPath(canvasPtr, mRenderPath.mNativePath, fillPaint .getNativeInstance()); } @@ -1228,7 +1229,7 @@ public class VectorDrawable_Delegate { final float finalStrokeScale = minScale * matrixScale; strokePaint.setStrokeWidth(fullPath.mStrokeWidth * finalStrokeScale); strokePaintDelegate.setShader(fullPath.mStrokeGradient); - Canvas_Delegate.nDrawPath(canvasPtr, mRenderPath.mNativePath, strokePaint + BaseCanvas_Delegate.nDrawPath(canvasPtr, mRenderPath.mNativePath, strokePaint .getNativeInstance()); } } diff --git a/tools/layoutlib/bridge/src/android/os/ServiceManager.java b/tools/layoutlib/bridge/src/android/os/ServiceManager.java index 3e1ec070c7d96..c96d2ca4c4359 100644 --- a/tools/layoutlib/bridge/src/android/os/ServiceManager.java +++ b/tools/layoutlib/bridge/src/android/os/ServiceManager.java @@ -30,6 +30,13 @@ public final class ServiceManager { return null; } + /** + * Is not supposed to return null, but that is fine for layoutlib. + */ + public static IBinder getServiceOrThrow(String name) throws ServiceNotFoundException { + return null; + } + /** * Place a new @a service called @a name into the service * manager. diff --git a/tools/layoutlib/bridge/src/android/os/SystemProperties_Delegate.java b/tools/layoutlib/bridge/src/android/os/SystemProperties_Delegate.java index af0c4569b08b5..d299add05eabb 100644 --- a/tools/layoutlib/bridge/src/android/os/SystemProperties_Delegate.java +++ b/tools/layoutlib/bridge/src/android/os/SystemProperties_Delegate.java @@ -102,4 +102,9 @@ public class SystemProperties_Delegate { /*package*/ static void native_add_change_callback() { // pass. } + + @LayoutlibDelegate + /*package*/ static void native_report_sysprop_change() { + // pass. + } } diff --git a/tools/layoutlib/bridge/src/android/view/RenderNode_Delegate.java b/tools/layoutlib/bridge/src/android/view/RenderNode_Delegate.java index 24f788766cc95..a801cb0606e09 100644 --- a/tools/layoutlib/bridge/src/android/view/RenderNode_Delegate.java +++ b/tools/layoutlib/bridge/src/android/view/RenderNode_Delegate.java @@ -21,6 +21,8 @@ import com.android.tools.layoutlib.annotations.LayoutlibDelegate; import android.graphics.Matrix; +import libcore.util.NativeAllocationRegistry_Delegate; + /** * Delegate implementing the native methods of {@link RenderNode} *

@@ -35,7 +37,7 @@ public class RenderNode_Delegate { // ---- delegate manager ---- private static final DelegateManager sManager = new DelegateManager(RenderNode_Delegate.class); - + private static long sFinalizer = -1; private float mLift; private float mTranslationX; @@ -62,8 +64,13 @@ public class RenderNode_Delegate { } @LayoutlibDelegate - /*package*/ static void nDestroyRenderNode(long renderNode) { - sManager.removeJavaReferenceFor(renderNode); + /*package*/ static long nGetNativeFinalizer() { + synchronized (RenderNode_Delegate.class) { + if (sFinalizer == -1) { + sFinalizer = NativeAllocationRegistry_Delegate.createFinalizer(sManager::removeJavaReferenceFor); + } + } + return sFinalizer; } @LayoutlibDelegate diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java index e80cbf27f2328..7526e090be500 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java @@ -24,12 +24,13 @@ import android.graphics.Canvas; import android.graphics.ColorFilter_Delegate; import android.graphics.Paint; import android.graphics.Paint_Delegate; +import android.graphics.PorterDuff; +import android.graphics.PorterDuff.Mode; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; import android.graphics.Region_Delegate; import android.graphics.Shader_Delegate; -import android.graphics.Xfermode_Delegate; import java.awt.AlphaComposite; import java.awt.Color; @@ -827,28 +828,9 @@ public class GcSnapshot { g.setComposite(AlphaComposite.getInstance(forceMode, (float) alpha / 255.f)); return; } - Xfermode_Delegate xfermodeDelegate = paint.getXfermode(); - if (xfermodeDelegate != null) { - if (xfermodeDelegate.isSupported()) { - Composite composite = xfermodeDelegate.getComposite(alpha); - assert composite != null; - if (composite != null) { - g.setComposite(composite); - return; - } - } else { - Bridge.getLog().fidelityWarning(LayoutLog.TAG_XFERMODE, - xfermodeDelegate.getSupportMessage(), - null /*throwable*/, null /*data*/); - } - } - // if there was no custom xfermode, but we have alpha (due to a shader and a non - // opaque alpha channel in the paint color), then we create an AlphaComposite anyway - // that will handle the alpha. - if (alpha != 0xFF) { - g.setComposite(AlphaComposite.getInstance( - AlphaComposite.SRC_OVER, (float) alpha / 255.f)); - } + Mode mode = PorterDuff.intToMode(paint.getPorterDuffMode()); + Composite composite = PorterDuffUtility.getComposite(mode, alpha); + g.setComposite(composite); } private void mapRect(AffineTransform matrix, RectF dst, RectF src) { diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/PorterDuffUtility.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/PorterDuffUtility.java index 80d7c68bcf06b..70e2eb17794a5 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/PorterDuffUtility.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/PorterDuffUtility.java @@ -24,14 +24,12 @@ import android.graphics.BlendComposite.BlendingMode; import android.graphics.PorterDuff; import android.graphics.PorterDuff.Mode; import android.graphics.PorterDuffColorFilter_Delegate; -import android.graphics.PorterDuffXfermode_Delegate; import java.awt.AlphaComposite; import java.awt.Composite; /** - * Provides various utility methods for {@link PorterDuffColorFilter_Delegate} and {@link - * PorterDuffXfermode_Delegate}. + * Provides various utility methods for {@link PorterDuffColorFilter_Delegate}. */ public final class PorterDuffUtility { diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java index bf61f7efc4bd9..b7d08f2c1556b 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java @@ -180,6 +180,7 @@ public final class CreateInfo implements ICreateInfo { "android.graphics.BitmapFactory#finishDecode", "android.graphics.BitmapFactory#setDensityFromOptions", "android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimatorRT#useLastSeenTarget", + "android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimatorRT#onDraw", "android.graphics.drawable.GradientDrawable#buildRing", "android.graphics.FontFamily#addFont", "android.graphics.Typeface#getSystemFontConfigLocation", @@ -206,7 +207,7 @@ public final class CreateInfo implements ICreateInfo { "android.view.MenuInflater#registerMenu", "android.view.RenderNode#getMatrix", "android.view.RenderNode#nCreate", - "android.view.RenderNode#nDestroyRenderNode", + "android.view.RenderNode#nGetNativeFinalizer", "android.view.RenderNode#nSetElevation", "android.view.RenderNode#nGetElevation", "android.view.RenderNode#nSetTranslationX", @@ -247,6 +248,7 @@ public final class CreateInfo implements ICreateInfo { */ public final static String[] DELEGATE_CLASS_NATIVES = new String[] { "android.animation.PropertyValuesHolder", + "android.graphics.BaseCanvas", "android.graphics.Bitmap", "android.graphics.BitmapFactory", "android.graphics.BitmapShader", @@ -275,7 +277,6 @@ public final class CreateInfo implements ICreateInfo { "android.graphics.PathEffect", "android.graphics.PathMeasure", "android.graphics.PorterDuffColorFilter", - "android.graphics.PorterDuffXfermode", "android.graphics.RadialGradient", "android.graphics.Rasterizer", "android.graphics.Region", @@ -283,7 +284,6 @@ public final class CreateInfo implements ICreateInfo { "android.graphics.SumPathEffect", "android.graphics.SweepGradient", "android.graphics.Typeface", - "android.graphics.Xfermode", "android.graphics.drawable.AnimatedVectorDrawable", "android.graphics.drawable.VectorDrawable", "android.os.SystemClock", diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java index 9bb91e599d77b..4b6cf4354d915 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java @@ -124,6 +124,7 @@ public class Main { "android.annotation.NonNull", // annotations "android.annotation.Nullable", // annotations "com.android.internal.transition.EpicenterTranslateClipReveal", + "com.android.internal.graphics.drawable.AnimationScaleListDrawable", }, excludeClasses, new String[] {