Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5802deab authored by Xavier Ducrohet's avatar Xavier Ducrohet
Browse files

More implementation of the layoutlib Paint/Canvas delegates.

Change-Id: I0c0029b9a679af4ae0178488f70b2a90292ea42d
parent 1d8479fa
Loading
Loading
Loading
Loading
+490 −46
Original line number Diff line number Diff line
@@ -19,10 +19,22 @@ package android.graphics;
import com.android.layoutlib.api.ILayoutLog;
import com.android.layoutlib.bridge.DelegateManager;

import android.graphics.Paint_Delegate.FontInfo;
import android.text.TextUtils;

import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.util.List;
import java.util.Stack;


/**
 * Delegate implementing the native methods of android.graphics.Canvas
 *
@@ -95,80 +107,177 @@ public class Canvas_Delegate {
    }

    /*package*/ static int getWidth(Canvas thisCanvas) {
        // FIXME
        throw new UnsupportedOperationException();
        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
        if (canvasDelegate == null) {
            assert false;
            return 0;
        }

        return canvasDelegate.mBufferedImage.getWidth();
    }

    /*package*/ static int getHeight(Canvas thisCanvas) {
        // FIXME
        throw new UnsupportedOperationException();
        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
        if (canvasDelegate == null) {
            assert false;
            return 0;
        }

        return canvasDelegate.mBufferedImage.getHeight();
    }

    /*package*/ static void translate(Canvas thisCanvas, float dx, float dy) {
        // FIXME
        throw new UnsupportedOperationException();
        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
        if (canvasDelegate == null) {
            assert false;
            return;
        }

        canvasDelegate.getGraphics2d().translate(dx, dy);
    }

    /*package*/ static void rotate(Canvas thisCanvas, float degrees) {
        // FIXME
        throw new UnsupportedOperationException();
        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
        if (canvasDelegate == null) {
            assert false;
            return;
        }

        canvasDelegate.getGraphics2d().rotate(Math.toRadians(degrees));
    }

    /*package*/ static void scale(Canvas thisCanvas, float sx, float sy) {
        // FIXME
        throw new UnsupportedOperationException();
        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
        if (canvasDelegate == null) {
            assert false;
            return;
        }

    /*package*/ static void skew(Canvas thisCanvas, float sx, float sy) {
        // FIXME
        throw new UnsupportedOperationException();
        canvasDelegate.getGraphics2d().scale(sx, sy);
    }

    /*package*/ static void skew(Canvas thisCanvas, float kx, float ky) {
        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
        if (canvasDelegate == null) {
            assert false;
            return;
        }

        // get the current top graphics2D object.
        Graphics2D g = canvasDelegate.getGraphics2d();

        // get its current matrix
        AffineTransform currentTx = g.getTransform();
        // get the AffineTransform for the given skew.
        float[] mtx = Matrix_Delegate.getSkew(kx, ky);
        AffineTransform matrixTx = Matrix_Delegate.getAffineTransform(mtx);

        // combine them so that the given matrix is applied after.
        currentTx.preConcatenate(matrixTx);

        // give it to the graphics2D as a new matrix replacing all previous transform
        g.setTransform(currentTx);
    }

    /*package*/ static boolean clipRect(Canvas thisCanvas, RectF rect) {
        // FIXME
        throw new UnsupportedOperationException();
        return clipRect(thisCanvas, rect.left, rect.top, rect.right, rect.bottom);
    }

    /*package*/ static boolean clipRect(Canvas thisCanvas, Rect rect) {
        // FIXME
        throw new UnsupportedOperationException();
        return clipRect(thisCanvas, rect.left, rect.top, rect.right, rect.bottom);
    }

    /*package*/ static boolean clipRect(Canvas thisCanvas, float left, float top, float right,
            float bottom) {
        // FIXME
        throw new UnsupportedOperationException();
        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
        if (canvasDelegate == null) {
            assert false;
            return false;
        }

        canvasDelegate.getGraphics2d().clipRect((int)left, (int)top, (int)(right-left),
                (int)(bottom-top));
        return true;
    }

    /*package*/ static boolean clipRect(Canvas thisCanvas, int left, int top, int right,
            int bottom) {
        // FIXME
        throw new UnsupportedOperationException();
        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
        if (canvasDelegate == null) {
            assert false;
            return false;
        }

        canvasDelegate.getGraphics2d().clipRect(left, top, right - left, bottom - top);
        return true;
    }

    /*package*/ static int save(Canvas thisCanvas) {
        // FIXME
        throw new UnsupportedOperationException();
        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
        if (canvasDelegate == null) {
            assert false;
            return 0;
        }

        // get the current save count
        int count = canvasDelegate.mGraphicsStack.size();

        // create a new graphics and add it to the stack
        Graphics2D g = (Graphics2D)canvasDelegate.getGraphics2d().create();
        canvasDelegate.mGraphicsStack.push(g);

        // return the old save count
        return count;

    }

    /*package*/ static int save(Canvas thisCanvas, int saveFlags) {
        // FIXME
        throw new UnsupportedOperationException();
        // FIXME implement save(flags)
        return save(thisCanvas);
    }

    /*package*/ static void restore(Canvas thisCanvas) {
        // FIXME
        throw new UnsupportedOperationException();
        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
        if (canvasDelegate == null) {
            assert false;
            return;
        }

        canvasDelegate.mGraphicsStack.pop();
    }

    /*package*/ static int getSaveCount(Canvas thisCanvas) {
        // FIXME
        throw new UnsupportedOperationException();
        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
        if (canvasDelegate == null) {
            assert false;
            return 0;
        }

        return canvasDelegate.mGraphicsStack.size();
    }

    /*package*/ static void restoreToCount(Canvas thisCanvas, int saveCount) {
        // FIXME
        throw new UnsupportedOperationException();
        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
        if (canvasDelegate == null) {
            assert false;
            return;
        }

        while (canvasDelegate.mGraphicsStack.size() > saveCount) {
            canvasDelegate.mGraphicsStack.pop();
        }
    }

    /*package*/ static void drawPoints(Canvas thisCanvas, float[] pts, int offset, int count,
@@ -296,8 +405,22 @@ public class Canvas_Delegate {

    /*package*/ static boolean native_getClipBounds(int nativeCanvas,
                                                       Rect bounds) {
        // FIXME
        throw new UnsupportedOperationException();
        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
        if (canvasDelegate == null) {
            assert false;
            return false;
        }

        Rectangle rect = canvasDelegate.getGraphics2d().getClipBounds();
        if (rect != null) {
            bounds.left = rect.x;
            bounds.top = rect.y;
            bounds.right = rect.x + rect.width;
            bounds.bottom = rect.y + rect.height;
            return true;
        }
        return false;
    }

    /*package*/ static void native_getCTM(int canvas, int matrix) {
@@ -309,14 +432,14 @@ public class Canvas_Delegate {
                                                     RectF rect,
                                                     int native_edgeType) {
        // FIXME
        throw new UnsupportedOperationException();
        return false;
    }

    /*package*/ static boolean native_quickReject(int nativeCanvas,
                                                     int path,
                                                     int native_edgeType) {
        // FIXME
        throw new UnsupportedOperationException();
        return false;
    }

    /*package*/ static boolean native_quickReject(int nativeCanvas,
@@ -324,7 +447,7 @@ public class Canvas_Delegate {
                                                     float right, float bottom,
                                                     int native_edgeType) {
        // FIXME
        throw new UnsupportedOperationException();
        return false;
    }

    /*package*/ static void native_drawRGB(int nativeCanvas, int r, int g,
@@ -371,8 +494,41 @@ public class Canvas_Delegate {
    /*package*/ static void native_drawRect(int nativeCanvas, float left,
                                               float top, float right,
                                               float bottom, int paint) {
        // FIXME
        throw new UnsupportedOperationException();
        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
        if (canvasDelegate == null) {
            assert false;
            return;
        }

        // get the delegate from the native int.
        Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint);
        if (paintDelegate == null) {
            assert false;
            return;
        }

        if (right > left && bottom > top) {
            // get a Graphics2D object configured with the drawing parameters.
            Graphics2D g = canvasDelegate.getCustomGraphics(paintDelegate);

            int style = paintDelegate.getStyle();

            // draw
            if (style == Paint.Style.FILL.nativeInt ||
                    style == Paint.Style.FILL_AND_STROKE.nativeInt) {
                g.fillRect((int)left, (int)top, (int)(right-left), (int)(bottom-top));
            }

            if (style == Paint.Style.STROKE.nativeInt ||
                    style == Paint.Style.FILL_AND_STROKE.nativeInt) {
                g.drawRect((int)left, (int)top, (int)(right-left), (int)(bottom-top));
            }

            // dispose Graphics2D object
            g.dispose();
        }

    }

    /*package*/ static void native_drawOval(int nativeCanvas, RectF oval,
@@ -423,8 +579,24 @@ public class Canvas_Delegate {
                                                 int nativePaintOrZero,
                                                 int screenDensity,
                                                 int bitmapDensity) {
        // FIXME
        throw new UnsupportedOperationException();
        // get the delegate from the native int.
        Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
        if (bitmapDelegate == null) {
            assert false;
            return;
        }

        BufferedImage image = bitmapDelegate.getImage();

        if (src == null) {
            drawBitmap(nativeCanvas, image, nativePaintOrZero,
                    0, 0, image.getWidth(), image.getHeight(),
                    (int)dst.left, (int)dst.top, (int)dst.right, (int)dst.bottom);
        } else {
            drawBitmap(nativeCanvas, image, nativePaintOrZero,
                    src.left, src.top, src.width(), src.height(),
                    (int)dst.left, (int)dst.top, (int)dst.right, (int)dst.bottom);
        }
    }

    /*package*/ static void native_drawBitmap(int nativeCanvas, int bitmap,
@@ -432,8 +604,24 @@ public class Canvas_Delegate {
                                                 int nativePaintOrZero,
                                                 int screenDensity,
                                                 int bitmapDensity) {
        // FIXME
        throw new UnsupportedOperationException();
        // get the delegate from the native int.
        Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
        if (bitmapDelegate == null) {
            assert false;
            return;
        }

        BufferedImage image = bitmapDelegate.getImage();

        if (src == null) {
            drawBitmap(nativeCanvas, image, nativePaintOrZero,
                    0, 0, image.getWidth(), image.getHeight(),
                    dst.left, dst.top, dst.right, dst.bottom);
        } else {
            drawBitmap(nativeCanvas, image, nativePaintOrZero,
                    src.left, src.top, src.width(), src.height(),
                    dst.left, dst.top, dst.right, dst.bottom);
        }
    }

    /*package*/ static void native_drawBitmap(int nativeCanvas, int[] colors,
@@ -471,15 +659,134 @@ public class Canvas_Delegate {
    /*package*/ static void native_drawText(int nativeCanvas, char[] text,
                                               int index, int count, float x,
                                               float y, int flags, int paint) {
        // FIXME
        throw new UnsupportedOperationException();
        // WARNING: the logic in this method is similar to Paint.measureText.
        // Any change to this method should be reflected in Paint.measureText

        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
        if (canvasDelegate == null) {
            assert false;
            return;
        }

        // get the delegate from the native int.
        Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint);
        if (paintDelegate == null) {
            assert false;
            return;
        }

        Graphics2D g = canvasDelegate.getGraphics2d();

        g = (Graphics2D)g.create();
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        // set the color. because this only handles RGB, the alpha channel is handled
        // as a composite.
        g.setColor(new Color(paintDelegate.getColor()));
        int alpha = paintDelegate.getAlpha();
        float falpha = alpha / 255.f;
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, falpha));


        // Paint.TextAlign indicates how the text is positioned relative to X.
        // LEFT is the default and there's nothing to do.
        if (paintDelegate.getTextAlign() != Paint.Align.LEFT.nativeInt) {
            float m = paintDelegate.measureText(text, index, count);
            if (paintDelegate.getTextAlign() == Paint.Align.CENTER.nativeInt) {
                x -= m / 2;
            } else if (paintDelegate.getTextAlign() == Paint.Align.RIGHT.nativeInt) {
                x -= m;
            }
        }

        List<FontInfo> fonts = paintDelegate.getFonts();
        try {
            if (fonts.size() > 0) {
                FontInfo mainFont = fonts.get(0);
                int i = index;
                int lastIndex = index + count;
                while (i < lastIndex) {
                    // always start with the main font.
                    int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
                    if (upTo == -1) {
                        // draw all the rest and exit.
                        g.setFont(mainFont.mFont);
                        g.drawChars(text, i, lastIndex - i, (int)x, (int)y);
                        return;
                    } else if (upTo > 0) {
                        // draw what's possible
                        g.setFont(mainFont.mFont);
                        g.drawChars(text, i, upTo - i, (int)x, (int)y);

                        // compute the width that was drawn to increase x
                        x += mainFont.mMetrics.charsWidth(text, i, upTo - i);

                        // move index to the first non displayed char.
                        i = upTo;

                        // don't call continue at this point. Since it is certain the main font
                        // cannot display the font a index upTo (now ==i), we move on to the
                        // fallback fonts directly.
                    }

                    // no char supported, attempt to read the next char(s) with the
                    // fallback font. In this case we only test the first character
                    // and then go back to test with the main font.
                    // Special test for 2-char characters.
                    boolean foundFont = false;
                    for (int f = 1 ; f < fonts.size() ; f++) {
                        FontInfo fontInfo = fonts.get(f);

                        // need to check that the font can display the character. We test
                        // differently if the char is a high surrogate.
                        int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
                        upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
                        if (upTo == -1) {
                            // draw that char
                            g.setFont(fontInfo.mFont);
                            g.drawChars(text, i, charCount, (int)x, (int)y);

                            // update x
                            x += fontInfo.mMetrics.charsWidth(text, i, charCount);

                            // update the index in the text, and move on
                            i += charCount;
                            foundFont = true;
                            break;

                        }
                    }

                    // in case no font can display the char, display it with the main font.
                    // (it'll put a square probably)
                    if (foundFont == false) {
                        int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;

                        g.setFont(mainFont.mFont);
                        g.drawChars(text, i, charCount, (int)x, (int)y);

                        // measure it to advance x
                        x += mainFont.mMetrics.charsWidth(text, i, charCount);

                        // and move to the next chars.
                        i += charCount;
                    }
                }
            }
        } finally {
            g.dispose();
        }
    }

    /*package*/ static void native_drawText(int nativeCanvas, String text,
                                               int start, int end, float x,
                                               float y, int flags, int paint) {
        // FIXME
        throw new UnsupportedOperationException();
        int count = end - start;
        char[] buffer = TemporaryBuffer.obtain(count);
        TextUtils.getChars(text, start, end, buffer, 0);

        native_drawText(nativeCanvas, buffer, 0, count, x, y, flags, paint);
    }


@@ -556,4 +863,141 @@ public class Canvas_Delegate {
        mBufferedImage = image;
        mGraphicsStack.push(mBufferedImage.createGraphics());
    }

    /**
     * Creates a new {@link Graphics2D} based on the {@link Paint} parameters.
     * <p/>The object must be disposed ({@link Graphics2D#dispose()}) after being used.
     */
    private Graphics2D getCustomGraphics(Paint_Delegate paint) {
        // make new one
        Graphics2D g = getGraphics2d();
        g = (Graphics2D)g.create();

        // configure it
        g.setColor(new Color(paint.getColor()));
        int alpha = paint.getAlpha();
        float falpha = alpha / 255.f;

        int style = paint.getStyle();
        if (style == Paint.Style.STROKE.nativeInt ||
                style == Paint.Style.FILL_AND_STROKE.nativeInt) {
            /* FIXME
            PathEffect e = paint.getPathEffect();
            if (e instanceof DashPathEffect) {
                DashPathEffect dpe = (DashPathEffect)e;
                g.setStroke(new BasicStroke(
                        paint.getStrokeWidth(),
                        paint.getStrokeCap().getJavaCap(),
                        paint.getStrokeJoin().getJavaJoin(),
                        paint.getStrokeMiter(),
                        dpe.getIntervals(),
                        dpe.getPhase()));
            } else {*/
                g.setStroke(new BasicStroke(
                        paint.getStrokeWidth(),
                        paint.getJavaCap(),
                        paint.getJavaJoin(),
                        paint.getStrokeMiter()));
          /*  }*/
        }
/*
        Xfermode xfermode = paint.getXfermode();
        if (xfermode instanceof PorterDuffXfermode) {
            PorterDuff.Mode mode = ((PorterDuffXfermode)xfermode).getMode();

            setModeInGraphics(mode, g, falpha);
        } else {
            if (mLogger != null && xfermode != null) {
                mLogger.warning(String.format(
                        "Xfermode '%1$s' is not supported in the Layout Editor.",
                        xfermode.getClass().getCanonicalName()));
            }
            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, falpha));
        }

        Shader shader = paint.getShader();
        if (shader != null) {
            java.awt.Paint shaderPaint = shader.getJavaPaint();
            if (shaderPaint != null) {
                g.setPaint(shaderPaint);
            } else {
                if (mLogger != null) {
                    mLogger.warning(String.format(
                            "Shader '%1$s' is not supported in the Layout Editor.",
                            shader.getClass().getCanonicalName()));
                }
            }
        }
*/
        return g;
    }


    private static void drawBitmap(
            int nativeCanvas,
            BufferedImage image,
            int nativePaintOrZero,
            int sleft, int stop, int sright, int sbottom,
            int dleft, int dtop, int dright, int dbottom) {
        // get the delegate from the native int.
        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
        if (canvasDelegate == null) {
            assert false;
            return;
        }

        // get the delegate from the native int.
        Paint_Delegate paintDelegate = null;
        if (nativePaintOrZero > 0) {
            paintDelegate = Paint_Delegate.getDelegate(nativePaintOrZero);
            if (paintDelegate == null) {
                assert false;
                return;
            }
        }

        drawBitmap(canvasDelegate, image, paintDelegate,
                sleft, stop, sright, sbottom,
                dleft, dtop, dright, dbottom);
    }

    private static void drawBitmap(
            Canvas_Delegate canvasDelegate,
            BufferedImage image,
            Paint_Delegate paintDelegate,
            int sleft, int stop, int sright, int sbottom,
            int dleft, int dtop, int dright, int dbottom) {

        Graphics2D g = canvasDelegate.getGraphics2d();

        Composite c = null;

        if (paintDelegate != null) {
            if (paintDelegate.isFilterBitmap()) {
                g = (Graphics2D)g.create();
                g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                        RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            }

            if (paintDelegate.getAlpha() != 0xFF) {
                c = g.getComposite();
                g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
                        paintDelegate.getAlpha()/255.f));
            }
        }

        g.drawImage(image, dleft, dtop, dright, dbottom,
                sleft, stop, sright, sbottom, null);

        if (paintDelegate != null) {
            if (paintDelegate.isFilterBitmap()) {
                g.dispose();
            }
            if (c != null) {
                g.setComposite(c);
            }
        }
    }

}
+18 −14

File changed.

Preview size limit exceeded, changes collapsed.

+212 −67

File changed.

Preview size limit exceeded, changes collapsed.