bug 1019836 - Support narrow char strings in android bridge r=snorp

This commit is contained in:
Brad Lassey 2014-06-04 15:04:12 -04:00
parent bad04e53f7
commit 07a99475ad
7 changed files with 77 additions and 30 deletions

View File

@ -12,12 +12,14 @@ public class AnnotationInfo {
public final boolean isStatic;
public final boolean isMultithreaded;
public final boolean noThrow;
public final boolean narrowChars;
public AnnotationInfo(String aWrapperName, boolean aIsStatic, boolean aIsMultithreaded,
boolean aNoThrow) {
boolean aNoThrow, boolean aNarrowChars) {
wrapperName = aWrapperName;
isStatic = aIsStatic;
isMultithreaded = aIsMultithreaded;
noThrow = aNoThrow;
narrowChars = aNarrowChars;
}
}

View File

@ -103,8 +103,8 @@ public class CodeGenerator {
Class<?> returnType = theMethod.getReturnType();
// Get the C++ method signature for this method.
String implementationSignature = Utils.getCImplementationMethodSignature(parameterTypes, returnType, CMethodName, mCClassName);
String headerSignature = Utils.getCHeaderMethodSignature(parameterTypes, theMethod.getParameterAnnotations(), returnType, CMethodName, mCClassName, shallGenerateStatic);
String implementationSignature = Utils.getCImplementationMethodSignature(parameterTypes, returnType, CMethodName, mCClassName, aMethodTuple.mAnnotationInfo.narrowChars);
String headerSignature = Utils.getCHeaderMethodSignature(parameterTypes, theMethod.getParameterAnnotations(), returnType, CMethodName, mCClassName, shallGenerateStatic, aMethodTuple.mAnnotationInfo.narrowChars);
// Add the header signature to the header file.
writeSignatureToHeader(headerSignature);
@ -113,10 +113,11 @@ public class CodeGenerator {
writeMethodBody(implementationSignature, CMethodName, theMethod, mClassToWrap,
aMethodTuple.mAnnotationInfo.isStatic,
aMethodTuple.mAnnotationInfo.isMultithreaded,
aMethodTuple.mAnnotationInfo.noThrow);
aMethodTuple.mAnnotationInfo.noThrow,
aMethodTuple.mAnnotationInfo.narrowChars);
}
private void generateGetterOrSetterBody(Class<?> aFieldType, String aFieldName, boolean aIsFieldStatic, boolean isSetter) {
private void generateGetterOrSetterBody(Class<?> aFieldType, String aFieldName, boolean aIsFieldStatic, boolean isSetter, boolean aNarrowChars) {
StringBuilder argumentContent = null;
if (isSetter) {
@ -133,7 +134,7 @@ public class CodeGenerator {
wrapperMethodBodies.append("return ");
if (isObjectReturningMethod) {
wrapperMethodBodies.append("static_cast<").append(Utils.getCReturnType(aFieldType)).append(">(");
wrapperMethodBodies.append("static_cast<").append(Utils.getCReturnType(aFieldType, aNarrowChars)).append(">(");
}
wrapperMethodBodies.append("env->Get");
@ -184,14 +185,14 @@ public class CodeGenerator {
boolean shallGenerateStatic = isFieldStatic || aFieldTuple.mAnnotationInfo.isStatic;
String getterName = "get" + CFieldName;
String getterSignature = Utils.getCImplementationMethodSignature(EMPTY_CLASS_ARRAY, fieldType, getterName, mCClassName);
String getterHeaderSignature = Utils.getCHeaderMethodSignature(EMPTY_CLASS_ARRAY, GETTER_ARGUMENT_ANNOTATIONS, fieldType, getterName, mCClassName, shallGenerateStatic);
String getterSignature = Utils.getCImplementationMethodSignature(EMPTY_CLASS_ARRAY, fieldType, getterName, mCClassName, aFieldTuple.mAnnotationInfo.narrowChars);
String getterHeaderSignature = Utils.getCHeaderMethodSignature(EMPTY_CLASS_ARRAY, GETTER_ARGUMENT_ANNOTATIONS, fieldType, getterName, mCClassName, shallGenerateStatic, aFieldTuple.mAnnotationInfo.narrowChars);
writeSignatureToHeader(getterHeaderSignature);
writeFunctionStartupBoilerPlate(getterSignature, fieldType, isFieldStatic, true);
generateGetterOrSetterBody(fieldType, CFieldName, isFieldStatic, false);
generateGetterOrSetterBody(fieldType, CFieldName, isFieldStatic, false, aFieldTuple.mAnnotationInfo.narrowChars);
// If field not final, also generate a setter function.
if (!isFieldFinal) {
@ -199,14 +200,14 @@ public class CodeGenerator {
Class<?>[] setterArguments = new Class<?>[]{fieldType};
String setterSignature = Utils.getCImplementationMethodSignature(setterArguments, Void.class, setterName, mCClassName);
String setterHeaderSignature = Utils.getCHeaderMethodSignature(setterArguments, SETTER_ARGUMENT_ANNOTATIONS, Void.class, setterName, mCClassName, shallGenerateStatic);
String setterSignature = Utils.getCImplementationMethodSignature(setterArguments, Void.class, setterName, mCClassName, aFieldTuple.mAnnotationInfo.narrowChars);
String setterHeaderSignature = Utils.getCHeaderMethodSignature(setterArguments, SETTER_ARGUMENT_ANNOTATIONS, Void.class, setterName, mCClassName, shallGenerateStatic, aFieldTuple.mAnnotationInfo.narrowChars);
writeSignatureToHeader(setterHeaderSignature);
writeFunctionStartupBoilerPlate(setterSignature, Void.class, isFieldStatic, true);
generateGetterOrSetterBody(fieldType, CFieldName, isFieldStatic, true);
generateGetterOrSetterBody(fieldType, CFieldName, isFieldStatic, true, aFieldTuple.mAnnotationInfo.narrowChars);
}
}
@ -217,8 +218,8 @@ public class CodeGenerator {
generateMemberCommon(theCtor, mCClassName, mClassToWrap);
String implementationSignature = Utils.getCImplementationMethodSignature(theCtor.getParameterTypes(), Void.class, CMethodName, mCClassName);
String headerSignature = Utils.getCHeaderMethodSignature(theCtor.getParameterTypes(), theCtor.getParameterAnnotations(), Void.class, CMethodName, mCClassName, false);
String implementationSignature = Utils.getCImplementationMethodSignature(theCtor.getParameterTypes(), Void.class, CMethodName, mCClassName, aCtorTuple.mAnnotationInfo.narrowChars);
String headerSignature = Utils.getCHeaderMethodSignature(theCtor.getParameterTypes(), theCtor.getParameterAnnotations(), Void.class, CMethodName, mCClassName, false, aCtorTuple.mAnnotationInfo.narrowChars);
// Slice off the "void " from the start of the constructor declaration.
headerSignature = headerSignature.substring(5);
@ -426,7 +427,7 @@ public class CodeGenerator {
*/
private void writeMethodBody(String methodSignature, String aCMethodName, Method aMethod,
Class<?> aClass, boolean aIsStaticBridgeMethod, boolean aIsMultithreaded,
boolean aNoThrow) {
boolean aNoThrow, boolean aNarrowChars) {
Class<?>[] argumentTypes = aMethod.getParameterTypes();
Class<?> returnType = aMethod.getReturnType();
@ -455,7 +456,7 @@ public class CodeGenerator {
if (isObjectReturningMethod) {
wrapperMethodBodies.append("jobject");
} else {
wrapperMethodBodies.append(Utils.getCReturnType(returnType));
wrapperMethodBodies.append(Utils.getCReturnType(returnType, aNarrowChars));
}
wrapperMethodBodies.append(" temp = ");
}
@ -494,8 +495,8 @@ public class CodeGenerator {
// value.
if (isObjectReturningMethod) {
wrapperMethodBodies.append(" ")
.append(Utils.getCReturnType(returnType))
.append(" ret = static_cast<").append(Utils.getCReturnType(returnType)).append(">(env->PopLocalFrame(temp));\n" +
.append(Utils.getCReturnType(returnType, aNarrowChars))
.append(" ret = static_cast<").append(Utils.getCReturnType(returnType, aNarrowChars)).append(">(env->PopLocalFrame(temp));\n" +
" return ret;\n");
} else if (!returnType.getCanonicalName().equals("void")) {
// If we're a primitive-returning function, just return the directly-obtained primative

View File

@ -76,6 +76,7 @@ public class GeneratableElementIterator implements Iterator<AnnotatableEntity> {
boolean isStaticStub = false;
boolean isMultithreadedStub = false;
boolean noThrow = false;
boolean narrowChars = false;
try {
// Determine the explicitly-given name of the stub to generate, if any.
final Method stubNameMethod = annotationType.getDeclaredMethod("stubName");
@ -97,6 +98,11 @@ public class GeneratableElementIterator implements Iterator<AnnotatableEntity> {
noThrowMethod.setAccessible(true);
noThrow = (Boolean) noThrowMethod.invoke(annotation);
// Determine if strings should be wide or narrow
final Method narrowCharsMethod = annotationType.getDeclaredMethod("narrowChars");
narrowCharsMethod.setAccessible(true);
narrowChars = (Boolean) narrowCharsMethod.invoke(annotation);
} catch (NoSuchMethodException e) {
System.err.println("Unable to find expected field on WrapElementForJNI annotation. Did the signature change?");
e.printStackTrace(System.err);
@ -118,7 +124,7 @@ public class GeneratableElementIterator implements Iterator<AnnotatableEntity> {
}
AnnotationInfo annotationInfo = new AnnotationInfo(
stubName, isStaticStub, isMultithreadedStub, noThrow);
stubName, isStaticStub, isMultithreadedStub, noThrow, narrowChars);
mNextReturnValue = new AnnotatableEntity(candidateElement, annotationInfo);
return;
}
@ -128,7 +134,7 @@ public class GeneratableElementIterator implements Iterator<AnnotatableEntity> {
// thanks to the "Generate everything" annotation.
if (mIterateEveryEntry) {
AnnotationInfo annotationInfo = new AnnotationInfo(
candidateElement.getName(), false, false, false);
candidateElement.getName(), false, false, false, false);
mNextReturnValue = new AnnotatableEntity(candidateElement, annotationInfo);
return;
}

View File

@ -137,7 +137,7 @@ public class Utils {
* @param type Class to determine the corresponding JNI type for.
* @return true if the type an object type, false otherwise.
*/
public static String getCParameterType(Class<?> type) {
public static String getCParameterType(Class<?> type, boolean aNarrowChars) {
String name = type.getCanonicalName();
if (sBasicCTypes.containsKey(name)) {
return sBasicCTypes.get(name);
@ -161,6 +161,9 @@ public class Utils {
// Check for CharSequences (Strings and things that are string-like)
if (isCharSequence(type)) {
if (aNarrowChars) {
return "const nsACString&";
}
return "const nsAString&";
}
@ -181,12 +184,12 @@ public class Utils {
* @param type The Java return type.
* @return A string representation of the C++ return type.
*/
public static String getCReturnType(Class<?> type) {
public static String getCReturnType(Class<?> type, boolean aNarrowChars) {
if (type.getCanonicalName().equals("java.lang.Void")) {
return "void";
}
String cParameterType = getCParameterType(type);
if (cParameterType.equals("const nsAString&")) {
String cParameterType = getCParameterType(type, aNarrowChars);
if (cParameterType.equals("const nsAString&") || cParameterType.equals("const nsACString&")) {
return "jstring";
} else {
return cParameterType;
@ -381,10 +384,10 @@ public class Utils {
* @param aCClassName Name of the C++ class into which the method is declared.
* @return The C++ method implementation signature for the method described.
*/
public static String getCImplementationMethodSignature(Class<?>[] aArgumentTypes, Class<?> aReturnType, String aCMethodName, String aCClassName) {
public static String getCImplementationMethodSignature(Class<?>[] aArgumentTypes, Class<?> aReturnType, String aCMethodName, String aCClassName, boolean aNarrowChars) {
StringBuilder retBuffer = new StringBuilder();
retBuffer.append(getCReturnType(aReturnType));
retBuffer.append(getCReturnType(aReturnType, aNarrowChars));
retBuffer.append(' ');
retBuffer.append(aCClassName);
retBuffer.append("::");
@ -393,7 +396,7 @@ public class Utils {
// Write argument types...
for (int aT = 0; aT < aArgumentTypes.length; aT++) {
retBuffer.append(getCParameterType(aArgumentTypes[aT]));
retBuffer.append(getCParameterType(aArgumentTypes[aT], aNarrowChars));
retBuffer.append(" a");
// We, imaginatively, call our arguments a1, a2, a3...
// The only way to preserve the names from Java would be to parse the
@ -420,7 +423,7 @@ public class Utils {
* @param aIsStaticStub true if the generated C++ method should be static, false otherwise.
* @return The generated C++ header method signature for the method described.
*/
public static String getCHeaderMethodSignature(Class<?>[] aArgumentTypes, Annotation[][] aArgumentAnnotations, Class<?> aReturnType, String aCMethodName, String aCClassName, boolean aIsStaticStub) {
public static String getCHeaderMethodSignature(Class<?>[] aArgumentTypes, Annotation[][] aArgumentAnnotations, Class<?> aReturnType, String aCMethodName, String aCClassName, boolean aIsStaticStub, boolean aNarrowChars) {
StringBuilder retBuffer = new StringBuilder();
// Add the static keyword, if applicable.
@ -429,14 +432,14 @@ public class Utils {
}
// Write return type..
retBuffer.append(getCReturnType(aReturnType));
retBuffer.append(getCReturnType(aReturnType, aNarrowChars));
retBuffer.append(' ');
retBuffer.append(aCMethodName);
retBuffer.append('(');
// Write argument types...
for (int aT = 0; aT < aArgumentTypes.length; aT++) {
retBuffer.append(getCParameterType(aArgumentTypes[aT]));
retBuffer.append(getCParameterType(aArgumentTypes[aT], aNarrowChars));
retBuffer.append(" a");
// We, imaginatively, call our arguments a1, a2, a3...
// The only way to preserve the names from Java would be to parse the

View File

@ -44,4 +44,6 @@ public @interface WrapElementForJNI {
* Any exception must be handled or cleared by the code calling the stub.
*/
boolean noThrow() default false;
boolean narrowChars() default false;
}

View File

@ -1011,3 +1011,30 @@ nsJNIString::nsJNIString(jstring jstr, JNIEnv *jenv)
}
jni->ReleaseStringChars(jstr, jCharPtr);
}
nsJNICString::nsJNICString(jstring jstr, JNIEnv *jenv)
{
if (!jstr) {
SetIsVoid(true);
return;
}
JNIEnv *jni = jenv;
if (!jni) {
jni = AndroidBridge::GetJNIEnv();
}
const char* jCharPtr = jni->GetStringUTFChars(jstr, nullptr);
if (!jCharPtr) {
SetIsVoid(true);
return;
}
jsize len = jni->GetStringUTFLength(jstr);
if (len <= 0) {
SetIsVoid(true);
} else {
Assign(jCharPtr, len);
}
jni->ReleaseStringUTFChars(jstr, jCharPtr);
}

View File

@ -750,6 +750,12 @@ public:
nsJNIString(jstring jstr, JNIEnv *jenv);
};
class nsJNICString : public nsCString
{
public:
nsJNICString(jstring jstr, JNIEnv *jenv);
};
}
#endif