/*
* $Id$
* This file is a part of the Arakhne Foundation Classes, http://www.arakhne.org/afc
*
* Copyright (c) 2000-2012 Stephane GALLAND.
* Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
* Universite de Technologie de Belfort-Montbeliard.
* Copyright (c) 2013-2016 The original authors, and other authors.
*
* 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 org.arakhne.afc.ui.vector.android;
import java.lang.ref.SoftReference;
import org.arakhne.afc.math.continous.object2d.Rectangle2f;
import org.arakhne.afc.math.continous.object2d.Shape2f;
import org.arakhne.afc.ui.vector.Font;
import org.arakhne.afc.ui.vector.FontMetrics;
import org.arakhne.afc.ui.vector.FontStyle;
import org.arakhne.afc.ui.vector.GlyphList;
import org.arakhne.afc.ui.vector.Stroke;
import org.arakhne.afc.ui.vector.VectorGraphics2D;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Paint.Cap;
import android.graphics.Paint.Join;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.Typeface;
/** Android implementation of the generic stroke, font and font metrics.
*
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
* @deprecated see JavaFX API
*/
@Deprecated
class AndroidPaint implements Stroke, org.arakhne.afc.ui.vector.Paint, Font, FontMetrics, NativeWrapper, Cloneable {
private static int toAndroid(FontStyle fs) {
switch(fs) {
case BOLD:
return Typeface.BOLD;
case BOLD_ITALIC:
return Typeface.BOLD_ITALIC;
case ITALIC:
return Typeface.ITALIC;
case PLAIN:
default:
return Typeface.NORMAL;
}
}
private static final Paint defaultPaint = new Paint();
/** Replies the default font.
*
* @return a copy of the the default font.
*/
public static AndroidPaint getDefaultFont() {
return new AndroidPaint(new Paint(defaultPaint));
}
/** Replies the font with the given attribute
*
* @param name
* @param style
* @param size
* @param context
* @return the font.
*/
public static AndroidPaint getFont(String name, FontStyle style, float size, VectorGraphics2D context) {
Paint pt = new Paint(((AndroidPaint)context.getFont()).getPaint());
pt.setTypeface(Typeface.create(name, toAndroid(style)));
pt.setTextSize(size);
return new AndroidPaint(pt);
}
private Paint paint;
/**
* @param paint
*/
public AndroidPaint(Paint paint) {
assert(paint!=null);
this.paint = paint;
}
/** Replies the painting context.
*
* @return the painting context.
*/
public Paint getPaint() {
return this.paint;
}
/**
* @param width
* @param join
* @param endCap
* @param mitterLimit
* @param dashes
* @param dashPhase
*/
public AndroidPaint(float width, LineJoin join, EndCap endCap,
float mitterLimit, float[] dashes, float dashPhase) {
this.paint = new Paint();
this.paint.setStyle(Style.FILL_AND_STROKE);
this.paint.setStrokeWidth(width);
this.paint.setStrokeMiter(mitterLimit);
switch(join) {
case BEVEL:
this.paint.setStrokeJoin(Join.BEVEL);
break;
case MITER:
this.paint.setStrokeJoin(Join.MITER);
break;
case ROUND:
this.paint.setStrokeJoin(Join.ROUND);
break;
default:
throw new IllegalArgumentException("join");
}
switch(endCap) {
case BUTT:
this.paint.setStrokeCap(Cap.BUTT);
break;
case ROUND:
this.paint.setStrokeCap(Cap.ROUND);
break;
case SQUARE:
this.paint.setStrokeCap(Cap.SQUARE);
break;
default:
throw new IllegalArgumentException("endCap");
}
if (dashes!=null && dashes.length>=2) {
this.paint.setPathEffect(new DashPathEffect(dashes, dashPhase));
}
}
@Override
public AndroidPaint clone() {
try {
AndroidPaint p = (AndroidPaint)super.clone();
p.paint = new Paint(this.paint);
return p;
}
catch (CloneNotSupportedException e) {
throw new Error(e);
}
}
@Override
public <T> T getNativeObject(Class<T> type) {
return type.cast(this.paint);
}
@Override
public float[] getDashArray() {
throw new UnsupportedOperationException();
}
@Override
public float getDashPhase() {
throw new UnsupportedOperationException();
}
@Override
public float getLineWidth() {
return this.paint.getStrokeWidth();
}
@Override
public LineJoin getLineJoin() {
switch(this.paint.getStrokeJoin()) {
case BEVEL:
return LineJoin.BEVEL;
case MITER:
return LineJoin.MITER;
case ROUND:
return LineJoin.ROUND;
default:
throw new IllegalStateException();
}
}
@Override
public EndCap getEndCap() {
switch(this.paint.getStrokeCap()) {
case BUTT:
return EndCap.BUTT;
case SQUARE:
return EndCap.SQUARE;
case ROUND:
return EndCap.ROUND;
default:
throw new IllegalStateException();
}
}
@Override
public float getMiterLimit() {
return this.paint.getStrokeMiter();
}
@Override
public Font getFont() {
return this;
}
@Override
public float getLeading() {
android.graphics.Paint.FontMetrics fm = this.paint.getFontMetrics();
return fm.leading;
}
@Override
public float getAscent() {
android.graphics.Paint.FontMetrics fm = this.paint.getFontMetrics();
return Math.abs(fm.ascent);
}
@Override
public float getDescent() {
android.graphics.Paint.FontMetrics fm = this.paint.getFontMetrics();
return Math.abs(fm.descent);
}
@Override
public float getHeight() {
return this.paint.getTextSize();
}
@Override
public float getMaxAscent() {
android.graphics.Paint.FontMetrics fm = this.paint.getFontMetrics();
return Math.abs(fm.top);
}
@Override
public float getMaxDescent() {
android.graphics.Paint.FontMetrics fm = this.paint.getFontMetrics();
return Math.abs(fm.bottom);
}
@Override
public float getMaxAdvance() {
return this.paint.measureText("m");
}
@Override
public float stringWidth(String str) {
return this.paint.measureText(str);
}
@Override
public Rectangle2f getStringBounds(String str) {
Rect r = new Rect();
this.paint.getTextBounds(str, 0, str.length(), r);
return new Rectangle2f(0, 0, r.width(), r.height());
}
@Override
public Rectangle2f getMaxCharBounds() {
return new Rectangle2f(0, 0, getMaxAdvance(), getHeight());
}
/** Replies the preferred size of the font.
*
* @return the size of the font; or {@code -1} if
* the size is unknown.
*/
@Override
public float getSize() {
return this.paint.getTextSize();
}
@Override
public String getFamily() {
return getName();
}
@Override
public String getFontName() {
return getPSName();
}
@Override
public String getName() {
Typeface tf = this.paint.getTypeface();
tf = Typeface.create(tf, Typeface.NORMAL);
if (tf.equals(Typeface.DEFAULT)) {
return "Normal";
}
if (tf.equals(Typeface.MONOSPACE)) {
return "Monospace";
}
if (tf.equals(Typeface.SANS_SERIF)) {
return "Sans";
}
if (tf.equals(Typeface.SERIF)) {
return "Serif";
}
return "Unknown";
}
@Override
public String getPSName() {
return getPhysicalPSName();
}
@Override
public String getPhysicalPSName() {
StringBuilder b = new StringBuilder();
b.append(getName());
b.append(".");
Typeface tf = this.paint.getTypeface();
if (tf==null) tf = Typeface.DEFAULT;
switch(tf.getStyle()) {
case Typeface.BOLD_ITALIC:
b.append("bolditalic");
break;
case Typeface.BOLD:
b.append("bold");
break;
case Typeface.ITALIC:
b.append("italic");
break;
default:
case Typeface.NORMAL:
b.append("plain");
break;
}
return b.toString();
}
@Override
public boolean isPlain() {
Typeface tf = this.paint.getTypeface();
if (tf==null) tf = Typeface.DEFAULT;
return !tf.isBold() && !tf.isItalic();
}
@Override
public boolean isBold() {
Typeface tf = this.paint.getTypeface();
if (tf==null) tf = Typeface.DEFAULT;
return tf.isBold();
}
@Override
public boolean isItalic() {
Typeface tf = this.paint.getTypeface();
if (tf==null) tf = Typeface.DEFAULT;
return tf.isItalic();
}
@Override
public Font deriveFont(float size) {
Paint pt = new Paint(this.paint);
pt.setTextSize(size);
return new AndroidPaint(pt);
}
@Override
public Font deriveFont(FontStyle style, float size) {
Paint pt = new Paint(this.paint);
pt.setTextSize(size);
pt.setTypeface(Typeface.create(pt.getTypeface(), toAndroid(style)));
return new AndroidPaint(pt);
}
@Override
public Font deriveFont(FontStyle style) {
Paint pt = new Paint(this.paint);
pt.setTypeface(Typeface.create(pt.getTypeface(), toAndroid(style)));
return new AndroidPaint(pt);
}
@Override
public float getItalicAngle() {
return 0;
}
@Override
public String toString() {
if (this.paint==null) return null;
return "color=0x"+Integer.toHexString(this.paint.getColor());
}
@Override
public GlyphList createGlyphList(VectorGraphics2D g, char... characters) {
return new AndroidGlyphList(characters);
}
@Override
public GlyphList createGlyphList(VectorGraphics2D g, String text) {
return new AndroidGlyphList(text);
}
/**
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
*/
private class AndroidGlyphList implements GlyphList {
private final char[] characters;
private SoftReference<float[]> widths = null;
private SoftReference<AndroidPath> globalPath = null;
private SoftReference<Rectangle2f> globalBounds = null;
/**
* @param characters
*/
public AndroidGlyphList(char... characters) {
this.characters = characters;
}
/**
* @param text
*/
public AndroidGlyphList(String text) {
this.characters = text.toCharArray();
}
@Override
public int size() {
return this.characters.length;
}
@Override
public Font getFont() {
return AndroidPaint.this.getFont();
}
@Override
public char getCharAt(int index) {
return this.characters[index];
}
@Override
public float getWidthAt(int index) {
float[] tab = (this.widths==null) ? null : this.widths.get();
if (tab==null) {
tab = new float[this.characters.length];
Paint paint = getPaint();
paint.getTextWidths(this.characters, 0, tab.length, tab);
this.widths = new SoftReference<>(tab);
}
return tab[index];
}
@Override
public Shape2f getOutlineAt(int index) {
Path path = new Path();
Paint paint = getPaint();
paint.getTextPath(this.characters, index, 1, 0, 0, path);
return new AndroidPath(path);
}
@Override
public Shape2f getOutlineAt(int index, float x, float y) {
Path path = new Path();
Paint paint = getPaint();
paint.getTextPath(this.characters, index, 1, x, y, path);
return new AndroidPath(path);
}
@Override
public Shape2f getOutline() {
AndroidPath p = (this.globalPath==null) ? null : this.globalPath.get();
if (p==null) {
Path path = new Path();
Paint paint = getPaint();
paint.getTextPath(this.characters, 0, this.characters.length, 0, 0, path);
p = new AndroidPath(path);
this.globalPath = new SoftReference<>(p);
}
return p;
}
@Override
public Shape2f getOutline(float x, float y) {
Path path = new Path();
Paint paint = getPaint();
paint.getTextPath(this.characters, 0, this.characters.length, 0, 0, path);
return new AndroidPath(path);
}
@Override
public Rectangle2f getBoundsAt(int index) {
Rect rect = new Rect();
Paint paint = getPaint();
paint.getTextBounds(this.characters, index, 1, rect);
return new Rectangle2f(
rect.left, rect.top,
rect.width(), rect.height());
}
@Override
public Rectangle2f getBoundsAt(int index, float x, float y) {
Rect rect = new Rect();
Paint paint = getPaint();
paint.getTextBounds(this.characters, index, 1, rect);
return new Rectangle2f(
rect.left + x, rect.top + y,
rect.width(), rect.height());
}
@Override
public Rectangle2f getBounds() {
Rectangle2f p = (this.globalBounds==null) ? null : this.globalBounds.get();
if (p==null) {
Rect rect = new Rect();
Paint paint = getPaint();
paint.getTextBounds(this.characters, 0, this.characters.length, rect);
p = new Rectangle2f(
rect.left, rect.top,
rect.width(), rect.height());
this.globalBounds = new SoftReference<>(p);
}
return p;
}
@Override
public Rectangle2f getBounds(float x, float y) {
Rect rect = new Rect();
Paint paint = getPaint();
paint.getTextBounds(this.characters, 0, this.characters.length, rect);
return new Rectangle2f(
rect.left + x, rect.top + y,
rect.width(), rect.height());
}
} // class AndroidGlyphList
}