diff options
author | David Kohen <kohen.d@gmail.com> | 2011-01-21 12:03:27 +0200 |
---|---|---|
committer | Steve Kondik <shade@chemlab.org> | 2011-01-22 20:51:31 -0500 |
commit | 139d6e9104d882ce6f69ec95c37be681dd91a2c4 (patch) | |
tree | e68e7b6b1aa64fa37830848c4ed5468589f9d26c /graphics | |
parent | 55ff9d2a7f3e5ebe0b1fb7647e75b8c5bf17f654 (diff) | |
download | frameworks_base-139d6e9104d882ce6f69ec95c37be681dd91a2c4.zip frameworks_base-139d6e9104d882ce6f69ec95c37be681dd91a2c4.tar.gz frameworks_base-139d6e9104d882ce6f69ec95c37be681dd91a2c4.tar.bz2 |
RTL and Arabic reshaping support cherry-picked from FroYo
Change-Id: I43ee8efec12fb1edbf956b52326262c80d579885
Diffstat (limited to 'graphics')
-rw-r--r-- | graphics/java/android/graphics/Canvas.java | 437 | ||||
-rw-r--r-- | graphics/java/android/graphics/Paint.java | 26 | ||||
-rw-r--r-- | graphics/java/android/graphics/utils/ArabicReshape.java | 403 |
3 files changed, 781 insertions, 85 deletions
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java index a587d0d..d8d7dd3 100644 --- a/graphics/java/android/graphics/Canvas.java +++ b/graphics/java/android/graphics/Canvas.java @@ -16,6 +16,7 @@ package android.graphics; +import android.graphics.utils.ArabicReshape; import android.text.TextUtils; import android.text.SpannedString; import android.text.SpannableString; @@ -34,7 +35,9 @@ import javax.microedition.khronos.opengles.GL; public class Canvas { // assigned in constructors, freed in finalizer final int mNativeCanvas; - + private static final char FIRST_RIGHT_TO_LEFT = '\u0590'; + private static final char LAST_RIGHT_TO_LEFT = '\u07b1'; + /* Our native canvas can be either a raster, gl, or picture canvas. If we are raster, then mGL will be null, and mBitmap may or may not be present (our default constructor creates a raster canvas but no @@ -44,7 +47,7 @@ public class Canvas { */ private Bitmap mBitmap; // if not null, mGL must be null private GL mGL; // if not null, mBitmap must be null - + // optional field set by the caller private DrawFilter mDrawFilter; @@ -53,7 +56,7 @@ public class Canvas { // Used to determine when compatibility scaling is in effect. private int mScreenDensity = Bitmap.DENSITY_NONE; - + // Used by native code @SuppressWarnings({"UnusedDeclaration"}) private int mSurfaceFormat; @@ -72,7 +75,7 @@ public class Canvas { /** * Construct a canvas with the specified bitmap to draw into. The bitmap * must be mutable. - * + * * <p>The initial target density of the canvas is the same as the given * bitmap's density. * @@ -88,7 +91,7 @@ public class Canvas { mBitmap = bitmap; mDensity = bitmap.mDensity; } - + /*package*/ Canvas(int nativeCanvas) { if (nativeCanvas == 0) { throw new IllegalStateException(); @@ -96,14 +99,14 @@ public class Canvas { mNativeCanvas = nativeCanvas; mDensity = Bitmap.getDefaultDensity(); } - + /** * Construct a canvas with the specified gl context. All drawing through * this canvas will be redirected to OpenGL. Note: some features may not * be supported in this mode (e.g. some GL implementations may not support * antialiasing or certain effects like ColorMatrix or certain Xfermodes). * However, no exception will be thrown in those cases. - * + * * <p>The initial target density of the canvas is the same as the initial * density of bitmaps as per {@link Bitmap#getDensity() Bitmap.getDensity()}. */ @@ -112,7 +115,7 @@ public class Canvas { mGL = gl; mDensity = Bitmap.getDefaultDensity(); } - + /** * Return the GL object associated with this canvas, or null if it is not * backed by GL. @@ -120,7 +123,7 @@ public class Canvas { public GL getGL() { return mGL; } - + /** * Call this to free up OpenGL resources that may be cached or allocated * on behalf of the Canvas. Any subsequent drawing with a GL-backed Canvas @@ -129,13 +132,13 @@ public class Canvas { public static void freeGlCaches() { freeCaches(); } - + /** * Specify a bitmap for the canvas to draw into. As a side-effect, also * updates the canvas's target density to match that of the bitmap. * * @param bitmap Specifies a mutable bitmap for the canvas to draw into. - * + * * @see #setDensity(int) * @see #getDensity() */ @@ -152,7 +155,7 @@ public class Canvas { mBitmap = bitmap; mDensity = bitmap.mDensity; } - + /** * Set the viewport dimensions if this canvas is GL based. If it is not, * this method is ignored and no exception is thrown. @@ -197,7 +200,7 @@ public class Canvas { * to determine the scaling factor when drawing a bitmap into it. * * @see #setDensity(int) - * @see Bitmap#getDensity() + * @see Bitmap#getDensity() */ public int getDensity() { return mDensity; @@ -213,7 +216,7 @@ public class Canvas { * {@link Bitmap#DENSITY_NONE} to disable bitmap scaling. * * @see #getDensity() - * @see Bitmap#setDensity(int) + * @see Bitmap#setDensity(int) */ public void setDensity(int density) { if (mBitmap != null) { @@ -226,7 +229,7 @@ public class Canvas { public void setScreenDensity(int density) { mScreenDensity = density; } - + // the SAVE_FLAG constants must match their native equivalents /** restore the current matrix when restore() is called */ @@ -240,8 +243,8 @@ public class Canvas { /** clip against the layer's bounds */ public static final int CLIP_TO_LAYER_SAVE_FLAG = 0x10; /** restore everything when restore() is called */ - public static final int ALL_SAVE_FLAG = 0x1F; - + public static final int ALL_SAVE_FLAG = 0x1F; + /** * Saves the current matrix and clip onto a private stack. Subsequent * calls to translate,scale,rotate,skew,concat or clipRect,clipPath @@ -252,7 +255,7 @@ public class Canvas { * @return The value to pass to restoreToCount() to balance this save() */ public native int save(); - + /** * Based on saveFlags, can save the current matrix and clip onto a private * stack. Subsequent calls to translate,scale,rotate,skew,concat or @@ -287,7 +290,7 @@ public class Canvas { paint != null ? paint.mNativePaint : 0, saveFlags); } - + /** * Helper version of saveLayer() that takes 4 values rather than a RectF. */ @@ -318,7 +321,7 @@ public class Canvas { alpha = Math.min(255, Math.max(0, alpha)); return native_saveLayerAlpha(mNativeCanvas, bounds, alpha, saveFlags); } - + /** * Helper for saveLayerAlpha() that takes 4 values instead of a RectF. */ @@ -422,7 +425,7 @@ public class Canvas { public void concat(Matrix matrix) { native_concat(mNativeCanvas, matrix.native_instance); } - + /** * Completely replace the current matrix with the specified matrix. If the * matrix parameter is null, then the current matrix is reset to identity. @@ -434,7 +437,7 @@ public class Canvas { native_setMatrix(mNativeCanvas, matrix == null ? 0 : matrix.native_instance); } - + /** * Return, in ctm, the current transformation matrix. This does not alter * the matrix in the canvas, but just returns a copy of it. @@ -442,7 +445,7 @@ public class Canvas { public void getMatrix(Matrix ctm) { native_getCTM(mNativeCanvas, ctm.native_instance); } - + /** * Return a new matrix with a copy of the canvas' current transformation * matrix. @@ -452,7 +455,7 @@ public class Canvas { getMatrix(m); return m; } - + /** * Modify the current clip with the specified rectangle. * @@ -488,7 +491,7 @@ public class Canvas { * @return true if the resulting clip is non-empty */ public native boolean clipRect(RectF rect); - + /** * Intersect the current clip with the specified rectangle, which is * expressed in local coordinates. @@ -497,7 +500,7 @@ public class Canvas { * @return true if the resulting clip is non-empty */ public native boolean clipRect(Rect rect); - + /** * Modify the current clip with the specified rectangle, which is * expressed in local coordinates. @@ -534,7 +537,7 @@ public class Canvas { */ public native boolean clipRect(float left, float top, float right, float bottom); - + /** * Intersect the current clip with the specified rectangle, which is * expressed in local coordinates. @@ -550,7 +553,7 @@ public class Canvas { */ public native boolean clipRect(int left, int top, int right, int bottom); - + /** * Modify the current clip with the specified path. * @@ -561,7 +564,7 @@ public class Canvas { public boolean clipPath(Path path, Region.Op op) { return native_clipPath(mNativeCanvas, path.ni(), op.nativeInt); } - + /** * Intersect the current clip with the specified path. * @@ -571,7 +574,7 @@ public class Canvas { public boolean clipPath(Path path) { return clipPath(path, Region.Op.INTERSECT); } - + /** * Modify the current clip with the specified region. Note that unlike * clipRect() and clipPath() which transform their arguments by the @@ -600,11 +603,11 @@ public class Canvas { public boolean clipRegion(Region region) { return clipRegion(region, Region.Op.INTERSECT); } - + public DrawFilter getDrawFilter() { return mDrawFilter; } - + public void setDrawFilter(DrawFilter filter) { int nativeFilter = 0; if (filter != null) { @@ -617,7 +620,7 @@ public class 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; } @@ -695,7 +698,7 @@ public class Canvas { public boolean getClipBounds(Rect bounds) { return native_getClipBounds(mNativeCanvas, bounds); } - + /** * Retrieve the clip bounds. * @@ -706,7 +709,7 @@ public class Canvas { getClipBounds(r); return r; } - + /** * Fill the entire canvas' bitmap (restricted to the current clip) with the * specified RGB color, using srcover porterduff mode. @@ -763,7 +766,7 @@ public class Canvas { public void drawPaint(Paint paint) { native_drawPaint(mNativeCanvas, paint.mNativePaint); } - + /** * Draw a series of points. Each point is centered at the coordinate * specified by pts[], and its diameter is specified by the paint's stroke @@ -853,7 +856,7 @@ public class Canvas { public void drawRect(Rect r, Paint paint) { drawRect(r.left, r.top, r.right, r.bottom, paint); } - + /** * Draw the specified Rect using the specified paint. The rectangle will @@ -949,7 +952,7 @@ public class Canvas { public void drawPath(Path path, Paint paint) { native_drawPath(mNativeCanvas, path.ni(), paint.mNativePaint); } - + private static void throwIfRecycled(Bitmap bitmap) { if (bitmap.isRecycled()) { throw new RuntimeException( @@ -960,7 +963,7 @@ public class Canvas { /** * Draw the specified bitmap, with its top/left corner at (x,y), using * the specified paint, transformed by the current matrix. - * + * * <p>Note: if the paint contains a maskfilter that generates a mask which * extends beyond the bitmap's original width/height (e.g. BlurMaskFilter), * then the bitmap will be drawn as if it were in a Shader with CLAMP mode. @@ -970,7 +973,7 @@ public class Canvas { * <p>If the bitmap and canvas have different densities, this function * will take care of automatically scaling the bitmap to draw at the * same density as the canvas. - * + * * @param bitmap The bitmap to be drawn * @param left The position of the left side of the bitmap being drawn * @param top The position of the top side of the bitmap being drawn @@ -987,7 +990,7 @@ public class Canvas { * Draw the specified bitmap, scaling/translating automatically to fill * the destination rectangle. If the source rectangle is not null, it * specifies the subset of the bitmap to draw. - * + * * <p>Note: if the paint contains a maskfilter that generates a mask which * extends beyond the bitmap's original width/height (e.g. BlurMaskFilter), * then the bitmap will be drawn as if it were in a Shader with CLAMP mode. @@ -998,7 +1001,7 @@ public class Canvas { * This is because the source and destination rectangle coordinate * spaces are in their respective densities, so must already have the * appropriate scaling factor applied. - * + * * @param bitmap The bitmap to be drawn * @param src May be null. The subset of the bitmap to be drawn * @param dst The rectangle that the bitmap will be scaled/translated @@ -1019,7 +1022,7 @@ public class Canvas { * Draw the specified bitmap, scaling/translating automatically to fill * the destination rectangle. If the source rectangle is not null, it * specifies the subset of the bitmap to draw. - * + * * <p>Note: if the paint contains a maskfilter that generates a mask which * extends beyond the bitmap's original width/height (e.g. BlurMaskFilter), * then the bitmap will be drawn as if it were in a Shader with CLAMP mode. @@ -1030,7 +1033,7 @@ public class Canvas { * This is because the source and destination rectangle coordinate * spaces are in their respective densities, so must already have the * appropriate scaling factor applied. - * + * * @param bitmap The bitmap to be drawn * @param src May be null. The subset of the bitmap to be drawn * @param dst The rectangle that the bitmap will be scaled/translated @@ -1046,7 +1049,7 @@ public class Canvas { paint != null ? paint.mNativePaint : 0, mScreenDensity, bitmap.mDensity); } - + /** * Treat the specified array of colors as a bitmap, and draw it. This gives * the same result as first creating a bitmap from the array, and then @@ -1093,7 +1096,7 @@ public class Canvas { native_drawBitmap(mNativeCanvas, colors, offset, stride, x, y, width, height, hasAlpha, paint != null ? paint.mNativePaint : 0); } - + /** Legacy version of drawBitmap(int[] colors, ...) that took ints for x,y */ public void drawBitmap(int[] colors, int offset, int stride, int x, int y, @@ -1103,7 +1106,7 @@ public class Canvas { drawBitmap(colors, offset, stride, (float)x, (float)y, width, height, hasAlpha, paint); } - + /** * Draw the bitmap using the specified matrix. * @@ -1115,13 +1118,13 @@ public class Canvas { nativeDrawBitmapMatrix(mNativeCanvas, bitmap.ni(), matrix.ni(), paint != null ? paint.mNativePaint : 0); } - + private static void checkRange(int length, int offset, int count) { if ((offset | count) < 0 || offset + count > length) { throw new ArrayIndexOutOfBoundsException(); } } - + /** * Draw the bitmap through the mesh, where mesh vertices are evenly * distributed across the bitmap. There are meshWidth+1 vertices across, and @@ -1168,18 +1171,18 @@ public class Canvas { verts, vertOffset, colors, colorOffset, paint != null ? paint.mNativePaint : 0); } - + public enum VertexMode { TRIANGLES(0), TRIANGLE_STRIP(1), TRIANGLE_FAN(2); - + VertexMode(int nativeInt) { this.nativeInt = nativeInt; } final int nativeInt; } - + /** * Draw the array of vertices, interpreted as triangles (based on mode). The * verts array is required, and specifies the x,y pairs for each vertex. If @@ -1208,7 +1211,7 @@ public class Canvas { * @param indices If not null, array of indices to reference into the * vertex (texs, colors) array. * @param indexCount number of entries in the indices array (if not null). - * @param paint Specifies the shader to use if the texs array is non-null. + * @param paint Specifies the shader to use if the texs array is non-null. */ public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset, @@ -1230,7 +1233,169 @@ public class Canvas { vertOffset, texs, texOffset, colors, colorOffset, indices, indexOffset, indexCount, paint.mNativePaint); } - + + /** + * Since the reshaping algorithm does not test for arabic prior to starting, this is made to + * @hide + **/ + public static boolean bidiTest(char[] text,int start,int srcCount) { + + boolean hasBidi=false; + + // Check if there are BiDi characters in the string, of so, we need to work. + for (int i=start;i<(srcCount+start);i++){ + if (text[i]>=FIRST_RIGHT_TO_LEFT&&text[i]<=LAST_RIGHT_TO_LEFT){ + hasBidi=true; + break; + } + } + return hasBidi; + } + /** + * Since the reshaping algorithm does not test for arabic prior to starting, this is made to + * @hide + **/ + public static boolean bidiTest(String text,int start,int srcCount) { + + boolean hasBidi=false; + + // Check if there are BiDi characters in the string, of so, we need to work. + for (int i=start;i<(srcCount+start);i++){ + if (text.charAt(i)>=FIRST_RIGHT_TO_LEFT&&text.charAt(i)<=LAST_RIGHT_TO_LEFT){ + hasBidi=true; + break; + } + } + return hasBidi; + } + /** + * A lightweight BiDi processing to make all draw text work with RTL languages. + * written from scratch by David Kohen (kohen dot d at gmail dot com) - 2010 + * @hide + **/ + public static char[] bidiProcess(char[] text,int start,int srcCount) { + + boolean hasBidi=false; + char[] destCharArray=new char[srcCount]; + + char[] buf = TemporaryBuffer.obtain(srcCount); + System.arraycopy(text,start, buf, 0, srcCount); + + // I'm doing the processing from the end of the string, since it worked well this way. + int count=0,srcIndex=0; + boolean rtlMode=true; + for (int i=0;i<srcCount;i++){ + srcIndex=srcCount-1-i; + if (buf[srcIndex]>=FIRST_RIGHT_TO_LEFT&&buf[srcIndex]<=LAST_RIGHT_TO_LEFT){ + destCharArray[i]=buf[srcIndex]; + // In rtl mode I'm mirroring glyphs. + rtlMode=true; + } + else { + srcIndex=srcCount-1-i; + if (count==0) { + // Direction neutral characters + if (buf[srcIndex]<='\u002f' || + (buf[srcIndex]>'\u0039' && buf[srcIndex]<='\u0040') || + (buf[srcIndex]>'\u005a' && buf[srcIndex]<='\u0060')|| + (buf[srcIndex]>'\u007a' && buf[srcIndex]<='\u00BF')) { + + if (rtlMode){ + switch (buf[srcIndex]) { + case '[': + destCharArray[i]=']'; + break; + case ']': + destCharArray[i]='['; + break; + case '}': + destCharArray[i]='{'; + break; + case '{': + destCharArray[i]='}'; + break; + case '(': + destCharArray[i]=')'; + break; + case ')': + destCharArray[i]='('; + break; + case '>': + destCharArray[i]='<'; + break; + case '<': + destCharArray[i]='>'; + break; + default: + destCharArray[i]=buf[srcIndex]; + break; + } + } else destCharArray[i]=buf[srcIndex]; + } else { + // Handling LTR embedded strings. + while (((srcIndex-count)>=0)&&((buf[srcIndex-count]<FIRST_RIGHT_TO_LEFT)||(buf[srcIndex-count]>LAST_RIGHT_TO_LEFT))){ + count++; + } + int index=0; + int punctuationMarks=0; + + // Handling direction neutral characters in the middle of LTR + while (count>0 && (srcIndex-(count)>=0) && + (buf[srcIndex-(count-1)]<='\u002f' || + (buf[srcIndex-(count-1)]>'\u0039' && buf[srcIndex-(count-1)]<='\u0040') || + (buf[srcIndex-(count-1)]>'\u005a' && buf[srcIndex-(count-1)]<='\u0060')|| + (buf[srcIndex-(count-1)]>'\u007a' && buf[srcIndex-(count-1)]<='\u00BF'))){ + destCharArray[i+(count-1)]=buf[srcIndex-(count-1)]; + count--; + punctuationMarks++; + } + + while (count>0){ + destCharArray[i+index]=buf[srcIndex-(count-1)]; + count--; + index++; + } + count=index+punctuationMarks-1; + } + } + else { + // Avoiding spaghetti code and mangling of loop counter + count--; + } + rtlMode=false; + } + } + return destCharArray; + } + + /** @hide **/ + public void drawText(char[] text, int index, int count, float x, float y, + Paint paint,boolean bidi) { + if (((index | count | (index + count)) < 0) || + (index + count) > text.length) { + throw new IndexOutOfBoundsException(); + } + boolean hasBidi=bidiTest(text,index,count); + if (hasBidi) { + if (bidi) { + char[] bidiText=bidiProcess(text,index,count); + String reshapedText=ArabicReshape.reshape(new String(bidiText)); + /* The reshaping may make the string smaller */ + native_drawText(mNativeCanvas, reshapedText.toCharArray(), 0, count - ((count - reshapedText.length())>0 ? (count - reshapedText.length()) : 0), x, y, + paint.mNativePaint); + } else { + String reshapedText=ArabicReshape.reshape(new String(text)); + /* The reshaping may make the string smaller */ + native_drawText(mNativeCanvas, reshapedText.toCharArray(), index, + count - ((text.length - reshapedText.length())>0 ? (text.length - reshapedText.length()) : 0), x, y, + paint.mNativePaint); + } + } else { + native_drawText(mNativeCanvas, text, index, count, x, y, + paint.mNativePaint); + } + } + /** * Draw the text, with origin at (x,y), using the specified paint. The * origin is interpreted based on the Align setting in the paint. @@ -1246,8 +1411,14 @@ public class Canvas { (text.length - index - count)) < 0) { throw new IndexOutOfBoundsException(); } - native_drawText(mNativeCanvas, text, index, count, x, y, - paint.mNativePaint); + + boolean hasBidi=bidiTest(text,index,count); + if (hasBidi) { + drawText(text,index,count,x,y,paint,true); + } else { + native_drawText(mNativeCanvas, text, index, count, x, y, + paint.mNativePaint); + } } /** @@ -1259,7 +1430,28 @@ public class Canvas { * @param y The y-coordinate of the origin of the text being drawn * @param paint The paint used for the text (e.g. color, size, style) */ - public native void drawText(String text, float x, float y, Paint paint); + private native void native_drawText(String text, float x, float y, Paint paint); + + /** @hide */ + public void drawText(String text, float x, float y, Paint paint,boolean bidi){ + boolean hasBidi=bidiTest(text,0,text.length()); + if (hasBidi) { + if (!bidi) { + native_drawText(ArabicReshape.reshape(text),x,y,paint); + } else { + if (text.length() > 0) { + String bidiText; + bidiText=new String(bidiProcess(text.toCharArray(),0,text.length())); + native_drawText(ArabicReshape.reshape(bidiText),x,y,paint); + } + } + } else { + native_drawText(text,x,y,paint); + } + } + public void drawText(String text, float x, float y, Paint paint){ + drawText(text,x,y,paint,true); + } /** * Draw the text, with origin at (x,y), using the specified paint. @@ -1277,8 +1469,16 @@ public class Canvas { if ((start | end | (end - start) | (text.length() - end)) < 0) { throw new IndexOutOfBoundsException(); } - native_drawText(mNativeCanvas, text, start, end, x, y, - paint.mNativePaint); + boolean hasBidi=bidiTest(text,start,end-start); + if (hasBidi) { + String reshapedText=ArabicReshape.reshape(new String(bidiProcess(text.toCharArray(),start,end-start))); + /* The reshaping may make the string smaller */ + native_drawText(mNativeCanvas, reshapedText, 0, end-start - ((end-start - reshapedText.length())>0?(end-start - reshapedText.length()):0), x, y, + paint.mNativePaint); + } else { + native_drawText(mNativeCanvas, text, start, end, x, y, + paint.mNativePaint); + } } /** @@ -1296,21 +1496,49 @@ public class Canvas { */ public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) { + drawText(text,start,end,x,y,paint,true); + } + + /** @hide */ + public void drawText(CharSequence text, int start, int end, float x, + float y, Paint paint,boolean bidi) { + boolean hasBidi=bidiTest(text.toString(),start,end-start); if (text instanceof String || text instanceof SpannedString || - text instanceof SpannableString) { - native_drawText(mNativeCanvas, text.toString(), start, end, x, y, + text instanceof SpannableString) { + if (hasBidi) { + if (bidi) { + String bidiText=new String(bidiProcess(text.toString().toCharArray(),start,end-start)); + String reshapedText=ArabicReshape.reshape(bidiText); + /* The reshaping may make the string smaller */ + native_drawText(mNativeCanvas, reshapedText, 0, (end-start) - ((end-start - reshapedText.length())>0 ? (end-start - reshapedText.length()) : 0), x, y, + paint.mNativePaint); + } else { + String reshapedText=ArabicReshape.reshape(text.toString()); + /* The reshaping may make the string smaller */ + native_drawText(mNativeCanvas, reshapedText, 0, (end-start) - ((end-start - reshapedText.length())>0 ? (end-start - reshapedText.length()) : 0), x, y, + paint.mNativePaint); + } + } else { + native_drawText(mNativeCanvas, text.toString() , start, end, x, y, paint.mNativePaint); + } } else if (text instanceof GraphicsOperations) { ((GraphicsOperations) text).drawText(this, start, end, x, y, - paint); - } - else { - char[] buf = TemporaryBuffer.obtain(end - start); - TextUtils.getChars(text, start, end, buf, 0); - drawText(buf, 0, end - start, x, y, paint); - TemporaryBuffer.recycle(buf); - } + paint); + } + else { + char[] buf = TemporaryBuffer.obtain(end - start); + TextUtils.getChars(text, start, end, buf, 0); + if (hasBidi) { + String reshapedText=ArabicReshape.reshape(new String(buf)); + /* The reshaping may make the string smaller */ + drawText(reshapedText.toCharArray(), 0, (end - start) - (((end - start) - reshapedText.length())>0?((end - start) - reshapedText.length()):0), x, y, paint,false); + } else { + drawText(buf, 0, end - start, x, y, paint,false); + } + TemporaryBuffer.recycle(buf); + } } /** @@ -1326,11 +1554,24 @@ public class Canvas { */ public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint) { - if (index < 0 || index + count > text.length || count*2 > pos.length) { + if (index < 0 || index + count > text.length || (index+count)*2 > pos.length) { throw new IndexOutOfBoundsException(); } - native_drawPosText(mNativeCanvas, text, index, count, pos, - paint.mNativePaint); + + boolean hasBidi=bidiTest(text,index,count); + if (hasBidi) { + float[] relativePos = new float[count*2]; + System.arraycopy(pos , index*2 , relativePos , 0, count*2); + char[] bidiText; + bidiText=bidiProcess(text,index,count); + String reshapedText=ArabicReshape.reshape(new String(bidiText)); + /* The reshaping may make the string smaller */ + native_drawPosText(mNativeCanvas, reshapedText.toCharArray(), 0, count - ((count - reshapedText.length())>0 ? (count - reshapedText.length()) : 0), relativePos, + paint.mNativePaint); + } else { + native_drawPosText(mNativeCanvas, text, index, count, pos, + paint.mNativePaint); + } } /** @@ -1345,7 +1586,16 @@ public class Canvas { if (text.length()*2 > pos.length) { throw new ArrayIndexOutOfBoundsException(); } - native_drawPosText(mNativeCanvas, text, pos, paint.mNativePaint); + + boolean hasBidi=bidiTest(text,0,text.length()); + if (hasBidi) { + String bidiText; + bidiText=new String(bidiProcess(text.toCharArray(),0,text.length())); + native_drawPosText(mNativeCanvas, ArabicReshape.reshape(bidiText), pos, paint.mNativePaint); + } else { + native_drawPosText(mNativeCanvas, text, pos, + paint.mNativePaint); + } } /** @@ -1366,9 +1616,21 @@ public class Canvas { if (index < 0 || index + count > text.length) { throw new ArrayIndexOutOfBoundsException(); } - native_drawTextOnPath(mNativeCanvas, text, index, count, - path.ni(), hOffset, vOffset, - paint.mNativePaint); + boolean hasBidi=bidiTest(text,index,count); + if (hasBidi) { + char[] bidiText; + bidiText=bidiProcess(text,index,count); + String reshapedText=ArabicReshape.reshape(new String(bidiText)); + /* The reshaping may make the string smaller */ + native_drawTextOnPath(mNativeCanvas, reshapedText.toCharArray(), 0, count - ((count - reshapedText.length())>0 ? (count - reshapedText.length()) : 0), + path.ni(), hOffset, vOffset, + paint.mNativePaint); + } else { + native_drawTextOnPath(mNativeCanvas, text, index, count, + path.ni(), hOffset, vOffset, + paint.mNativePaint); + } + // TODO: Handle index>0 } /** @@ -1387,8 +1649,17 @@ public class Canvas { public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) { if (text.length() > 0) { - native_drawTextOnPath(mNativeCanvas, text, path.ni(), - hOffset, vOffset, paint.mNativePaint); + boolean hasBidi=bidiTest(text,0,text.length()); + if (hasBidi) { + String bidiText; + bidiText=new String(bidiProcess(text.toCharArray(),0,text.length())); + native_drawTextOnPath(mNativeCanvas, ArabicReshape.reshape(bidiText), path.ni(), + hOffset, vOffset, paint.mNativePaint); + } else { + native_drawTextOnPath(mNativeCanvas, text, + path.ni(), hOffset, vOffset, + paint.mNativePaint); + } } } @@ -1396,14 +1667,14 @@ public class Canvas { * Save the canvas state, draw the picture, and restore the canvas state. * This differs from picture.draw(canvas), which does not perform any * save/restore. - * + * * @param picture The picture to be drawn */ public void drawPicture(Picture picture) { picture.endRecording(); native_drawPicture(mNativeCanvas, picture.ni()); } - + /** * Draw the picture, stretched to fit into the dst rectangle. */ @@ -1417,7 +1688,7 @@ public class Canvas { drawPicture(picture); restore(); } - + /** * Draw the picture, stretched to fit into the dst rectangle. */ @@ -1431,7 +1702,7 @@ public class Canvas { drawPicture(picture); restore(); } - + protected void finalize() throws Throwable { super.finalize(); // If the constructor threw an exception before setting mNativeCanvas, the native finalizer @@ -1552,7 +1823,7 @@ public class Canvas { float[] verts, int vertOffset, float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices, int indexOffset, int indexCount, int nPaint); - + private static native void native_drawText(int nativeCanvas, char[] text, int index, int count, float x, float y, int paint); diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index 3e3f87b..6d6f730 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -16,6 +16,7 @@ package android.graphics; +import android.graphics.utils.ArabicReshape; import android.text.TextUtils; import android.text.SpannableString; import android.text.SpannedString; @@ -1299,7 +1300,18 @@ public class Paint { if ((index | count) < 0 || index + count > text.length) { throw new ArrayIndexOutOfBoundsException(); } - native_getTextPath(mNativePaint, text, index, count, x, y, path.ni()); + boolean hasBidi=Canvas.bidiTest(text,index,count); + if (hasBidi) { + char[] bidiText; + bidiText=Canvas.bidiProcess(text,index,count); + String reshapedText=ArabicReshape.reshape(new String(bidiText)); + /* The reshaping may make the string smaller */ + native_getTextPath(mNativePaint, reshapedText.toCharArray(), 0, + count - ((count-reshapedText.length())>0 ? (count-reshapedText.length()) : 0), + x, y, path.ni()); + } else { + native_getTextPath(mNativePaint, text, index, count, x, y, path.ni()); + } } /** @@ -1320,7 +1332,17 @@ public class Paint { if ((start | end | (end - start) | (text.length() - end)) < 0) { throw new IndexOutOfBoundsException(); } - native_getTextPath(mNativePaint, text, start, end, x, y, path.ni()); + boolean hasBidi=Canvas.bidiTest(text,start,start+end); + if (hasBidi) { + char[] bidiText; + bidiText=Canvas.bidiProcess(text.toCharArray(),start,start+end); + String reshapedText=ArabicReshape.reshape(new String(bidiText)); + /* The reshaping may make the string smaller */ + native_getTextPath(mNativePaint, reshapedText, 0, end-start - ((end-start - reshapedText.length())>0 ? (end-start - reshapedText.length()) : 0), + x, y, path.ni()); + } else { + native_getTextPath(mNativePaint, text, start, end, x, y, path.ni()); + } } /** diff --git a/graphics/java/android/graphics/utils/ArabicReshape.java b/graphics/java/android/graphics/utils/ArabicReshape.java new file mode 100644 index 0000000..785b4c6 --- /dev/null +++ b/graphics/java/android/graphics/utils/ArabicReshape.java @@ -0,0 +1,403 @@ +/* + * Copyright (C) 2010 Abdulaziz Alhussien + * + * 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. + */ + +/* @hide */ +package android.graphics.utils; + +/** + * This code is for Arabic Reshaping. + * Writtien by Abdulaziz Alhussien. + * azizanroid@gmail.com + * + * This code is used in Mirsal, Ibrahim Keyboard, Arabic Contact, Arabic notepad applications + * + * @hide + */ +public class ArabicReshape { + + static final char RIGHT_LEFT_CHAR = 0x0001; + static final char RIGHT_NOLEFT_CHAR_ALEF = 0x0006; + static final char RIGHT_NOLEFT_CHAR = 0x0004; + static final char RIGHT_LEFT_CHAR_LAM = 0x0003; + static final char TANWEEN = 0x000C; + static final char TASHKEEL = 0x000A; + static final char TATWEEL_CHAR = 0x0008; + static final char NORIGHT_NOLEFT_CHAR = 0x0007; + static final char NOTUSED_CHAR = 0x000F; + static final char NOTARABIC_CHAR = 0x0000; + static final char RIGHT_LEFT_CHAR_MASK = 0x0880; + static final char RIGHT_NOLEFT_CHAR_MASK = 0x0800; + static final char LEFT_CHAR_MASK = 0x0080; + + private static final char allchar[][] = { + {0x0621, 0x0007, 0xFE80, 0xFE80, 0xFE80, 0xFE80}, + {0x0622, 0x0806, 0xFE81, 0xFE82, 0xFEF5, 0xFEF6}, + {0x0623, 0x0806, 0xFE83, 0xFE84, 0xFEF7, 0xFEF8}, + {0x0624, 0x0804, 0xFE85, 0xFE86, 0xFE86, 0xFE86}, + {0x0625, 0x0806, 0xFE87, 0xFE88, 0xFEF9, 0xFEFA}, + {0x0626, 0x0881, 0xFE89, 0xFE8A, 0xFE8B, 0xFE8C}, + {0x0627, 0x0806, 0xFE8D, 0xFE8E, 0xFEFB, 0xFEFC}, + {0x0628, 0x0881, 0xFE8F, 0xFE90, 0xFE91, 0xFE92}, + {0x0629, 0x0804, 0xFE93, 0xFE94, 0xFE94, 0xFE94}, + {0x062A, 0x0881, 0xFE95, 0xFE96, 0xFE97, 0xFE98}, + {0x062B, 0x0881, 0xFE99, 0xFE9A, 0xFE9B, 0xFE9C}, + {0x062C, 0x0881, 0xFE9D, 0xFE9E, 0xFE9F, 0xFEA0}, + {0x062D, 0x0881, 0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4}, + {0x062E, 0x0881, 0xFEA5, 0xFEA6, 0xFEA7, 0xFEA8}, + {0x062F, 0x0804, 0xFEA9, 0xFEAA, 0xFEAA, 0xFEAA}, + {0x0630, 0x0804, 0xFEAB, 0xFEAC, 0xFEAC, 0xFEAC}, + {0x0631, 0x0804, 0xFEAD, 0xFEAE, 0xFEAE, 0xFEAE}, + {0x0632, 0x0804, 0xFEAF, 0xFEB0, 0xFEB0, 0xFEB0}, + {0x0633, 0x0881, 0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4}, + {0x0634, 0x0881, 0xFEB5, 0xFEB6, 0xFEB7, 0xFEB8}, + {0x0635, 0x0881, 0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC}, + {0x0636, 0x0881, 0xFEBD, 0xFEBE, 0xFEBF, 0xFEC0}, + {0x0637, 0x0881, 0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4}, + {0x0638, 0x0881, 0xFEC5, 0xFEC6, 0xFEC7, 0xFEC8}, + {0x0639, 0x0881, 0xFEC9, 0xFECA, 0xFECB, 0xFECC}, + {0x063A, 0x0881, 0xFECD, 0xFECE, 0xFECF, 0xFED0}, + {0x063B, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x063C, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x063D, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x063E, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x063F, 0x000F, 0x0, 0x0, 0x0, 0x0}, + + {0x0640, 0x0888, 0x0640, 0x0640, 0x0640, 0x0640}, + {0x0641, 0x0881, 0xFED1, 0xFED2, 0xFED3, 0xFED4}, + {0x0642, 0x0881, 0xFED5, 0xFED6, 0xFED7, 0xFED8}, + {0x0643, 0x0881, 0xFED9, 0xFEDA, 0xFEDB, 0xFEDC}, + {0x0644, 0x0883, 0xFEDD, 0xFEDE, 0xFEDF, 0xFEE0}, + {0x0645, 0x0881, 0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4}, + {0x0646, 0x0881, 0xFEE5, 0xFEE6, 0xFEE7, 0xFEE8}, + {0x0647, 0x0881, 0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC}, + {0x0648, 0x0804, 0xFEED, 0xFEEE, 0xFEEE, 0xFEEE}, + {0x0649, 0x0804, 0xFEEF, 0xFEF0, 0xFEF0, 0xFEF0}, + {0x064A, 0x0881, 0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4}, + {0x064B, 0x000C, 0x064B, 0xFE70, 0xFE71, 0xFE70}, + {0x064C, 0x000C, 0x064C, 0xFE72, 0xFE72, 0xFE72}, + {0x064D, 0x000C, 0x064D, 0xFE74, 0xFE74, 0xFE74}, + {0x064E, 0x000A, 0x064E, 0xFE76, 0xFE77, 0xFE76}, + {0x064F, 0x000A, 0x064F, 0xFE78, 0xFE79, 0xFE78}, + {0x0650, 0x000A, 0x0650, 0xFE7A, 0xFE7B, 0xFE7A}, + {0x0651, 0x000A, 0x0651, 0xFE7C, 0xFE7D, 0xFE7C}, + {0x0652, 0x000A, 0x0652, 0xFE7E, 0xFE7F, 0xFE7E}, + + {0x0653, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x0654, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x0655, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x0656, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x0657, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x0658, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x0659, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x065A, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x065B, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x065C, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x065D, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x065E, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x065F, 0x000F, 0x0, 0x0, 0x0, 0x0}, + + {0x0660, 0x000B, 0x0660, 0x0660, 0x0660, 0x0660}, + {0x0661, 0x000B, 0x0661, 0x0661, 0x0661, 0x0661}, + {0x0662, 0x000B, 0x0662, 0x0662, 0x0662, 0x0662}, + {0x0663, 0x000B, 0x0663, 0x0663, 0x0663, 0x0663}, + {0x0664, 0x000B, 0x0665, 0x0664, 0x0664, 0x0664}, + {0x0665, 0x000B, 0x0665, 0x0665, 0x0665, 0x0665}, + {0x0666, 0x000B, 0x0666, 0x0666, 0x0666, 0x0666}, + {0x0667, 0x000B, 0x0667, 0x0667, 0x0667, 0x0667}, + {0x0668, 0x000B, 0x0668, 0x0668, 0x0668, 0x0668}, + {0x0669, 0x000B, 0x0669, 0x0669, 0x0669, 0x0669}, + + {0x066A, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x066B, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x066C, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x066D, 0x000F, 0x0, 0x0, 0x0, 0x0}, + + {0x066E, 0x000E, 0x065E, 0x065E, 0x065E, 0x065E}, + {0x066F, 0x000E, 0x065F, 0x065F, 0x065F, 0x065F}, + + {0x0670, 0x000F, 0x0, 0x0, 0x0, 0x0}, + + {0x0671, 0x0804, 0xFB50, 0xFB51, 0xFB51, 0xFB51}, + {0x0672, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x0673, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x0674, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x0675, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x0676, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x0677, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x0678, 0x000F, 0x0, 0x0, 0x0, 0x0}, + + + {0x0679, 0x0881, 0xFB66, 0xFB67, 0xFB68, 0xFB69}, + {0x067A, 0x0881, 0xFB5E, 0xFB5F, 0xFB60, 0xFB61}, + {0x067B, 0x0881, 0xFB52, 0xFB53, 0xFB54, 0xFB55}, + {0x067C, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x067D, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x067E, 0x0881, 0xFB56, 0xFB57, 0xFB58, 0xFB59}, + {0x067F, 0x0881, 0xFB62, 0xFB63, 0xFB64, 0xFB65}, + {0x0680, 0x0881, 0xFB5A, 0xFB5B, 0xFB5C, 0xFB5D}, + + {0x0681, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x0682, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x0683, 0x0881, 0xFB76, 0xFB77, 0xFB78, 0xFB79}, + {0x0684, 0x0881, 0xFB72, 0xFB73, 0xFB74, 0xFB75}, + {0x0685, 0x000F, 0x0, 0x0, 0x0, 0x0}, + + {0x0686, 0x0881, 0xFB7A, 0xFB7B, 0xFB7C, 0xFB7D}, + {0x0687, 0x0881, 0xFB7E, 0xFB7F, 0xFB80, 0xFB81}, + {0x0688, 0x0804, 0xFB88, 0xFB89, 0xFB89, 0xFB89}, + {0x0689, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x068A, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x068B, 0x000F, 0x0, 0x0, 0x0, 0x0}, + + {0x068C, 0x0804, 0xFB84, 0xFB85, 0xFB85, 0xFB85}, + {0x068D, 0x0804, 0xFB82, 0xFB83, 0xFB83, 0xFB83}, + {0x068E, 0x0804, 0xFB86, 0xFB87, 0xFB83, 0xFB83}, + {0x068F, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x0690, 0x000F, 0x0, 0x0, 0x0, 0x0}, + + {0x0691, 0x0804, 0xFB8C, 0xFB8D, 0xFB8D, 0xFB8D}, + {0x0692, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x0693, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x0694, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x0695, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x0696, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x0697, 0x000F, 0x0, 0x0, 0x0, 0x0}, + + {0x0698, 0x0804, 0xFB8A, 0xFB8B, 0xFB8B, 0xFB8B}, + {0x0699, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x069A, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x069B, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x069C, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x069D, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x069E, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x069F, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x06A0, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x06A1, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x06A2, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x06A3, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x06A4, 0x0881, 0xFB6A, 0xFB6B, 0xFB6C, 0xFB6D}, + {0x06A5, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x06A6, 0x0881, 0xFB6E, 0xFB6F, 0xFB70, 0xFB71}, + {0x06A7, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x06A8, 0x000F, 0x0, 0x0, 0x0, 0x0}, + + {0x06A9, 0x0881, 0xFB8E, 0xFB8F, 0xFB90, 0xFB91}, + {0x06AA, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x06AB, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x06AC, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x06AD, 0x0881, 0xFBD3, 0xFBD4, 0xFBD5, 0xFBD6}, + {0x06AE, 0x000F, 0x0, 0x0, 0x0, 0x0}, + + {0x06AF, 0x0881, 0xFB92, 0xFB93, 0xFB94, 0xFB95}, + {0x06B0, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x06B1, 0x0881, 0xFB9A, 0xFB9B, 0xFB9C, 0xFB9D}, + {0x06B2, 0x000F, 0x0, 0x0, 0x0, 0x0}, + + {0x06B3, 0x0881, 0xFB96, 0xFB97, 0xFB98, 0xFB99}, + {0x06B4, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x06B5, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x06B6, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x06B7, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x06B8, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x06B9, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x06BA, 0x0804, 0xFB9E, 0xFB9F, 0xFB9F, 0xFB9F}, + {0x06BB, 0x0881, 0xFBA0, 0xFBA1, 0xFBA2, 0xFBA3}, + {0x06BC, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x06BD, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x06BE, 0x0881, 0xFBAA, 0xFBAB, 0xFBAC, 0xFBAD}, + {0x06BF, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x06C0, 0x0804, 0xFBA4, 0xFBA5, 0xFBA5, 0xFBA5}, + {0x06C1, 0x0881, 0xFBA6, 0xFBA7, 0xFBA8, 0xFBA9}, + {0x06C2, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x06C3, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x06C4, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x06C5, 0x0804, 0xFBE0, 0xFBE1, 0xFBE1, 0xFBE1}, + {0x06C6, 0x0804, 0xFBD9, 0xFBDA, 0xFBDA, 0xFBDA}, + {0x06C7, 0x0804, 0xFBD7, 0xFBD8, 0xFBD8, 0xFBD8}, + {0x06C8, 0x0804, 0xFBDB, 0xFBDC, 0xFBDC, 0xFBDC}, + {0x06C9, 0x0804, 0xFBE2, 0xFBE3, 0xFBE3, 0xFBE3}, + {0x06CA, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x06CB, 0x0804, 0xFBDE, 0xFBDF, 0xFBDF, 0xFBDF}, + {0x06CC, 0x0881, 0xFBFC, 0xFBFD, 0xFBFE, 0xFBFF}, + {0x06CD, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x06CE, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x06CF, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x06D0, 0x0881, 0xFBE4, 0xFBE5, 0xFBE6, 0xFBE7}, + {0x06D1, 0x000F, 0x0, 0x0, 0x0, 0x0}, + {0x06D2, 0x0804, 0xFBAE, 0xFBAF, 0xFBAF, 0xFBAF}, + {0x06D3, 0x0804, 0xFBB0, 0xFBB1, 0xFBB1, 0xFBB1} + }; + + /* @hide */ + public static String reshape(String Str) { + String Temp = " " + Str + " "; + char pre, at, post; + StringBuilder reshapedString = new StringBuilder(); + int i = 0; + int len = Str.length(); + + char post_post; + char pre_pre = ' '; + + while (i < len) { + pre = Temp.charAt(i + 2); + at = Temp.charAt(i + 1); + post = Temp.charAt(i); + + int which_case = getCase(at); + int what_case_post = getCase(post); + int what_case_pre = getCase(pre); + int what_case_post_post; + int what_case_pre_pre; + // which_case=0x000F& + // Log.v("what case"," :" +which_case); + int pre_step = 0; + if (what_case_pre == TASHKEEL) { + pre = pre_pre; + what_case_pre = getCase(pre); + } + if ((what_case_pre & LEFT_CHAR_MASK) == LEFT_CHAR_MASK) { + pre_step = 1; + + } + + switch (which_case & 0x000F) { + + case NOTUSED_CHAR: + case NOTARABIC_CHAR: + + reshapedString.append(at); + + i++; + continue; + case NORIGHT_NOLEFT_CHAR: + case TATWEEL_CHAR: + reshapedString.append(getShape(at, 0)); + + i++; + continue; + case RIGHT_LEFT_CHAR_LAM: + + if ((what_case_post & 0x000F) == RIGHT_NOLEFT_CHAR_ALEF) { + reshapedString.append(getShape(post, pre_step + 2)); + i = i + 2; + + continue; + } else if ((what_case_post & RIGHT_NOLEFT_CHAR_MASK) == RIGHT_NOLEFT_CHAR_MASK) { + reshapedString.append(getShape(at, 2 + pre_step)); + i = i + 1; + + continue; + + } else if (what_case_post == TANWEEN) { + reshapedString.append(getShape(at, pre_step)); + i = i + 1; + continue; + + } else if (what_case_post == TASHKEEL) { + post_post = Temp.charAt(i + 3); + what_case_post_post = getCase(post_post); + if ((what_case_post_post & RIGHT_NOLEFT_CHAR_MASK) == RIGHT_NOLEFT_CHAR_MASK) { + reshapedString.append(getShape(at, 2 + pre_step)); + i = i + 1; + + continue; + + } else { + reshapedString.append(getShape(at, pre_step)); + i = i + 1; + continue; + + } + + } else { + reshapedString.append(getShape(at, pre_step)); + i = i + 1; + continue; + + } + + case RIGHT_LEFT_CHAR: + if ((what_case_post & RIGHT_NOLEFT_CHAR_MASK) == RIGHT_NOLEFT_CHAR_MASK) { + reshapedString.append(getShape(at, 2 + pre_step)); + i = i + 1; + continue; + + } else if (what_case_post == TANWEEN) { + reshapedString.append(getShape(at, pre_step)); + i = i + 1; + continue; + + } else if (what_case_post == TASHKEEL) { + post_post = Temp.charAt(i + 3); + what_case_post_post = getCase(post_post); + if ((what_case_post_post & RIGHT_NOLEFT_CHAR_MASK) == RIGHT_NOLEFT_CHAR_MASK) { + reshapedString.append(getShape(at, 2 + pre_step)); + i = i + 1; + continue; + + } else { + reshapedString.append(getShape(at, pre_step)); + i = i + 1; + continue; + + } + + } else { + reshapedString.append(getShape(at, pre_step)); + i = i + 1; + continue; + + } + case RIGHT_NOLEFT_CHAR_ALEF: + case RIGHT_NOLEFT_CHAR: + reshapedString.append(getShape(at, pre_step)); + i = i + 1; + continue; + case TASHKEEL: + reshapedString.append(getShape(at, 0)); + i++; + pre_pre = pre; + continue; + case TANWEEN: + reshapedString.append(getShape(at, 0)); + i++; + pre_pre = pre; + continue; + + default: + reshapedString.append(getShape(at, 0)); + i++; + + } + } + + return reshapedString.toString(); + } + + static int getCase(char ch) { + if (ch < 0x0621 || ch > 0x06d2) { + return 0; + } else { + return allchar[(int) ch - 0x0621][1]; + } + } + + static char getShape(char ch, int which_shape) { + return allchar[(int) ch - 0x0621][2 + which_shape]; + } + +} |