issue #2970:crash for CCLabelTTF when setting dimension width less than the font height

This commit is contained in:
samuelhu 2013-10-31 16:59:55 +08:00
parent 77de0b580a
commit 15cf519757
2 changed files with 123 additions and 97 deletions

View File

@ -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);

View File

@ -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<String> strList = new LinkedList<String>();
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<String> strList = new LinkedList<String>();
for (int i = 0; i < maxLines; i++) {
@ -360,37 +382,37 @@ public class Cocos2dxBitmap {
}
private static LinkedList<String> 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<String> strList = new LinkedList<String>();
/* 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;
}
}
}