Merge "Add JIT system properties"
diff --git a/rs/java/android/renderscript/Allocation.java b/rs/java/android/renderscript/Allocation.java
index a211b70..91e3b81 100644
--- a/rs/java/android/renderscript/Allocation.java
+++ b/rs/java/android/renderscript/Allocation.java
@@ -60,6 +60,7 @@
boolean mReadAllowed = true;
boolean mWriteAllowed = true;
+ boolean mAutoPadding = false;
int mSelectedX;
int mSelectedY;
int mSelectedZ;
@@ -270,6 +271,17 @@
}
/**
+ * @hide
+ * Enable/Disable AutoPadding for Vec3 elements.
+ *
+ * @param useAutoPadding True: enable AutoPadding; flase: disable AutoPadding
+ *
+ */
+ public void setAutoPadding(boolean useAutoPadding) {
+ mAutoPadding = useAutoPadding;
+ }
+
+ /**
* Get the size of the Allocation in bytes.
*
* @return size of the Allocation in bytes.
@@ -785,6 +797,7 @@
copy1DRangeFromUnchecked(xoff, count, data);
}
+
/**
* This is only intended to be used by auto-generated code reflected from
* the RenderScript script files.
@@ -804,20 +817,6 @@
*
* @param xoff
* @param yoff
- * @param component_number
- * @param fp
- */
- public void setFromFieldPacker(int xoff, int yoff, int component_number, FieldPacker fp) {
- setFromFieldPacker(xoff, yoff, 0, component_number, fp);
- }
-
- /**
- * @hide
- * This is only intended to be used by auto-generated code reflected from
- * the RenderScript script files.
- *
- * @param xoff
- * @param yoff
* @param zoff
* @param component_number
* @param fp
@@ -851,7 +850,7 @@
component_number, data, data_length);
}
- private void data1DChecks(int off, int count, int len, int dataSize) {
+ private void data1DChecks(int off, int count, int len, int dataSize, boolean usePadding) {
mRS.validate();
if(off < 0) {
throw new RSIllegalArgumentException("Offset must be >= 0.");
@@ -863,8 +862,14 @@
throw new RSIllegalArgumentException("Overflow, Available count " + mCurrentCount +
", got " + count + " at offset " + off + ".");
}
- if(len < dataSize) {
- throw new RSIllegalArgumentException("Array too small for allocation type.");
+ if(usePadding) {
+ if(len < dataSize / 4 * 3) {
+ throw new RSIllegalArgumentException("Array too small for allocation type.");
+ }
+ } else {
+ if(len < dataSize) {
+ throw new RSIllegalArgumentException("Array too small for allocation type.");
+ }
}
}
@@ -886,8 +891,14 @@
Element.DataType dt, int arrayLen) {
Trace.traceBegin(RenderScript.TRACE_TAG, "copy1DRangeFromUnchecked");
final int dataSize = mType.mElement.getBytesSize() * count;
- data1DChecks(off, count, arrayLen * dt.mSize, dataSize);
- mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, array, dataSize, dt);
+ // AutoPadding for Vec3 Element
+ boolean usePadding = false;
+ if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
+ usePadding = true;
+ }
+ data1DChecks(off, count, arrayLen * dt.mSize, dataSize, usePadding);
+ mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, array, dataSize, dt,
+ mType.mElement.mType.mSize, usePadding);
Trace.traceEnd(RenderScript.TRACE_TAG);
}
@@ -1064,8 +1075,24 @@
Trace.traceBegin(RenderScript.TRACE_TAG, "copy2DRangeFromUnchecked");
mRS.validate();
validate2DRange(xoff, yoff, w, h);
+ final int dataSize = mType.mElement.getBytesSize() * w * h;
+ // AutoPadding for Vec3 Element
+ boolean usePadding = false;
+ int sizeBytes = arrayLen * dt.mSize;
+ if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
+ if (dataSize / 4 * 3 > sizeBytes) {
+ throw new RSIllegalArgumentException("Array too small for allocation type.");
+ }
+ usePadding = true;
+ sizeBytes = dataSize;
+ } else {
+ if (dataSize > sizeBytes) {
+ throw new RSIllegalArgumentException("Array too small for allocation type.");
+ }
+ }
mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, w, h,
- array, arrayLen * dt.mSize, dt);
+ array, sizeBytes, dt,
+ mType.mElement.mType.mSize, usePadding);
Trace.traceEnd(RenderScript.TRACE_TAG);
}
@@ -1226,8 +1253,24 @@
Trace.traceBegin(RenderScript.TRACE_TAG, "copy3DRangeFromUnchecked");
mRS.validate();
validate3DRange(xoff, yoff, zoff, w, h, d);
+ final int dataSize = mType.mElement.getBytesSize() * w * h * d;
+ // AutoPadding for Vec3 Element
+ boolean usePadding = false;
+ int sizeBytes = arrayLen * dt.mSize;
+ if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
+ if (dataSize / 4 * 3 > sizeBytes) {
+ throw new RSIllegalArgumentException("Array too small for allocation type.");
+ }
+ usePadding = true;
+ sizeBytes = dataSize;
+ } else {
+ if (dataSize > sizeBytes) {
+ throw new RSIllegalArgumentException("Array too small for allocation type.");
+ }
+ }
mRS.nAllocationData3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD, w, h, d,
- array, arrayLen * dt.mSize, dt);
+ array, sizeBytes, dt,
+ mType.mElement.mType.mSize, usePadding);
Trace.traceEnd(RenderScript.TRACE_TAG);
}
@@ -1242,7 +1285,7 @@
* @param w Width of the region to update
* @param h Height of the region to update
* @param d Depth of the region to update
- * @param data to be placed into the allocation
+ * @param array to be placed into the allocation
*/
public void copy3DRangeFrom(int xoff, int yoff, int zoff, int w, int h, int d, Object array) {
Trace.traceBegin(RenderScript.TRACE_TAG, "copy3DRangeFrom");
@@ -1296,7 +1339,11 @@
private void copyTo(Object array, Element.DataType dt, int arrayLen) {
Trace.traceBegin(RenderScript.TRACE_TAG, "copyTo");
mRS.validate();
- mRS.nAllocationRead(getID(mRS), array, dt);
+ boolean usePadding = false;
+ if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
+ usePadding = true;
+ }
+ mRS.nAllocationRead(getID(mRS), array, dt, mType.mElement.mType.mSize, usePadding);
Trace.traceEnd(RenderScript.TRACE_TAG);
}
@@ -1363,35 +1410,8 @@
/**
* @hide
- * Copy subelement from the Allocation into an object array.
- * This is intended to be used with user defined structs
- *
- * @param xoff
- * @param component_number
- * @param array
- */
- public void copyElementTo(int xoff, int component_number, Object array) {
- copyElementTo(xoff, 0, 0, component_number, array);
- }
-
- /**
- * @hide
- * Copy subelement from the Allocation into an object array.
- * This is intended to be used with user defined structs
- *
- * @param xoff
- * @param yoff
- * @param component_number
- * @param array
- */
- public void copyElementTo(int xoff, int yoff, int component_number, Object array) {
- copyElementTo(xoff, yoff, 0, component_number, array);
- }
-
- /**
- * @hide
- * Copy subelement from the Allocation into an object array.
- * This is intended to be used with user defined structs
+ * This is only intended to be used by auto-generated code reflected from
+ * the RenderScript script files and should not be used by developers.
*
* @param xoff
* @param yoff
@@ -1399,8 +1419,7 @@
* @param component_number
* @param array
*/
- public void copyElementTo(int xoff, int yoff, int zoff, int component_number, Object array) {
- Trace.traceBegin(RenderScript.TRACE_TAG, "copyElementTo");
+ public void copyToFieldPacker(int xoff, int yoff, int zoff, int component_number, FieldPacker fp) {
mRS.validate();
if (component_number >= mType.mElement.mElements.length) {
throw new RSIllegalArgumentException("Component_number " + component_number + " out of range.");
@@ -1415,19 +1434,18 @@
throw new RSIllegalArgumentException("Offset z must be >= 0.");
}
- Element.DataType dt = validateObjectIsPrimitiveArray(array, false);
- int array_size = java.lang.reflect.Array.getLength(array) * dt.mSize;
+ final byte[] data = fp.getData();
+ int data_length = fp.getPos();
int eSize = mType.mElement.mElements[component_number].getBytesSize();
eSize *= mType.mElement.mArraySizes[component_number];
- if (array_size < eSize) {
- throw new RSIllegalArgumentException("Array Size (bytes)" + array_size +
- " is smaller than component size " + eSize + ".");
+ if (data_length != eSize) {
+ throw new RSIllegalArgumentException("Field packer sizelength " + data_length +
+ " does not match component size " + eSize + ".");
}
mRS.nAllocationElementRead(getIDSafe(), xoff, yoff, zoff, mSelectedLOD,
- component_number, array, eSize, dt);
- Trace.traceEnd(RenderScript.TRACE_TAG);
+ component_number, data, data_length);
}
/**
* Resize a 1D allocation. The contents of the allocation are preserved.
@@ -1465,8 +1483,14 @@
Element.DataType dt, int arrayLen) {
Trace.traceBegin(RenderScript.TRACE_TAG, "copy1DRangeToUnchecked");
final int dataSize = mType.mElement.getBytesSize() * count;
- data1DChecks(off, count, arrayLen * dt.mSize, dataSize);
- mRS.nAllocationRead1D(getIDSafe(), off, mSelectedLOD, count, array, dataSize, dt);
+ // AutoPadding for Vec3 Element
+ boolean usePadding = false;
+ if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
+ usePadding = true;
+ }
+ data1DChecks(off, count, arrayLen * dt.mSize, dataSize, usePadding);
+ mRS.nAllocationRead1D(getIDSafe(), off, mSelectedLOD, count, array, dataSize, dt,
+ mType.mElement.mType.mSize, usePadding);
Trace.traceEnd(RenderScript.TRACE_TAG);
}
@@ -1620,8 +1644,23 @@
Trace.traceBegin(RenderScript.TRACE_TAG, "copy2DRangeToUnchecked");
mRS.validate();
validate2DRange(xoff, yoff, w, h);
+ final int dataSize = mType.mElement.getBytesSize() * w * h;
+ // AutoPadding for Vec3 Element
+ boolean usePadding = false;
+ int sizeBytes = arrayLen * dt.mSize;
+ if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
+ if (dataSize / 4 * 3 > sizeBytes) {
+ throw new RSIllegalArgumentException("Array too small for allocation type.");
+ }
+ usePadding = true;
+ sizeBytes = dataSize;
+ } else {
+ if (dataSize > sizeBytes) {
+ throw new RSIllegalArgumentException("Array too small for allocation type.");
+ }
+ }
mRS.nAllocationRead2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, w, h,
- array, arrayLen * dt.mSize, dt);
+ array, sizeBytes, dt, mType.mElement.mType.mSize, usePadding);
Trace.traceEnd(RenderScript.TRACE_TAG);
}
@@ -1649,7 +1688,7 @@
* @param yoff Y offset of the region to copy in this Allocation
* @param w Width of the region to copy
* @param h Height of the region to copy
- * @param array Dest Array to be copied into
+ * @param data Dest Array to be copied into
*/
public void copy2DRangeTo(int xoff, int yoff, int w, int h, byte[] data) {
validateIsInt8();
@@ -1665,7 +1704,7 @@
* @param yoff Y offset of the region to copy in this Allocation
* @param w Width of the region to copy
* @param h Height of the region to copy
- * @param array Dest Array to be copied into
+ * @param data Dest Array to be copied into
*/
public void copy2DRangeTo(int xoff, int yoff, int w, int h, short[] data) {
validateIsInt16();
@@ -1681,7 +1720,7 @@
* @param yoff Y offset of the region to copy in this Allocation
* @param w Width of the region to copy
* @param h Height of the region to copy
- * @param array Dest Array to be copied into
+ * @param data Dest Array to be copied into
*/
public void copy2DRangeTo(int xoff, int yoff, int w, int h, int[] data) {
validateIsInt32();
@@ -1697,7 +1736,7 @@
* @param yoff Y offset of the region to copy in this Allocation
* @param w Width of the region to copy
* @param h Height of the region to copy
- * @param array Dest Array to be copied into
+ * @param data Dest Array to be copied into
*/
public void copy2DRangeTo(int xoff, int yoff, int w, int h, float[] data) {
validateIsFloat32();
@@ -1715,8 +1754,23 @@
Trace.traceBegin(RenderScript.TRACE_TAG, "copy3DRangeToUnchecked");
mRS.validate();
validate3DRange(xoff, yoff, zoff, w, h, d);
+ final int dataSize = mType.mElement.getBytesSize() * w * h * d;
+ // AutoPadding for Vec3 Element
+ boolean usePadding = false;
+ int sizeBytes = arrayLen * dt.mSize;
+ if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
+ if (dataSize / 4 * 3 > sizeBytes) {
+ throw new RSIllegalArgumentException("Array too small for allocation type.");
+ }
+ usePadding = true;
+ sizeBytes = dataSize;
+ } else {
+ if (dataSize > sizeBytes) {
+ throw new RSIllegalArgumentException("Array too small for allocation type.");
+ }
+ }
mRS.nAllocationRead3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD, w, h, d,
- array, arrayLen * dt.mSize, dt);
+ array, sizeBytes, dt, mType.mElement.mType.mSize, usePadding);
Trace.traceEnd(RenderScript.TRACE_TAG);
}
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index 3b40431..b992d44 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -485,10 +485,12 @@
}
- native void rsnAllocationData1D(long con, long id, int off, int mip, int count, Object d, int sizeBytes, int dt);
- synchronized void nAllocationData1D(long id, int off, int mip, int count, Object d, int sizeBytes, Element.DataType dt) {
+ native void rsnAllocationData1D(long con, long id, int off, int mip, int count, Object d, int sizeBytes, int dt,
+ int mSize, boolean usePadding);
+ synchronized void nAllocationData1D(long id, int off, int mip, int count, Object d, int sizeBytes, Element.DataType dt,
+ int mSize, boolean usePadding) {
validate();
- rsnAllocationData1D(mContext, id, off, mip, count, d, sizeBytes, dt.mID);
+ rsnAllocationData1D(mContext, id, off, mip, count, d, sizeBytes, dt.mID, mSize, usePadding);
}
native void rsnAllocationElementData(long con,long id, int xoff, int yoff, int zoff, int mip, int compIdx, byte[] d, int sizeBytes);
@@ -518,11 +520,13 @@
}
native void rsnAllocationData2D(long con, long id, int xoff, int yoff, int mip, int face,
- int w, int h, Object d, int sizeBytes, int dt);
+ int w, int h, Object d, int sizeBytes, int dt,
+ int mSize, boolean usePadding);
synchronized void nAllocationData2D(long id, int xoff, int yoff, int mip, int face,
- int w, int h, Object d, int sizeBytes, Element.DataType dt) {
+ int w, int h, Object d, int sizeBytes, Element.DataType dt,
+ int mSize, boolean usePadding) {
validate();
- rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes, dt.mID);
+ rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes, dt.mID, mSize, usePadding);
}
native void rsnAllocationData2D(long con, long id, int xoff, int yoff, int mip, int face, Bitmap b);
@@ -550,50 +554,56 @@
}
native void rsnAllocationData3D(long con, long id, int xoff, int yoff, int zoff, int mip,
- int w, int h, int depth, Object d, int sizeBytes, int dt);
+ int w, int h, int depth, Object d, int sizeBytes, int dt,
+ int mSize, boolean usePadding);
synchronized void nAllocationData3D(long id, int xoff, int yoff, int zoff, int mip,
- int w, int h, int depth, Object d, int sizeBytes, Element.DataType dt) {
+ int w, int h, int depth, Object d, int sizeBytes, Element.DataType dt,
+ int mSize, boolean usePadding) {
validate();
- rsnAllocationData3D(mContext, id, xoff, yoff, zoff, mip, w, h, depth, d, sizeBytes, dt.mID);
+ rsnAllocationData3D(mContext, id, xoff, yoff, zoff, mip, w, h, depth, d, sizeBytes,
+ dt.mID, mSize, usePadding);
}
- native void rsnAllocationRead(long con, long id, Object d, int dt);
- synchronized void nAllocationRead(long id, Object d, Element.DataType dt) {
+ native void rsnAllocationRead(long con, long id, Object d, int dt, int mSize, boolean usePadding);
+ synchronized void nAllocationRead(long id, Object d, Element.DataType dt, int mSize, boolean usePadding) {
validate();
- rsnAllocationRead(mContext, id, d, dt.mID);
+ rsnAllocationRead(mContext, id, d, dt.mID, mSize, usePadding);
}
native void rsnAllocationRead1D(long con, long id, int off, int mip, int count, Object d,
- int sizeBytes, int dt);
+ int sizeBytes, int dt, int mSize, boolean usePadding);
synchronized void nAllocationRead1D(long id, int off, int mip, int count, Object d,
- int sizeBytes, Element.DataType dt) {
+ int sizeBytes, Element.DataType dt, int mSize, boolean usePadding) {
validate();
- rsnAllocationRead1D(mContext, id, off, mip, count, d, sizeBytes, dt.mID);
+ rsnAllocationRead1D(mContext, id, off, mip, count, d, sizeBytes, dt.mID, mSize, usePadding);
}
native void rsnAllocationElementRead(long con,long id, int xoff, int yoff, int zoff,
- int mip, int compIdx, Object d, int sizeBytes, int dt);
+ int mip, int compIdx, byte[] d, int sizeBytes);
synchronized void nAllocationElementRead(long id, int xoff, int yoff, int zoff,
- int mip, int compIdx, Object d, int sizeBytes,
- Element.DataType dt) {
+ int mip, int compIdx, byte[] d, int sizeBytes) {
validate();
- rsnAllocationElementRead(mContext, id, xoff, yoff, zoff, mip, compIdx, d, sizeBytes, dt.mID);
+ rsnAllocationElementRead(mContext, id, xoff, yoff, zoff, mip, compIdx, d, sizeBytes);
}
native void rsnAllocationRead2D(long con, long id, int xoff, int yoff, int mip, int face,
- int w, int h, Object d, int sizeBytes, int dt);
+ int w, int h, Object d, int sizeBytes, int dt,
+ int mSize, boolean usePadding);
synchronized void nAllocationRead2D(long id, int xoff, int yoff, int mip, int face,
- int w, int h, Object d, int sizeBytes, Element.DataType dt) {
+ int w, int h, Object d, int sizeBytes, Element.DataType dt,
+ int mSize, boolean usePadding) {
validate();
- rsnAllocationRead2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes, dt.mID);
+ rsnAllocationRead2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes, dt.mID, mSize, usePadding);
}
native void rsnAllocationRead3D(long con, long id, int xoff, int yoff, int zoff, int mip,
- int w, int h, int depth, Object d, int sizeBytes, int dt);
+ int w, int h, int depth, Object d, int sizeBytes, int dt,
+ int mSize, boolean usePadding);
synchronized void nAllocationRead3D(long id, int xoff, int yoff, int zoff, int mip,
- int w, int h, int depth, Object d, int sizeBytes, Element.DataType dt) {
+ int w, int h, int depth, Object d, int sizeBytes, Element.DataType dt,
+ int mSize, boolean usePadding) {
validate();
- rsnAllocationRead3D(mContext, id, xoff, yoff, zoff, mip, w, h, depth, d, sizeBytes, dt.mID);
+ rsnAllocationRead3D(mContext, id, xoff, yoff, zoff, mip, w, h, depth, d, sizeBytes, dt.mID, mSize, usePadding);
}
native long rsnAllocationGetType(long con, long id);
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index a145166..f2c9d31 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -54,10 +54,12 @@
#define PER_ARRAY_TYPE(flag, fnc, readonly, ...) { \
jint len = 0; \
void *ptr = nullptr; \
+ void *srcPtr = nullptr; \
size_t typeBytes = 0; \
jint relFlag = 0; \
if (readonly) { \
/* The on-release mode should only be JNI_ABORT for read-only accesses. */ \
+ /* readonly = true, also indicates we are copying to the allocation . */ \
relFlag = JNI_ABORT; \
} \
switch(dataType) { \
@@ -65,14 +67,50 @@
len = _env->GetArrayLength((jfloatArray)data); \
ptr = _env->GetFloatArrayElements((jfloatArray)data, flag); \
typeBytes = 4; \
- fnc(__VA_ARGS__); \
+ if (usePadding) { \
+ srcPtr = ptr; \
+ len = len / 3 * 4; \
+ if (count == 0) { \
+ count = len / 4; \
+ } \
+ ptr = malloc (len * typeBytes); \
+ if (readonly) { \
+ copyWithPadding(ptr, srcPtr, mSize, count); \
+ fnc(__VA_ARGS__); \
+ } else { \
+ fnc(__VA_ARGS__); \
+ copyWithUnPadding(srcPtr, ptr, mSize, count); \
+ } \
+ free(ptr); \
+ ptr = srcPtr; \
+ } else { \
+ fnc(__VA_ARGS__); \
+ } \
_env->ReleaseFloatArrayElements((jfloatArray)data, (jfloat *)ptr, relFlag); \
return; \
case RS_TYPE_FLOAT_64: \
len = _env->GetArrayLength((jdoubleArray)data); \
ptr = _env->GetDoubleArrayElements((jdoubleArray)data, flag); \
typeBytes = 8; \
- fnc(__VA_ARGS__); \
+ if (usePadding) { \
+ srcPtr = ptr; \
+ len = len / 3 * 4; \
+ if (count == 0) { \
+ count = len / 4; \
+ } \
+ ptr = malloc (len * typeBytes); \
+ if (readonly) { \
+ copyWithPadding(ptr, srcPtr, mSize, count); \
+ fnc(__VA_ARGS__); \
+ } else { \
+ fnc(__VA_ARGS__); \
+ copyWithUnPadding(srcPtr, ptr, mSize, count); \
+ } \
+ free(ptr); \
+ ptr = srcPtr; \
+ } else { \
+ fnc(__VA_ARGS__); \
+ } \
_env->ReleaseDoubleArrayElements((jdoubleArray)data, (jdouble *)ptr, relFlag); \
return; \
case RS_TYPE_SIGNED_8: \
@@ -80,7 +118,25 @@
len = _env->GetArrayLength((jbyteArray)data); \
ptr = _env->GetByteArrayElements((jbyteArray)data, flag); \
typeBytes = 1; \
- fnc(__VA_ARGS__); \
+ if (usePadding) { \
+ srcPtr = ptr; \
+ len = len / 3 * 4; \
+ if (count == 0) { \
+ count = len / 4; \
+ } \
+ ptr = malloc (len * typeBytes); \
+ if (readonly) { \
+ copyWithPadding(ptr, srcPtr, mSize, count); \
+ fnc(__VA_ARGS__); \
+ } else { \
+ fnc(__VA_ARGS__); \
+ copyWithUnPadding(srcPtr, ptr, mSize, count); \
+ } \
+ free(ptr); \
+ ptr = srcPtr; \
+ } else { \
+ fnc(__VA_ARGS__); \
+ } \
_env->ReleaseByteArrayElements((jbyteArray)data, (jbyte*)ptr, relFlag); \
return; \
case RS_TYPE_SIGNED_16: \
@@ -88,7 +144,25 @@
len = _env->GetArrayLength((jshortArray)data); \
ptr = _env->GetShortArrayElements((jshortArray)data, flag); \
typeBytes = 2; \
- fnc(__VA_ARGS__); \
+ if (usePadding) { \
+ srcPtr = ptr; \
+ len = len / 3 * 4; \
+ if (count == 0) { \
+ count = len / 4; \
+ } \
+ ptr = malloc (len * typeBytes); \
+ if (readonly) { \
+ copyWithPadding(ptr, srcPtr, mSize, count); \
+ fnc(__VA_ARGS__); \
+ } else { \
+ fnc(__VA_ARGS__); \
+ copyWithUnPadding(srcPtr, ptr, mSize, count); \
+ } \
+ free(ptr); \
+ ptr = srcPtr; \
+ } else { \
+ fnc(__VA_ARGS__); \
+ } \
_env->ReleaseShortArrayElements((jshortArray)data, (jshort *)ptr, relFlag); \
return; \
case RS_TYPE_SIGNED_32: \
@@ -96,7 +170,25 @@
len = _env->GetArrayLength((jintArray)data); \
ptr = _env->GetIntArrayElements((jintArray)data, flag); \
typeBytes = 4; \
- fnc(__VA_ARGS__); \
+ if (usePadding) { \
+ srcPtr = ptr; \
+ len = len / 3 * 4; \
+ if (count == 0) { \
+ count = len / 4; \
+ } \
+ ptr = malloc (len * typeBytes); \
+ if (readonly) { \
+ copyWithPadding(ptr, srcPtr, mSize, count); \
+ fnc(__VA_ARGS__); \
+ } else { \
+ fnc(__VA_ARGS__); \
+ copyWithUnPadding(srcPtr, ptr, mSize, count); \
+ } \
+ free(ptr); \
+ ptr = srcPtr; \
+ } else { \
+ fnc(__VA_ARGS__); \
+ } \
_env->ReleaseIntArrayElements((jintArray)data, (jint *)ptr, relFlag); \
return; \
case RS_TYPE_SIGNED_64: \
@@ -104,13 +196,31 @@
len = _env->GetArrayLength((jlongArray)data); \
ptr = _env->GetLongArrayElements((jlongArray)data, flag); \
typeBytes = 8; \
- fnc(__VA_ARGS__); \
+ if (usePadding) { \
+ srcPtr = ptr; \
+ len = len / 3 * 4; \
+ if (count == 0) { \
+ count = len / 4; \
+ } \
+ ptr = malloc (len * typeBytes); \
+ if (readonly) { \
+ copyWithPadding(ptr, srcPtr, mSize, count); \
+ fnc(__VA_ARGS__); \
+ } else { \
+ fnc(__VA_ARGS__); \
+ copyWithUnPadding(srcPtr, ptr, mSize, count); \
+ } \
+ free(ptr); \
+ ptr = srcPtr; \
+ } else { \
+ fnc(__VA_ARGS__); \
+ } \
_env->ReleaseLongArrayElements((jlongArray)data, (jlong *)ptr, relFlag); \
return; \
default: \
break; \
} \
- UNUSED(len, ptr, typeBytes, relFlag); \
+ UNUSED(len, ptr, srcPtr, typeBytes, relFlag); \
}
@@ -184,6 +294,32 @@
// ---------------------------------------------------------------------------
+static void copyWithPadding(void* ptr, void* srcPtr, int mSize, int count) {
+ int sizeBytesPad = mSize * 4;
+ int sizeBytes = mSize * 3;
+ uint8_t *dst = static_cast<uint8_t *>(ptr);
+ uint8_t *src = static_cast<uint8_t *>(srcPtr);
+ for (int i = 0; i < count; i++) {
+ memcpy(dst, src, sizeBytes);
+ dst += sizeBytesPad;
+ src += sizeBytes;
+ }
+}
+
+static void copyWithUnPadding(void* ptr, void* srcPtr, int mSize, int count) {
+ int sizeBytesPad = mSize * 4;
+ int sizeBytes = mSize * 3;
+ uint8_t *dst = static_cast<uint8_t *>(ptr);
+ uint8_t *src = static_cast<uint8_t *>(srcPtr);
+ for (int i = 0; i < count; i++) {
+ memcpy(dst, src, sizeBytes);
+ dst += sizeBytes;
+ src += sizeBytesPad;
+ }
+}
+
+
+// ---------------------------------------------------------------------------
static void
nContextFinish(JNIEnv *_env, jobject _this, jlong con)
{
@@ -1014,7 +1150,8 @@
// Copies from the Java object data into the Allocation pointed to by _alloc.
static void
nAllocationData1D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint offset, jint lod,
- jint count, jobject data, jint sizeBytes, jint dataType)
+ jint count, jobject data, jint sizeBytes, jint dataType, jint mSize,
+ jboolean usePadding)
{
RsAllocation *alloc = (RsAllocation *)_alloc;
if (kLogApi) {
@@ -1022,8 +1159,8 @@
"dataType(%i)", (RsContext)con, (RsAllocation)alloc, offset, count, sizeBytes,
dataType);
}
- PER_ARRAY_TYPE(nullptr, rsAllocation1DData, true, (RsContext)con, alloc, offset, lod, count,
- ptr, sizeBytes);
+ PER_ARRAY_TYPE(nullptr, rsAllocation1DData, true,
+ (RsContext)con, alloc, offset, lod, count, ptr, sizeBytes);
}
static void
@@ -1048,7 +1185,8 @@
// Copies from the Java object data into the Allocation pointed to by _alloc.
static void
nAllocationData2D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xoff, jint yoff, jint lod, jint _face,
- jint w, jint h, jobject data, jint sizeBytes, jint dataType)
+ jint w, jint h, jobject data, jint sizeBytes, jint dataType, jint mSize,
+ jboolean usePadding)
{
RsAllocation *alloc = (RsAllocation *)_alloc;
RsAllocationCubemapFace face = (RsAllocationCubemapFace)_face;
@@ -1056,7 +1194,9 @@
ALOGD("nAllocation2DData, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i) "
"type(%i)", (RsContext)con, alloc, xoff, yoff, w, h, sizeBytes, dataType);
}
- PER_ARRAY_TYPE(nullptr, rsAllocation2DData, true, (RsContext)con, alloc, xoff, yoff, lod, face, w, h, ptr, sizeBytes, 0);
+ int count = w * h;
+ PER_ARRAY_TYPE(nullptr, rsAllocation2DData, true,
+ (RsContext)con, alloc, xoff, yoff, lod, face, w, h, ptr, sizeBytes, 0);
}
// Copies from the Allocation pointed to by srcAlloc into the Allocation
@@ -1090,7 +1230,8 @@
// Copies from the Java object data into the Allocation pointed to by _alloc.
static void
nAllocationData3D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xoff, jint yoff, jint zoff, jint lod,
- jint w, jint h, jint d, jobject data, int sizeBytes, int dataType)
+ jint w, jint h, jint d, jobject data, jint sizeBytes, jint dataType,
+ jint mSize, jboolean usePadding)
{
RsAllocation *alloc = (RsAllocation *)_alloc;
if (kLogApi) {
@@ -1098,7 +1239,9 @@
" h(%i), d(%i), sizeBytes(%i)", (RsContext)con, (RsAllocation)alloc, xoff, yoff, zoff,
lod, w, h, d, sizeBytes);
}
- PER_ARRAY_TYPE(nullptr, rsAllocation3DData, true, (RsContext)con, alloc, xoff, yoff, zoff, lod, w, h, d, ptr, sizeBytes, 0);
+ int count = w * h * d;
+ PER_ARRAY_TYPE(nullptr, rsAllocation3DData, true,
+ (RsContext)con, alloc, xoff, yoff, zoff, lod, w, h, d, ptr, sizeBytes, 0);
}
// Copies from the Allocation pointed to by srcAlloc into the Allocation
@@ -1130,47 +1273,57 @@
// Copies from the Allocation pointed to by _alloc into the Java object data.
static void
-nAllocationRead(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jobject data, int dataType)
+nAllocationRead(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jobject data, jint dataType,
+ jint mSize, jboolean usePadding)
{
RsAllocation *alloc = (RsAllocation *)_alloc;
if (kLogApi) {
ALOGD("nAllocationRead, con(%p), alloc(%p)", (RsContext)con, (RsAllocation)alloc);
}
- PER_ARRAY_TYPE(0, rsAllocationRead, false, (RsContext)con, alloc, ptr, len * typeBytes);
+ int count = 0;
+ PER_ARRAY_TYPE(0, rsAllocationRead, false,
+ (RsContext)con, alloc, ptr, len * typeBytes);
}
// Copies from the Allocation pointed to by _alloc into the Java object data.
static void
nAllocationRead1D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint offset, jint lod,
- jint count, jobject data, int sizeBytes, int dataType)
+ jint count, jobject data, jint sizeBytes, jint dataType,
+ jint mSize, jboolean usePadding)
{
RsAllocation *alloc = (RsAllocation *)_alloc;
if (kLogApi) {
ALOGD("nAllocation1DRead, con(%p), adapter(%p), offset(%i), count(%i), sizeBytes(%i), "
"dataType(%i)", (RsContext)con, alloc, offset, count, sizeBytes, dataType);
}
- PER_ARRAY_TYPE(0, rsAllocation1DRead, false, (RsContext)con, alloc, offset, lod, count, ptr, sizeBytes);
+ PER_ARRAY_TYPE(0, rsAllocation1DRead, false,
+ (RsContext)con, alloc, offset, lod, count, ptr, sizeBytes);
}
// Copies from the Element in the Allocation pointed to by _alloc into the Java array data.
static void
-nAllocationElementRead(JNIEnv *_env, jobject _this, jlong con, jlong _alloc,
+nAllocationElementRead(JNIEnv *_env, jobject _this, jlong con, jlong alloc,
jint xoff, jint yoff, jint zoff,
- jint lod, jint compIdx, jobject data, jint sizeBytes, int dataType)
+ jint lod, jint compIdx, jbyteArray data, jint sizeBytes)
{
- RsAllocation *alloc = (RsAllocation *)_alloc;
+ jint len = _env->GetArrayLength(data);
if (kLogApi) {
- ALOGD("nAllocationElementRead, con(%p), alloc(%p), xoff(%i), yoff(%i), zoff(%i), comp(%i), "
- "sizeBytes(%i)", (RsContext)con, alloc, xoff, yoff, zoff, compIdx, sizeBytes);
+ ALOGD("nAllocationElementRead, con(%p), alloc(%p), xoff(%i), yoff(%i), zoff(%i), comp(%i), len(%i), "
+ "sizeBytes(%i)", (RsContext)con, (RsAllocation)alloc, xoff, yoff, zoff, compIdx, len,
+ sizeBytes);
}
- PER_ARRAY_TYPE(0, rsAllocationElementRead, false, (RsContext)con, alloc,
- xoff, yoff, zoff, lod, ptr, sizeBytes, compIdx);
+ jbyte *ptr = _env->GetByteArrayElements(data, nullptr);
+ rsAllocationElementRead((RsContext)con, (RsAllocation)alloc,
+ xoff, yoff, zoff,
+ lod, ptr, sizeBytes, compIdx);
+ _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
}
// Copies from the Allocation pointed to by _alloc into the Java object data.
static void
nAllocationRead2D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xoff, jint yoff, jint lod, jint _face,
- jint w, jint h, jobject data, int sizeBytes, int dataType)
+ jint w, jint h, jobject data, jint sizeBytes, jint dataType,
+ jint mSize, jboolean usePadding)
{
RsAllocation *alloc = (RsAllocation *)_alloc;
RsAllocationCubemapFace face = (RsAllocationCubemapFace)_face;
@@ -1178,13 +1331,16 @@
ALOGD("nAllocation2DRead, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i) "
"type(%i)", (RsContext)con, alloc, xoff, yoff, w, h, sizeBytes, dataType);
}
- PER_ARRAY_TYPE(0, rsAllocation2DRead, false, (RsContext)con, alloc, xoff, yoff, lod, face, w, h,
- ptr, sizeBytes, 0);
+ int count = w * h;
+ PER_ARRAY_TYPE(0, rsAllocation2DRead, false,
+ (RsContext)con, alloc, xoff, yoff, lod, face, w, h, ptr, sizeBytes, 0);
}
+
// Copies from the Allocation pointed to by _alloc into the Java object data.
static void
nAllocationRead3D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xoff, jint yoff, jint zoff, jint lod,
- jint w, jint h, jint d, jobject data, int sizeBytes, int dataType)
+ jint w, jint h, jint d, jobject data, int sizeBytes, int dataType,
+ jint mSize, jboolean usePadding)
{
RsAllocation *alloc = (RsAllocation *)_alloc;
if (kLogApi) {
@@ -1192,8 +1348,9 @@
" h(%i), d(%i), sizeBytes(%i)", (RsContext)con, (RsAllocation)alloc, xoff, yoff, zoff,
lod, w, h, d, sizeBytes);
}
- PER_ARRAY_TYPE(0, rsAllocation3DRead, false, (RsContext)con, alloc, xoff, yoff, zoff, lod, w, h, d,
- ptr, sizeBytes, 0);
+ int count = w * h * d;
+ PER_ARRAY_TYPE(nullptr, rsAllocation3DRead, false,
+ (RsContext)con, alloc, xoff, yoff, zoff, lod, w, h, d, ptr, sizeBytes, 0);
}
static jlong
@@ -2214,17 +2371,17 @@
{"rsnAllocationSetSurface", "(JJLandroid/view/Surface;)V", (void*)nAllocationSetSurface },
{"rsnAllocationIoSend", "(JJ)V", (void*)nAllocationIoSend },
{"rsnAllocationIoReceive", "(JJ)V", (void*)nAllocationIoReceive },
-{"rsnAllocationData1D", "(JJIIILjava/lang/Object;II)V", (void*)nAllocationData1D },
+{"rsnAllocationData1D", "(JJIIILjava/lang/Object;IIIZ)V", (void*)nAllocationData1D },
{"rsnAllocationElementData", "(JJIIIII[BI)V", (void*)nAllocationElementData },
-{"rsnAllocationData2D", "(JJIIIIIILjava/lang/Object;II)V", (void*)nAllocationData2D },
+{"rsnAllocationData2D", "(JJIIIIIILjava/lang/Object;IIIZ)V", (void*)nAllocationData2D },
{"rsnAllocationData2D", "(JJIIIIIIJIIII)V", (void*)nAllocationData2D_alloc },
-{"rsnAllocationData3D", "(JJIIIIIIILjava/lang/Object;II)V", (void*)nAllocationData3D },
+{"rsnAllocationData3D", "(JJIIIIIIILjava/lang/Object;IIIZ)V", (void*)nAllocationData3D },
{"rsnAllocationData3D", "(JJIIIIIIIJIIII)V", (void*)nAllocationData3D_alloc },
-{"rsnAllocationRead", "(JJLjava/lang/Object;I)V", (void*)nAllocationRead },
-{"rsnAllocationRead1D", "(JJIIILjava/lang/Object;II)V", (void*)nAllocationRead1D },
-{"rsnAllocationElementRead", "(JJIIIIILjava/lang/Object;II)V", (void*)nAllocationElementRead },
-{"rsnAllocationRead2D", "(JJIIIIIILjava/lang/Object;II)V", (void*)nAllocationRead2D },
-{"rsnAllocationRead3D", "(JJIIIIIIILjava/lang/Object;II)V", (void*)nAllocationRead3D },
+{"rsnAllocationRead", "(JJLjava/lang/Object;IIZ)V", (void*)nAllocationRead },
+{"rsnAllocationRead1D", "(JJIIILjava/lang/Object;IIIZ)V", (void*)nAllocationRead1D },
+{"rsnAllocationElementRead", "(JJIIIII[BI)V", (void*)nAllocationElementRead },
+{"rsnAllocationRead2D", "(JJIIIIIILjava/lang/Object;IIIZ)V", (void*)nAllocationRead2D },
+{"rsnAllocationRead3D", "(JJIIIIIIILjava/lang/Object;IIIZ)V", (void*)nAllocationRead3D },
{"rsnAllocationGetType", "(JJ)J", (void*)nAllocationGetType},
{"rsnAllocationResize1D", "(JJI)V", (void*)nAllocationResize1D },
{"rsnAllocationGenerateMipmaps", "(JJ)V", (void*)nAllocationGenerateMipmaps },
diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java
index 4a8e318..1772856 100644
--- a/services/core/java/com/android/server/pm/KeySetManagerService.java
+++ b/services/core/java/com/android/server/pm/KeySetManagerService.java
@@ -415,9 +415,9 @@
// Get the package's known keys and KeySets
ArraySet<Long> deletableKeySets = getOriginalKeySetsByPackageNameLPr(packageName);
ArraySet<Long> deletableKeys = new ArraySet<Long>();
- ArraySet<Long> knownKeys = null;
- for (Long ks : deletableKeySets) {
- knownKeys = mKeySetMapping.get(ks);
+ final int origDksSize = deletableKeySets.size();
+ for (int i = 0; i < origDksSize; i++) {
+ ArraySet<Long> knownKeys = mKeySetMapping.get(deletableKeySets.valueAt(i));
if (knownKeys != null) {
deletableKeys.addAll(knownKeys);
}
@@ -430,9 +430,9 @@
}
ArraySet<Long> knownKeySets = getOriginalKeySetsByPackageNameLPr(pkgName);
deletableKeySets.removeAll(knownKeySets);
- knownKeys = new ArraySet<Long>();
- for (Long ks : knownKeySets) {
- knownKeys = mKeySetMapping.get(ks);
+ final int kksSize = knownKeySets.size();
+ for (int i = 0; i < kksSize; i++) {
+ ArraySet<Long> knownKeys = mKeySetMapping.get(knownKeySets.valueAt(i));
if (knownKeys != null) {
deletableKeys.removeAll(knownKeys);
}
@@ -441,18 +441,22 @@
// The remaining keys and KeySets are not relied on by any other
// application and so can be safely deleted.
- for (Long ks : deletableKeySets) {
+ final int dksSize = deletableKeySets.size();
+ for (int i = 0; i < dksSize; i++) {
+ Long ks = deletableKeySets.valueAt(i);
mKeySets.delete(ks);
mKeySetMapping.delete(ks);
}
- for (Long keyId : deletableKeys) {
- mPublicKeys.delete(keyId);
+ final int dkSize = deletableKeys.size();
+ for (int i = 0; i < dkSize; i++) {
+ mPublicKeys.delete(deletableKeys.valueAt(i));
}
// Now remove the deleted KeySets from each package's signingKeySets
for (String pkgName : mPackages.keySet()) {
PackageSetting p = mPackages.get(pkgName);
- for (Long ks : deletableKeySets) {
+ for (int i = 0; i < dksSize; i++) {
+ Long ks = deletableKeySets.valueAt(i);
p.keySetData.removeSigningKeySet(ks);
}
}
diff --git a/tools/aapt/Images.cpp b/tools/aapt/Images.cpp
index 5ab177b..063b4e6 100644
--- a/tools/aapt/Images.cpp
+++ b/tools/aapt/Images.cpp
@@ -481,8 +481,9 @@
// assuming the image is a round rect, compute the radius by marching
// diagonally from the top left corner towards the center
- image->outlineAlpha = max(max_alpha_over_row(image->rows[innerMidY], innerStartX, innerEndX),
- max_alpha_over_col(image->rows, innerMidX, innerStartY, innerStartY));
+ image->outlineAlpha = std::max(
+ max_alpha_over_row(image->rows[innerMidY], innerStartX, innerEndX),
+ max_alpha_over_col(image->rows, innerMidX, innerStartY, innerStartY));
int diagonalInset = 0;
find_max_opacity(image->rows, innerStartX, innerStartY, innerMidX, innerMidY, 1, 1,
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 0ec1aeb..9861be2 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -1802,7 +1802,7 @@
}
const ResTable& featureTable = featureAssetManager.getResources(false);
- mTypeIdOffset = max(mTypeIdOffset,
+ mTypeIdOffset = std::max(mTypeIdOffset,
findLargestTypeIdForPackage(featureTable, mAssetsPackage));
}
@@ -2667,20 +2667,16 @@
const String8 defaultLocale;
// For all strings...
- for (map<String16, map<String8, SourcePos> >::iterator nameIter = mLocalizations.begin();
- nameIter != mLocalizations.end();
- nameIter++) {
- const map<String8, SourcePos>& configSrcMap = nameIter->second;
+ for (const auto& nameIter : mLocalizations) {
+ const std::map<String8, SourcePos>& configSrcMap = nameIter.second;
// Look for strings with no default localization
if (configSrcMap.count(defaultLocale) == 0) {
SourcePos().warning("string '%s' has no default translation.",
- String8(nameIter->first).string());
+ String8(nameIter.first).string());
if (mBundle->getVerbose()) {
- for (map<String8, SourcePos>::const_iterator locales = configSrcMap.begin();
- locales != configSrcMap.end();
- locales++) {
- locales->second.printf("locale %s found", locales->first.string());
+ for (const auto& locale : configSrcMap) {
+ locale.second.printf("locale %s found", locale.first.string());
}
}
// !!! TODO: throw an error here in some circumstances
@@ -2691,8 +2687,8 @@
const char* allConfigs = mBundle->getConfigurations().string();
const char* start = allConfigs;
const char* comma;
-
- set<String8> missingConfigs;
+
+ std::set<String8> missingConfigs;
AaptLocaleValue locale;
do {
String8 config;
@@ -2726,13 +2722,11 @@
if (!missingConfigs.empty()) {
String8 configStr;
- for (set<String8>::iterator iter = missingConfigs.begin();
- iter != missingConfigs.end();
- iter++) {
- configStr.appendFormat(" %s", iter->string());
+ for (const auto& iter : missingConfigs) {
+ configStr.appendFormat(" %s", iter.string());
}
SourcePos().warning("string '%s' is missing %u required localizations:%s",
- String8(nameIter->first).string(),
+ String8(nameIter.first).string(),
(unsigned int)missingConfigs.size(),
configStr.string());
}
diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h
index eac5dd3..a939dd3 100644
--- a/tools/aapt/ResourceTable.h
+++ b/tools/aapt/ResourceTable.h
@@ -16,8 +16,6 @@
#include <queue>
#include <set>
-using namespace std;
-
class XMLNode;
class ResourceTable;
@@ -28,7 +26,7 @@
XML_COMPILE_STRIP_WHITESPACE = 1<<3,
XML_COMPILE_STRIP_RAW_VALUES = 1<<4,
XML_COMPILE_UTF8 = 1<<5,
-
+
XML_COMPILE_STANDARD_RESOURCE =
XML_COMPILE_STRIP_COMMENTS | XML_COMPILE_ASSIGN_ATTRIBUTE_IDS
| XML_COMPILE_STRIP_WHITESPACE | XML_COMPILE_STRIP_RAW_VALUES
@@ -115,7 +113,7 @@
* and would mess up iteration order for the existing
* resources.
*/
- queue<CompileResourceWorkItem>& getWorkQueue() {
+ std::queue<CompileResourceWorkItem>& getWorkQueue() {
return mWorkQueue;
}
@@ -577,10 +575,10 @@
size_t mNumLocal;
SourcePos mCurrentXmlPos;
Bundle* mBundle;
-
+
// key = string resource name, value = set of locales in which that name is defined
- map<String16, map<String8, SourcePos> > mLocalizations;
- queue<CompileResourceWorkItem> mWorkQueue;
+ std::map<String16, std::map<String8, SourcePos>> mLocalizations;
+ std::queue<CompileResourceWorkItem> mWorkQueue;
};
#endif