diff options
author | Xavier Ducrohet <xav@android.com> | 2010-10-28 11:52:00 -0700 |
---|---|---|
committer | Xavier Ducrohet <xav@android.com> | 2010-11-01 13:31:47 -0700 |
commit | 9f63ff263b0a97f0fa63e97136c18f6abccbfc68 (patch) | |
tree | 51941d0fad58ffb49097b1da5c7b7551da16a570 /tools | |
parent | 5c95212f6a8f5786b8199cdc4bb3725d15ada993 (diff) | |
download | frameworks_base-9f63ff263b0a97f0fa63e97136c18f6abccbfc68.zip frameworks_base-9f63ff263b0a97f0fa63e97136c18f6abccbfc68.tar.gz frameworks_base-9f63ff263b0a97f0fa63e97136c18f6abccbfc68.tar.bz2 |
Layoutlib Canvas and Paint implementation through native delegates
Also fix native delegate generation to put "this" parameter even
for methods that don't have any parameters.
Change-Id: I5dd0c505871370ff7b4cda16de84a5b3ae438f73
Diffstat (limited to 'tools')
12 files changed, 1370 insertions, 2487 deletions
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java index 24fba72..e97b1e6 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java @@ -60,6 +60,20 @@ public class Bitmap_Delegate { // ---- Public Helper methods ---- /** + * Returns the native delegate associated to a given {@link Bitmap_Delegate} object. + */ + public static Bitmap_Delegate getDelegate(Bitmap bitmap) { + return sManager.getDelegate(bitmap.mNativeBitmap); + } + + /** + * Returns the native delegate associated to a given an int referencing a {@link Bitmap} object. + */ + public static Bitmap_Delegate getDelegate(int native_bitmap) { + return sManager.getDelegate(native_bitmap); + } + + /** * Creates and returns a {@link Bitmap} initialized with the given file content. */ public static Bitmap createBitmap(File input, Density density) throws IOException { @@ -118,6 +132,13 @@ public class Bitmap_Delegate { return BufferedImage.TYPE_INT_ARGB; } + /** + * Returns the {@link BufferedImage} used by the delegate of the given {@link Bitmap}. + */ + public BufferedImage getImage() { + return mImage; + } + // ---- native methods ---- /*package*/ static Bitmap nativeCreate(int[] colors, int offset, int stride, int width, @@ -127,8 +148,7 @@ public class Bitmap_Delegate { // create the image BufferedImage image = new BufferedImage(width, height, imageType); - // fill it - //image.setRGB(x, y, rgb) + // FIXME fill the bitmap! // create a delegate with the content of the stream. Bitmap_Delegate delegate = new Bitmap_Delegate(image); diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas.java b/tools/layoutlib/bridge/src/android/graphics/Canvas.java deleted file mode 100644 index 24da812..0000000 --- a/tools/layoutlib/bridge/src/android/graphics/Canvas.java +++ /dev/null @@ -1,1247 +0,0 @@ -/* - * Copyright (C) 2008 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.api.ILayoutLog; - -import android.graphics.Paint.Align; -import android.graphics.Paint.FontInfo; -import android.graphics.Paint.Style; -import android.graphics.Region.Op; - -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; - -/** - * Re-implementation of the Canvas, 100% in java on top of a BufferedImage. - */ -public class Canvas extends _Original_Canvas { - - private BufferedImage mBufferedImage; - private final Stack<Graphics2D> mGraphicsStack = new Stack<Graphics2D>(); - private final ILayoutLog mLogger; - - public Canvas() { - mLogger = null; - // the mBufferedImage will be taken from a bitmap in #setBitmap() - } - - public Canvas(Bitmap bitmap) { - mLogger = null; - mBufferedImage = Bitmap_Delegate.getImage(bitmap); - mGraphicsStack.push(mBufferedImage.createGraphics()); - } - - public Canvas(int nativeCanvas) { - mLogger = null; - throw new UnsupportedOperationException("Can't create Canvas(int)"); - } - - // custom constructors for our use. - public Canvas(int width, int height, ILayoutLog logger) { - mLogger = logger; - mBufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); - mGraphicsStack.push(mBufferedImage.createGraphics()); - } - - public Canvas(int width, int height) { - this(width, height, null /* logger*/); - } - - // custom mehtods - public BufferedImage getImage() { - return mBufferedImage; - } - - public Graphics2D getGraphics2d() { - return mGraphicsStack.peek(); - } - - public void dispose() { - while (mGraphicsStack.size() > 0) { - mGraphicsStack.pop().dispose(); - } - } - - /** - * 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 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; - - Style style = paint.getStyle(); - if (style == Style.STROKE || style == Style.FILL_AND_STROKE) { - 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.getStrokeCap().getJavaCap(), - paint.getStrokeJoin().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 void setModeInGraphics(PorterDuff.Mode mode, Graphics2D g, float falpha) { - switch (mode) { - case CLEAR: - g.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, falpha)); - break; - case DARKEN: - break; - case DST: - g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST, falpha)); - break; - case DST_ATOP: - g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_ATOP, falpha)); - break; - case DST_IN: - g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_IN, falpha)); - break; - case DST_OUT: - g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_OUT, falpha)); - break; - case DST_OVER: - g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_OVER, falpha)); - break; - case LIGHTEN: - break; - case MULTIPLY: - break; - case SCREEN: - break; - case SRC: - g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC, falpha)); - break; - case SRC_ATOP: - g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, falpha)); - break; - case SRC_IN: - g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN, falpha)); - break; - case SRC_OUT: - g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OUT, falpha)); - break; - case SRC_OVER: - g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, falpha)); - break; - case XOR: - g.setComposite(AlphaComposite.getInstance(AlphaComposite.XOR, falpha)); - break; - } - } - - - // -------------------- - // OVERRIDEN ENUMS - // This is needed since we rename Canvas into _Original_Canvas - // -------------------- - - public enum EdgeType { - BW(0), //!< treat edges by just rounding to nearest pixel boundary - AA(1); //!< treat edges by rounding-out, since they may be antialiased - - EdgeType(int nativeInt) { - this.nativeInt = nativeInt; - } - final int nativeInt; - } - - - // -------------------- - // OVERRIDEN METHODS - // -------------------- - - /* (non-Javadoc) - * @see android.graphics.Canvas#setBitmap(android.graphics.Bitmap) - */ - @Override - public void setBitmap(Bitmap bitmap) { - mBufferedImage = Bitmap_Delegate.getImage(bitmap); - mGraphicsStack.push(mBufferedImage.createGraphics()); - } - - - /* (non-Javadoc) - * @see android.graphics.Canvas#translate(float, float) - */ - @Override - public void translate(float dx, float dy) { - getGraphics2d().translate(dx, dy); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#save() - */ - @Override - public int save() { - // get the current save count - int count = mGraphicsStack.size(); - - // create a new graphics and add it to the stack - Graphics2D g = (Graphics2D)getGraphics2d().create(); - mGraphicsStack.push(g); - - // return the old save count - return count; - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#save(int) - */ - @Override - public int save(int saveFlags) { - // For now we ignore saveFlags - return save(); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#restore() - */ - @Override - public void restore() { - mGraphicsStack.pop(); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#restoreToCount(int) - */ - @Override - public void restoreToCount(int saveCount) { - while (mGraphicsStack.size() > saveCount) { - mGraphicsStack.pop(); - } - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#getSaveCount() - */ - @Override - public int getSaveCount() { - return mGraphicsStack.size(); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#clipRect(float, float, float, float, android.graphics.Region.Op) - */ - @Override - public boolean clipRect(float left, float top, float right, float bottom, Op op) { - return clipRect(left, top, right, bottom); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#clipRect(float, float, float, float) - */ - @Override - public boolean clipRect(float left, float top, float right, float bottom) { - getGraphics2d().clipRect((int)left, (int)top, (int)(right-left), (int)(bottom-top)); - return true; - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#clipRect(int, int, int, int) - */ - @Override - public boolean clipRect(int left, int top, int right, int bottom) { - getGraphics2d().clipRect(left, top, right-left, bottom-top); - return true; - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#clipRect(android.graphics.Rect, android.graphics.Region.Op) - */ - @Override - public boolean clipRect(Rect rect, Op op) { - return clipRect(rect.left, rect.top, rect.right, rect.bottom); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#clipRect(android.graphics.Rect) - */ - @Override - public boolean clipRect(Rect rect) { - return clipRect(rect.left, rect.top, rect.right, rect.bottom); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#clipRect(android.graphics.RectF, android.graphics.Region.Op) - */ - @Override - public boolean clipRect(RectF rect, Op op) { - return clipRect(rect.left, rect.top, rect.right, rect.bottom); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#clipRect(android.graphics.RectF) - */ - @Override - public boolean clipRect(RectF rect) { - return clipRect(rect.left, rect.top, rect.right, rect.bottom); - } - - public boolean quickReject(RectF rect, EdgeType type) { - return false; - } - - @Override - public boolean quickReject(RectF rect, _Original_Canvas.EdgeType type) { - throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN"); - } - - public boolean quickReject(Path path, EdgeType type) { - return false; - } - - @Override - public boolean quickReject(Path path, _Original_Canvas.EdgeType type) { - throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN"); - } - - public boolean quickReject(float left, float top, float right, float bottom, - EdgeType type) { - return false; - } - - @Override - public boolean quickReject(float left, float top, float right, float bottom, - _Original_Canvas.EdgeType type) { - throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN"); - } - - /** - * Retrieve the clip bounds, returning true if they are non-empty. - * - * @param bounds Return the clip bounds here. If it is null, ignore it but - * still return true if the current clip is non-empty. - * @return true if the current clip is non-empty. - */ - @Override - public boolean getClipBounds(Rect bounds) { - Rectangle rect = 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; - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawColor(int, android.graphics.PorterDuff.Mode) - */ - @Override - public void drawColor(int color, PorterDuff.Mode mode) { - Graphics2D g = getGraphics2d(); - - // save old color - Color c = g.getColor(); - - Composite composite = g.getComposite(); - - // get the alpha from the color - int alpha = color >>> 24; - float falpha = alpha / 255.f; - - setModeInGraphics(mode, g, falpha); - - g.setColor(new Color(color)); - - g.fillRect(0, 0, getWidth(), getHeight()); - - g.setComposite(composite); - - // restore color - g.setColor(c); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawColor(int) - */ - @Override - public void drawColor(int color) { - drawColor(color, PorterDuff.Mode.SRC_OVER); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawARGB(int, int, int, int) - */ - @Override - public void drawARGB(int a, int r, int g, int b) { - drawColor(a << 24 | r << 16 | g << 8 | b, PorterDuff.Mode.SRC_OVER); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawRGB(int, int, int) - */ - @Override - public void drawRGB(int r, int g, int b) { - drawColor(0xFF << 24 | r << 16 | g << 8 | b, PorterDuff.Mode.SRC_OVER); - } - - - /* (non-Javadoc) - * @see android.graphics.Canvas#getWidth() - */ - @Override - public int getWidth() { - return mBufferedImage.getWidth(); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#getHeight() - */ - @Override - public int getHeight() { - return mBufferedImage.getHeight(); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawPaint(android.graphics.Paint) - */ - @Override - public void drawPaint(Paint paint) { - drawColor(paint.getColor()); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawBitmap(android.graphics.Bitmap, float, float, android.graphics.Paint) - */ - @Override - public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) { - drawBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), - (int)left, (int)top, - (int)left+bitmap.getWidth(), (int)top+bitmap.getHeight(), paint); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawBitmap(android.graphics.Bitmap, android.graphics.Matrix, android.graphics.Paint) - */ - @Override - public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) { - boolean needsRestore = false; - if (matrix.isIdentity() == false) { - // create a new graphics and apply the matrix to it - save(); // this creates a new Graphics2D, and stores it for children call to use - needsRestore = true; - Graphics2D g = getGraphics2d(); // get the newly create Graphics2D - - // get the Graphics2D current matrix - AffineTransform currentTx = g.getTransform(); - // get the AffineTransform from the matrix - AffineTransform matrixTx = Matrix_Delegate.getAffineTransform(matrix); - - // combine them so that the matrix is applied after. - currentTx.preConcatenate(matrixTx); - - // give it to the graphics as a new matrix replacing all previous transform - g.setTransform(currentTx); - } - - // draw the bitmap - drawBitmap(bitmap, 0, 0, paint); - - if (needsRestore) { - // remove the new graphics - restore(); - } - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawBitmap(android.graphics.Bitmap, android.graphics.Rect, android.graphics.Rect, android.graphics.Paint) - */ - @Override - public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) { - if (src == null) { - drawBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), - dst.left, dst.top, dst.right, dst.bottom, paint); - } else { - drawBitmap(bitmap, src.left, src.top, src.width(), src.height(), - dst.left, dst.top, dst.right, dst.bottom, paint); - } - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawBitmap(android.graphics.Bitmap, android.graphics.Rect, android.graphics.RectF, android.graphics.Paint) - */ - @Override - public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) { - if (src == null) { - drawBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), - (int)dst.left, (int)dst.top, (int)dst.right, (int)dst.bottom, paint); - } else { - drawBitmap(bitmap, src.left, src.top, src.width(), src.height(), - (int)dst.left, (int)dst.top, (int)dst.right, (int)dst.bottom, paint); - } - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawBitmap(int[], int, int, int, int, int, int, boolean, android.graphics.Paint) - */ - @Override - public void drawBitmap(int[] colors, int offset, int stride, int x, int y, int width, - int height, boolean hasAlpha, Paint paint) { - throw new UnsupportedOperationException(); - } - - private void drawBitmap(Bitmap bitmap, int sleft, int stop, int sright, int sbottom, int dleft, - int dtop, int dright, int dbottom, Paint paint) { - BufferedImage image = Bitmap_Delegate.getImage(bitmap); - - Graphics2D g = getGraphics2d(); - - Composite c = null; - - if (paint != null) { - if (paint.isFilterBitmap()) { - g = (Graphics2D)g.create(); - g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, - RenderingHints.VALUE_INTERPOLATION_BILINEAR); - } - - if (paint.getAlpha() != 0xFF) { - c = g.getComposite(); - g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, - paint.getAlpha()/255.f)); - } - } - - g.drawImage(image, dleft, dtop, dright, dbottom, - sleft, stop, sright, sbottom, null); - - if (paint != null) { - if (paint.isFilterBitmap()) { - g.dispose(); - } - if (c != null) { - g.setComposite(c); - } - } - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#rotate(float, float, float) - */ - @Override - public void rotate(float degrees, float px, float py) { - if (degrees != 0) { - Graphics2D g = getGraphics2d(); - g.translate(px, py); - g.rotate(Math.toRadians(degrees)); - g.translate(-px, -py); - } - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#rotate(float) - */ - @Override - public void rotate(float degrees) { - getGraphics2d().rotate(Math.toRadians(degrees)); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#scale(float, float, float, float) - */ - @Override - public void scale(float sx, float sy, float px, float py) { - Graphics2D g = getGraphics2d(); - g.translate(px, py); - g.scale(sx, sy); - g.translate(-px, -py); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#scale(float, float) - */ - @Override - public void scale(float sx, float sy) { - getGraphics2d().scale(sx, sy); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawText(char[], int, int, float, float, android.graphics.Paint) - */ - @Override - public void drawText(char[] text, int index, int count, float x, float y, Paint paint) { - // WARNING: the logic in this method is similar to Paint.measureText. - // Any change to this method should be reflected in Paint.measureText - Graphics2D g = 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(paint.getColor())); - int alpha = paint.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 (paint.getTextAlign() != Align.LEFT) { - float m = paint.measureText(text, index, count); - if (paint.getTextAlign() == Align.CENTER) { - x -= m / 2; - } else if (paint.getTextAlign() == Align.RIGHT) { - x -= m; - } - } - - List<FontInfo> fonts = paint.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(); - } - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawText(java.lang.CharSequence, int, int, float, float, android.graphics.Paint) - */ - @Override - public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) { - drawText(text.toString().toCharArray(), start, end - start, x, y, paint); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawText(java.lang.String, float, float, android.graphics.Paint) - */ - @Override - public void drawText(String text, float x, float y, Paint paint) { - drawText(text.toCharArray(), 0, text.length(), x, y, paint); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawText(java.lang.String, int, int, float, float, android.graphics.Paint) - */ - @Override - public void drawText(String text, int start, int end, float x, float y, Paint paint) { - drawText(text.toCharArray(), start, end - start, x, y, paint); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawRect(android.graphics.RectF, android.graphics.Paint) - */ - @Override - public void drawRect(RectF rect, Paint paint) { - doDrawRect((int)rect.left, (int)rect.top, (int)rect.width(), (int)rect.height(), paint); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawRect(float, float, float, float, android.graphics.Paint) - */ - @Override - public void drawRect(float left, float top, float right, float bottom, Paint paint) { - doDrawRect((int)left, (int)top, (int)(right-left), (int)(bottom-top), paint); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawRect(android.graphics.Rect, android.graphics.Paint) - */ - @Override - public void drawRect(Rect r, Paint paint) { - doDrawRect(r.left, r.top, r.width(), r.height(), paint); - } - - private final void doDrawRect(int left, int top, int width, int height, Paint paint) { - if (width > 0 && height > 0) { - // get a Graphics2D object configured with the drawing parameters. - Graphics2D g = getCustomGraphics(paint); - - Style style = paint.getStyle(); - - // draw - if (style == Style.FILL || style == Style.FILL_AND_STROKE) { - g.fillRect(left, top, width, height); - } - - if (style == Style.STROKE || style == Style.FILL_AND_STROKE) { - g.drawRect(left, top, width, height); - } - - // dispose Graphics2D object - g.dispose(); - } - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawRoundRect(android.graphics.RectF, float, float, android.graphics.Paint) - */ - @Override - public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) { - if (rect.width() > 0 && rect.height() > 0) { - // get a Graphics2D object configured with the drawing parameters. - Graphics2D g = getCustomGraphics(paint); - - Style style = paint.getStyle(); - - // draw - - int arcWidth = (int)(rx * 2); - int arcHeight = (int)(ry * 2); - - if (style == Style.FILL || style == Style.FILL_AND_STROKE) { - g.fillRoundRect((int)rect.left, (int)rect.top, (int)rect.width(), (int)rect.height(), - arcWidth, arcHeight); - } - - if (style == Style.STROKE || style == Style.FILL_AND_STROKE) { - g.drawRoundRect((int)rect.left, (int)rect.top, (int)rect.width(), (int)rect.height(), - arcWidth, arcHeight); - } - - // dispose Graphics2D object - g.dispose(); - } - } - - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawLine(float, float, float, float, android.graphics.Paint) - */ - @Override - public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) { - // get a Graphics2D object configured with the drawing parameters. - Graphics2D g = getCustomGraphics(paint); - - g.drawLine((int)startX, (int)startY, (int)stopX, (int)stopY); - - // dispose Graphics2D object - g.dispose(); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawLines(float[], int, int, android.graphics.Paint) - */ - @Override - public void drawLines(float[] pts, int offset, int count, Paint paint) { - // get a Graphics2D object configured with the drawing parameters. - Graphics2D g = getCustomGraphics(paint); - - for (int i = 0 ; i < count ; i += 4) { - g.drawLine((int)pts[i + offset], (int)pts[i + offset + 1], - (int)pts[i + offset + 2], (int)pts[i + offset + 3]); - } - - // dispose Graphics2D object - g.dispose(); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawLines(float[], android.graphics.Paint) - */ - @Override - public void drawLines(float[] pts, Paint paint) { - drawLines(pts, 0, pts.length, paint); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawCircle(float, float, float, android.graphics.Paint) - */ - @Override - public void drawCircle(float cx, float cy, float radius, Paint paint) { - // get a Graphics2D object configured with the drawing parameters. - Graphics2D g = getCustomGraphics(paint); - - Style style = paint.getStyle(); - - int size = (int)(radius * 2); - - // draw - if (style == Style.FILL || style == Style.FILL_AND_STROKE) { - g.fillOval((int)(cx - radius), (int)(cy - radius), size, size); - } - - if (style == Style.STROKE || style == Style.FILL_AND_STROKE) { - g.drawOval((int)(cx - radius), (int)(cy - radius), size, size); - } - - // dispose Graphics2D object - g.dispose(); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawOval(android.graphics.RectF, android.graphics.Paint) - */ - @Override - public void drawOval(RectF oval, Paint paint) { - // get a Graphics2D object configured with the drawing parameters. - Graphics2D g = getCustomGraphics(paint); - - Style style = paint.getStyle(); - - // draw - if (style == Style.FILL || style == Style.FILL_AND_STROKE) { - g.fillOval((int)oval.left, (int)oval.top, (int)oval.width(), (int)oval.height()); - } - - if (style == Style.STROKE || style == Style.FILL_AND_STROKE) { - g.drawOval((int)oval.left, (int)oval.top, (int)oval.width(), (int)oval.height()); - } - - // dispose Graphics2D object - g.dispose(); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawPath(android.graphics.Path, android.graphics.Paint) - */ - @Override - public void drawPath(Path path, Paint paint) { - // get a Graphics2D object configured with the drawing parameters. - Graphics2D g = getCustomGraphics(paint); - - Style style = paint.getStyle(); - - // draw - if (style == Style.FILL || style == Style.FILL_AND_STROKE) { - g.fill(path.getAwtShape()); - } - - if (style == Style.STROKE || style == Style.FILL_AND_STROKE) { - g.draw(path.getAwtShape()); - } - - // dispose Graphics2D object - g.dispose(); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#setMatrix(android.graphics.Matrix) - */ - @Override - public void setMatrix(Matrix matrix) { - // get the new current graphics - Graphics2D g = getGraphics2d(); - - // and apply the matrix - g.setTransform(Matrix_Delegate.getAffineTransform(matrix)); - - if (mLogger != null && Matrix_Delegate.hasPerspective(matrix)) { - mLogger.warning("android.graphics.Canvas#setMatrix(android.graphics.Matrix) only supports affine transformations in the Layout Editor."); - } - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#concat(android.graphics.Matrix) - */ - @Override - public void concat(Matrix matrix) { - // get the current top graphics2D object. - Graphics2D g = getGraphics2d(); - - // get its current matrix - AffineTransform currentTx = g.getTransform(); - // get the AffineTransform of the given matrix - AffineTransform matrixTx = Matrix_Delegate.getAffineTransform(matrix); - - // 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); - } - - - // -------------------- - - /* (non-Javadoc) - * @see android.graphics.Canvas#clipPath(android.graphics.Path, android.graphics.Region.Op) - */ - @Override - public boolean clipPath(Path path, Op op) { - // TODO Auto-generated method stub - return super.clipPath(path, op); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#clipPath(android.graphics.Path) - */ - @Override - public boolean clipPath(Path path) { - // TODO Auto-generated method stub - return super.clipPath(path); - } - - - /* (non-Javadoc) - * @see android.graphics.Canvas#clipRegion(android.graphics.Region, android.graphics.Region.Op) - */ - @Override - public boolean clipRegion(Region region, Op op) { - // TODO Auto-generated method stub - return super.clipRegion(region, op); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#clipRegion(android.graphics.Region) - */ - @Override - public boolean clipRegion(Region region) { - // TODO Auto-generated method stub - return super.clipRegion(region); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawArc(android.graphics.RectF, float, float, boolean, android.graphics.Paint) - */ - @Override - public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, - Paint paint) { - // TODO Auto-generated method stub - super.drawArc(oval, startAngle, sweepAngle, useCenter, paint); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawBitmapMesh(android.graphics.Bitmap, int, int, float[], int, int[], int, android.graphics.Paint) - */ - @Override - public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts, - int vertOffset, int[] colors, int colorOffset, Paint paint) { - // TODO Auto-generated method stub - super.drawBitmapMesh(bitmap, meshWidth, meshHeight, verts, vertOffset, colors, colorOffset, paint); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawPicture(android.graphics.Picture, android.graphics.Rect) - */ - @Override - public void drawPicture(Picture picture, Rect dst) { - // TODO Auto-generated method stub - super.drawPicture(picture, dst); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawPicture(android.graphics.Picture, android.graphics.RectF) - */ - @Override - public void drawPicture(Picture picture, RectF dst) { - // TODO Auto-generated method stub - super.drawPicture(picture, dst); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawPicture(android.graphics.Picture) - */ - @Override - public void drawPicture(Picture picture) { - // TODO Auto-generated method stub - super.drawPicture(picture); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawPoint(float, float, android.graphics.Paint) - */ - @Override - public void drawPoint(float x, float y, Paint paint) { - // TODO Auto-generated method stub - super.drawPoint(x, y, paint); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawPoints(float[], int, int, android.graphics.Paint) - */ - @Override - public void drawPoints(float[] pts, int offset, int count, Paint paint) { - // TODO Auto-generated method stub - super.drawPoints(pts, offset, count, paint); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawPoints(float[], android.graphics.Paint) - */ - @Override - public void drawPoints(float[] pts, Paint paint) { - // TODO Auto-generated method stub - super.drawPoints(pts, paint); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawPosText(char[], int, int, float[], android.graphics.Paint) - */ - @Override - public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint) { - // TODO Auto-generated method stub - super.drawPosText(text, index, count, pos, paint); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawPosText(java.lang.String, float[], android.graphics.Paint) - */ - @Override - public void drawPosText(String text, float[] pos, Paint paint) { - // TODO Auto-generated method stub - super.drawPosText(text, pos, paint); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawTextOnPath(char[], int, int, android.graphics.Path, float, float, android.graphics.Paint) - */ - @Override - public void drawTextOnPath(char[] text, int index, int count, Path path, float offset, - float offset2, Paint paint) { - // TODO Auto-generated method stub - super.drawTextOnPath(text, index, count, path, offset, offset2, paint); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawTextOnPath(java.lang.String, android.graphics.Path, float, float, android.graphics.Paint) - */ - @Override - public void drawTextOnPath(String text, Path path, float offset, float offset2, Paint paint) { - // TODO Auto-generated method stub - super.drawTextOnPath(text, path, offset, offset2, paint); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawVertices(android.graphics.Canvas.VertexMode, int, float[], int, float[], int, int[], int, short[], int, int, android.graphics.Paint) - */ - @Override - public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset, - float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices, - int indexOffset, int indexCount, Paint paint) { - // TODO Auto-generated method stub - super.drawVertices(mode, vertexCount, verts, vertOffset, texs, texOffset, colors, colorOffset, - indices, indexOffset, indexCount, paint); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#getDrawFilter() - */ - @Override - public DrawFilter getDrawFilter() { - // TODO Auto-generated method stub - return super.getDrawFilter(); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#getMatrix() - */ - @Override - public Matrix getMatrix() { - // TODO Auto-generated method stub - return super.getMatrix(); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#getMatrix(android.graphics.Matrix) - */ - @Override - public void getMatrix(Matrix ctm) { - // TODO Auto-generated method stub - super.getMatrix(ctm); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#isOpaque() - */ - @Override - public boolean isOpaque() { - // TODO Auto-generated method stub - return super.isOpaque(); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#saveLayer(float, float, float, float, android.graphics.Paint, int) - */ - @Override - public int saveLayer(float left, float top, float right, float bottom, Paint paint, - int saveFlags) { - // TODO Auto-generated method stub - return super.saveLayer(left, top, right, bottom, paint, saveFlags); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#saveLayer(android.graphics.RectF, android.graphics.Paint, int) - */ - @Override - public int saveLayer(RectF bounds, Paint paint, int saveFlags) { - // TODO Auto-generated method stub - return super.saveLayer(bounds, paint, saveFlags); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#saveLayerAlpha(float, float, float, float, int, int) - */ - @Override - public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha, - int saveFlags) { - // TODO Auto-generated method stub - return super.saveLayerAlpha(left, top, right, bottom, alpha, saveFlags); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#saveLayerAlpha(android.graphics.RectF, int, int) - */ - @Override - public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags) { - // TODO Auto-generated method stub - return super.saveLayerAlpha(bounds, alpha, saveFlags); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#setDrawFilter(android.graphics.DrawFilter) - */ - @Override - public void setDrawFilter(DrawFilter filter) { - // TODO Auto-generated method stub - super.setDrawFilter(filter); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#skew(float, float) - */ - @Override - public void skew(float sx, float sy) { - // TODO Auto-generated method stub - super.skew(sx, sy); - } - - - -} diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java new file mode 100644 index 0000000..6627d37 --- /dev/null +++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java @@ -0,0 +1,559 @@ +/* + * 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.api.ILayoutLog; +import com.android.layoutlib.bridge.DelegateManager; + +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.util.Stack; + +/** + * Delegate implementing the native methods of android.graphics.Canvas + * + * Through the layoutlib_create tool, the original native methods of Canvas 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 Canvas class. + * + * @see DelegateManager + * + */ +public class Canvas_Delegate { + + // ---- delegate manager ---- + private static final DelegateManager<Canvas_Delegate> sManager = + new DelegateManager<Canvas_Delegate>(); + + // ---- delegate helper data ---- + + // ---- delegate data ---- + private BufferedImage mBufferedImage; + private final Stack<Graphics2D> mGraphicsStack = new Stack<Graphics2D>(); + private ILayoutLog mLogger; + + // ---- 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.mNativeCanvas); + } + + /** + * Returns the native delegate associated to a given an int referencing a {@link Canvas} object. + */ + public static Canvas_Delegate getDelegate(int native_canvas) { + return sManager.getDelegate(native_canvas); + } + + /** + * Sets the layoutlib logger into the canvas. + * @param logger + */ + public void setLogger(ILayoutLog logger) { + mLogger = logger; + } + + /** + * Returns the current {@link Graphics2D} used to draw. + */ + public Graphics2D getGraphics2d() { + return mGraphicsStack.peek(); + } + + /** + * Disposes of the {@link Graphics2D} stack. + */ + public void dispose() { + + } + + // ---- native methods ---- + + /*package*/ static boolean isOpaque(Canvas thisCanvas) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int getWidth(Canvas thisCanvas) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int getHeight(Canvas thisCanvas) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void translate(Canvas thisCanvas, float dx, float dy) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void rotate(Canvas thisCanvas, float degrees) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void scale(Canvas thisCanvas, float sx, float sy) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void skew(Canvas thisCanvas, float sx, float sy) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static boolean clipRect(Canvas thisCanvas, RectF rect) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static boolean clipRect(Canvas thisCanvas, Rect rect) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static boolean clipRect(Canvas thisCanvas, float left, float top, float right, + float bottom) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static boolean clipRect(Canvas thisCanvas, int left, int top, int right, + int bottom) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int save(Canvas thisCanvas) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int save(Canvas thisCanvas, int saveFlags) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void restore(Canvas thisCanvas) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int getSaveCount(Canvas thisCanvas) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void restoreToCount(Canvas thisCanvas, int saveCount) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void drawPoints(Canvas thisCanvas, float[] pts, int offset, int count, + Paint paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void drawPoint(Canvas thisCanvas, float x, float y, Paint paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void drawLines(Canvas thisCanvas, float[] pts, int offset, int count, + Paint paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void freeCaches() { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int initRaster(int nativeBitmapOrZero) { + if (nativeBitmapOrZero > 0) { + // get the Bitmap from the int + Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(nativeBitmapOrZero); + + // create a new Canvas_Delegate with the given bitmap and return its new native int. + Canvas_Delegate newDelegate = new Canvas_Delegate(bitmapDelegate.getImage()); + + return sManager.addDelegate(newDelegate); + } else { + // create a new Canvas_Delegate and return its new native int. + Canvas_Delegate newDelegate = new Canvas_Delegate(); + + return sManager.addDelegate(newDelegate); + } + } + + /*package*/ static void native_setBitmap(int nativeCanvas, int bitmap) { + // 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. + Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap); + if (bitmapDelegate == null) { + assert false; + return; + } + + canvasDelegate.setBitmap(bitmapDelegate.getImage()); + } + + /*package*/ static int native_saveLayer(int nativeCanvas, RectF bounds, + int paint, int layerFlags) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int native_saveLayer(int nativeCanvas, float l, + float t, float r, float b, + int paint, int layerFlags) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int native_saveLayerAlpha(int nativeCanvas, + RectF bounds, int alpha, + int layerFlags) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int native_saveLayerAlpha(int nativeCanvas, float l, + float t, float r, float b, + int alpha, int layerFlags) { + // FIXME + throw new UnsupportedOperationException(); + } + + + /*package*/ static void native_concat(int nCanvas, int nMatrix) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_setMatrix(int nCanvas, int nMatrix) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static boolean native_clipRect(int nCanvas, + float left, float top, + float right, float bottom, + int regionOp) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static boolean native_clipPath(int nativeCanvas, + int nativePath, + int regionOp) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static boolean native_clipRegion(int nativeCanvas, + int nativeRegion, + int regionOp) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void nativeSetDrawFilter(int nativeCanvas, + int nativeFilter) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static boolean native_getClipBounds(int nativeCanvas, + Rect bounds) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_getCTM(int canvas, int matrix) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static boolean native_quickReject(int nativeCanvas, + RectF rect, + int native_edgeType) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static boolean native_quickReject(int nativeCanvas, + int path, + int native_edgeType) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static boolean native_quickReject(int nativeCanvas, + float left, float top, + float right, float bottom, + int native_edgeType) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawRGB(int nativeCanvas, int r, int g, + int b) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawARGB(int nativeCanvas, int a, int r, + int g, int b) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawColor(int nativeCanvas, int color) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawColor(int nativeCanvas, int color, + int mode) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawPaint(int nativeCanvas, int paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawLine(int nativeCanvas, float startX, + float startY, float stopX, + float stopY, int paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawRect(int nativeCanvas, RectF rect, + int paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawRect(int nativeCanvas, float left, + float top, float right, + float bottom, int paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawOval(int nativeCanvas, RectF oval, + int paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawCircle(int nativeCanvas, float cx, + float cy, float radius, + int paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawArc(int nativeCanvas, RectF oval, + float startAngle, float sweep, + boolean useCenter, int paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawRoundRect(int nativeCanvas, + RectF rect, float rx, + float ry, int paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawPath(int nativeCanvas, int path, + int paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawBitmap(Canvas thisCanvas, int nativeCanvas, int bitmap, + float left, float top, + int nativePaintOrZero, + int canvasDensity, + int screenDensity, + int bitmapDensity) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawBitmap(Canvas thisCanvas, int nativeCanvas, int bitmap, + Rect src, RectF dst, + int nativePaintOrZero, + int screenDensity, + int bitmapDensity) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawBitmap(int nativeCanvas, int bitmap, + Rect src, Rect dst, + int nativePaintOrZero, + int screenDensity, + int bitmapDensity) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawBitmap(int nativeCanvas, int[] colors, + int offset, int stride, float x, + float y, int width, int height, + boolean hasAlpha, + int nativePaintOrZero) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void nativeDrawBitmapMatrix(int nCanvas, int nBitmap, + int nMatrix, int nPaint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void nativeDrawBitmapMesh(int nCanvas, int nBitmap, + int meshWidth, int meshHeight, + float[] verts, int vertOffset, + int[] colors, int colorOffset, int nPaint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void nativeDrawVertices(int nCanvas, int mode, int n, + float[] verts, int vertOffset, float[] texs, int texOffset, + int[] colors, int colorOffset, short[] indices, + int indexOffset, int indexCount, int nPaint) { + // FIXME + throw new UnsupportedOperationException(); + } + + + /*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(); + } + + /*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(); + } + + + /*package*/ static void native_drawTextRun(int nativeCanvas, String text, + int start, int end, int contextStart, int contextEnd, + float x, float y, int flags, int paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + + /*package*/ static void native_drawTextRun(int nativeCanvas, char[] text, + int start, int count, int contextStart, int contextCount, + float x, float y, int flags, int paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + + /*package*/ static void native_drawPosText(int nativeCanvas, + char[] text, int index, + int count, float[] pos, + int paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawPosText(int nativeCanvas, + String text, float[] pos, + int paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawTextOnPath(int nativeCanvas, + char[] text, int index, + int count, int path, + float hOffset, + float vOffset, int bidiFlags, + int paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawTextOnPath(int nativeCanvas, + String text, int path, + float hOffset, + float vOffset, + int flags, int paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawPicture(int nativeCanvas, + int nativePicture) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void finalizer(int nativeCanvas) { + sManager.removeDelegate(nativeCanvas); + } + + // ---- Private delegate/helper methods ---- + + private Canvas_Delegate(BufferedImage image) { + setBitmap(image); + } + + private Canvas_Delegate() { + } + + private void setBitmap(BufferedImage image) { + mBufferedImage = image; + mGraphicsStack.push(mBufferedImage.createGraphics()); + } +} diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint.java b/tools/layoutlib/bridge/src/android/graphics/Paint.java deleted file mode 100644 index 2de21c1..0000000 --- a/tools/layoutlib/bridge/src/android/graphics/Paint.java +++ /dev/null @@ -1,1211 +0,0 @@ -/* - * Copyright (C) 2008 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 android.text.SpannableString; -import android.text.SpannableStringBuilder; -import android.text.SpannedString; -import android.text.TextUtils; - -import java.awt.BasicStroke; -import java.awt.Font; -import java.awt.Toolkit; -import java.awt.font.FontRenderContext; -import java.awt.geom.AffineTransform; -import java.awt.geom.Rectangle2D; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * A paint implementation overridden by the LayoutLib bridge. - */ -public class Paint extends _Original_Paint { - - private int mColor = 0xFFFFFFFF; - private float mStrokeWidth = 1.f; - private float mTextSize = 20; - private float mScaleX = 1; - private float mSkewX = 0; - private Align mAlign = Align.LEFT; - private Style mStyle = Style.FILL; - private float mStrokeMiter = 4.0f; - private Cap mCap = Cap.BUTT; - private Join mJoin = Join.MITER; - private int mFlags = 0; - - /** - * Class associating a {@link Font} and it's {@link java.awt.FontMetrics}. - */ - public static final class FontInfo { - Font mFont; - java.awt.FontMetrics mMetrics; - } - - private List<FontInfo> mFonts; - private final FontRenderContext mFontContext = new FontRenderContext( - new AffineTransform(), true, true); - - public static final int ANTI_ALIAS_FLAG = _Original_Paint.ANTI_ALIAS_FLAG; - public static final int FILTER_BITMAP_FLAG = _Original_Paint.FILTER_BITMAP_FLAG; - public static final int DITHER_FLAG = _Original_Paint.DITHER_FLAG; - public static final int UNDERLINE_TEXT_FLAG = _Original_Paint.UNDERLINE_TEXT_FLAG; - public static final int STRIKE_THRU_TEXT_FLAG = _Original_Paint.STRIKE_THRU_TEXT_FLAG; - public static final int FAKE_BOLD_TEXT_FLAG = _Original_Paint.FAKE_BOLD_TEXT_FLAG; - public static final int LINEAR_TEXT_FLAG = _Original_Paint.LINEAR_TEXT_FLAG; - public static final int SUBPIXEL_TEXT_FLAG = _Original_Paint.SUBPIXEL_TEXT_FLAG; - public static final int DEV_KERN_TEXT_FLAG = _Original_Paint.DEV_KERN_TEXT_FLAG; - - public static class FontMetrics extends _Original_Paint.FontMetrics { - } - - public static class FontMetricsInt extends _Original_Paint.FontMetricsInt { - } - - /** - * The Style specifies if the primitive being drawn is filled, - * stroked, or both (in the same color). The default is FILL. - */ - public enum Style { - /** - * Geometry and text drawn with this style will be filled, ignoring all - * stroke-related settings in the paint. - */ - FILL (0), - /** - * Geometry and text drawn with this style will be stroked, respecting - * the stroke-related fields on the paint. - */ - STROKE (1), - /** - * Geometry and text drawn with this style will be both filled and - * stroked at the same time, respecting the stroke-related fields on - * the paint. - */ - FILL_AND_STROKE (2); - - Style(int nativeInt) { - this.nativeInt = nativeInt; - } - final int nativeInt; - } - - /** - * The Cap specifies the treatment for the beginning and ending of - * stroked lines and paths. The default is BUTT. - */ - public enum Cap { - /** - * The stroke ends with the path, and does not project beyond it. - */ - BUTT (0), - /** - * The stroke projects out as a square, with the center at the end - * of the path. - */ - ROUND (1), - /** - * The stroke projects out as a semicircle, with the center at the - * end of the path. - */ - SQUARE (2); - - private Cap(int nativeInt) { - this.nativeInt = nativeInt; - } - final int nativeInt; - - /** custom for layoutlib */ - public int getJavaCap() { - switch (this) { - case BUTT: - return BasicStroke.CAP_BUTT; - case ROUND: - return BasicStroke.CAP_ROUND; - default: - case SQUARE: - return BasicStroke.CAP_SQUARE; - } - } - } - - /** - * The Join specifies the treatment where lines and curve segments - * join on a stroked path. The default is MITER. - */ - public enum Join { - /** - * The outer edges of a join meet at a sharp angle - */ - MITER (0), - /** - * The outer edges of a join meet in a circular arc. - */ - ROUND (1), - /** - * The outer edges of a join meet with a straight line - */ - BEVEL (2); - - private Join(int nativeInt) { - this.nativeInt = nativeInt; - } - final int nativeInt; - - /** custom for layoutlib */ - public int getJavaJoin() { - switch (this) { - default: - case MITER: - return BasicStroke.JOIN_MITER; - case ROUND: - return BasicStroke.JOIN_ROUND; - case BEVEL: - return BasicStroke.JOIN_BEVEL; - } - } - } - - /** - * Align specifies how drawText aligns its text relative to the - * [x,y] coordinates. The default is LEFT. - */ - public enum Align { - /** - * The text is drawn to the right of the x,y origin - */ - LEFT (0), - /** - * The text is drawn centered horizontally on the x,y origin - */ - CENTER (1), - /** - * The text is drawn to the left of the x,y origin - */ - RIGHT (2); - - private Align(int nativeInt) { - this.nativeInt = nativeInt; - } - final int nativeInt; - } - - public Paint() { - this(0); - } - - /* - * Do not remove or com.android.layoutlib.bridge.TestClassReplacement fails. - */ - @Override - public void finalize() { } - - public Paint(int flags) { - setFlags(flags | DEFAULT_PAINT_FLAGS); - initFont(); - } - - public Paint(Paint paint) { - set(paint); - initFont(); - } - - @Override - public void reset() { - super.reset(); - } - - /** - * Returns the list of {@link Font} objects. The first item is the main font, the rest - * are fall backs for characters not present in the main font. - */ - public List<FontInfo> getFonts() { - return mFonts; - } - - private void initFont() { - mTypeface = Typeface.DEFAULT; - updateFontObject(); - } - - /** - * Update the {@link Font} object from the typeface, text size and scaling - */ - @SuppressWarnings("deprecation") - private void updateFontObject() { - if (mTypeface != null) { - // Get the fonts from the TypeFace object. - List<Font> fonts = Typeface_Delegate.getFonts(mTypeface); - - // create new font objects as well as FontMetrics, based on the current text size - // and skew info. - ArrayList<FontInfo> infoList = new ArrayList<FontInfo>(fonts.size()); - for (Font font : fonts) { - FontInfo info = new FontInfo(); - info.mFont = font.deriveFont(mTextSize); - if (mScaleX != 1.0 || mSkewX != 0) { - // TODO: support skew - info.mFont = info.mFont.deriveFont(new AffineTransform( - mScaleX, mSkewX, 0, 0, 1, 0)); - } - info.mMetrics = Toolkit.getDefaultToolkit().getFontMetrics(info.mFont); - - infoList.add(info); - } - - mFonts = Collections.unmodifiableList(infoList); - } - } - - //---------------------------------------- - - public void set(Paint src) { - if (this != src) { - mColor = src.mColor; - mTextSize = src.mTextSize; - mScaleX = src.mScaleX; - mSkewX = src.mSkewX; - mAlign = src.mAlign; - mStyle = src.mStyle; - mFlags = src.mFlags; - - updateFontObject(); - - super.set(src); - } - } - - @Override - public void setCompatibilityScaling(float factor) { - super.setCompatibilityScaling(factor); - } - - @Override - public int getFlags() { - return mFlags; - } - - @Override - public void setFlags(int flags) { - mFlags = flags; - } - - @Override - public boolean isAntiAlias() { - return super.isAntiAlias(); - } - - @Override - public boolean isDither() { - return super.isDither(); - } - - @Override - public boolean isLinearText() { - return super.isLinearText(); - } - - @Override - public boolean isStrikeThruText() { - return super.isStrikeThruText(); - } - - @Override - public boolean isUnderlineText() { - return super.isUnderlineText(); - } - - @Override - public boolean isFakeBoldText() { - return super.isFakeBoldText(); - } - - @Override - public boolean isSubpixelText() { - return super.isSubpixelText(); - } - - @Override - public boolean isFilterBitmap() { - return super.isFilterBitmap(); - } - - /** - * Return the font's recommended interline spacing, given the Paint's - * settings for typeface, textSize, etc. If metrics is not null, return the - * fontmetric values in it. - * - * @param metrics If this object is not null, its fields are filled with - * the appropriate values given the paint's text attributes. - * @return the font's recommended interline spacing. - */ - public float getFontMetrics(FontMetrics metrics) { - if (mFonts.size() > 0) { - java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics; - if (metrics != null) { - // Android expects negative ascent so we invert the value from Java. - metrics.top = - javaMetrics.getMaxAscent(); - metrics.ascent = - javaMetrics.getAscent(); - metrics.descent = javaMetrics.getDescent(); - metrics.bottom = javaMetrics.getMaxDescent(); - metrics.leading = javaMetrics.getLeading(); - } - - return javaMetrics.getHeight(); - } - - return 0; - } - - public int getFontMetricsInt(FontMetricsInt metrics) { - if (mFonts.size() > 0) { - java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics; - if (metrics != null) { - // Android expects negative ascent so we invert the value from Java. - metrics.top = - javaMetrics.getMaxAscent(); - metrics.ascent = - javaMetrics.getAscent(); - metrics.descent = javaMetrics.getDescent(); - metrics.bottom = javaMetrics.getMaxDescent(); - metrics.leading = javaMetrics.getLeading(); - } - - return javaMetrics.getHeight(); - } - - return 0; - } - - /** - * Reimplemented to return Paint.FontMetrics instead of _Original_Paint.FontMetrics - */ - public FontMetrics getFontMetrics() { - FontMetrics fm = new FontMetrics(); - getFontMetrics(fm); - return fm; - } - - /** - * Reimplemented to return Paint.FontMetricsInt instead of _Original_Paint.FontMetricsInt - */ - public FontMetricsInt getFontMetricsInt() { - FontMetricsInt fm = new FontMetricsInt(); - getFontMetricsInt(fm); - return fm; - } - - - - @Override - public float getFontMetrics(_Original_Paint.FontMetrics metrics) { - throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN"); - } - - @Override - public int getFontMetricsInt(_Original_Paint.FontMetricsInt metrics) { - throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN"); - } - - @Override - public Typeface setTypeface(Typeface typeface) { - if (typeface != null) { - mTypeface = typeface; - } else { - mTypeface = Typeface.DEFAULT; - } - - updateFontObject(); - - return typeface; - } - - @Override - public Typeface getTypeface() { - return super.getTypeface(); - } - - @Override - public int getColor() { - return mColor; - } - - @Override - public void setColor(int color) { - mColor = color; - } - - @Override - public void setARGB(int a, int r, int g, int b) { - super.setARGB(a, r, g, b); - } - - @Override - public void setAlpha(int alpha) { - mColor = (alpha << 24) | (mColor & 0x00FFFFFF); - } - - @Override - public int getAlpha() { - return mColor >>> 24; - } - - /** - * Set or clear the shader object. - * <p /> - * Pass null to clear any previous shader. - * As a convenience, the parameter passed is also returned. - * - * @param shader May be null. the new shader to be installed in the paint - * @return shader - */ - @Override - public Shader setShader(Shader shader) { - return mShader = shader; - } - - @Override - public Shader getShader() { - return super.getShader(); - } - - /** - * Set or clear the paint's colorfilter, returning the parameter. - * - * @param filter May be null. The new filter to be installed in the paint - * @return filter - */ - @Override - public ColorFilter setColorFilter(ColorFilter filter) { - mColorFilter = filter; - return filter; - } - - @Override - public ColorFilter getColorFilter() { - return super.getColorFilter(); - } - - /** - * Set or clear the xfermode object. - * <p /> - * Pass null to clear any previous xfermode. - * As a convenience, the parameter passed is also returned. - * - * @param xfermode May be null. The xfermode to be installed in the paint - * @return xfermode - */ - @Override - public Xfermode setXfermode(Xfermode xfermode) { - return mXfermode = xfermode; - } - - @Override - public Xfermode getXfermode() { - return super.getXfermode(); - } - - @Override - public Rasterizer setRasterizer(Rasterizer rasterizer) { - mRasterizer = rasterizer; - return rasterizer; - } - - @Override - public Rasterizer getRasterizer() { - return super.getRasterizer(); - } - - @Override - public void setShadowLayer(float radius, float dx, float dy, int color) { - // TODO Auto-generated method stub - } - - @Override - public void clearShadowLayer() { - super.clearShadowLayer(); - } - - public void setTextAlign(Align align) { - mAlign = align; - } - - @Override - public void setTextAlign(android.graphics._Original_Paint.Align align) { - throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN"); - } - - public Align getTextAlign() { - return mAlign; - } - - public void setStyle(Style style) { - mStyle = style; - } - - @Override - public void setStyle(android.graphics._Original_Paint.Style style) { - throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN"); - } - - public Style getStyle() { - return mStyle; - } - - @Override - public void setDither(boolean dither) { - mFlags |= dither ? DITHER_FLAG : ~DITHER_FLAG; - } - - @Override - public void setAntiAlias(boolean aa) { - mFlags |= aa ? ANTI_ALIAS_FLAG : ~ANTI_ALIAS_FLAG; - } - - @Override - public void setFakeBoldText(boolean flag) { - mFlags |= flag ? FAKE_BOLD_TEXT_FLAG : ~FAKE_BOLD_TEXT_FLAG; - } - - @Override - public void setLinearText(boolean flag) { - mFlags |= flag ? LINEAR_TEXT_FLAG : ~LINEAR_TEXT_FLAG; - } - - @Override - public void setSubpixelText(boolean flag) { - mFlags |= flag ? SUBPIXEL_TEXT_FLAG : ~SUBPIXEL_TEXT_FLAG; - } - - @Override - public void setUnderlineText(boolean flag) { - mFlags |= flag ? UNDERLINE_TEXT_FLAG : ~UNDERLINE_TEXT_FLAG; - } - - @Override - public void setStrikeThruText(boolean flag) { - mFlags |= flag ? STRIKE_THRU_TEXT_FLAG : ~STRIKE_THRU_TEXT_FLAG; - } - - @Override - public void setFilterBitmap(boolean flag) { - mFlags |= flag ? FILTER_BITMAP_FLAG : ~FILTER_BITMAP_FLAG; - } - - @Override - public float getStrokeWidth() { - return mStrokeWidth; - } - - @Override - public void setStrokeWidth(float width) { - mStrokeWidth = width; - } - - @Override - public float getStrokeMiter() { - return mStrokeMiter; - } - - @Override - public void setStrokeMiter(float miter) { - mStrokeMiter = miter; - } - - @Override - public void setStrokeCap(android.graphics._Original_Paint.Cap cap) { - throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN"); - } - - public void setStrokeCap(Cap cap) { - mCap = cap; - } - - public Cap getStrokeCap() { - return mCap; - } - - @Override - public void setStrokeJoin(android.graphics._Original_Paint.Join join) { - throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN"); - } - - public void setStrokeJoin(Join join) { - mJoin = join; - } - - public Join getStrokeJoin() { - return mJoin; - } - - @Override - public boolean getFillPath(Path src, Path dst) { - return super.getFillPath(src, dst); - } - - @Override - public PathEffect setPathEffect(PathEffect effect) { - mPathEffect = effect; - return effect; - } - - @Override - public PathEffect getPathEffect() { - return super.getPathEffect(); - } - - @Override - public MaskFilter setMaskFilter(MaskFilter maskfilter) { - mMaskFilter = maskfilter; - return maskfilter; - } - - @Override - public MaskFilter getMaskFilter() { - return super.getMaskFilter(); - } - - /** - * Return the paint's text size. - * - * @return the paint's text size. - */ - @Override - public float getTextSize() { - return mTextSize; - } - - /** - * Set the paint's text size. This value must be > 0 - * - * @param textSize set the paint's text size. - */ - @Override - public void setTextSize(float textSize) { - mTextSize = textSize; - - updateFontObject(); - } - - /** - * Return the paint's horizontal scale factor for text. The default value - * is 1.0. - * - * @return the paint's scale factor in X for drawing/measuring text - */ - @Override - public float getTextScaleX() { - return mScaleX; - } - - /** - * Set the paint's horizontal scale factor for text. The default value - * is 1.0. Values > 1.0 will stretch the text wider. Values < 1.0 will - * stretch the text narrower. - * - * @param scaleX set the paint's scale in X for drawing/measuring text. - */ - @Override - public void setTextScaleX(float scaleX) { - mScaleX = scaleX; - - updateFontObject(); - } - - /** - * Return the paint's horizontal skew factor for text. The default value - * is 0. - * - * @return the paint's skew factor in X for drawing text. - */ - @Override - public float getTextSkewX() { - return mSkewX; - } - - /** - * Set the paint's horizontal skew factor for text. The default value - * is 0. For approximating oblique text, use values around -0.25. - * - * @param skewX set the paint's skew factor in X for drawing text. - */ - @Override - public void setTextSkewX(float skewX) { - mSkewX = skewX; - - updateFontObject(); - } - - @Override - public float getFontSpacing() { - return super.getFontSpacing(); - } - - /** - * Return the distance above (negative) the baseline (ascent) based on the - * current typeface and text size. - * - * @return the distance above (negative) the baseline (ascent) based on the - * current typeface and text size. - */ - @Override - public float ascent() { - if (mFonts.size() > 0) { - java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics; - // Android expects negative ascent so we invert the value from Java. - return - javaMetrics.getAscent(); - } - - return 0; - } - - /** - * Return the distance below (positive) the baseline (descent) based on the - * current typeface and text size. - * - * @return the distance below (positive) the baseline (descent) based on - * the current typeface and text size. - */ - @Override - public float descent() { - if (mFonts.size() > 0) { - java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics; - return javaMetrics.getDescent(); - } - - return 0; - } - - /** - * Return the width of the text. - * - * @param text The text to measure - * @param index The index of the first character to start measuring - * @param count THe number of characters to measure, beginning with start - * @return The width of the text - */ - @Override - public float measureText(char[] text, int index, int count) { - // WARNING: the logic in this method is similar to Canvas.drawText. - // Any change to this method should be reflected in Canvas.drawText - if (mFonts.size() > 0) { - FontInfo mainFont = mFonts.get(0); - int i = index; - int lastIndex = index + count; - float total = 0f; - while (i < lastIndex) { - // always start with the main font. - int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex); - if (upTo == -1) { - // shortcut to exit - return total + mainFont.mMetrics.charsWidth(text, i, lastIndex - i); - } else if (upTo > 0) { - total += mainFont.mMetrics.charsWidth(text, i, upTo - i); - 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 < mFonts.size() ; f++) { - FontInfo fontInfo = mFonts.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) { - total += fontInfo.mMetrics.charsWidth(text, i, charCount); - i += charCount; - foundFont = true; - break; - - } - } - - // in case no font can display the char, measure it with the main font. - if (foundFont == false) { - int size = Character.isHighSurrogate(text[i]) ? 2 : 1; - total += mainFont.mMetrics.charsWidth(text, i, size); - i += size; - } - } - } - - return 0; - } - - /** - * Return the width of the text. - * - * @param text The text to measure - * @param start The index of the first character to start measuring - * @param end 1 beyond the index of the last character to measure - * @return The width of the text - */ - @Override - public float measureText(String text, int start, int end) { - return measureText(text.toCharArray(), start, end - start); - } - - /** - * Return the width of the text. - * - * @param text The text to measure - * @return The width of the text - */ - @Override - public float measureText(String text) { - return measureText(text.toCharArray(), 0, text.length()); - } - - /* - * re-implement to call SpannableStringBuilder.measureText with a Paint object - * instead of an _Original_Paint - */ - @Override - public float measureText(CharSequence text, int start, int end) { - if (text instanceof String) { - return measureText((String)text, start, end); - } - if (text instanceof SpannedString || - text instanceof SpannableString) { - return measureText(text.toString(), start, end); - } - if (text instanceof SpannableStringBuilder) { - return ((SpannableStringBuilder)text).measureText(start, end, this); - } - - char[] buf = TemporaryBuffer.obtain(end - start); - TextUtils.getChars(text, start, end, buf, 0); - float result = measureText(buf, 0, end - start); - TemporaryBuffer.recycle(buf); - return result; - } - - /** - * Measure the text, stopping early if the measured width exceeds maxWidth. - * Return the number of chars that were measured, and if measuredWidth is - * not null, return in it the actual width measured. - * - * @param text The text to measure - * @param index The offset into text to begin measuring at - * @param count The number of maximum number of entries to measure. If count - * is negative, then the characters before index are measured - * in reverse order. This allows for measuring the end of - * string. - * @param maxWidth The maximum width to accumulate. - * @param measuredWidth Optional. If not null, returns the actual width - * measured. - * @return The number of chars that were measured. Will always be <= - * abs(count). - */ - @Override - public int breakText(char[] text, int index, int count, - float maxWidth, float[] measuredWidth) { - int inc = count > 0 ? 1 : -1; - - int measureIndex = 0; - float measureAcc = 0; - for (int i = index ; i != index + count ; i += inc, measureIndex++) { - int start, end; - if (i < index) { - start = i; - end = index; - } else { - start = index; - end = i; - } - - // measure from start to end - float res = measureText(text, start, end - start + 1); - - if (measuredWidth != null) { - measuredWidth[measureIndex] = res; - } - - measureAcc += res; - if (res > maxWidth) { - // we should not return this char index, but since it's 0-based and we need - // to return a count, we simply return measureIndex; - return measureIndex; - } - - } - - return measureIndex; - } - - /** - * Measure the text, stopping early if the measured width exceeds maxWidth. - * Return the number of chars that were measured, and if measuredWidth is - * not null, return in it the actual width measured. - * - * @param text The text to measure - * @param measureForwards If true, measure forwards, starting at index. - * Otherwise, measure backwards, starting with the - * last character in the string. - * @param maxWidth The maximum width to accumulate. - * @param measuredWidth Optional. If not null, returns the actual width - * measured. - * @return The number of chars that were measured. Will always be <= - * abs(count). - */ - @Override - public int breakText(String text, boolean measureForwards, - float maxWidth, float[] measuredWidth) { - return breakText(text, - 0 /* start */, text.length() /* end */, - measureForwards, maxWidth, measuredWidth); - } - - /** - * Measure the text, stopping early if the measured width exceeds maxWidth. - * Return the number of chars that were measured, and if measuredWidth is - * not null, return in it the actual width measured. - * - * @param text The text to measure - * @param start The offset into text to begin measuring at - * @param end The end of the text slice to measure. - * @param measureForwards If true, measure forwards, starting at start. - * Otherwise, measure backwards, starting with end. - * @param maxWidth The maximum width to accumulate. - * @param measuredWidth Optional. If not null, returns the actual width - * measured. - * @return The number of chars that were measured. Will always be <= - * abs(end - start). - */ - @Override - public int breakText(CharSequence text, int start, int end, boolean measureForwards, - float maxWidth, float[] measuredWidth) { - char[] buf = new char[end - start]; - int result; - - TextUtils.getChars(text, start, end, buf, 0); - - if (measureForwards) { - result = breakText(buf, 0, end - start, maxWidth, measuredWidth); - } else { - result = breakText(buf, 0, -(end - start), maxWidth, measuredWidth); - } - - return result; - } - - /** - * Return the advance widths for the characters in the string. - * - * @param text The text to measure - * @param index The index of the first char to to measure - * @param count The number of chars starting with index to measure - * @param widths array to receive the advance widths of the characters. - * Must be at least a large as count. - * @return the actual number of widths returned. - */ - @Override - public int getTextWidths(char[] text, int index, int count, - float[] widths) { - if (mFonts.size() > 0) { - if ((index | count) < 0 || index + count > text.length - || count > widths.length) { - throw new ArrayIndexOutOfBoundsException(); - } - - // FIXME: handle multi-char characters. - // Need to figure out if the lengths of the width array takes into account - // multi-char characters. - for (int i = 0; i < count; i++) { - char c = text[i + index]; - boolean found = false; - for (FontInfo info : mFonts) { - if (info.mFont.canDisplay(c)) { - widths[i] = info.mMetrics.charWidth(c); - found = true; - break; - } - } - - if (found == false) { - // we stop there. - return i; - } - } - - return count; - } - - return 0; - } - - /** - * Return the advance widths for the characters in the string. - * - * @param text The text to measure - * @param start The index of the first char to to measure - * @param end The end of the text slice to measure - * @param widths array to receive the advance widths of the characters. - * Must be at least a large as the text. - * @return the number of unichars in the specified text. - */ - @Override - public int getTextWidths(String text, int start, int end, float[] widths) { - if ((start | end | (end - start) | (text.length() - end)) < 0) { - throw new IndexOutOfBoundsException(); - } - if (end - start > widths.length) { - throw new ArrayIndexOutOfBoundsException(); - } - - return getTextWidths(text.toCharArray(), start, end - start, widths); - } - - /* - * re-implement to call SpannableStringBuilder.getTextWidths with a Paint object - * instead of an _Original_Paint - */ - @Override - public int getTextWidths(CharSequence text, int start, int end, float[] widths) { - if (text instanceof String) { - return getTextWidths((String)text, start, end, widths); - } - if (text instanceof SpannedString || text instanceof SpannableString) { - return getTextWidths(text.toString(), start, end, widths); - } - if (text instanceof SpannableStringBuilder) { - return ((SpannableStringBuilder)text).getTextWidths(start, end, widths, this); - } - - char[] buf = TemporaryBuffer.obtain(end - start); - TextUtils.getChars(text, start, end, buf, 0); - int result = getTextWidths(buf, 0, end - start, widths); - TemporaryBuffer.recycle(buf); - return result; - } - - @Override - public int getTextWidths(String text, float[] widths) { - return super.getTextWidths(text, widths); - } - - /** - * Return the path (outline) for the specified text. - * Note: just like Canvas.drawText, this will respect the Align setting in - * the paint. - * - * @param text The text to retrieve the path from - * @param index The index of the first character in text - * @param count The number of characterss starting with index - * @param x The x coordinate of the text's origin - * @param y The y coordinate of the text's origin - * @param path The path to receive the data describing the text. Must - * be allocated by the caller. - */ - @Override - public void getTextPath(char[] text, int index, int count, - float x, float y, Path path) { - - // TODO this is the ORIGINAL implementation. REPLACE AS NEEDED OR REMOVE - - if ((index | count) < 0 || index + count > text.length) { - throw new ArrayIndexOutOfBoundsException(); - } - - // TODO native_getTextPath(mNativePaint, text, index, count, x, y, path.ni()); - - throw new UnsupportedOperationException("IMPLEMENT AS NEEDED"); - } - - /** - * Return the path (outline) for the specified text. - * Note: just like Canvas.drawText, this will respect the Align setting - * in the paint. - * - * @param text The text to retrieve the path from - * @param start The first character in the text - * @param end 1 past the last charcter in the text - * @param x The x coordinate of the text's origin - * @param y The y coordinate of the text's origin - * @param path The path to receive the data describing the text. Must - * be allocated by the caller. - */ - @Override - public void getTextPath(String text, int start, int end, - float x, float y, Path path) { - if ((start | end | (end - start) | (text.length() - end)) < 0) { - throw new IndexOutOfBoundsException(); - } - - getTextPath(text.toCharArray(), start, end - start, x, y, path); - } - - /** - * Return in bounds (allocated by the caller) the smallest rectangle that - * encloses all of the characters, with an implied origin at (0,0). - * - * @param text String to measure and return its bounds - * @param start Index of the first char in the string to measure - * @param end 1 past the last char in the string measure - * @param bounds Returns the unioned bounds of all the text. Must be - * allocated by the caller. - */ - @Override - public void getTextBounds(String text, int start, int end, Rect bounds) { - if ((start | end | (end - start) | (text.length() - end)) < 0) { - throw new IndexOutOfBoundsException(); - } - if (bounds == null) { - throw new NullPointerException("need bounds Rect"); - } - - getTextBounds(text.toCharArray(), start, end - start, bounds); - } - - /** - * Return in bounds (allocated by the caller) the smallest rectangle that - * encloses all of the characters, with an implied origin at (0,0). - * - * @param text Array of chars to measure and return their unioned bounds - * @param index Index of the first char in the array to measure - * @param count The number of chars, beginning at index, to measure - * @param bounds Returns the unioned bounds of all the text. Must be - * allocated by the caller. - */ - @Override - public void getTextBounds(char[] text, int index, int count, Rect bounds) { - // FIXME - if (mFonts.size() > 0) { - if ((index | count) < 0 || index + count > text.length) { - throw new ArrayIndexOutOfBoundsException(); - } - if (bounds == null) { - throw new NullPointerException("need bounds Rect"); - } - - FontInfo mainInfo = mFonts.get(0); - - Rectangle2D rect = mainInfo.mFont.getStringBounds(text, index, index + count, mFontContext); - bounds.set(0, 0, (int)rect.getWidth(), (int)rect.getHeight()); - } - } - - public static void finalizer(int foo) { - // pass - } -} diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java new file mode 100644 index 0000000..e8079ed --- /dev/null +++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java @@ -0,0 +1,750 @@ +/* + * 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.DelegateManager; + +import android.graphics.Paint.FontMetrics; +import android.graphics.Paint.FontMetricsInt; + +import java.awt.Font; +import java.awt.Toolkit; +import java.awt.font.FontRenderContext; +import java.awt.geom.AffineTransform; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Delegate implementing the native methods of android.graphics.Paint + * + * Through the layoutlib_create tool, the original native methods of Paint 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 Paint class. + * + * @see DelegateManager + * + */ +public class Paint_Delegate { + + /** + * Class associating a {@link Font} and it's {@link java.awt.FontMetrics}. + */ + public static final class FontInfo { + Font mFont; + java.awt.FontMetrics mMetrics; + } + + // ---- delegate manager ---- + private static final DelegateManager<Paint_Delegate> sManager = + new DelegateManager<Paint_Delegate>(); + + // ---- delegate helper data ---- + private List<FontInfo> mFonts; + private final FontRenderContext mFontContext = new FontRenderContext( + new AffineTransform(), true, true); + + // ---- delegate data ---- + private int mFlags; + private int mColor; + private int mStyle; + private int mCap; + private int mJoin; + private int mAlign; + private int mTypeface; + private float mStrokeWidth; + private float mStrokeMiter; + private float mTextSize; + private float mTextScaleX; + private float mTextSkewX; + + + // ---- Public Helper methods ---- + + /** + * Returns the list of {@link Font} objects. The first item is the main font, the rest + * are fall backs for characters not present in the main font. + */ + public List<FontInfo> getFonts() { + return mFonts; + } + + + // ---- native methods ---- + + /*package*/ static int getFlags(Paint thisPaint) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return 0; + } + + return delegate.mFlags; + } + + /*package*/ static void setFlags(Paint thisPaint, int flags) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return; + } + + delegate.mFlags = flags; + } + + /*package*/ static void setFilterBitmap(Paint thisPaint, boolean filter) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void setAntiAlias(Paint thisPaint, boolean aa) { + setFlag(thisPaint, Paint.ANTI_ALIAS_FLAG, aa); + } + + /*package*/ static void setSubpixelText(Paint thisPaint, boolean subpixelText) { + setFlag(thisPaint, Paint.SUBPIXEL_TEXT_FLAG, subpixelText); + } + + /*package*/ static void setUnderlineText(Paint thisPaint, boolean underlineText) { + setFlag(thisPaint, Paint.UNDERLINE_TEXT_FLAG, underlineText); + } + + /*package*/ static void setStrikeThruText(Paint thisPaint, boolean strikeThruText) { + setFlag(thisPaint, Paint.STRIKE_THRU_TEXT_FLAG, strikeThruText); + } + + /*package*/ static void setFakeBoldText(Paint thisPaint, boolean fakeBoldText) { + setFlag(thisPaint, Paint.FAKE_BOLD_TEXT_FLAG, fakeBoldText); + } + + /*package*/ static void setDither(Paint thisPaint, boolean dither) { + setFlag(thisPaint, Paint.DITHER_FLAG, dither); + } + + /*package*/ static void setLinearText(Paint thisPaint, boolean linearText) { + setFlag(thisPaint, Paint.LINEAR_TEXT_FLAG, linearText); + } + + /*package*/ static int getColor(Paint thisPaint) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return 0; + } + + return delegate.mColor; + } + + /*package*/ static void setColor(Paint thisPaint, int color) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return; + } + + delegate.mColor = color; + } + + /*package*/ static int getAlpha(Paint thisPaint) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return 0; + } + + return delegate.mColor >>> 24; + } + + /*package*/ static void setAlpha(Paint thisPaint, int a) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return; + } + + delegate.mColor = (a << 24) | (delegate.mColor & 0x00FFFFFF); + } + + /*package*/ static float getStrokeWidth(Paint thisPaint) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return 1.f; + } + + return delegate.mStrokeWidth; + } + + /*package*/ static void setStrokeWidth(Paint thisPaint, float width) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return; + } + + delegate.mStrokeWidth = width; + } + + /*package*/ static float getStrokeMiter(Paint thisPaint) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return 1.f; + } + + return delegate.mStrokeMiter; + } + + /*package*/ static void setStrokeMiter(Paint thisPaint, float miter) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return; + } + + delegate.mStrokeMiter = miter; + } + + /*package*/ static void nSetShadowLayer(Paint thisPaint, float radius, float dx, float dy, + int color) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static float getTextSize(Paint thisPaint) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return 1.f; + } + + return delegate.mTextSize; + } + + /*package*/ static void setTextSize(Paint thisPaint, float textSize) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return; + } + + delegate.mTextSize = textSize; + } + + /*package*/ static float getTextScaleX(Paint thisPaint) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return 1.f; + } + + return delegate.mTextScaleX; + } + + /*package*/ static void setTextScaleX(Paint thisPaint, float scaleX) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return; + } + + delegate.mTextScaleX = scaleX; + } + + /*package*/ static float getTextSkewX(Paint thisPaint) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return 1.f; + } + + return delegate.mTextSkewX; + } + + /*package*/ static void setTextSkewX(Paint thisPaint, float skewX) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return; + } + + delegate.mTextSkewX = skewX; + } + + /*package*/ static float ascent(Paint thisPaint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static float descent(Paint thisPaint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static float getFontMetrics(Paint thisPaint, FontMetrics metrics) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int getFontMetricsInt(Paint thisPaint, FontMetricsInt fmi) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static float native_measureText(Paint thisPaint, char[] text, int index, + int count) { + // WARNING: the logic in this method is similar to Canvas.drawText. + // Any change to this method should be reflected in Canvas.drawText + + // get the delegate + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return 0; + } + + if (delegate.mFonts.size() > 0) { + FontInfo mainFont = delegate.mFonts.get(0); + int i = index; + int lastIndex = index + count; + float total = 0f; + while (i < lastIndex) { + // always start with the main font. + int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex); + if (upTo == -1) { + // shortcut to exit + return total + mainFont.mMetrics.charsWidth(text, i, lastIndex - i); + } else if (upTo > 0) { + total += mainFont.mMetrics.charsWidth(text, i, upTo - i); + 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 < delegate.mFonts.size() ; f++) { + FontInfo fontInfo = delegate.mFonts.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) { + total += fontInfo.mMetrics.charsWidth(text, i, charCount); + i += charCount; + foundFont = true; + break; + + } + } + + // in case no font can display the char, measure it with the main font. + if (foundFont == false) { + int size = Character.isHighSurrogate(text[i]) ? 2 : 1; + total += mainFont.mMetrics.charsWidth(text, i, size); + i += size; + } + } + } + + return 0; + } + + /*package*/ static float native_measureText(Paint thisPaint, String text, int start, int end) { + return native_measureText(thisPaint, text.toCharArray(), start, end - start); + } + + /*package*/ static float native_measureText(Paint thisPaint, String text) { + return native_measureText(thisPaint, text.toCharArray(), 0, text.length()); + } + + /*package*/ static int native_breakText(Paint thisPaint, char[] text, int index, int count, + float maxWidth, float[] measuredWidth) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int native_breakText(Paint thisPaint, String text, boolean measureForwards, + float maxWidth, float[] measuredWidth) { + // FIXME + throw new UnsupportedOperationException(); + } + + + /*package*/ static int native_init() { + Paint_Delegate newDelegate = new Paint_Delegate(); + return sManager.addDelegate(newDelegate); + } + + /*package*/ static int native_initWithPaint(int paint) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(paint); + if (delegate == null) { + assert false; + return 0; + } + + Paint_Delegate newDelegate = new Paint_Delegate(delegate); + return sManager.addDelegate(newDelegate); + } + + /*package*/ static void native_reset(int native_object) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(native_object); + if (delegate == null) { + assert false; + return; + } + + delegate.reset(); + } + + /*package*/ static void native_set(int native_dst, int native_src) { + // get the delegate from the native int. + Paint_Delegate delegate_dst = sManager.getDelegate(native_dst); + if (delegate_dst == null) { + assert false; + return; + } + + // get the delegate from the native int. + Paint_Delegate delegate_src = sManager.getDelegate(native_src); + if (delegate_src == null) { + assert false; + return; + } + + delegate_dst.set(delegate_src); + } + + /*package*/ static int native_getStyle(int native_object) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(native_object); + if (delegate == null) { + assert false; + return 0; + } + + return delegate.mStyle; + } + + /*package*/ static void native_setStyle(int native_object, int style) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(native_object); + if (delegate == null) { + assert false; + return; + } + + delegate.mStyle = style; + } + + /*package*/ static int native_getStrokeCap(int native_object) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(native_object); + if (delegate == null) { + assert false; + return 0; + } + + return delegate.mCap; + } + + /*package*/ static void native_setStrokeCap(int native_object, int cap) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(native_object); + if (delegate == null) { + assert false; + return; + } + + delegate.mCap = cap; + } + + /*package*/ static int native_getStrokeJoin(int native_object) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(native_object); + if (delegate == null) { + assert false; + return 0; + } + + return delegate.mJoin; + } + + /*package*/ static void native_setStrokeJoin(int native_object, int join) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(native_object); + if (delegate == null) { + assert false; + return; + } + + delegate.mJoin = join; + } + + /*package*/ static boolean native_getFillPath(int native_object, int src, int dst) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int native_setShader(int native_object, int shader) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int native_setColorFilter(int native_object, int filter) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int native_setXfermode(int native_object, int xfermode) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int native_setPathEffect(int native_object, int effect) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int native_setMaskFilter(int native_object, int maskfilter) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int native_setTypeface(int native_object, int typeface) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(native_object); + if (delegate == null) { + assert false; + return 0; + } + + return delegate.mTypeface = typeface; + } + + /*package*/ static int native_setRasterizer(int native_object, int rasterizer) { + // FIXME + throw new UnsupportedOperationException(); + } + + + /*package*/ static int native_getTextAlign(int native_object) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(native_object); + if (delegate == null) { + assert false; + return 0; + } + + return delegate.mAlign; + } + + /*package*/ static void native_setTextAlign(int native_object, int align) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(native_object); + if (delegate == null) { + assert false; + return; + } + + delegate.mAlign = align; + } + + /*package*/ static float native_getFontMetrics(int native_paint, FontMetrics metrics) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int native_getTextWidths(int native_object, char[] text, int index, + int count, float[] widths) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int native_getTextWidths(int native_object, String text, int start, + int end, float[] widths) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static float native_getTextRunAdvances(int native_object, + char[] text, int index, int count, int contextIndex, int contextCount, + int flags, float[] advances, int advancesIndex) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static float native_getTextRunAdvances(int native_object, + String text, int start, int end, int contextStart, int contextEnd, + int flags, float[] advances, int advancesIndex) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int native_getTextRunCursor(Paint thisPaint, int native_object, char[] text, + int contextStart, int contextLength, int flags, int offset, int cursorOpt) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int native_getTextRunCursor(Paint thisPaint, int native_object, String text, + int contextStart, int contextEnd, int flags, int offset, int cursorOpt) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_getTextPath(int native_object, int bidiFlags, + char[] text, int index, int count, float x, float y, int path) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_getTextPath(int native_object, int bidiFlags, + String text, int start, int end, float x, float y, int path) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void nativeGetStringBounds(int nativePaint, String text, int start, + int end, Rect bounds) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void nativeGetCharArrayBounds(int nativePaint, char[] text, int index, + int count, Rect bounds) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void finalizer(int nativePaint) { + sManager.removeDelegate(nativePaint); + } + + // ---- Private delegate/helper methods ---- + + private Paint_Delegate() { + reset(); + + mTypeface = Typeface.sDefaults[0].native_instance; + updateFontObject(); + } + + private Paint_Delegate(Paint_Delegate paint) { + set(paint); + updateFontObject(); + } + + private void set(Paint_Delegate paint) { + mFlags = paint.mFlags; + mColor = paint.mColor; + mStyle = paint.mStyle; + mCap = paint.mCap; + mJoin = paint.mJoin; + mAlign = paint.mAlign; + mTypeface = paint.mTypeface; + mStrokeWidth = paint.mStrokeWidth; + mStrokeMiter = paint.mStrokeMiter; + mTextSize = paint.mTextSize; + mTextScaleX = paint.mTextScaleX; + mTextSkewX = paint.mTextSkewX; + } + + private void reset() { + mFlags = Paint.DEFAULT_PAINT_FLAGS; + mColor = 0; + mStyle = 0; + mCap = 0; + mJoin = 0; + mAlign = 0; + mTypeface = 0; + mStrokeWidth = 1.f; + mStrokeMiter = 2.f; + mTextSize = 20.f; + mTextScaleX = 1.f; + mTextSkewX = 0.f; + } + + /** + * Update the {@link Font} object from the typeface, text size and scaling + */ + private void updateFontObject() { + if (mTypeface != 0) { + // Get the fonts from the TypeFace object. + List<Font> fonts = Typeface_Delegate.getFonts(mTypeface); + + // create new font objects as well as FontMetrics, based on the current text size + // and skew info. + ArrayList<FontInfo> infoList = new ArrayList<FontInfo>(fonts.size()); + for (Font font : fonts) { + FontInfo info = new FontInfo(); + info.mFont = font.deriveFont(mTextSize); + if (mTextScaleX != 1.0 || mTextSkewX != 0) { + // TODO: support skew + info.mFont = info.mFont.deriveFont(new AffineTransform( + mTextScaleX, mTextSkewX, 0, 0, 1, 0)); + } + info.mMetrics = Toolkit.getDefaultToolkit().getFontMetrics(info.mFont); + + infoList.add(info); + } + + mFonts = Collections.unmodifiableList(infoList); + } + } + + private static void setFlag(Paint thisPaint, int flagMask, boolean flagValue) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return; + } + + if (flagValue) { + delegate.mFlags |= flagMask; + } else { + delegate.mFlags &= ~flagMask; + } + } +} diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java index 248bdab..7e90e7d 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java @@ -72,7 +72,11 @@ public final class Typeface_Delegate { } public static List<Font> getFonts(Typeface typeface) { - Typeface_Delegate delegate = sManager.getDelegate(typeface.native_instance); + return getFonts(typeface.native_instance); + } + + public static List<Font> getFonts(int native_int) { + Typeface_Delegate delegate = sManager.getDelegate(native_int); if (delegate == null) { assert false; return null; diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java index 9eb83c8..cdb4148 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java @@ -24,6 +24,7 @@ import com.android.layoutlib.api.IProjectCallback; import com.android.layoutlib.api.IResourceValue; import com.android.layoutlib.api.IStyleResourceValue; import com.android.layoutlib.api.IXmlPullParser; +import com.android.layoutlib.api.IDensityBasedResourceValue.Density; import com.android.layoutlib.api.ILayoutResult.ILayoutViewInfo; import com.android.layoutlib.bridge.LayoutResult.LayoutViewInfo; import com.android.ninepatch.NinePatch; @@ -33,7 +34,9 @@ import com.android.tools.layoutlib.create.OverrideMethod; import android.content.ClipData; import android.content.res.Configuration; import android.graphics.Bitmap; +import android.graphics.Bitmap_Delegate; import android.graphics.Canvas; +import android.graphics.Canvas_Delegate; import android.graphics.Rect; import android.graphics.Region; import android.graphics.Typeface_Delegate; @@ -64,6 +67,7 @@ import android.widget.FrameLayout; import android.widget.TabHost; import android.widget.TabWidget; +import java.awt.image.BufferedImage; import java.lang.ref.SoftReference; import java.lang.reflect.Field; import java.lang.reflect.Modifier; @@ -450,13 +454,28 @@ public final class Bridge implements ILayoutBridge { view.layout(0, screenOffset, screenWidth, screenHeight); // draw the views - Canvas canvas = new Canvas(screenWidth, screenHeight - screenOffset, logger); + // create the BufferedImage into which the layout will be rendered. + BufferedImage image = new BufferedImage(screenWidth, screenHeight - screenOffset, + BufferedImage.TYPE_INT_ARGB); + + // create an Android bitmap around the BufferedImage + Bitmap bitmap = Bitmap_Delegate.createBitmap(image, Density.getEnum(density)); + + // create a Canvas around the Android bitmap + Canvas canvas = new Canvas(bitmap); + + // to set the logger, get the native delegate + Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(canvas); + canvasDelegate.setLogger(logger); + root.draw(canvas); - canvas.dispose(); + canvasDelegate.dispose(); + + return new LayoutResult( + visit(((ViewGroup)view).getChildAt(0), context), + image); - return new LayoutResult(visit(((ViewGroup)view).getChildAt(0), context), - canvas.getImage()); } catch (PostInflateException e) { return new LayoutResult(ILayoutResult.ERROR, "Error during post inflation process:\n" + e.getMessage()); diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/NinePatchDrawable.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/NinePatchDrawable.java index abbf2f0..2c92567 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/NinePatchDrawable.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/NinePatchDrawable.java @@ -19,6 +19,7 @@ package com.android.layoutlib.bridge; import com.android.ninepatch.NinePatch; import android.graphics.Canvas; +import android.graphics.Canvas_Delegate; import android.graphics.ColorFilter; import android.graphics.Rect; import android.graphics.drawable.Drawable; @@ -80,7 +81,8 @@ public class NinePatchDrawable extends Drawable { @Override public void draw(Canvas canvas) { Rect r = getBounds(); - m9Patch.draw(canvas.getGraphics2d(), r.left, r.top, r.width(), r.height()); + Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(canvas); + m9Patch.draw(canvasDelegate.getGraphics2d(), r.left, r.top, r.width(), r.height()); return; } diff --git a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/AndroidGraphicsTests.java b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/AndroidGraphicsTests.java index 6e14e82..ba3c51a 100644 --- a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/AndroidGraphicsTests.java +++ b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/AndroidGraphicsTests.java @@ -17,8 +17,6 @@ package com.android.layoutlib.bridge; import android.graphics.Matrix; -import android.graphics.Paint; -import android.graphics._Original_Paint; import android.text.TextPaint; import junit.framework.TestCase; @@ -58,14 +56,6 @@ public class AndroidGraphicsTests extends TestCase { } } - public void testPaint() { - _Original_Paint o = new _Original_Paint(); - assertNotNull(o); - - Paint p = new Paint(); - assertNotNull(p); - } - public void textTextPaint() { TextPaint p = new TextPaint(); assertNotNull(p); diff --git a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/TestNativeDelegate.java b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/TestNativeDelegate.java index 7c1eecd..a86b5c9 100644 --- a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/TestNativeDelegate.java +++ b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/TestNativeDelegate.java @@ -87,7 +87,11 @@ public class TestNativeDelegate extends TestCase { try { // try to load the method with the given parameter types. - delegateClass.getDeclaredMethod(originalMethod.getName(), parameters); + Method delegateMethod = delegateClass.getDeclaredMethod(originalMethod.getName(), + parameters); + + // check that the method is static + assertTrue((delegateMethod.getModifiers() & Modifier.STATIC) == Modifier.STATIC); } catch (NoSuchMethodException e) { // compute a full class name that's long but not too long. StringBuilder sb = new StringBuilder(originalMethod.getName() + "("); 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 0ecb474..c845cc4 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 @@ -104,7 +104,9 @@ public final class CreateInfo implements ICreateInfo { */ private final static String[] DELEGATE_CLASS_NATIVES = new String[] { "android.graphics.Bitmap", + "android.graphics.Canvas", "android.graphics.Matrix", + "android.graphics.Paint", "android.graphics.Typeface", }; @@ -126,11 +128,9 @@ public final class CreateInfo implements ICreateInfo { new String[] { "android.graphics.BitmapFactory", "android.graphics._Original_BitmapFactory", "android.graphics.BitmapShader", "android.graphics._Original_BitmapShader", - "android.graphics.Canvas", "android.graphics._Original_Canvas", "android.graphics.ComposeShader", "android.graphics._Original_ComposeShader", "android.graphics.DashPathEffect", "android.graphics._Original_DashPathEffect", "android.graphics.LinearGradient", "android.graphics._Original_LinearGradient", - "android.graphics.Paint", "android.graphics._Original_Paint", "android.graphics.Path", "android.graphics._Original_Path", "android.graphics.PorterDuffXfermode", "android.graphics._Original_PorterDuffXfermode", "android.graphics.RadialGradient", "android.graphics._Original_RadialGradient", @@ -150,13 +150,6 @@ public final class CreateInfo implements ICreateInfo { */ private final static String[] DELETE_RETURNS = new String[] { - "android.graphics.Paint", // class to delete methods from - "android.graphics.Paint$Align", // list of type identifying methods to delete - "android.graphics.Paint$Style", - "android.graphics.Paint$Join", - "android.graphics.Paint$Cap", - "android.graphics.Paint$FontMetrics", - "android.graphics.Paint$FontMetricsInt", null }; // separator, for next class/methods list. } diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java index 21d6682..c7968a4 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java @@ -169,7 +169,7 @@ class DelegateMethodAdapter implements MethodVisitor { // Construct the descriptor of the delegate. For a static method, it's the same // however for an instance method we need to pass the 'this' reference first String desc = mDesc; - if (!mIsStatic && argTypes.length > 0) { + if (!mIsStatic) { Type[] argTypes2 = new Type[argTypes.length + 1]; argTypes2[0] = Type.getObjectType(mClassName); |