blob: 9d4970f4150cfe49c7f328e457521c523cd18897 [file] [log] [blame]
/*
* 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.Bridge;
import com.android.layoutlib.bridge.impl.DelegateManager;
import android.graphics.Paint.FontMetrics;
import android.graphics.Paint.FontMetricsInt;
import android.text.TextUtils;
import java.awt.BasicStroke;
import java.awt.Font;
import java.awt.Shape;
import java.awt.Stroke;
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}.
*/
/*package*/ 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 mTextAlign;
private int mTypeface;
private float mStrokeWidth;
private float mStrokeMiter;
private float mTextSize;
private float mTextScaleX;
private float mTextSkewX;
private int mXfermode;
private int mColorFilter;
private int mShader;
private int mPathEffect;
private int mMaskFilter;
private int mRasterizer;
// ---- Public Helper methods ----
public static Paint_Delegate getDelegate(int native_paint) {
return sManager.getDelegate(native_paint);
}
/**
* 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;
}
public boolean isAntiAliased() {
return (mFlags & Paint.ANTI_ALIAS_FLAG) != 0;
}
public boolean isFilterBitmap() {
return (mFlags & Paint.FILTER_BITMAP_FLAG) != 0;
}
public int getStyle() {
return mStyle;
}
public int getColor() {
return mColor;
}
public int getAlpha() {
return mColor >>> 24;
}
public void setAlpha(int alpha) {
mColor = (alpha << 24) | (mColor & 0x00FFFFFF);
}
public int getTextAlign() {
return mTextAlign;
}
public float getStrokeWidth() {
return mStrokeWidth;
}
/**
* returns the value of stroke miter needed by the java api.
*/
public float getJavaStrokeMiter() {
float miter = mStrokeMiter * mStrokeWidth;
if (miter < 1.f) {
miter = 1.f;
}
return miter;
}
public int getJavaCap() {
switch (Paint.sCapArray[mCap]) {
case BUTT:
return BasicStroke.CAP_BUTT;
case ROUND:
return BasicStroke.CAP_ROUND;
default:
case SQUARE:
return BasicStroke.CAP_SQUARE;
}
}
public int getJavaJoin() {
switch (Paint.sJoinArray[mJoin]) {
default:
case MITER:
return BasicStroke.JOIN_MITER;
case ROUND:
return BasicStroke.JOIN_ROUND;
case BEVEL:
return BasicStroke.JOIN_BEVEL;
}
}
public Stroke getJavaStroke() {
PathEffect_Delegate effectDelegate = PathEffect_Delegate.getDelegate(mPathEffect);
if (effectDelegate != null) {
if (effectDelegate.isSupported()) {
Stroke stroke = effectDelegate.getStroke(this);
assert stroke != null;
if (stroke != null) {
return stroke;
}
} else {
Bridge.getLog().fidelityWarning(null,
effectDelegate.getSupportMessage(),
null);
}
}
// if no custom stroke as been set, set the default one.
return new BasicStroke(
getStrokeWidth(),
getJavaCap(),
getJavaJoin(),
getJavaStrokeMiter());
}
/**
* Returns the {@link Xfermode} delegate or null if none have been set
*
* @return the delegate or null.
*/
public Xfermode_Delegate getXfermode() {
return Xfermode_Delegate.getDelegate(mXfermode);
}
/**
* Returns the {@link ColorFilter} delegate or null if none have been set
*
* @return the delegate or null.
*/
public ColorFilter_Delegate getColorFilter() {
return ColorFilter_Delegate.getDelegate(mColorFilter);
}
/**
* Returns the {@link Shader} delegate or null if none have been set
*
* @return the delegate or null.
*/
public Shader_Delegate getShader() {
return Shader_Delegate.getDelegate(mShader);
}
/**
* Returns the {@link MaskFilter} delegate or null if none have been set
*
* @return the delegate or null.
*/
public MaskFilter_Delegate getMaskFilter() {
return MaskFilter_Delegate.getDelegate(mMaskFilter);
}
/**
* Returns the {@link Rasterizer} delegate or null if none have been set
*
* @return the delegate or null.
*/
public Rasterizer_Delegate getRasterizer() {
return Rasterizer_Delegate.getDelegate(mRasterizer);
}
// ---- 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) {
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) {
return;
}
delegate.mFlags = flags;
}
/*package*/ static void setFilterBitmap(Paint thisPaint, boolean filter) {
setFlag(thisPaint, Paint.FILTER_BITMAP_FLAG, filter);
}
/*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) {
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) {
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) {
return 0;
}
return delegate.getAlpha();
}
/*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) {
return;
}
delegate.setAlpha(a);
}
/*package*/ static float getStrokeWidth(Paint thisPaint) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
if (delegate == null) {
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) {
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) {
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) {
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) {
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) {
return;
}
delegate.mTextSize = textSize;
delegate.updateFontObject();
}
/*package*/ static float getTextScaleX(Paint thisPaint) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
if (delegate == null) {
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) {
return;
}
delegate.mTextScaleX = scaleX;
delegate.updateFontObject();
}
/*package*/ static float getTextSkewX(Paint thisPaint) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
if (delegate == null) {
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) {
return;
}
delegate.mTextSkewX = skewX;
delegate.updateFontObject();
}
/*package*/ static float ascent(Paint thisPaint) {
// get the delegate
Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
if (delegate == null) {
return 0;
}
if (delegate.mFonts.size() > 0) {
java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics;
// Android expects negative ascent so we invert the value from Java.
return - javaMetrics.getAscent();
}
return 0;
}
/*package*/ static float descent(Paint thisPaint) {
// get the delegate
Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
if (delegate == null) {
return 0;
}
if (delegate.mFonts.size() > 0) {
java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics;
return javaMetrics.getDescent();
}
return 0;
}
/*package*/ static float getFontMetrics(Paint thisPaint, FontMetrics metrics) {
// get the delegate
Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
if (delegate == null) {
return 0;
}
return delegate.getFontMetrics(metrics);
}
/*package*/ static int getFontMetricsInt(Paint thisPaint, FontMetricsInt fmi) {
// get the delegate
Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
if (delegate == null) {
return 0;
}
if (delegate.mFonts.size() > 0) {
java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics;
if (fmi != null) {
// Android expects negative ascent so we invert the value from Java.
fmi.top = - javaMetrics.getMaxAscent();
fmi.ascent = - javaMetrics.getAscent();
fmi.descent = javaMetrics.getDescent();
fmi.bottom = javaMetrics.getMaxDescent();
fmi.leading = javaMetrics.getLeading();
}
return javaMetrics.getHeight();
}
return 0;
}
/*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) {
return 0;
}
return delegate.measureText(text, index, count);
}
/*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) {
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) {
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) {
return;
}
// get the delegate from the native int.
Paint_Delegate delegate_src = sManager.getDelegate(native_src);
if (delegate_src == null) {
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) {
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) {
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) {
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) {
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) {
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) {
return;
}
delegate.mJoin = join;
}
/*package*/ static boolean native_getFillPath(int native_object, int src, int dst) {
Paint_Delegate paint = sManager.getDelegate(native_object);
if (paint == null) {
return false;
}
Path_Delegate srcPath = Path_Delegate.getDelegate(src);
if (srcPath == null) {
return true;
}
Path_Delegate dstPath = Path_Delegate.getDelegate(dst);
if (dstPath == null) {
return true;
}
Stroke stroke = paint.getJavaStroke();
Shape strokeShape = stroke.createStrokedShape(srcPath.getJavaShape());
dstPath.setJavaShape(strokeShape);
// FIXME figure out the return value?
return true;
}
/*package*/ static int native_setShader(int native_object, int shader) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
if (delegate == null) {
return shader;
}
return delegate.mShader = shader;
}
/*package*/ static int native_setColorFilter(int native_object, int filter) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
if (delegate == null) {
return filter;
}
delegate.mColorFilter = filter;
// since none of those are supported, display a fidelity warning right away
ColorFilter_Delegate filterDelegate = delegate.getColorFilter();
if (filterDelegate != null && filterDelegate.isSupported() == false) {
Bridge.getLog().fidelityWarning(null, filterDelegate.getSupportMessage(), null);
}
return filter;
}
/*package*/ static int native_setXfermode(int native_object, int xfermode) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
if (delegate == null) {
return xfermode;
}
return delegate.mXfermode = xfermode;
}
/*package*/ static int native_setPathEffect(int native_object, int effect) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
if (delegate == null) {
return effect;
}
return delegate.mPathEffect = effect;
}
/*package*/ static int native_setMaskFilter(int native_object, int maskfilter) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
if (delegate == null) {
return maskfilter;
}
delegate.mMaskFilter = maskfilter;
// since none of those are supported, display a fidelity warning right away
MaskFilter_Delegate filterDelegate = delegate.getMaskFilter();
if (filterDelegate != null && filterDelegate.isSupported() == false) {
Bridge.getLog().fidelityWarning(null, filterDelegate.getSupportMessage(), null);
}
return maskfilter;
}
/*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) {
return 0;
}
delegate.mTypeface = typeface;
delegate.updateFontObject();
return delegate.mTypeface;
}
/*package*/ static int native_setRasterizer(int native_object, int rasterizer) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
if (delegate == null) {
return rasterizer;
}
delegate.mRasterizer = rasterizer;
// since none of those are supported, display a fidelity warning right away
Rasterizer_Delegate rasterizerDelegate = delegate.getRasterizer();
if (rasterizerDelegate != null && rasterizerDelegate.isSupported() == false) {
Bridge.getLog().fidelityWarning(null, rasterizerDelegate.getSupportMessage(), null);
}
return rasterizer;
}
/*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) {
return 0;
}
return delegate.mTextAlign;
}
/*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) {
return;
}
delegate.mTextAlign = align;
}
/*package*/ static float native_getFontMetrics(int native_paint, FontMetrics metrics) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_paint);
if (delegate == null) {
return 0.f;
}
return delegate.getFontMetrics(metrics);
}
/*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) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
if (delegate == null) {
return 0.f;
}
if (delegate.mFonts.size() > 0) {
// FIXME: handle multi-char characters (see measureText)
float totalAdvance = 0;
for (int i = 0; i < count; i++) {
char c = text[i + index];
boolean found = false;
for (FontInfo info : delegate.mFonts) {
if (info.mFont.canDisplay(c)) {
float adv = info.mMetrics.charWidth(c);
totalAdvance += adv;
if (advances != null) {
advances[i] = adv;
}
found = true;
break;
}
}
if (found == false) {
// no advance for this char.
if (advances != null) {
advances[i] = 0.f;
}
}
}
return totalAdvance;
}
return 0;
}
/*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: support contextStart, contextEnd and direction flag
int count = end - start;
char[] buffer = TemporaryBuffer.obtain(count);
TextUtils.getChars(text, start, end, buffer, 0);
return native_getTextRunAdvances(native_object, buffer, 0, count, contextStart,
contextEnd - contextStart, flags, advances, advancesIndex);
}
/*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 ----
/*package*/ Paint_Delegate() {
reset();
}
private Paint_Delegate(Paint_Delegate paint) {
set(paint);
}
private void set(Paint_Delegate paint) {
mFlags = paint.mFlags;
mColor = paint.mColor;
mStyle = paint.mStyle;
mCap = paint.mCap;
mJoin = paint.mJoin;
mTextAlign = paint.mTextAlign;
mTypeface = paint.mTypeface;
mStrokeWidth = paint.mStrokeWidth;
mStrokeMiter = paint.mStrokeMiter;
mTextSize = paint.mTextSize;
mTextScaleX = paint.mTextScaleX;
mTextSkewX = paint.mTextSkewX;
mXfermode = paint.mXfermode;
mColorFilter = paint.mColorFilter;
mShader = paint.mShader;
mPathEffect = paint.mPathEffect;
mMaskFilter = paint.mMaskFilter;
mRasterizer = paint.mRasterizer;
updateFontObject();
}
private void reset() {
mFlags = Paint.DEFAULT_PAINT_FLAGS;
mColor = 0xFF000000;
mStyle = Paint.Style.FILL.nativeInt;
mCap = Paint.Cap.BUTT.nativeInt;
mJoin = Paint.Join.MITER.nativeInt;
mTextAlign = 0;
mTypeface = Typeface.sDefaults[0].native_instance;
mStrokeWidth = 1.f;
mStrokeMiter = 4.f;
mTextSize = 20.f;
mTextScaleX = 1.f;
mTextSkewX = 0.f;
mXfermode = 0;
mColorFilter = 0;
mShader = 0;
mPathEffect = 0;
mMaskFilter = 0;
mRasterizer = 0;
updateFontObject();
}
/**
* Update the {@link Font} object from the typeface, text size and scaling
*/
@SuppressWarnings("deprecation")
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);
}
}
/*package*/ float measureText(char[] text, int index, int count) {
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;
}
private 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;
}
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) {
return;
}
if (flagValue) {
delegate.mFlags |= flagMask;
} else {
delegate.mFlags &= ~flagMask;
}
}
}