From 15cf5197573b852e07c0a64bc8f3446b8401309b Mon Sep 17 00:00:00 2001 From: samuelhu Date: Thu, 31 Oct 2013 16:59:55 +0800 Subject: [PATCH] issue #2970:crash for CCLabelTTF when setting dimension width less than the font height --- cocos/2d/platform/android/CCImage.cpp | 10 +- .../src/org/cocos2dx/lib/Cocos2dxBitmap.java | 210 ++++++++++-------- 2 files changed, 123 insertions(+), 97 deletions(-) diff --git a/cocos/2d/platform/android/CCImage.cpp b/cocos/2d/platform/android/CCImage.cpp index 0fdfe6445e..ba722d7fad 100644 --- a/cocos/2d/platform/android/CCImage.cpp +++ b/cocos/2d/platform/android/CCImage.cpp @@ -81,7 +81,7 @@ public: { JniMethodInfo methodInfo; if (! JniHelper::getStaticMethodInfo(methodInfo, "org/cocos2dx/lib/Cocos2dxBitmap", "createTextBitmapShadowStroke", - "(Ljava/lang/String;Ljava/lang/String;IFFFIIIZFFFFZFFFF)V")) + "(Ljava/lang/String;Ljava/lang/String;IFFFIIIZFFFFZFFFF)Z")) { CCLOG("%s %d: error to get methodInfo", __FILE__, __LINE__); return false; @@ -109,8 +109,12 @@ public: jstring jstrText = methodInfo.env->NewStringUTF(text); jstring jstrFont = methodInfo.env->NewStringUTF(fullPathOrFontName.c_str()); - methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID, jstrText, - jstrFont, (int)fontSize, textTintR, textTintG, textTintB, eAlignMask, nWidth, nHeight, shadow, shadowDeltaX, -shadowDeltaY, shadowBlur, shadowOpacity, stroke, strokeColorR, strokeColorG, strokeColorB, strokeSize); + if(!methodInfo.env->CallStaticBooleanMethod(methodInfo.classID, methodInfo.methodID, jstrText, + jstrFont, (int)fontSize, textTintR, textTintG, textTintB, eAlignMask, nWidth, nHeight, shadow, shadowDeltaX, -shadowDeltaY, shadowBlur, shadowOpacity, stroke, strokeColorR, strokeColorG, strokeColorB, strokeSize)) + { + return false; + } + methodInfo.env->DeleteLocalRef(jstrText); methodInfo.env->DeleteLocalRef(jstrFont); diff --git a/cocos/2d/platform/android/java/src/org/cocos2dx/lib/Cocos2dxBitmap.java b/cocos/2d/platform/android/java/src/org/cocos2dx/lib/Cocos2dxBitmap.java index 2660097a45..ef0ba4074e 100644 --- a/cocos/2d/platform/android/java/src/org/cocos2dx/lib/Cocos2dxBitmap.java +++ b/cocos/2d/platform/android/java/src/org/cocos2dx/lib/Cocos2dxBitmap.java @@ -58,7 +58,7 @@ public class Cocos2dxBitmap { // Fields // =========================================================== - private static Context sContext; + private static Context _context; // =========================================================== // Constructors @@ -68,8 +68,8 @@ public class Cocos2dxBitmap { // Getter & Setter // =========================================================== - public static void setContext(final Context pContext) { - Cocos2dxBitmap.sContext = pContext; + public static void setContext(final Context context) { + Cocos2dxBitmap._context = context; } // =========================================================== @@ -80,8 +80,8 @@ public class Cocos2dxBitmap { // Methods // =========================================================== - private static native void nativeInitBitmapDC(final int pWidth, - final int pHeight, final byte[] pPixels); + private static native void nativeInitBitmapDC(final int width, + final int height, final byte[] pixels); /** * @param pWidth @@ -89,36 +89,49 @@ public class Cocos2dxBitmap { * @param pHeight * the height to draw, it can be 0 */ - public static void createTextBitmap(String pString, final String pFontName, - final int pFontSize, final int pAlignment, final int pWidth, - final int pHeight) { + public static void createTextBitmap(String string, final String fontName, + final int fontSize, final int alignment, final int width, + final int height) { // - createTextBitmapShadowStroke( pString, pFontName, pFontSize, 1.0f, 1.0f, 1.0f, // text font and color - pAlignment, pWidth, pHeight, // alignment and size + createTextBitmapShadowStroke( string, fontName, fontSize, 1.0f, 1.0f, 1.0f, // text font and color + alignment, width, height, // alignment and size false, 0.0f, 0.0f, 0.0f, 0.0f, // no shadow false, 1.0f, 1.0f, 1.0f, 1.0f); // no stroke } - public static void createTextBitmapShadowStroke(String pString, final String pFontName, final int pFontSize, + public static boolean createTextBitmapShadowStroke(String string, final String fontName, final int fontSize, final float fontTintR, final float fontTintG, final float fontTintB, - final int pAlignment, final int pWidth, final int pHeight, final boolean shadow, + final int alignment, final int width, final int height, final boolean shadow, final float shadowDX, final float shadowDY, final float shadowBlur, final float shadowOpacity, final boolean stroke, final float strokeR, final float strokeG, final float strokeB, final float strokeSize) { - final int horizontalAlignment = pAlignment & 0x0F; - final int verticalAlignment = (pAlignment >> 4) & 0x0F; + final int horizontalAlignment = alignment & 0x0F; + final int verticalAlignment = (alignment >> 4) & 0x0F; + + string = Cocos2dxBitmap.refactorString(string); + final Paint paint = Cocos2dxBitmap.newPaint(fontName, fontSize, horizontalAlignment); + /** + * if the first word width less than designed width,It means no words to show + */ + if(0 != width) + { + final int firstWordWidth = (int) FloatMath.ceil(paint.measureText(string, 0,1)); + if ( firstWordWidth > width) + { + Log.w("createTextBitmapShadowStroke warning:","the input width is less than the width of the pString's first word\n"); + return false; + } + } - pString = Cocos2dxBitmap.refactorString(pString); - final Paint paint = Cocos2dxBitmap.newPaint(pFontName, pFontSize, horizontalAlignment); // set the paint color paint.setARGB(255, (int)(255.0 * fontTintR), (int)(255.0 * fontTintG), (int)(255.0 * fontTintB)); - final TextProperty textProperty = Cocos2dxBitmap.computeTextProperty(pString, pWidth, pHeight, paint); - final int bitmapTotalHeight = (pHeight == 0 ? textProperty.mTotalHeight: pHeight); + final TextProperty textProperty = Cocos2dxBitmap.computeTextProperty(string, width, height, paint); + final int bitmapTotalHeight = (height == 0 ? textProperty.mTotalHeight: height); // padding needed when using shadows (not used otherwise) float bitmapPaddingX = 0.0f; @@ -144,6 +157,13 @@ public class Cocos2dxBitmap { renderTextDeltaY = bitmapPaddingY; } } + + if (0 == textProperty.mMaxWidth || 0 == bitmapTotalHeight) + { + Log.w("createTextBitmapShadowStroke warning:","textProperty MaxWidth is 0 or bitMapTotalHeight is 0\n"); + return false; + } + final Bitmap bitmap = Bitmap.createBitmap(textProperty.mMaxWidth + (int)bitmapPaddingX, bitmapTotalHeight + (int)bitmapPaddingY, Bitmap.Config.ARGB_8888); @@ -154,7 +174,7 @@ public class Cocos2dxBitmap { final FontMetricsInt fontMetricsInt = paint.getFontMetricsInt(); int x = 0; - int y = Cocos2dxBitmap.computeY(fontMetricsInt, pHeight, textProperty.mTotalHeight, verticalAlignment); + int y = Cocos2dxBitmap.computeY(fontMetricsInt, height, textProperty.mTotalHeight, verticalAlignment); final String[] lines = textProperty.mLines; @@ -169,13 +189,13 @@ public class Cocos2dxBitmap { // draw again with stroke on if needed if ( stroke ) { - final Paint paintStroke = Cocos2dxBitmap.newPaint(pFontName, pFontSize, horizontalAlignment); + final Paint paintStroke = Cocos2dxBitmap.newPaint(fontName, fontSize, horizontalAlignment); paintStroke.setStyle(Paint.Style.STROKE); paintStroke.setStrokeWidth(strokeSize * 0.5f); paintStroke.setARGB(255, (int) (strokeR * 255), (int) (strokeG * 255), (int) (strokeB * 255)); x = 0; - y = Cocos2dxBitmap.computeY(fontMetricsInt, pHeight, textProperty.mTotalHeight, verticalAlignment); + y = Cocos2dxBitmap.computeY(fontMetricsInt, height, textProperty.mTotalHeight, verticalAlignment); final String[] lines2 = textProperty.mLines; for (final String line : lines2) { @@ -189,33 +209,35 @@ public class Cocos2dxBitmap { } Cocos2dxBitmap.initNativeObject(bitmap); + + return true; } - private static Paint newPaint(final String pFontName, final int pFontSize, - final int pHorizontalAlignment) { + private static Paint newPaint(final String fontName, final int fontSize, + final int horizontalAlignment) { final Paint paint = new Paint(); paint.setColor(Color.WHITE); - paint.setTextSize(pFontSize); + paint.setTextSize(fontSize); paint.setAntiAlias(true); /* Set type face for paint, now it support .ttf file. */ - if (pFontName.endsWith(".ttf")) { + if (fontName.endsWith(".ttf")) { try { final Typeface typeFace = Cocos2dxTypefaces.get( - Cocos2dxBitmap.sContext, pFontName); + Cocos2dxBitmap._context, fontName); paint.setTypeface(typeFace); } catch (final Exception e) { Log.e("Cocos2dxBitmap", "error to create ttf type face: " - + pFontName); + + fontName); /* The file may not find, use system font. */ - paint.setTypeface(Typeface.create(pFontName, Typeface.NORMAL)); + paint.setTypeface(Typeface.create(fontName, Typeface.NORMAL)); } } else { - paint.setTypeface(Typeface.create(pFontName, Typeface.NORMAL)); + paint.setTypeface(Typeface.create(fontName, Typeface.NORMAL)); } - switch (pHorizontalAlignment) { + switch (horizontalAlignment) { case HORIZONTALALIGN_CENTER: paint.setTextAlign(Align.CENTER); break; @@ -231,22 +253,22 @@ public class Cocos2dxBitmap { return paint; } - private static TextProperty computeTextProperty(final String pString, - final int pWidth, final int pHeight, final Paint pPaint) { - final FontMetricsInt fm = pPaint.getFontMetricsInt(); + private static TextProperty computeTextProperty(final String string, + final int width, final int height, final Paint paint) { + final FontMetricsInt fm = paint.getFontMetricsInt(); final int h = (int) Math.ceil(fm.bottom - fm.top); int maxContentWidth = 0; - final String[] lines = Cocos2dxBitmap.splitString(pString, pWidth, - pHeight, pPaint); + final String[] lines = Cocos2dxBitmap.splitString(string, width, + height, paint); - if (pWidth != 0) { - maxContentWidth = pWidth; + if (width != 0) { + maxContentWidth = width; } else { /* Compute the max width. */ int temp = 0; for (final String line : lines) { - temp = (int) FloatMath.ceil(pPaint.measureText(line, 0, + temp = (int) FloatMath.ceil(paint.measureText(line, 0, line.length())); if (temp > maxContentWidth) { maxContentWidth = temp; @@ -257,16 +279,16 @@ public class Cocos2dxBitmap { return new TextProperty(maxContentWidth, h, lines); } - private static int computeX(final String pText, final int pMaxWidth, - final int pHorizontalAlignment) { + private static int computeX(final String text, final int maxWidth, + final int horizontalAlignment) { int ret = 0; - switch (pHorizontalAlignment) { + switch (horizontalAlignment) { case HORIZONTALALIGN_CENTER: - ret = pMaxWidth / 2; + ret = maxWidth / 2; break; case HORIZONTALALIGN_RIGHT: - ret = pMaxWidth; + ret = maxWidth; break; case HORIZONTALALIGN_LEFT: default: @@ -276,22 +298,22 @@ public class Cocos2dxBitmap { return ret; } - private static int computeY(final FontMetricsInt pFontMetricsInt, - final int pConstrainHeight, final int pTotalHeight, - final int pVerticalAlignment) { - int y = -pFontMetricsInt.top; + private static int computeY(final FontMetricsInt fontMetricsInt, + final int constrainHeight, final int totalHeight, + final int verticalAlignment) { + int y = -fontMetricsInt.top; - if (pConstrainHeight > pTotalHeight) { - switch (pVerticalAlignment) { + if (constrainHeight > totalHeight) { + switch (verticalAlignment) { case VERTICALALIGN_TOP: - y = -pFontMetricsInt.top; + y = -fontMetricsInt.top; break; case VERTICALALIGN_CENTER: - y = -pFontMetricsInt.top + (pConstrainHeight - pTotalHeight) + y = -fontMetricsInt.top + (constrainHeight - totalHeight) / 2; break; case VERTICALALIGN_BOTTOM: - y = -pFontMetricsInt.top + (pConstrainHeight - pTotalHeight); + y = -fontMetricsInt.top + (constrainHeight - totalHeight); break; default: break; @@ -305,26 +327,26 @@ public class Cocos2dxBitmap { * If maxWidth or maxHeight is not 0, split the string to fix the maxWidth * and maxHeight. */ - private static String[] splitString(final String pString, - final int pMaxWidth, final int pMaxHeight, final Paint pPaint) { - final String[] lines = pString.split("\\n"); + private static String[] splitString(final String string, + final int maxWidth, final int maxHeight, final Paint paint) { + final String[] lines = string.split("\\n"); String[] ret = null; - final FontMetricsInt fm = pPaint.getFontMetricsInt(); + final FontMetricsInt fm = paint.getFontMetricsInt(); final int heightPerLine = (int) Math.ceil(fm.bottom - fm.top); - final int maxLines = pMaxHeight / heightPerLine; + final int maxLines = maxHeight / heightPerLine; - if (pMaxWidth != 0) { + if (maxWidth != 0) { final LinkedList strList = new LinkedList(); for (final String line : lines) { /* * The width of line is exceed maxWidth, should divide it into * two or more lines. */ - final int lineWidth = (int) FloatMath.ceil(pPaint + final int lineWidth = (int) FloatMath.ceil(paint .measureText(line)); - if (lineWidth > pMaxWidth) { + if (lineWidth > maxWidth) { strList.addAll(Cocos2dxBitmap.divideStringWithMaxWidth( - line, pMaxWidth, pPaint)); + line, maxWidth, paint)); } else { strList.add(line); } @@ -344,7 +366,7 @@ public class Cocos2dxBitmap { ret = new String[strList.size()]; strList.toArray(ret); - } else if (pMaxHeight != 0 && lines.length > maxLines) { + } else if (maxHeight != 0 && lines.length > maxLines) { /* Remove exceeding lines. */ final LinkedList strList = new LinkedList(); for (int i = 0; i < maxLines; i++) { @@ -360,37 +382,37 @@ public class Cocos2dxBitmap { } private static LinkedList divideStringWithMaxWidth( - final String pString, final int pMaxWidth, final Paint pPaint) { - final int charLength = pString.length(); + final String string, final int maxWidth, final Paint paint) { + final int charLength = string.length(); int start = 0; int tempWidth = 0; final LinkedList strList = new LinkedList(); /* Break a String into String[] by the width & should wrap the word. */ for (int i = 1; i <= charLength; ++i) { - tempWidth = (int) FloatMath.ceil(pPaint.measureText(pString, start, + tempWidth = (int) FloatMath.ceil(paint.measureText(string, start, i)); - if (tempWidth >= pMaxWidth) { - final int lastIndexOfSpace = pString.substring(0, i) + if (tempWidth >= maxWidth) { + final int lastIndexOfSpace = string.substring(0, i) .lastIndexOf(" "); if (lastIndexOfSpace != -1 && lastIndexOfSpace > start) { /* Should wrap the word. */ - strList.add(pString.substring(start, lastIndexOfSpace)); + strList.add(string.substring(start, lastIndexOfSpace)); i = lastIndexOfSpace + 1; // skip space } else { /* Should not exceed the width. */ - if (tempWidth > pMaxWidth) { - strList.add(pString.substring(start, i - 1)); + if (tempWidth > maxWidth) { + strList.add(string.substring(start, i - 1)); /* Compute from previous char. */ --i; } else { - strList.add(pString.substring(start, i)); + strList.add(string.substring(start, i)); } } /* Remove spaces at the beginning of a new line. */ - while (i < charLength && pString.charAt(i) == ' ') { + while (i < charLength && string.charAt(i) == ' ') { ++i; } @@ -400,15 +422,15 @@ public class Cocos2dxBitmap { /* Add the last chars. */ if (start < charLength) { - strList.add(pString.substring(start)); + strList.add(string.substring(start)); } return strList; } - private static String refactorString(final String pString) { + private static String refactorString(final String string) { /* Avoid error when content is "". */ - if (pString.compareTo("") == 0) { + if (string.compareTo("") == 0) { return " "; } @@ -416,7 +438,7 @@ public class Cocos2dxBitmap { * If the font of "\n" is "" or "\n", insert " " in front of it. For * example: "\nabc" -> " \nabc" "\nabc\n\n" -> " \nabc\n \n". */ - final StringBuilder strBuilder = new StringBuilder(pString); + final StringBuilder strBuilder = new StringBuilder(string); int start = 0; int index = strBuilder.indexOf("\n"); while (index != -1) { @@ -437,23 +459,23 @@ public class Cocos2dxBitmap { return strBuilder.toString(); } - private static void initNativeObject(final Bitmap pBitmap) { - final byte[] pixels = Cocos2dxBitmap.getPixels(pBitmap); + private static void initNativeObject(final Bitmap bitmap) { + final byte[] pixels = Cocos2dxBitmap.getPixels(bitmap); if (pixels == null) { return; } - Cocos2dxBitmap.nativeInitBitmapDC(pBitmap.getWidth(), - pBitmap.getHeight(), pixels); + Cocos2dxBitmap.nativeInitBitmapDC(bitmap.getWidth(), + bitmap.getHeight(), pixels); } - private static byte[] getPixels(final Bitmap pBitmap) { - if (pBitmap != null) { - final byte[] pixels = new byte[pBitmap.getWidth() - * pBitmap.getHeight() * 4]; + private static byte[] getPixels(final Bitmap bitmap) { + if (bitmap != null) { + final byte[] pixels = new byte[bitmap.getWidth() + * bitmap.getHeight() * 4]; final ByteBuffer buf = ByteBuffer.wrap(pixels); buf.order(ByteOrder.nativeOrder()); - pBitmap.copyPixelsToBuffer(buf); + bitmap.copyPixelsToBuffer(buf); return pixels; } @@ -484,9 +506,9 @@ public class Cocos2dxBitmap { return incr_text_size; } - private static String getStringWithEllipsis(String pString, float width, + private static String getStringWithEllipsis(String string, float width, float fontSize) { - if (TextUtils.isEmpty(pString)) { + if (TextUtils.isEmpty(string)) { return ""; } @@ -494,7 +516,7 @@ public class Cocos2dxBitmap { paint.setTypeface(Typeface.DEFAULT); paint.setTextSize(fontSize); - return TextUtils.ellipsize(pString, paint, width, + return TextUtils.ellipsize(string, paint, width, TextUtils.TruncateAt.END).toString(); } @@ -510,12 +532,12 @@ public class Cocos2dxBitmap { private final int mHeightPerLine; private final String[] mLines; - TextProperty(final int pMaxWidth, final int pHeightPerLine, - final String[] pLines) { - this.mMaxWidth = pMaxWidth; - this.mHeightPerLine = pHeightPerLine; - this.mTotalHeight = pHeightPerLine * pLines.length; - this.mLines = pLines; + TextProperty(final int maxWidth, final int heightPerLine, + final String[] lines) { + this.mMaxWidth = maxWidth; + this.mHeightPerLine = heightPerLine; + this.mTotalHeight = heightPerLine * lines.length; + this.mLines = lines; } } }