diff options
Diffstat (limited to 'core/jni')
21 files changed, 1090 insertions, 784 deletions
diff --git a/core/jni/Android.mk b/core/jni/Android.mk index a008e96..722dacb 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -24,7 +24,6 @@ LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES LOCAL_SRC_FILES:= \ ActivityManager.cpp \ AndroidRuntime.cpp \ - CursorWindow.cpp \ Time.cpp \ com_google_android_gles_jni_EGLImpl.cpp \ com_google_android_gles_jni_GLImpl.cpp.arm \ @@ -48,6 +47,8 @@ LOCAL_SRC_FILES:= \ android_view_InputChannel.cpp \ android_view_InputQueue.cpp \ android_view_KeyEvent.cpp \ + android_view_HardwareRenderer.cpp \ + android_view_GLES20Canvas.cpp \ android_view_MotionEvent.cpp \ android_text_AndroidCharacter.cpp \ android_text_AndroidBidi.cpp \ @@ -139,6 +140,7 @@ LOCAL_SRC_FILES:= \ LOCAL_C_INCLUDES += \ $(JNI_H_INCLUDE) \ $(LOCAL_PATH)/android/graphics \ + $(LOCAL_PATH)/../../libs/hwui \ $(call include-path-for, bluedroid) \ $(call include-path-for, libhardware)/hardware \ $(call include-path-for, libhardware_legacy)/hardware_legacy \ @@ -167,6 +169,7 @@ LOCAL_SHARED_LIBRARIES := \ libbinder \ libnetutils \ libui \ + libhwui \ libsurfaceflinger_client \ libcamera_client \ libskiagl \ diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 6fb1369..19bb36f 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -114,6 +114,8 @@ extern int register_android_graphics_Xfermode(JNIEnv* env); extern int register_android_graphics_PixelFormat(JNIEnv* env); extern int register_com_android_internal_graphics_NativeUtils(JNIEnv *env); extern int register_android_view_Display(JNIEnv* env); +extern int register_android_view_GLES20Canvas(JNIEnv* env); +extern int register_android_view_HardwareRenderer(JNIEnv* env); extern int register_android_view_Surface(JNIEnv* env); extern int register_android_view_ViewRoot(JNIEnv* env); extern int register_android_database_CursorWindow(JNIEnv* env); @@ -1211,6 +1213,8 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_nio_utils), REG_JNI(register_android_graphics_PixelFormat), REG_JNI(register_android_graphics_Graphics), + REG_JNI(register_android_view_GLES20Canvas), + REG_JNI(register_android_view_HardwareRenderer), REG_JNI(register_android_view_Surface), REG_JNI(register_android_view_ViewRoot), REG_JNI(register_com_google_android_gles_jni_EGLImpl), diff --git a/core/jni/CursorWindow.cpp b/core/jni/CursorWindow.cpp deleted file mode 100644 index 7877921..0000000 --- a/core/jni/CursorWindow.cpp +++ /dev/null @@ -1,413 +0,0 @@ -/* - * Copyright (C) 2006-2007 The Android Open Source Project - * - * 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. - */ - -#undef LOG_TAG -#define LOG_TAG "CursorWindow" - -#include <utils/Log.h> -#include <binder/MemoryHeapBase.h> -#include <binder/MemoryBase.h> - -#include <assert.h> -#include <string.h> -#include <stdlib.h> - -#include <jni.h> -#include <JNIHelp.h> - -#include "CursorWindow.h" - - -namespace android { - -CursorWindow::CursorWindow(size_t maxSize) : - mMaxSize(maxSize) -{ -} - -bool CursorWindow::setMemory(const sp<IMemory>& memory) -{ - mMemory = memory; - mData = (uint8_t *) memory->pointer(); - if (mData == NULL) { - return false; - } - mHeader = (window_header_t *) mData; - - // Make the window read-only - ssize_t size = memory->size(); - mSize = size; - mMaxSize = size; - mFreeOffset = size; -LOG_WINDOW("Created CursorWindow from existing IMemory: mFreeOffset = %d, numRows = %d, numColumns = %d, mSize = %d, mMaxSize = %d, mData = %p", mFreeOffset, mHeader->numRows, mHeader->numColumns, mSize, mMaxSize, mData); - return true; -} - -bool CursorWindow::initBuffer(bool localOnly) -{ - //TODO Use a non-memory dealer mmap region for localOnly - - sp<MemoryHeapBase> heap; - heap = new MemoryHeapBase(mMaxSize, 0, "CursorWindow"); - if (heap != NULL) { - mMemory = new MemoryBase(heap, 0, mMaxSize); - if (mMemory != NULL) { - mData = (uint8_t *) mMemory->pointer(); - if (mData) { - mHeader = (window_header_t *) mData; - mSize = mMaxSize; - - // Put the window into a clean state - clear(); - LOG_WINDOW("Created CursorWindow with new MemoryDealer: mFreeOffset = %d, mSize = %d, mMaxSize = %d, mData = %p", mFreeOffset, mSize, mMaxSize, mData); - return true; - } - } - LOGE("CursorWindow heap allocation failed"); - return false; - } else { - LOGE("failed to create the CursorWindow heap"); - return false; - } -} - -CursorWindow::~CursorWindow() -{ - // Everything that matters is a smart pointer -} - -void CursorWindow::clear() -{ - mHeader->numRows = 0; - mHeader->numColumns = 0; - mFreeOffset = sizeof(window_header_t) + ROW_SLOT_CHUNK_SIZE; - // Mark the first chunk's next 'pointer' as null - *((uint32_t *)(mData + mFreeOffset - sizeof(uint32_t))) = 0; -} - -int32_t CursorWindow::freeSpace() -{ - int32_t freeSpace = mSize - mFreeOffset; - if (freeSpace < 0) { - freeSpace = 0; - } - return freeSpace; -} - -field_slot_t * CursorWindow::allocRow() -{ - // Fill in the row slot - row_slot_t * rowSlot = allocRowSlot(); - if (rowSlot == NULL) { - return NULL; - } - - // Allocate the slots for the field directory - size_t fieldDirSize = mHeader->numColumns * sizeof(field_slot_t); - uint32_t fieldDirOffset = alloc(fieldDirSize); - if (!fieldDirOffset) { - mHeader->numRows--; - LOGE("The row failed, so back out the new row accounting from allocRowSlot %d", mHeader->numRows); - return NULL; - } - field_slot_t * fieldDir = (field_slot_t *)offsetToPtr(fieldDirOffset); - memset(fieldDir, 0x0, fieldDirSize); - -LOG_WINDOW("Allocated row %u, rowSlot is at offset %u, fieldDir is %d bytes at offset %u\n", (mHeader->numRows - 1), ((uint8_t *)rowSlot) - mData, fieldDirSize, fieldDirOffset); - rowSlot->offset = fieldDirOffset; - - return fieldDir; -} - -uint32_t CursorWindow::alloc(size_t requestedSize, bool aligned) -{ - int32_t size; - uint32_t padding; - if (aligned) { - // 4 byte alignment - padding = 4 - (mFreeOffset & 0x3); - } else { - padding = 0; - } - - size = requestedSize + padding; - - if (size > freeSpace()) { - LOGE("need to grow: mSize = %d, size = %d, freeSpace() = %d, numRows = %d", mSize, size, freeSpace(), mHeader->numRows); - // Only grow the window if the first row doesn't fit - if (mHeader->numRows > 1) { -LOGE("not growing since there are already %d row(s), max size %d", mHeader->numRows, mMaxSize); - return 0; - } - - // Find a new size that will fit the allocation - int allocated = mSize - freeSpace(); - int newSize = mSize + WINDOW_ALLOCATION_SIZE; - while (size > (newSize - allocated)) { - newSize += WINDOW_ALLOCATION_SIZE; - if (newSize > mMaxSize) { - LOGE("Attempting to grow window beyond max size (%d)", mMaxSize); - return 0; - } - } -LOG_WINDOW("found size %d", newSize); - mSize = newSize; - } - - uint32_t offset = mFreeOffset + padding; - mFreeOffset += size; - return offset; -} - -row_slot_t * CursorWindow::getRowSlot(int row) -{ - LOG_WINDOW("enter getRowSlot current row num %d, this row %d", mHeader->numRows, row); - int chunkNum = row / ROW_SLOT_CHUNK_NUM_ROWS; - int chunkPos = row % ROW_SLOT_CHUNK_NUM_ROWS; - int chunkPtrOffset = sizeof(window_header_t) + ROW_SLOT_CHUNK_SIZE - sizeof(uint32_t); - uint8_t * rowChunk = mData + sizeof(window_header_t); - for (int i = 0; i < chunkNum; i++) { - rowChunk = offsetToPtr(*((uint32_t *)(mData + chunkPtrOffset))); - chunkPtrOffset = rowChunk - mData + (ROW_SLOT_CHUNK_NUM_ROWS * sizeof(row_slot_t)); - } - return (row_slot_t *)(rowChunk + (chunkPos * sizeof(row_slot_t))); - LOG_WINDOW("exit getRowSlot current row num %d, this row %d", mHeader->numRows, row); -} - -row_slot_t * CursorWindow::allocRowSlot() -{ - int chunkNum = mHeader->numRows / ROW_SLOT_CHUNK_NUM_ROWS; - int chunkPos = mHeader->numRows % ROW_SLOT_CHUNK_NUM_ROWS; - int chunkPtrOffset = sizeof(window_header_t) + ROW_SLOT_CHUNK_SIZE - sizeof(uint32_t); - uint8_t * rowChunk = mData + sizeof(window_header_t); -LOG_WINDOW("Allocating row slot, mHeader->numRows is %d, chunkNum is %d, chunkPos is %d", mHeader->numRows, chunkNum, chunkPos); - for (int i = 0; i < chunkNum; i++) { - uint32_t nextChunkOffset = *((uint32_t *)(mData + chunkPtrOffset)); -LOG_WINDOW("nextChunkOffset is %d", nextChunkOffset); - if (nextChunkOffset == 0) { - // Allocate a new row chunk - nextChunkOffset = alloc(ROW_SLOT_CHUNK_SIZE, true); - if (nextChunkOffset == 0) { - return NULL; - } - rowChunk = offsetToPtr(nextChunkOffset); -LOG_WINDOW("allocated new chunk at %d, rowChunk = %p", nextChunkOffset, rowChunk); - *((uint32_t *)(mData + chunkPtrOffset)) = rowChunk - mData; - // Mark the new chunk's next 'pointer' as null - *((uint32_t *)(rowChunk + ROW_SLOT_CHUNK_SIZE - sizeof(uint32_t))) = 0; - } else { -LOG_WINDOW("follwing 'pointer' to next chunk, offset of next pointer is %d", chunkPtrOffset); - rowChunk = offsetToPtr(nextChunkOffset); - chunkPtrOffset = rowChunk - mData + (ROW_SLOT_CHUNK_NUM_ROWS * sizeof(row_slot_t)); - } - } - mHeader->numRows++; - - return (row_slot_t *)(rowChunk + (chunkPos * sizeof(row_slot_t))); -} - -field_slot_t * CursorWindow::getFieldSlotWithCheck(int row, int column) -{ - if (row < 0 || row >= mHeader->numRows || column < 0 || column >= mHeader->numColumns) { - LOGE("Bad request for field slot %d,%d. numRows = %d, numColumns = %d", row, column, mHeader->numRows, mHeader->numColumns); - return NULL; - } - row_slot_t * rowSlot = getRowSlot(row); - if (!rowSlot) { - LOGE("Failed to find rowSlot for row %d", row); - return NULL; - } - if (rowSlot->offset == 0 || rowSlot->offset >= mSize) { - LOGE("Invalid rowSlot, offset = %d", rowSlot->offset); - return NULL; - } - int fieldDirOffset = rowSlot->offset; - return ((field_slot_t *)offsetToPtr(fieldDirOffset)) + column; -} - -uint32_t CursorWindow::read_field_slot(int row, int column, field_slot_t * slotOut) -{ - if (row < 0 || row >= mHeader->numRows || column < 0 || column >= mHeader->numColumns) { - LOGE("Bad request for field slot %d,%d. numRows = %d, numColumns = %d", row, column, mHeader->numRows, mHeader->numColumns); - return -1; - } - row_slot_t * rowSlot = getRowSlot(row); - if (!rowSlot) { - LOGE("Failed to find rowSlot for row %d", row); - return -1; - } - if (rowSlot->offset == 0 || rowSlot->offset >= mSize) { - LOGE("Invalid rowSlot, offset = %d", rowSlot->offset); - return -1; - } -LOG_WINDOW("Found field directory for %d,%d at rowSlot %d, offset %d", row, column, (uint8_t *)rowSlot - mData, rowSlot->offset); - field_slot_t * fieldDir = (field_slot_t *)offsetToPtr(rowSlot->offset); -LOG_WINDOW("Read field_slot_t %d,%d: offset = %d, size = %d, type = %d", row, column, fieldDir[column].data.buffer.offset, fieldDir[column].data.buffer.size, fieldDir[column].type); - - // Copy the data to the out param - slotOut->data.buffer.offset = fieldDir[column].data.buffer.offset; - slotOut->data.buffer.size = fieldDir[column].data.buffer.size; - slotOut->type = fieldDir[column].type; - return 0; -} - -void CursorWindow::copyIn(uint32_t offset, uint8_t const * data, size_t size) -{ - assert(offset + size <= mSize); - memcpy(mData + offset, data, size); -} - -void CursorWindow::copyIn(uint32_t offset, int64_t data) -{ - assert(offset + sizeof(int64_t) <= mSize); - memcpy(mData + offset, (uint8_t *)&data, sizeof(int64_t)); -} - -void CursorWindow::copyIn(uint32_t offset, double data) -{ - assert(offset + sizeof(double) <= mSize); - memcpy(mData + offset, (uint8_t *)&data, sizeof(double)); -} - -void CursorWindow::copyOut(uint32_t offset, uint8_t * data, size_t size) -{ - assert(offset + size <= mSize); - memcpy(data, mData + offset, size); -} - -int64_t CursorWindow::copyOutLong(uint32_t offset) -{ - int64_t value; - assert(offset + sizeof(int64_t) <= mSize); - memcpy(&value, mData + offset, sizeof(int64_t)); - return value; -} - -double CursorWindow::copyOutDouble(uint32_t offset) -{ - double value; - assert(offset + sizeof(double) <= mSize); - memcpy(&value, mData + offset, sizeof(double)); - return value; -} - -bool CursorWindow::putLong(unsigned int row, unsigned int col, int64_t value) -{ - field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col); - if (!fieldSlot) { - return false; - } - -#if WINDOW_STORAGE_INLINE_NUMERICS - fieldSlot->data.l = value; -#else - int offset = alloc(sizeof(int64_t)); - if (!offset) { - return false; - } - - copyIn(offset, value); - - fieldSlot->data.buffer.offset = offset; - fieldSlot->data.buffer.size = sizeof(int64_t); -#endif - fieldSlot->type = FIELD_TYPE_INTEGER; - return true; -} - -bool CursorWindow::putDouble(unsigned int row, unsigned int col, double value) -{ - field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col); - if (!fieldSlot) { - return false; - } - -#if WINDOW_STORAGE_INLINE_NUMERICS - fieldSlot->data.d = value; -#else - int offset = alloc(sizeof(int64_t)); - if (!offset) { - return false; - } - - copyIn(offset, value); - - fieldSlot->data.buffer.offset = offset; - fieldSlot->data.buffer.size = sizeof(double); -#endif - fieldSlot->type = FIELD_TYPE_FLOAT; - return true; -} - -bool CursorWindow::putNull(unsigned int row, unsigned int col) -{ - field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col); - if (!fieldSlot) { - return false; - } - - fieldSlot->type = FIELD_TYPE_NULL; - fieldSlot->data.buffer.offset = 0; - fieldSlot->data.buffer.size = 0; - return true; -} - -bool CursorWindow::getLong(unsigned int row, unsigned int col, int64_t * valueOut) -{ - field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col); - if (!fieldSlot || fieldSlot->type != FIELD_TYPE_INTEGER) { - return false; - } - -#if WINDOW_STORAGE_INLINE_NUMERICS - *valueOut = fieldSlot->data.l; -#else - *valueOut = copyOutLong(fieldSlot->data.buffer.offset); -#endif - return true; -} - -bool CursorWindow::getDouble(unsigned int row, unsigned int col, double * valueOut) -{ - field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col); - if (!fieldSlot || fieldSlot->type != FIELD_TYPE_FLOAT) { - return false; - } - -#if WINDOW_STORAGE_INLINE_NUMERICS - *valueOut = fieldSlot->data.d; -#else - *valueOut = copyOutDouble(fieldSlot->data.buffer.offset); -#endif - return true; -} - -bool CursorWindow::getNull(unsigned int row, unsigned int col, bool * valueOut) -{ - field_slot_t * fieldSlot = getFieldSlotWithCheck(row, col); - if (!fieldSlot) { - return false; - } - - if (fieldSlot->type != FIELD_TYPE_NULL) { - *valueOut = false; - } else { - *valueOut = true; - } - return true; -} - -}; // namespace android diff --git a/core/jni/CursorWindow.h b/core/jni/CursorWindow.h deleted file mode 100644 index 3fcb560..0000000 --- a/core/jni/CursorWindow.h +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * 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. - */ - -#ifndef _ANDROID__DATABASE_WINDOW_H -#define _ANDROID__DATABASE_WINDOW_H - -#include <cutils/log.h> -#include <stddef.h> -#include <stdint.h> - -#include <binder/IMemory.h> -#include <utils/RefBase.h> - -#include <jni.h> - -#define DEFAULT_WINDOW_SIZE 4096 -#define MAX_WINDOW_SIZE (1024 * 1024) -#define WINDOW_ALLOCATION_SIZE 4096 - -#define ROW_SLOT_CHUNK_NUM_ROWS 16 - -// Row slots are allocated in chunks of ROW_SLOT_CHUNK_NUM_ROWS, -// with an offset after the rows that points to the next chunk -#define ROW_SLOT_CHUNK_SIZE ((ROW_SLOT_CHUNK_NUM_ROWS * sizeof(row_slot_t)) + sizeof(uint32_t)) - - -#if LOG_NDEBUG - -#define IF_LOG_WINDOW() if (false) -#define LOG_WINDOW(...) - -#else - -#define IF_LOG_WINDOW() IF_LOG(LOG_DEBUG, "CursorWindow") -#define LOG_WINDOW(...) LOG(LOG_DEBUG, "CursorWindow", __VA_ARGS__) - -#endif - - -// When defined to true strings are stored as UTF8, otherwise they're UTF16 -#define WINDOW_STORAGE_UTF8 1 - -// When defined to true numberic values are stored inline in the field_slot_t, otherwise they're allocated in the window -#define WINDOW_STORAGE_INLINE_NUMERICS 1 - -namespace android { - -typedef struct -{ - uint32_t numRows; - uint32_t numColumns; -} window_header_t; - -typedef struct -{ - uint32_t offset; -} row_slot_t; - -typedef struct -{ - uint8_t type; - union { - double d; - int64_t l; - struct { - uint32_t offset; - uint32_t size; - } buffer; - } data; -} __attribute__((packed)) field_slot_t; - -#define FIELD_TYPE_INTEGER 1 -#define FIELD_TYPE_FLOAT 2 -#define FIELD_TYPE_STRING 3 -#define FIELD_TYPE_BLOB 4 -#define FIELD_TYPE_NULL 5 - -/** - * This class stores a set of rows from a database in a buffer. The begining of the - * window has first chunk of row_slot_ts, which are offsets to the row directory, followed by - * an offset to the next chunk in a linked-list of additional chunk of row_slot_ts in case - * the pre-allocated chunk isn't big enough to refer to all rows. Each row directory has a - * field_slot_t per column, which has the size, offset, and type of the data for that field. - * Note that the data types come from sqlite3.h. - */ -class CursorWindow -{ -public: - CursorWindow(size_t maxSize); - CursorWindow(){} - bool setMemory(const sp<IMemory>&); - ~CursorWindow(); - - bool initBuffer(bool localOnly); - sp<IMemory> getMemory() {return mMemory;} - - size_t size() {return mSize;} - uint8_t * data() {return mData;} - uint32_t getNumRows() {return mHeader->numRows;} - uint32_t getNumColumns() {return mHeader->numColumns;} - void freeLastRow() { - if (mHeader->numRows > 0) { - mHeader->numRows--; - } - } - bool setNumColumns(uint32_t numColumns) - { - uint32_t cur = mHeader->numColumns; - if (cur > 0 && cur != numColumns) { - LOGE("Trying to go from %d columns to %d", cur, numColumns); - return false; - } - mHeader->numColumns = numColumns; - return true; - } - - int32_t freeSpace(); - - void clear(); - - /** - * Allocate a row slot and its directory. The returned - * pointer points to the begining of the row's directory - * or NULL if there wasn't room. The directory is - * initialied with NULL entries for each field. - */ - field_slot_t * allocRow(); - - /** - * Allocate a portion of the window. Returns the offset - * of the allocation, or 0 if there isn't enough space. - * If aligned is true, the allocation gets 4 byte alignment. - */ - uint32_t alloc(size_t size, bool aligned = false); - - uint32_t read_field_slot(int row, int column, field_slot_t * slot); - - /** - * Copy data into the window at the given offset. - */ - void copyIn(uint32_t offset, uint8_t const * data, size_t size); - void copyIn(uint32_t offset, int64_t data); - void copyIn(uint32_t offset, double data); - - void copyOut(uint32_t offset, uint8_t * data, size_t size); - int64_t copyOutLong(uint32_t offset); - double copyOutDouble(uint32_t offset); - - bool putLong(unsigned int row, unsigned int col, int64_t value); - bool putDouble(unsigned int row, unsigned int col, double value); - bool putNull(unsigned int row, unsigned int col); - - bool getLong(unsigned int row, unsigned int col, int64_t * valueOut); - bool getDouble(unsigned int row, unsigned int col, double * valueOut); - bool getNull(unsigned int row, unsigned int col, bool * valueOut); - - uint8_t * offsetToPtr(uint32_t offset) {return mData + offset;} - - row_slot_t * allocRowSlot(); - - row_slot_t * getRowSlot(int row); - - /** - * return NULL if Failed to find rowSlot or - * Invalid rowSlot - */ - field_slot_t * getFieldSlotWithCheck(int row, int column); - field_slot_t * getFieldSlot(int row, int column) - { - int fieldDirOffset = getRowSlot(row)->offset; - return ((field_slot_t *)offsetToPtr(fieldDirOffset)) + column; - } - -private: - uint8_t * mData; - size_t mSize; - size_t mMaxSize; - window_header_t * mHeader; - sp<IMemory> mMemory; - - /** - * Offset of the lowest unused data byte in the array. - */ - uint32_t mFreeOffset; -}; - -}; // namespace android - -#endif diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index 88bbafd..b062264 100644 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -313,6 +313,10 @@ static int Bitmap_config(JNIEnv* env, jobject, SkBitmap* bitmap) { return bitmap->config();
}
+static int Bitmap_getGenerationId(JNIEnv* env, jobject, SkBitmap* bitmap) {
+ return bitmap->getGenerationID();
+}
+
static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, SkBitmap* bitmap) {
return !bitmap->isOpaque();
}
@@ -606,6 +610,7 @@ static JNINativeMethod gBitmapMethods[] = { (void*)Bitmap_writeToParcel },
{ "nativeExtractAlpha", "(II[I)Landroid/graphics/Bitmap;",
(void*)Bitmap_extractAlpha },
+ { "nativeGenerationId", "(I)I", (void*)Bitmap_getGenerationId },
{ "nativeGetPixel", "(III)I", (void*)Bitmap_getPixel },
{ "nativeGetPixels", "(I[IIIIIII)V", (void*)Bitmap_getPixels },
{ "nativeSetPixel", "(IIII)V", (void*)Bitmap_setPixel },
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp index e1e9536..2e49c64 100644 --- a/core/jni/android/graphics/Canvas.cpp +++ b/core/jni/android/graphics/Canvas.cpp @@ -30,6 +30,11 @@ #include "SkBoundaryPatch.h" #include "SkMeshUtils.h" +#include "unicode/ubidi.h" +#include "unicode/ushape.h" + +#include <utils/Log.h> + #define TIME_DRAWx static uint32_t get_thread_msec() { @@ -52,6 +57,24 @@ namespace android { class SkCanvasGlue { public: + enum { + kDirection_LTR = 0, + kDirection_RTL = 1 + }; + + enum { + kDirection_Mask = 0x1 + }; + + enum { + kBidi_LTR = 0, + kBidi_RTL = 1, + kBidi_Default_LTR = 2, + kBidi_Default_RTL = 3, + kBidi_Force_LTR = 4, + kBidi_Force_RTL = 5 + }; + static void finalizer(JNIEnv* env, jobject clazz, SkCanvas* canvas) { canvas->unref(); } @@ -743,45 +766,252 @@ public: canvas->drawVertices(mode, ptCount, verts, texs, colors, NULL, indices, indexCount, *paint); } - - static void drawText___CIIFFPaint(JNIEnv* env, jobject, SkCanvas* canvas, - jcharArray text, int index, int count, - jfloat x, jfloat y, SkPaint* paint) { - jchar* textArray = env->GetCharArrayElements(text, NULL); - jsize textCount = env->GetArrayLength(text); + + /** + * Character-based Arabic shaping. + * + * We'll use harfbuzz and glyph-based shaping instead once we're set up for it. + * + * @context the text context + * @start the start of the text to render + * @count the length of the text to render, start + count must be <= contextCount + * @contextCount the length of the context + * @shaped where to put the shaped text, must have capacity for count uchars + * @return the length of the shaped text, or -1 if error + */ + static int shapeRtlText(const jchar* context, jsize start, jsize count, jsize contextCount, + jchar* shaped, UErrorCode &status) { + jchar buffer[contextCount]; + + // Use fixed length since we need to keep start and count valid + u_shapeArabic(context, contextCount, buffer, contextCount, + U_SHAPE_LENGTH_FIXED_SPACES_NEAR | + U_SHAPE_TEXT_DIRECTION_LOGICAL | U_SHAPE_LETTERS_SHAPE | + U_SHAPE_X_LAMALEF_SUB_ALTERNATE, &status); + + if (U_SUCCESS(status)) { + // trim out 0xffff following ligatures, if any + int end = 0; + for (int i = start, e = start + count; i < e; ++i) { + if (buffer[i] != 0xffff) { + buffer[end++] = buffer[i]; + } + } + count = end; + // LOG(LOG_INFO, "CSRTL", "start %d count %d ccount %d\n", start, count, contextCount); + ubidi_writeReverse(buffer, count, shaped, count, UBIDI_DO_MIRRORING | UBIDI_OUTPUT_REVERSE + | UBIDI_KEEP_BASE_COMBINING, &status); + if (U_SUCCESS(status)) { + return count; + } + } + + return -1; + } + + /** + * Basic character-based layout supporting rtl and arabic shaping. + * Runs bidi on the text and generates a reordered, shaped line in buffer, returning + * the length. + * @text the text + * @len the length of the text in uchars + * @dir receives the resolved paragraph direction + * @buffer the buffer to receive the reordered, shaped line. Must have capacity of + * at least len jchars. + * @flags line bidi flags + * @return the length of the reordered, shaped line, or -1 if error + */ + static jint layoutLine(const jchar* text, jint len, jint flags, int &dir, jchar* buffer, + UErrorCode &status) { + static int RTL_OPTS = UBIDI_DO_MIRRORING | UBIDI_KEEP_BASE_COMBINING | + UBIDI_REMOVE_BIDI_CONTROLS | UBIDI_OUTPUT_REVERSE; + + UBiDiLevel bidiReq = 0; + switch (flags) { + case kBidi_LTR: bidiReq = 0; break; // no ICU constant, canonical LTR level + case kBidi_RTL: bidiReq = 1; break; // no ICU constant, canonical RTL level + case kBidi_Default_LTR: bidiReq = UBIDI_DEFAULT_LTR; break; + case kBidi_Default_RTL: bidiReq = UBIDI_DEFAULT_RTL; break; + case kBidi_Force_LTR: memcpy(buffer, text, len * sizeof(jchar)); return len; + case kBidi_Force_RTL: return shapeRtlText(text, 0, len, len, buffer, status); + } + + int32_t result = -1; + + UBiDi* bidi = ubidi_open(); + if (bidi) { + ubidi_setPara(bidi, text, len, bidiReq, NULL, &status); + if (U_SUCCESS(status)) { + dir = ubidi_getParaLevel(bidi) & 0x1; // 0 if ltr, 1 if rtl + + int rc = ubidi_countRuns(bidi, &status); + if (U_SUCCESS(status)) { + // LOG(LOG_INFO, "LAYOUT", "para bidiReq=%d dir=%d rc=%d\n", bidiReq, dir, rc); + + int32_t slen = 0; + for (int i = 0; i < rc; ++i) { + int32_t start; + int32_t length; + UBiDiDirection runDir = ubidi_getVisualRun(bidi, i, &start, &length); + // LOG(LOG_INFO, "LAYOUT", " [%2d] runDir=%d start=%3d len=%3d\n", i, runDir, start, length); + if (runDir == UBIDI_RTL) { + slen += shapeRtlText(text + start, 0, length, length, buffer + slen, status); + } else { + memcpy(buffer + slen, text + start, length * sizeof(jchar)); + slen += length; + } + } + if (U_SUCCESS(status)) { + result = slen; + } + } + } + ubidi_close(bidi); + } + + return result; + } + + // Returns true if we might need layout. If bidiFlags force LTR, assume no layout, if + // bidiFlags indicate there probably is RTL, assume we do, otherwise scan the text + // looking for a character >= the first RTL character in unicode and assume we do if + // we find one. + static bool needsLayout(const jchar* text, jint len, jint bidiFlags) { + if (bidiFlags == kBidi_Force_LTR) { + return false; + } + if ((bidiFlags == kBidi_RTL) || (bidiFlags == kBidi_Default_RTL) || + bidiFlags == kBidi_Force_RTL) { + return true; + } + for (int i = 0; i < len; ++i) { + if (text[i] >= 0x0590) { + return true; + } + } + return false; + } + + // Draws a paragraph of text on a single line, running bidi and shaping + static void drawText(JNIEnv* env, SkCanvas* canvas, const jchar* text, jsize len, + jfloat x, jfloat y, int bidiFlags, SkPaint* paint) { + SkScalar x_ = SkFloatToScalar(x); SkScalar y_ = SkFloatToScalar(y); - canvas->drawText(textArray + index, count << 1, x_, y_, *paint); - env->ReleaseCharArrayElements(text, textArray, 0); + + SkPaint::Align horiz = paint->getTextAlign(); + + const jchar *workText = text; + jchar *buffer = NULL; + int dir = kDirection_LTR; + if (needsLayout(text, len, bidiFlags)) { + buffer =(jchar *) malloc(len * sizeof(jchar)); + if (!buffer) { + return; + } + UErrorCode status = U_ZERO_ERROR; + len = layoutLine(text, len, bidiFlags, dir, buffer, status); // might change len, dir + if (!U_SUCCESS(status)) { + LOG(LOG_WARN, "LAYOUT", "drawText error %d\n", status); + free(buffer); + return; // can't render + } + + workText = buffer; // use the shaped text + } + + bool trimLeft = false; + bool trimRight = false; + + switch (horiz) { + case SkPaint::kLeft_Align: trimLeft = dir & kDirection_Mask; break; + case SkPaint::kCenter_Align: trimLeft = trimRight = true; break; + case SkPaint::kRight_Align: trimRight = !(dir & kDirection_Mask); + default: break; + } + const jchar* workLimit = workText + len; + + if (trimLeft) { + while (workText < workLimit && *workText == ' ') { + ++workText; + } + } + if (trimRight) { + while (workLimit > workText && *(workLimit - 1) == ' ') { + --workLimit; + } + } + int32_t workBytes = (workLimit - workText) << 1; + + canvas->drawText(workText, workBytes, x_, y_, *paint); + + free(buffer); } - - static void drawText__StringIIFFPaint(JNIEnv* env, jobject, - SkCanvas* canvas, jstring text, int start, int end, - jfloat x, jfloat y, SkPaint* paint) { - const void* text_ = env->GetStringChars(text, NULL); + + static void drawText___CIIFFIPaint(JNIEnv* env, jobject, SkCanvas* canvas, + jcharArray text, int index, int count, + jfloat x, jfloat y, int flags, SkPaint* paint) { + jchar* textArray = env->GetCharArrayElements(text, NULL); + drawText(env, canvas, textArray + index, count, x, y, flags, paint); + env->ReleaseCharArrayElements(text, textArray, JNI_ABORT); + } + + static void drawText__StringIIFFIPaint(JNIEnv* env, jobject, + SkCanvas* canvas, jstring text, + int start, int end, + jfloat x, jfloat y, int flags, SkPaint* paint) { + const jchar* textArray = env->GetStringChars(text, NULL); + drawText(env, canvas, textArray + start, end - start, x, y, flags, paint); + env->ReleaseStringChars(text, textArray); + } + + // Draws a unidirectional run of text. + static void drawTextRun(JNIEnv* env, SkCanvas* canvas, const jchar* chars, + jint start, jint count, jint contextCount, + jfloat x, jfloat y, int dirFlags, SkPaint* paint) { + SkScalar x_ = SkFloatToScalar(x); SkScalar y_ = SkFloatToScalar(y); - canvas->drawText((const uint16_t*)text_ + start, (end - start) << 1, - x_, y_, *paint); - env->ReleaseStringChars(text, (const jchar*) text_); - } - - static void drawString(JNIEnv* env, jobject canvas, jstring text, - jfloat x, jfloat y, jobject paint) { - NPE_CHECK_RETURN_VOID(env, canvas); - NPE_CHECK_RETURN_VOID(env, paint); - NPE_CHECK_RETURN_VOID(env, text); - size_t count = env->GetStringLength(text); - if (0 == count) { - return; + + uint8_t rtl = dirFlags & 0x1; + if (rtl) { + SkAutoSTMalloc<80, jchar> buffer(contextCount); + UErrorCode status = U_ZERO_ERROR; + count = shapeRtlText(chars, start, count, contextCount, buffer.get(), status); + if (U_SUCCESS(status)) { + canvas->drawText(buffer.get(), count << 1, x_, y_, *paint); + } else { + LOG(LOG_WARN, "LAYOUT", "drawTextRun error %d\n", status); + } + } else { + canvas->drawText(chars + start, count << 1, x_, y_, *paint); } - const jchar* text_ = env->GetStringChars(text, NULL); - SkCanvas* c = GraphicsJNI::getNativeCanvas(env, canvas); - c->drawText(text_, count << 1, SkFloatToScalar(x), SkFloatToScalar(y), - *GraphicsJNI::getNativePaint(env, paint)); - env->ReleaseStringChars(text, text_); } - + + static void drawTextRun___CIIIIFFIPaint( + JNIEnv* env, jobject, SkCanvas* canvas, jcharArray text, int index, + int count, int contextIndex, int contextCount, + jfloat x, jfloat y, int dirFlags, SkPaint* paint) { + + jchar* chars = env->GetCharArrayElements(text, NULL); + drawTextRun(env, canvas, chars + contextIndex, index - contextIndex, + count, contextCount, x, y, dirFlags, paint); + env->ReleaseCharArrayElements(text, chars, JNI_ABORT); + } + + static void drawTextRun__StringIIIIFFIPaint( + JNIEnv* env, jobject obj, SkCanvas* canvas, jstring text, jint start, + jint end, jint contextStart, jint contextEnd, + jfloat x, jfloat y, jint dirFlags, SkPaint* paint) { + + jint count = end - start; + jint contextCount = contextEnd - contextStart; + const jchar* chars = env->GetStringChars(text, NULL); + drawTextRun(env, canvas, chars + contextStart, start - contextStart, + count, contextCount, x, y, dirFlags, paint); + env->ReleaseStringChars(text, chars); + } + static void drawPosText___CII_FPaint(JNIEnv* env, jobject, SkCanvas* canvas, jcharArray text, int index, int count, jfloatArray pos, SkPaint* paint) { @@ -804,10 +1034,11 @@ public: } delete[] posPtr; } - + static void drawPosText__String_FPaint(JNIEnv* env, jobject, SkCanvas* canvas, jstring text, - jfloatArray pos, SkPaint* paint) { + jfloatArray pos, + SkPaint* paint) { const void* text_ = text ? env->GetStringChars(text, NULL) : NULL; int byteLength = text ? env->GetStringLength(text) : 0; float* posArray = pos ? env->GetFloatArrayElements(pos, NULL) : NULL; @@ -827,27 +1058,44 @@ public: } delete[] posPtr; } - + + static void drawTextOnPath(JNIEnv *env, SkCanvas* canvas, const jchar* text, int count, + int bidiFlags, SkPath* path, jfloat hOffset, jfloat vOffset, SkPaint* paint) { + + if (!needsLayout(text, count, bidiFlags)) { + canvas->drawTextOnPathHV(text, count << 1, *path, + SkFloatToScalar(hOffset), SkFloatToScalar(vOffset), *paint); + return; + } + + SkAutoSTMalloc<80, jchar> buffer(count); + int dir = kDirection_LTR; + UErrorCode status = U_ZERO_ERROR; + count = layoutLine(text, count, bidiFlags, dir, buffer.get(), status); + if (U_SUCCESS(status)) { + canvas->drawTextOnPathHV(buffer.get(), count << 1, *path, + SkFloatToScalar(hOffset), SkFloatToScalar(vOffset), *paint); + } + } + static void drawTextOnPath___CIIPathFFPaint(JNIEnv* env, jobject, - SkCanvas* canvas, jcharArray text, int index, int count, - SkPath* path, jfloat hOffset, jfloat vOffset, SkPaint* paint) { + SkCanvas* canvas, jcharArray text, int index, int count, + SkPath* path, jfloat hOffset, jfloat vOffset, jint bidiFlags, SkPaint* paint) { jchar* textArray = env->GetCharArrayElements(text, NULL); - canvas->drawTextOnPathHV(textArray + index, count << 1, *path, - SkFloatToScalar(hOffset), SkFloatToScalar(vOffset), *paint); + drawTextOnPath(env, canvas, textArray, count, bidiFlags, path, hOffset, vOffset, paint); env->ReleaseCharArrayElements(text, textArray, 0); } - + static void drawTextOnPath__StringPathFFPaint(JNIEnv* env, jobject, - SkCanvas* canvas, jstring text, SkPath* path, - jfloat hOffset, jfloat vOffset, SkPaint* paint) { + SkCanvas* canvas, jstring text, SkPath* path, + jfloat hOffset, jfloat vOffset, jint bidiFlags, SkPaint* paint) { const jchar* text_ = env->GetStringChars(text, NULL); - int byteLength = env->GetStringLength(text) << 1; - canvas->drawTextOnPathHV(text_, byteLength, *path, - SkFloatToScalar(hOffset), SkFloatToScalar(vOffset), *paint); + int count = env->GetStringLength(text); + drawTextOnPath(env, canvas, text_, count, bidiFlags, path, hOffset, vOffset, paint); env->ReleaseStringChars(text, text_); } - + static bool getClipBounds(JNIEnv* env, jobject, SkCanvas* canvas, jobject bounds) { SkRect r; @@ -940,26 +1188,27 @@ static JNINativeMethod gCanvasMethods[] = { (void*) SkCanvasGlue::drawBitmapRR}, {"native_drawBitmap", "(I[IIIFFIIZI)V", (void*)SkCanvasGlue::drawBitmapArray}, - {"nativeDrawBitmapMatrix", "(IIII)V", (void*)SkCanvasGlue::drawBitmapMatrix}, {"nativeDrawBitmapMesh", "(IIII[FI[III)V", (void*)SkCanvasGlue::drawBitmapMesh}, {"nativeDrawVertices", "(III[FI[FI[II[SIII)V", (void*)SkCanvasGlue::drawVertices}, - {"native_drawText","(I[CIIFFI)V", - (void*) SkCanvasGlue::drawText___CIIFFPaint}, - {"native_drawText","(ILjava/lang/String;IIFFI)V", - (void*) SkCanvasGlue::drawText__StringIIFFPaint}, - {"drawText","(Ljava/lang/String;FFLandroid/graphics/Paint;)V", - (void*) SkCanvasGlue::drawString}, + {"native_drawText","(I[CIIFFII)V", + (void*) SkCanvasGlue::drawText___CIIFFIPaint}, + {"native_drawText","(ILjava/lang/String;IIFFII)V", + (void*) SkCanvasGlue::drawText__StringIIFFIPaint}, + {"native_drawTextRun","(I[CIIIIFFII)V", + (void*) SkCanvasGlue::drawTextRun___CIIIIFFIPaint}, + {"native_drawTextRun","(ILjava/lang/String;IIIIFFII)V", + (void*) SkCanvasGlue::drawTextRun__StringIIIIFFIPaint}, {"native_drawPosText","(I[CII[FI)V", (void*) SkCanvasGlue::drawPosText___CII_FPaint}, {"native_drawPosText","(ILjava/lang/String;[FI)V", (void*) SkCanvasGlue::drawPosText__String_FPaint}, - {"native_drawTextOnPath","(I[CIIIFFI)V", + {"native_drawTextOnPath","(I[CIIIFFII)V", (void*) SkCanvasGlue::drawTextOnPath___CIIPathFFPaint}, - {"native_drawTextOnPath","(ILjava/lang/String;IFFI)V", + {"native_drawTextOnPath","(ILjava/lang/String;IFFII)V", (void*) SkCanvasGlue::drawTextOnPath__StringPathFFPaint}, {"native_drawPicture", "(II)V", (void*) SkCanvasGlue::drawPicture}, diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp index 780badc..ca9c9de 100644 --- a/core/jni/android/graphics/Paint.cpp +++ b/core/jni/android/graphics/Paint.cpp @@ -31,6 +31,10 @@ #include "SkShader.h" #include "SkTypeface.h" #include "SkXfermode.h" +#include "unicode/ushape.h" + +// temporary for debugging +#include <utils/Log.h> namespace android { @@ -57,6 +61,9 @@ static void defaultSettingsForAndroid(SkPaint* paint) { class SkPaintGlue { public: + enum MoveOpt { + AFTER, AT_OR_AFTER, BEFORE, AT_OR_BEFORE, AT + }; static void finalizer(JNIEnv* env, jobject clazz, SkPaint* obj) { delete obj; @@ -395,7 +402,184 @@ public: env->ReleaseStringChars(text, textArray); return count; } - + + static jfloat doTextRunAdvances(JNIEnv *env, SkPaint *paint, const jchar *text, jint start, jint count, jint contextCount, jint flags, + jfloatArray advances, jint advancesIndex) { + jfloat advancesArray[count]; + jchar buffer[contextCount]; + + SkScalar* scalarArray = (SkScalar *)advancesArray; + jfloat totalAdvance = 0; + + // this is where we'd call harfbuzz + // for now we just use ushape.c + + int widths; + if (flags & 0x1) { // rtl, call arabic shaping in case + UErrorCode status = U_ZERO_ERROR; + // Use fixed length since we need to keep start and count valid + u_shapeArabic(text, contextCount, buffer, contextCount, + U_SHAPE_LENGTH_FIXED_SPACES_NEAR | + U_SHAPE_TEXT_DIRECTION_LOGICAL | U_SHAPE_LETTERS_SHAPE | + U_SHAPE_X_LAMALEF_SUB_ALTERNATE, &status); + // we shouldn't fail unless there's an out of memory condition, + // in which case we're hosed anyway + for (int i = start, e = i + count; i < e; ++i) { + if (buffer[i] == 0xffff) { + buffer[i] = 0x200b; // zero-width-space for skia + } + } + widths = paint->getTextWidths(buffer + start, count << 1, scalarArray); + } else { + widths = paint->getTextWidths(text + start, count << 1, scalarArray); + } + + if (widths < count) { + // Skia operates on code points, not code units, so surrogate pairs return only + // one value. Expand the result so we have one value per UTF-16 code unit. + + // Note, skia's getTextWidth gets confused if it encounters a surrogate pair, + // leaving the remaining widths zero. Not nice. + const jchar *chars = text + start; + for (int i = 0, p = 0; i < widths; ++i) { + totalAdvance += advancesArray[p++] = SkScalarToFloat(scalarArray[i]); + if (p < count && chars[p] >= 0xdc00 && chars[p] < 0xe000 && + chars[p-1] >= 0xd800 && chars[p-1] < 0xdc00) { + advancesArray[p++] = 0; + } + } + } else { + for (int i = 0; i < count; i++) { + totalAdvance += advancesArray[i] = SkScalarToFloat(scalarArray[i]); + } + } + + if (advances != NULL) { + env->SetFloatArrayRegion(advances, advancesIndex, count, advancesArray); + } + return totalAdvance; + } + + static float getTextRunAdvances___CIIIII_FI(JNIEnv* env, jobject clazz, SkPaint* paint, + jcharArray text, jint index, jint count, jint contextIndex, jint contextCount, + jint flags, jfloatArray advances, jint advancesIndex) { + jchar* textArray = env->GetCharArrayElements(text, NULL); + jfloat result = doTextRunAdvances(env, paint, textArray + contextIndex, + index - contextIndex, count, contextCount, flags, advances, advancesIndex); + env->ReleaseCharArrayElements(text, textArray, JNI_ABORT); + return result; + } + + static float getTextRunAdvances__StringIIIII_FI(JNIEnv* env, jobject clazz, SkPaint* paint, + jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint flags, + jfloatArray advances, jint advancesIndex) { + const jchar* textArray = env->GetStringChars(text, NULL); + jfloat result = doTextRunAdvances(env, paint, textArray + contextStart, + start - contextStart, end - start, contextEnd - contextStart, flags, advances, + advancesIndex); + env->ReleaseStringChars(text, textArray); + return result; + } + + static jint doTextRunCursor(JNIEnv *env, SkPaint* paint, const jchar *text, jint start, + jint count, jint flags, jint offset, jint opt) { + SkScalar scalarArray[count]; + jchar buffer[count]; + + // this is where we'd call harfbuzz + // for now we just use ushape.c and widths returned from skia + + int widths; + if (flags & 0x1) { // rtl, call arabic shaping in case + UErrorCode status = U_ZERO_ERROR; + // Use fixed length since we need to keep start and count valid + u_shapeArabic(text + start, count, buffer, count, + U_SHAPE_LENGTH_FIXED_SPACES_NEAR | U_SHAPE_TEXT_DIRECTION_LOGICAL | + U_SHAPE_LETTERS_SHAPE | U_SHAPE_X_LAMALEF_SUB_ALTERNATE, &status); + // we shouldn't fail unless there's an out of memory condition, + // in which case we're hosed anyway + for (int i = 0; i < count; ++i) { + if (buffer[i] == 0xffff) { + buffer[i] = 0x200b; // zero-width-space for skia + } + } + widths = paint->getTextWidths(buffer, count << 1, scalarArray); + } else { + widths = paint->getTextWidths(text + start, count << 1, scalarArray); + } + + if (widths < count) { + // Skia operates on code points, not code units, so surrogate pairs return only one + // value. Expand the result so we have one value per UTF-16 code unit. + + // Note, skia's getTextWidth gets confused if it encounters a surrogate pair, + // leaving the remaining widths zero. Not nice. + const jchar *chars = text + start; + for (int i = count, p = widths - 1; --i > p;) { + if (chars[i] >= 0xdc00 && chars[i] < 0xe000 && + chars[i-1] >= 0xd800 && chars[i-1] < 0xdc00) { + scalarArray[i] = 0; + } else { + scalarArray[i] = scalarArray[--p]; + } + } + } + + jint pos = offset - start; + switch (opt) { + case AFTER: + if (pos < count) { + pos += 1; + } + // fall through + case AT_OR_AFTER: + while (pos < count && scalarArray[pos] == 0) { + ++pos; + } + break; + case BEFORE: + if (pos > 0) { + --pos; + } + // fall through + case AT_OR_BEFORE: + while (pos > 0 && scalarArray[pos] == 0) { + --pos; + } + break; + case AT: + default: + if (scalarArray[pos] == 0) { + pos = -1; + } + break; + } + + if (pos != -1) { + pos += start; + } + + return pos; + } + + static jint getTextRunCursor___C(JNIEnv* env, jobject clazz, SkPaint* paint, jcharArray text, + jint contextStart, jint contextCount, jint flags, jint offset, jint cursorOpt) { + jchar* textArray = env->GetCharArrayElements(text, NULL); + jint result = doTextRunCursor(env, paint, textArray, contextStart, contextCount, flags, + offset, cursorOpt); + env->ReleaseCharArrayElements(text, textArray, JNI_ABORT); + return result; + } + + static jint getTextRunCursor__String(JNIEnv* env, jobject clazz, SkPaint* paint, jstring text, + jint contextStart, jint contextEnd, jint flags, jint offset, jint cursorOpt) { + const jchar* textArray = env->GetStringChars(text, NULL); + jint result = doTextRunCursor(env, paint, textArray, contextStart, + contextEnd - contextStart, flags, offset, cursorOpt); + env->ReleaseStringChars(text, textArray); + return result; + } + static void getTextPath___CIIFFPath(JNIEnv* env, jobject clazz, SkPaint* paint, jcharArray text, int index, int count, jfloat x, jfloat y, SkPath* path) { const jchar* textArray = env->GetCharArrayElements(text, NULL); paint->getTextPath(textArray + index, count << 1, SkFloatToScalar(x), SkFloatToScalar(y), path); @@ -576,6 +760,13 @@ static JNINativeMethod methods[] = { {"native_breakText","(Ljava/lang/String;ZF[F)I", (void*) SkPaintGlue::breakTextS}, {"native_getTextWidths","(I[CII[F)I", (void*) SkPaintGlue::getTextWidths___CII_F}, {"native_getTextWidths","(ILjava/lang/String;II[F)I", (void*) SkPaintGlue::getTextWidths__StringII_F}, + {"native_getTextRunAdvances","(I[CIIIII[FI)F", (void*) + SkPaintGlue::getTextRunAdvances___CIIIII_FI}, + {"native_getTextRunAdvances","(ILjava/lang/String;IIIII[FI)F", + (void*) SkPaintGlue::getTextRunAdvances__StringIIIII_FI}, + {"native_getTextRunCursor", "(I[CIIIII)I", (void*) SkPaintGlue::getTextRunCursor___C}, + {"native_getTextRunCursor", "(ILjava/lang/String;IIIII)I", + (void*) SkPaintGlue::getTextRunCursor__String}, {"native_getTextPath","(I[CIIFFI)V", (void*) SkPaintGlue::getTextPath___CIIFFPath}, {"native_getTextPath","(ILjava/lang/String;IIFFI)V", (void*) SkPaintGlue::getTextPath__StringIIFFPath}, {"nativeGetStringBounds", "(ILjava/lang/String;IILandroid/graphics/Rect;)V", diff --git a/core/jni/android_bluetooth_common.cpp b/core/jni/android_bluetooth_common.cpp index 9a8f1b8..53ac625 100644 --- a/core/jni/android_bluetooth_common.cpp +++ b/core/jni/android_bluetooth_common.cpp @@ -68,6 +68,10 @@ static Properties adapter_properties[] = { {"UUIDs", DBUS_TYPE_ARRAY}, }; +static Properties input_properties[] = { + {"Connected", DBUS_TYPE_BOOLEAN}, +}; + typedef union { char *str_val; int int_val; @@ -698,6 +702,11 @@ jobjectArray parse_remote_device_property_change(JNIEnv *env, DBusMessage *msg) sizeof(remote_device_properties) / sizeof(Properties)); } +jobjectArray parse_input_property_change(JNIEnv *env, DBusMessage *msg) { + return parse_property_change(env, msg, (Properties *) &input_properties, + sizeof(input_properties) / sizeof(Properties)); +} + jobjectArray parse_adapter_properties(JNIEnv *env, DBusMessageIter *iter) { return parse_properties(env, iter, (Properties *) &adapter_properties, sizeof(adapter_properties) / sizeof(Properties)); @@ -708,6 +717,11 @@ jobjectArray parse_remote_device_properties(JNIEnv *env, DBusMessageIter *iter) sizeof(remote_device_properties) / sizeof(Properties)); } +jobjectArray parse_input_properties(JNIEnv *env, DBusMessageIter *iter) { + return parse_properties(env, iter, (Properties *) &input_properties, + sizeof(input_properties) / sizeof(Properties)); +} + int get_bdaddr(const char *str, bdaddr_t *ba) { char *d = ((char *)ba) + 5, *endp; int i; diff --git a/core/jni/android_bluetooth_common.h b/core/jni/android_bluetooth_common.h index 378bb6f..27a00ae 100644 --- a/core/jni/android_bluetooth_common.h +++ b/core/jni/android_bluetooth_common.h @@ -162,6 +162,8 @@ jobjectArray parse_adapter_properties(JNIEnv *env, DBusMessageIter *iter); jobjectArray parse_remote_device_properties(JNIEnv *env, DBusMessageIter *iter); jobjectArray parse_remote_device_property_change(JNIEnv *env, DBusMessage *msg); jobjectArray parse_adapter_property_change(JNIEnv *env, DBusMessage *msg); +jobjectArray parse_input_properties(JNIEnv *env, DBusMessageIter *iter); +jobjectArray parse_input_property_change(JNIEnv *env, DBusMessage *msg); void append_variant(DBusMessageIter *iter, int type, void *val); int get_bdaddr(const char *str, bdaddr_t *ba); void get_bdaddr_as_string(const bdaddr_t *ba, char *str); diff --git a/core/jni/android_database_CursorWindow.cpp b/core/jni/android_database_CursorWindow.cpp index 91449bc..040dac3 100644 --- a/core/jni/android_database_CursorWindow.cpp +++ b/core/jni/android_database_CursorWindow.cpp @@ -29,7 +29,7 @@ #include <string.h> #include <unistd.h> -#include "CursorWindow.h" +#include "binder/CursorWindow.h" #include "sqlite3_exception.h" #include "android_util_Binder.h" @@ -225,70 +225,6 @@ LOG_WINDOW("Getting blob for %d,%d from %p", row, column, window); return NULL; } -static jboolean isBlob_native(JNIEnv* env, jobject object, jint row, jint column) -{ - int32_t err; - CursorWindow * window = GET_WINDOW(env, object); -LOG_WINDOW("Checking if column is a blob or null for %d,%d from %p", row, column, window); - - field_slot_t field; - err = window->read_field_slot(row, column, &field); - if (err != 0) { - throwExceptionWithRowCol(env, row, column); - return NULL; - } - - return field.type == FIELD_TYPE_BLOB || field.type == FIELD_TYPE_NULL; -} - -static jboolean isString_native(JNIEnv* env, jobject object, jint row, jint column) -{ - int32_t err; - CursorWindow * window = GET_WINDOW(env, object); -LOG_WINDOW("Checking if column is a string or null for %d,%d from %p", row, column, window); - - field_slot_t field; - err = window->read_field_slot(row, column, &field); - if (err != 0) { - throwExceptionWithRowCol(env, row, column); - return NULL; - } - - return field.type == FIELD_TYPE_STRING || field.type == FIELD_TYPE_NULL; -} - -static jboolean isInteger_native(JNIEnv* env, jobject object, jint row, jint column) -{ - int32_t err; - CursorWindow * window = GET_WINDOW(env, object); -LOG_WINDOW("Checking if column is an integer for %d,%d from %p", row, column, window); - - field_slot_t field; - err = window->read_field_slot(row, column, &field); - if (err != 0) { - throwExceptionWithRowCol(env, row, column); - return NULL; - } - - return field.type == FIELD_TYPE_INTEGER; -} - -static jboolean isFloat_native(JNIEnv* env, jobject object, jint row, jint column) -{ - int32_t err; - CursorWindow * window = GET_WINDOW(env, object); -LOG_WINDOW("Checking if column is a float for %d,%d from %p", row, column, window); - - field_slot_t field; - err = window->read_field_slot(row, column, &field); - if (err != 0) { - throwExceptionWithRowCol(env, row, column); - return NULL; - } - - return field.type == FIELD_TYPE_FLOAT; -} - static jstring getString_native(JNIEnv* env, jobject object, jint row, jint column) { int32_t err; @@ -487,10 +423,9 @@ LOG_WINDOW("Getting double for %d,%d from %p", row, column, window); } } -static jboolean isNull_native(JNIEnv* env, jobject object, jint row, jint column) +bool isNull_native(CursorWindow *window, jint row, jint column) { - CursorWindow * window = GET_WINDOW(env, object); -LOG_WINDOW("Checking for NULL at %d,%d from %p", row, column, window); + LOG_WINDOW("Checking for NULL at %d,%d from %p", row, column, window); bool isNull; if (window->getNull(row, column, &isNull)) { @@ -652,6 +587,26 @@ static void freeLastRow(JNIEnv * env, jobject object) { window->freeLastRow(); } +static jint getType_native(JNIEnv* env, jobject object, jint row, jint column) +{ + int32_t err; + CursorWindow * window = GET_WINDOW(env, object); + LOG_WINDOW("returning column type affinity for %d,%d from %p", row, column, window); + + if (isNull_native(window, row, column)) { + return FIELD_TYPE_NULL; + } + + field_slot_t field; + err = window->read_field_slot(row, column, &field); + if (err != 0) { + throwExceptionWithRowCol(env, row, column); + return NULL; + } + + return field.type; +} + static JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ @@ -662,11 +617,9 @@ static JNINativeMethod sMethods[] = {"close_native", "()V", (void *)native_close}, {"getLong_native", "(II)J", (void *)getLong_native}, {"getBlob_native", "(II)[B", (void *)getBlob_native}, - {"isBlob_native", "(II)Z", (void *)isBlob_native}, {"getString_native", "(II)Ljava/lang/String;", (void *)getString_native}, {"copyStringToBuffer_native", "(IIILandroid/database/CharArrayBuffer;)[C", (void *)copyStringToBuffer_native}, {"getDouble_native", "(II)D", (void *)getDouble_native}, - {"isNull_native", "(II)Z", (void *)isNull_native}, {"getNumRows_native", "()I", (void *)getNumRows}, {"setNumColumns_native", "(I)Z", (void *)setNumColumns}, {"allocRow_native", "()Z", (void *)allocRow}, @@ -676,9 +629,7 @@ static JNINativeMethod sMethods[] = {"putDouble_native", "(DII)Z", (void *)putDouble_native}, {"freeLastRow_native", "()V", (void *)freeLastRow}, {"putNull_native", "(II)Z", (void *)putNull_native}, - {"isString_native", "(II)Z", (void *)isString_native}, - {"isFloat_native", "(II)Z", (void *)isFloat_native}, - {"isInteger_native", "(II)Z", (void *)isInteger_native}, + {"getType_native", "(II)I", (void *)getType_native}, }; int register_android_database_CursorWindow(JNIEnv * env) diff --git a/core/jni/android_database_SQLiteCompiledSql.cpp b/core/jni/android_database_SQLiteCompiledSql.cpp index 8d1c39e..de4c5c8 100644 --- a/core/jni/android_database_SQLiteCompiledSql.cpp +++ b/core/jni/android_database_SQLiteCompiledSql.cpp @@ -91,22 +91,11 @@ static void native_compile(JNIEnv* env, jobject object, jstring sqlString) compile(env, object, GET_HANDLE(env, object), sqlString); } -static void native_finalize(JNIEnv* env, jobject object) -{ - int err; - sqlite3_stmt * statement = GET_STATEMENT(env, object); - - if (statement != NULL) { - sqlite3_finalize(statement); - env->SetIntField(object, gStatementField, 0); - } -} static JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ {"native_compile", "(Ljava/lang/String;)V", (void *)native_compile}, - {"native_finalize", "()V", (void *)native_finalize}, }; int register_android_database_SQLiteCompiledSql(JNIEnv * env) diff --git a/core/jni/android_database_SQLiteDatabase.cpp b/core/jni/android_database_SQLiteDatabase.cpp index 36234a9..5a92193 100644 --- a/core/jni/android_database_SQLiteDatabase.cpp +++ b/core/jni/android_database_SQLiteDatabase.cpp @@ -63,8 +63,8 @@ enum { static jfieldID offset_db_handle; -static char *createStr(const char *path) { - int len = strlen(path); +static char *createStr(const char *path, short extra) { + int len = strlen(path) + extra; char *str = (char *)malloc(len + 1); strncpy(str, path, len); str[len] = NULL; @@ -85,7 +85,7 @@ static void registerLoggingFunc(const char *path) { } LOGV("Registering sqlite logging func \n"); - int err = sqlite3_config(SQLITE_CONFIG_LOG, &sqlLogger, (void *)createStr(path)); + int err = sqlite3_config(SQLITE_CONFIG_LOG, &sqlLogger, (void *)createStr(path, 0)); if (err != SQLITE_OK) { LOGE("sqlite_config failed error_code = %d. THIS SHOULD NEVER occur.\n", err); return; @@ -176,13 +176,17 @@ done: if (handle != NULL) sqlite3_close(handle); } -static char *getDatabaseName(JNIEnv* env, sqlite3 * handle, jstring databaseName) { +static char *getDatabaseName(JNIEnv* env, sqlite3 * handle, jstring databaseName, short connNum) { char const *path = env->GetStringUTFChars(databaseName, NULL); if (path == NULL) { LOGE("Failure in getDatabaseName(). VM ran out of memory?\n"); return NULL; // VM would have thrown OutOfMemoryError } - char *dbNameStr = createStr(path); + char *dbNameStr = createStr(path, 4); + if (connNum > 999) { // TODO: if number of pooled connections > 999, fix this line. + connNum = -1; + } + sprintf(dbNameStr + strlen(path), "|%03d", connNum); env->ReleaseStringUTFChars(databaseName, path); return dbNameStr; } @@ -192,10 +196,10 @@ static void sqlTrace(void *databaseName, const char *sql) { } /* public native void enableSqlTracing(); */ -static void enableSqlTracing(JNIEnv* env, jobject object, jstring databaseName) +static void enableSqlTracing(JNIEnv* env, jobject object, jstring databaseName, jshort connType) { sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle); - sqlite3_trace(handle, &sqlTrace, (void *)getDatabaseName(env, handle, databaseName)); + sqlite3_trace(handle, &sqlTrace, (void *)getDatabaseName(env, handle, databaseName, connType)); } static void sqlProfile(void *databaseName, const char *sql, sqlite3_uint64 tm) { @@ -204,13 +208,13 @@ static void sqlProfile(void *databaseName, const char *sql, sqlite3_uint64 tm) { } /* public native void enableSqlProfiling(); */ -static void enableSqlProfiling(JNIEnv* env, jobject object, jstring databaseName) +static void enableSqlProfiling(JNIEnv* env, jobject object, jstring databaseName, jshort connType) { sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle); - sqlite3_profile(handle, &sqlProfile, (void *)getDatabaseName(env, handle, databaseName)); + sqlite3_profile(handle, &sqlProfile, (void *)getDatabaseName(env, handle, databaseName, + connType)); } - /* public native void close(); */ static void dbclose(JNIEnv* env, jobject object) { @@ -251,7 +255,8 @@ static void native_execSQL(JNIEnv* env, jobject object, jstring sqlString) jsize sqlLen = env->GetStringLength(sqlString); if (sql == NULL || sqlLen == 0) { - jniThrowException(env, "java/lang/IllegalArgumentException", "You must supply an SQL string"); + jniThrowException(env, "java/lang/IllegalArgumentException", + "You must supply an SQL string"); return; } @@ -261,7 +266,8 @@ static void native_execSQL(JNIEnv* env, jobject object, jstring sqlString) if (err != SQLITE_OK) { char const * sql8 = env->GetStringUTFChars(sqlString, NULL); - LOGE("Failure %d (%s) on %p when preparing '%s'.\n", err, sqlite3_errmsg(handle), handle, sql8); + LOGE("Failure %d (%s) on %p when preparing '%s'.\n", err, sqlite3_errmsg(handle), + handle, sql8); throw_sqlite3_exception(env, handle, sql8); env->ReleaseStringUTFChars(sqlString, sql8); return; @@ -272,10 +278,12 @@ static void native_execSQL(JNIEnv* env, jobject object, jstring sqlString) if (stepErr != SQLITE_DONE) { if (stepErr == SQLITE_ROW) { - throw_sqlite3_exception(env, "Queries cannot be performed using execSQL(), use query() instead."); + throw_sqlite3_exception(env, + "Queries cannot be performed using execSQL(), use query() instead."); } else { char const * sql8 = env->GetStringUTFChars(sqlString, NULL); - LOGE("Failure %d (%s) on %p when executing '%s'\n", err, sqlite3_errmsg(handle), handle, sql8); + LOGE("Failure %d (%s) on %p when executing '%s'\n", err, sqlite3_errmsg(handle), + handle, sql8); throw_sqlite3_exception(env, handle, sql8); env->ReleaseStringUTFChars(sqlString, sql8); @@ -443,19 +451,27 @@ static jint native_releaseMemory(JNIEnv *env, jobject clazz) return sqlite3_release_memory(SQLITE_SOFT_HEAP_LIMIT); } +static void native_finalize(JNIEnv* env, jobject object, jint statementId) +{ + if (statementId > 0) { + sqlite3_finalize((sqlite3_stmt *)statementId); + } +} + static JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ {"dbopen", "(Ljava/lang/String;I)V", (void *)dbopen}, {"dbclose", "()V", (void *)dbclose}, - {"enableSqlTracing", "(Ljava/lang/String;)V", (void *)enableSqlTracing}, - {"enableSqlProfiling", "(Ljava/lang/String;)V", (void *)enableSqlProfiling}, + {"enableSqlTracing", "(Ljava/lang/String;S)V", (void *)enableSqlTracing}, + {"enableSqlProfiling", "(Ljava/lang/String;S)V", (void *)enableSqlProfiling}, {"native_execSQL", "(Ljava/lang/String;)V", (void *)native_execSQL}, {"lastInsertRow", "()J", (void *)lastInsertRow}, {"lastChangeCount", "()I", (void *)lastChangeCount}, {"native_setLocale", "(Ljava/lang/String;I)V", (void *)native_setLocale}, {"native_getDbLookaside", "()I", (void *)native_getDbLookaside}, {"releaseMemory", "()I", (void *)native_releaseMemory}, + {"native_finalize", "(I)V", (void *)native_finalize}, }; int register_android_database_SQLiteDatabase(JNIEnv *env) @@ -474,7 +490,8 @@ int register_android_database_SQLiteDatabase(JNIEnv *env) return -1; } - return AndroidRuntime::registerNativeMethods(env, "android/database/sqlite/SQLiteDatabase", sMethods, NELEM(sMethods)); + return AndroidRuntime::registerNativeMethods(env, "android/database/sqlite/SQLiteDatabase", + sMethods, NELEM(sMethods)); } /* throw a SQLiteException with a message appropriate for the error in handle */ @@ -523,6 +540,7 @@ void throw_sqlite3_exception(JNIEnv* env, int errcode, exceptionClass = "android/database/sqlite/SQLiteDiskIOException"; break; case SQLITE_CORRUPT: + case SQLITE_NOTADB: // treat "unsupported file format" error as corruption also exceptionClass = "android/database/sqlite/SQLiteDatabaseCorruptException"; break; case SQLITE_CONSTRAINT: diff --git a/core/jni/android_database_SQLiteQuery.cpp b/core/jni/android_database_SQLiteQuery.cpp index 4427168..747ee50 100644 --- a/core/jni/android_database_SQLiteQuery.cpp +++ b/core/jni/android_database_SQLiteQuery.cpp @@ -29,7 +29,7 @@ #include <string.h> #include <unistd.h> -#include "CursorWindow.h" +#include "binder/CursorWindow.h" #include "sqlite3_exception.h" diff --git a/core/jni/android_database_SQLiteStatement.cpp b/core/jni/android_database_SQLiteStatement.cpp index ff2ed5d..0341e0b 100644 --- a/core/jni/android_database_SQLiteStatement.cpp +++ b/core/jni/android_database_SQLiteStatement.cpp @@ -58,7 +58,9 @@ static void native_execute(JNIEnv* env, jobject object) err = sqlite3_step(statement); // Throw an exception if an error occured - if (err != SQLITE_DONE) { + if (err == SQLITE_ROW) { + LOGV("Queries cannot be performed using execute(). use SQLiteDatabase.query() instead."); + } else if (err != SQLITE_DONE) { throw_sqlite3_exception_errcode(env, err, sqlite3_errmsg(handle)); } diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp index 50df9d3..feb0dad 100644 --- a/core/jni/android_net_NetUtils.cpp +++ b/core/jni/android_net_NetUtils.cpp @@ -22,8 +22,29 @@ #include <utils/Log.h> #include <arpa/inet.h> -#include <netutils/ifc.h> -#include <netutils/dhcp.h> +extern "C" { +int ifc_enable(const char *ifname); +int ifc_disable(const char *ifname); +int ifc_add_host_route(const char *ifname, uint32_t addr); +int ifc_remove_host_routes(const char *ifname); +int ifc_set_default_route(const char *ifname, uint32_t gateway); +int ifc_get_default_route(const char *ifname); +int ifc_remove_default_route(const char *ifname); +int ifc_reset_connections(const char *ifname); +int ifc_configure(const char *ifname, in_addr_t ipaddr, in_addr_t netmask, in_addr_t gateway, in_addr_t dns1, in_addr_t dns2); + +int dhcp_do_request(const char *ifname, + in_addr_t *ipaddr, + in_addr_t *gateway, + in_addr_t *mask, + in_addr_t *dns1, + in_addr_t *dns2, + in_addr_t *server, + uint32_t *lease); +int dhcp_stop(const char *ifname); +int dhcp_release_lease(const char *ifname); +char *dhcp_get_errmsg(); +} #define NETUTILS_PKG_NAME "android/net/NetworkUtils" diff --git a/core/jni/android_net_wifi_Wifi.cpp b/core/jni/android_net_wifi_Wifi.cpp index 3fc0d58..7392442 100644 --- a/core/jni/android_net_wifi_Wifi.cpp +++ b/core/jni/android_net_wifi_Wifi.cpp @@ -30,6 +30,23 @@ namespace android { static jboolean sScanModeActive = false; +/* + * The following remembers the jfieldID's of the fields + * of the DhcpInfo Java object, so that we don't have + * to look them up every time. + */ +static struct fieldIds { + jclass dhcpInfoClass; + jmethodID constructorId; + jfieldID ipaddress; + jfieldID gateway; + jfieldID netmask; + jfieldID dns1; + jfieldID dns2; + jfieldID serverAddress; + jfieldID leaseDuration; +} dhcpInfoFieldIds; + static int doCommand(const char *cmd, char *replybuf, int replybuflen) { size_t reply_len = replybuflen - 1; @@ -476,6 +493,28 @@ static jboolean android_net_wifi_clearBlacklistCommand(JNIEnv* env, jobject claz return doBooleanCommand("BLACKLIST clear", "OK"); } +static jboolean android_net_wifi_doDhcpRequest(JNIEnv* env, jobject clazz, jobject info) +{ + jint ipaddr, gateway, mask, dns1, dns2, server, lease; + jboolean succeeded = ((jboolean)::do_dhcp_request(&ipaddr, &gateway, &mask, + &dns1, &dns2, &server, &lease) == 0); + if (succeeded && dhcpInfoFieldIds.dhcpInfoClass != NULL) { + env->SetIntField(info, dhcpInfoFieldIds.ipaddress, ipaddr); + env->SetIntField(info, dhcpInfoFieldIds.gateway, gateway); + env->SetIntField(info, dhcpInfoFieldIds.netmask, mask); + env->SetIntField(info, dhcpInfoFieldIds.dns1, dns1); + env->SetIntField(info, dhcpInfoFieldIds.dns2, dns2); + env->SetIntField(info, dhcpInfoFieldIds.serverAddress, server); + env->SetIntField(info, dhcpInfoFieldIds.leaseDuration, lease); + } + return succeeded; +} + +static jstring android_net_wifi_getDhcpError(JNIEnv* env, jobject clazz) +{ + return env->NewStringUTF(::get_dhcp_error_string()); +} + // ---------------------------------------------------------------------------- /* @@ -532,6 +571,9 @@ static JNINativeMethod gWifiMethods[] = { { "setScanResultHandlingCommand", "(I)Z", (void*) android_net_wifi_setScanResultHandlingCommand }, { "addToBlacklistCommand", "(Ljava/lang/String;)Z", (void*) android_net_wifi_addToBlacklistCommand }, { "clearBlacklistCommand", "()Z", (void*) android_net_wifi_clearBlacklistCommand }, + + { "doDhcpRequest", "(Landroid/net/DhcpInfo;)Z", (void*) android_net_wifi_doDhcpRequest }, + { "getDhcpError", "()Ljava/lang/String;", (void*) android_net_wifi_getDhcpError }, }; int register_android_net_wifi_WifiManager(JNIEnv* env) @@ -539,6 +581,18 @@ int register_android_net_wifi_WifiManager(JNIEnv* env) jclass wifi = env->FindClass(WIFI_PKG_NAME); LOG_FATAL_IF(wifi == NULL, "Unable to find class " WIFI_PKG_NAME); + dhcpInfoFieldIds.dhcpInfoClass = env->FindClass("android/net/DhcpInfo"); + if (dhcpInfoFieldIds.dhcpInfoClass != NULL) { + dhcpInfoFieldIds.constructorId = env->GetMethodID(dhcpInfoFieldIds.dhcpInfoClass, "<init>", "()V"); + dhcpInfoFieldIds.ipaddress = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "ipAddress", "I"); + dhcpInfoFieldIds.gateway = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "gateway", "I"); + dhcpInfoFieldIds.netmask = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "netmask", "I"); + dhcpInfoFieldIds.dns1 = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "dns1", "I"); + dhcpInfoFieldIds.dns2 = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "dns2", "I"); + dhcpInfoFieldIds.serverAddress = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "serverAddress", "I"); + dhcpInfoFieldIds.leaseDuration = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "leaseDuration", "I"); + } + return AndroidRuntime::registerNativeMethods(env, WIFI_PKG_NAME, gWifiMethods, NELEM(gWifiMethods)); } diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp index 01b6711..3c88158 100644 --- a/core/jni/android_server_BluetoothEventLoop.cpp +++ b/core/jni/android_server_BluetoothEventLoop.cpp @@ -64,6 +64,8 @@ static jmethodID method_onDisplayPasskey; static jmethodID method_onAgentAuthorize; static jmethodID method_onAgentCancel; +static jmethodID method_onInputDevicePropertyChanged; + typedef event_loop_native_data_t native_data_t; #define EVENT_LOOP_REFS 10 @@ -116,6 +118,9 @@ static void classInitNative(JNIEnv* env, jclass clazz) { "(Ljava/lang/String;I)V"); method_onDisplayPasskey = env->GetMethodID(clazz, "onDisplayPasskey", "(Ljava/lang/String;II)V"); + method_onInputDevicePropertyChanged = env->GetMethodID(clazz, "onInputDevicePropertyChanged", + "(Ljava/lang/String;[Ljava/lang/String;)V"); + field_mNativeData = env->GetFieldID(clazz, "mNativeData", "I"); #endif @@ -853,6 +858,22 @@ static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg, method_onDeviceDisconnectRequested, env->NewStringUTF(remote_device_path)); goto success; + } else if (dbus_message_is_signal(msg, + "org.bluez.Input", + "PropertyChanged")) { + + jobjectArray str_array = + parse_input_property_change(env, msg); + if (str_array != NULL) { + const char *c_path = dbus_message_get_path(msg); + env->CallVoidMethod(nat->me, + method_onInputDevicePropertyChanged, + env->NewStringUTF(c_path), + str_array); + } else { + LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); + } + goto success; } ret = a2dp_event_filter(msg, env); diff --git a/core/jni/android_server_BluetoothService.cpp b/core/jni/android_server_BluetoothService.cpp index 4420aca..a52a74c 100644 --- a/core/jni/android_server_BluetoothService.cpp +++ b/core/jni/android_server_BluetoothService.cpp @@ -16,6 +16,8 @@ #define DBUS_ADAPTER_IFACE BLUEZ_DBUS_BASE_IFC ".Adapter" #define DBUS_DEVICE_IFACE BLUEZ_DBUS_BASE_IFC ".Device" +#define DBUS_INPUT_IFACE BLUEZ_DBUS_BASE_IFC ".Input" + #define LOG_TAG "BluetoothService.cpp" #include "android_bluetooth_common.h" @@ -881,6 +883,43 @@ static jboolean setLinkTimeoutNative(JNIEnv *env, jobject object, jstring object return JNI_FALSE; } +static jboolean connectInputDeviceNative(JNIEnv *env, jobject object, jstring path) { + LOGV(__FUNCTION__); +#ifdef HAVE_BLUETOOTH + native_data_t *nat = get_native_data(env, object); + if (nat) { + const char *c_path = env->GetStringUTFChars(path, NULL); + + bool ret = dbus_func_args_async(env, nat->conn, -1, NULL, NULL, nat, + c_path, DBUS_INPUT_IFACE, "Connect", + DBUS_TYPE_INVALID); + + env->ReleaseStringUTFChars(path, c_path); + return ret ? JNI_TRUE : JNI_FALSE; + } +#endif + return JNI_FALSE; +} + +static jboolean disconnectInputDeviceNative(JNIEnv *env, jobject object, + jstring path) { + LOGV(__FUNCTION__); +#ifdef HAVE_BLUETOOTH + native_data_t *nat = get_native_data(env, object); + if (nat) { + const char *c_path = env->GetStringUTFChars(path, NULL); + + bool ret = dbus_func_args_async(env, nat->conn, -1, NULL, NULL, nat, + c_path, DBUS_INPUT_IFACE, "Disconnect", + DBUS_TYPE_INVALID); + + env->ReleaseStringUTFChars(path, c_path); + return ret ? JNI_TRUE : JNI_FALSE; + } +#endif + return JNI_FALSE; +} + static JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ {"classInitNative", "()V", (void*)classInitNative}, @@ -926,6 +965,9 @@ static JNINativeMethod sMethods[] = { {"addRfcommServiceRecordNative", "(Ljava/lang/String;JJS)I", (void *)addRfcommServiceRecordNative}, {"removeServiceRecordNative", "(I)Z", (void *)removeServiceRecordNative}, {"setLinkTimeoutNative", "(Ljava/lang/String;I)Z", (void *)setLinkTimeoutNative}, + // HID functions + {"connectInputDeviceNative", "(Ljava/lang/String;)Z", (void *)connectInputDeviceNative}, + {"disconnectInputDeviceNative", "(Ljava/lang/String;)Z", (void *)disconnectInputDeviceNative}, }; int register_android_server_BluetoothService(JNIEnv *env) { diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp new file mode 100644 index 0000000..47f5bfc --- /dev/null +++ b/core/jni/android_view_GLES20Canvas.cpp @@ -0,0 +1,315 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * 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. + */ + +#include "jni.h" +#include <nativehelper/JNIHelp.h> +#include <android_runtime/AndroidRuntime.h> +#include <utils/ResourceTypes.h> + +#include <SkBitmap.h> +#include <SkCanvas.h> +#include <SkMatrix.h> +#include <SkPaint.h> +#include <SkXfermode.h> + +#include <OpenGLRenderer.h> +#include <Rect.h> +#include <ui/Rect.h> + +namespace android { + +using namespace uirenderer; + +// ---------------------------------------------------------------------------- +// Java APIs +// ---------------------------------------------------------------------------- + +static struct { + jclass clazz; + jmethodID set; +} gRectClassInfo; + +// ---------------------------------------------------------------------------- +// Constructors +// ---------------------------------------------------------------------------- + +static OpenGLRenderer* android_view_GLES20Canvas_createRenderer(JNIEnv* env, jobject canvas) { + return new OpenGLRenderer; +} + +static void android_view_GLES20Canvas_destroyRenderer(JNIEnv* env, jobject canvas, + OpenGLRenderer* renderer) { + delete renderer; +} + +// ---------------------------------------------------------------------------- +// Setup +// ---------------------------------------------------------------------------- + +static void android_view_GLES20Canvas_setViewport(JNIEnv* env, jobject canvas, + OpenGLRenderer* renderer, jint width, jint height) { + renderer->setViewport(width, height); +} + +static void android_view_GLES20Canvas_prepare(JNIEnv* env, jobject canvas, + OpenGLRenderer* renderer) { + renderer->prepare(); +} + +// ---------------------------------------------------------------------------- +// State +// ---------------------------------------------------------------------------- + +static jint android_view_GLES20Canvas_save(JNIEnv* env, jobject canvas, OpenGLRenderer* renderer, + jint flags) { + return renderer->save(flags); +} + +static jint android_view_GLES20Canvas_getSaveCount(JNIEnv* env, jobject canvas, + OpenGLRenderer* renderer) { + return renderer->getSaveCount(); +} + +static void android_view_GLES20Canvas_restore(JNIEnv* env, jobject canvas, + OpenGLRenderer* renderer) { + renderer->restore(); +} + +static void android_view_GLES20Canvas_restoreToCount(JNIEnv* env, jobject canvas, + OpenGLRenderer* renderer, jint saveCount) { + renderer->restoreToCount(saveCount); +} + +// ---------------------------------------------------------------------------- +// Layers +// ---------------------------------------------------------------------------- + +static jint android_view_GLES20Canvas_saveLayer(JNIEnv* env, jobject canvas, + OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom, + SkPaint* paint, jint saveFlags) { + return renderer->saveLayer(left, top, right, bottom, paint, saveFlags); +} + +static jint android_view_GLES20Canvas_saveLayerAlpha(JNIEnv* env, jobject canvas, + OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom, + jint alpha, jint saveFlags) { + return renderer->saveLayerAlpha(left, top, right, bottom, alpha, saveFlags); +} + +// ---------------------------------------------------------------------------- +// Clipping +// ---------------------------------------------------------------------------- + +static bool android_view_GLES20Canvas_quickReject(JNIEnv* env, jobject canvas, + OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom, + SkCanvas::EdgeType edge) { + return renderer->quickReject(left, top, right, bottom); +} + +static bool android_view_GLES20Canvas_clipRectF(JNIEnv* env, jobject canvas, + OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom) { + return renderer->clipRect(left, top, right, bottom); +} + +static bool android_view_GLES20Canvas_clipRect(JNIEnv* env, jobject canvas, + OpenGLRenderer* renderer, jint left, jint top, jint right, jint bottom) { + return renderer->clipRect(float(left), float(top), float(right), float(bottom)); +} + +static bool android_view_GLES20Canvas_getClipBounds(JNIEnv* env, jobject canvas, + OpenGLRenderer* renderer, jobject rect) { + const android::uirenderer::Rect& bounds(renderer->getClipBounds()); + + env->CallVoidMethod(rect, gRectClassInfo.set, + int(bounds.left), int(bounds.top), int(bounds.right), int(bounds.bottom)); + + return !bounds.isEmpty(); +} + +// ---------------------------------------------------------------------------- +// Transforms +// ---------------------------------------------------------------------------- + +static void android_view_GLES20Canvas_translate(JNIEnv* env, jobject canvas, + OpenGLRenderer* renderer, jfloat dx, jfloat dy) { + renderer->translate(dx, dy); +} + +static void android_view_GLES20Canvas_rotate(JNIEnv* env, jobject canvas, + OpenGLRenderer* renderer, jfloat degrees) { + renderer->rotate(degrees); +} + +static void android_view_GLES20Canvas_scale(JNIEnv* env, jobject canvas, + OpenGLRenderer* renderer, jfloat sx, jfloat sy) { + renderer->scale(sx, sy); +} + +static void android_view_GLES20Canvas_setMatrix(JNIEnv* env, jobject canvas, + OpenGLRenderer* renderer, SkMatrix* matrix) { + renderer->setMatrix(matrix); +} + +static void android_view_GLES20Canvas_getMatrix(JNIEnv* env, jobject canvas, + OpenGLRenderer* renderer, SkMatrix* matrix) { + renderer->getMatrix(matrix); +} + +static void android_view_GLES20Canvas_concatMatrix(JNIEnv* env, jobject canvas, + OpenGLRenderer* renderer, SkMatrix* matrix) { + renderer->concatMatrix(matrix); +} + +// ---------------------------------------------------------------------------- +// Drawing +// ---------------------------------------------------------------------------- + +static void android_view_GLES20Canvas_drawBitmap(JNIEnv* env, jobject canvas, + OpenGLRenderer* renderer, SkBitmap* bitmap, float left, float top, + SkPaint* paint, jint bitmapDensity, jint canvasDensity,jint screenDensity) { + if (canvasDensity == bitmapDensity || canvasDensity == 0 || bitmapDensity == 0) { + renderer->drawBitmap(bitmap, left, top, paint); + } else { + renderer->save(0); + const float scale = canvasDensity / float(bitmapDensity); + renderer->translate(left, top); + renderer->scale(scale, scale); + renderer->drawBitmap(bitmap, left, top, paint); + renderer->restore(); + } +} + +static void android_view_GLES20Canvas_drawBitmapRect(JNIEnv* env, jobject canvas, + OpenGLRenderer* renderer, SkBitmap* bitmap, + float srcLeft, float srcTop, float srcRight, float srcBottom, + float dstLeft, float dstTop, float dstRight, float dstBottom, + SkPaint* paint, jint bitmapDensity, jint canvasDensity, jint screenDensity) { + if (canvasDensity == bitmapDensity || canvasDensity == 0 || bitmapDensity == 0) { + renderer->drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom, + dstLeft, dstTop, dstRight, dstBottom, paint); + } else { + // TODO: implement + } +} + +static void android_view_GLES20Canvas_drawBitmapMatrix(JNIEnv* env, jobject canvas, + OpenGLRenderer* renderer, SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint, + jint bitmapDensity, jint canvasDensity,jint screenDensity) { + if (canvasDensity == bitmapDensity || canvasDensity == 0 || bitmapDensity == 0) { + renderer->drawBitmap(bitmap, matrix, paint); + } else { + // TODO: implement + } +} + +static void android_view_GLES20Canvas_drawPatch(JNIEnv* env, jobject canvas, + OpenGLRenderer* renderer, SkBitmap* bitmap, jbyteArray chunks, + float left, float top, float right, float bottom, SkPaint* paint, + jint bitmapDensity, jint canvasDensity,jint screenDensity) { + + jbyte* storage = env->GetByteArrayElements(chunks, NULL); + Res_png_9patch* patch = reinterpret_cast<Res_png_9patch*>(storage); + Res_png_9patch::deserialize(patch); + + if (canvasDensity == bitmapDensity || canvasDensity == 0 || bitmapDensity == 0) { + renderer->drawPatch(bitmap, patch, left, top, right, bottom, paint); + } else { + renderer->save(0); + const float scale = canvasDensity / float(bitmapDensity); + renderer->translate(left, top); + renderer->scale(scale, scale); + left = top = 0.0f; + right = (right - left) / scale; + bottom = (bottom - top) / scale; + renderer->drawPatch(bitmap, patch, left, top, right, bottom, paint); + renderer->restore(); + } + + // TODO: make sure that 0 is correct for the flags + env->ReleaseByteArrayElements(chunks, storage, 0); +} + +static void android_view_GLES20Canvas_drawColor(JNIEnv* env, jobject canvas, + OpenGLRenderer* renderer, jint color, SkXfermode::Mode mode) { + renderer->drawColor(color, mode); +} + +static void android_view_GLES20Canvas_drawRect(JNIEnv* env, jobject canvas, + OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom, + SkPaint* paint) { + renderer->drawRect(left, top, right, bottom, paint); +} + +// ---------------------------------------------------------------------------- +// JNI Glue +// ---------------------------------------------------------------------------- + +const char* const kClassPathName = "android/view/GLES20Canvas"; + +static JNINativeMethod gMethods[] = { + { "nCreateRenderer", "()I", (void*) android_view_GLES20Canvas_createRenderer }, + { "nDestroyRenderer", "(I)V", (void*) android_view_GLES20Canvas_destroyRenderer }, + { "nSetViewport", "(III)V", (void*) android_view_GLES20Canvas_setViewport }, + { "nPrepare", "(I)V", (void*) android_view_GLES20Canvas_prepare }, + + { "nSave", "(II)I", (void*) android_view_GLES20Canvas_save }, + { "nRestore", "(I)V", (void*) android_view_GLES20Canvas_restore }, + { "nRestoreToCount", "(II)V", (void*) android_view_GLES20Canvas_restoreToCount }, + { "nGetSaveCount", "(I)I", (void*) android_view_GLES20Canvas_getSaveCount }, + + { "nSaveLayer", "(IFFFFII)I", (void*) android_view_GLES20Canvas_saveLayer }, + { "nSaveLayerAlpha", "(IFFFFII)I", (void*) android_view_GLES20Canvas_saveLayerAlpha }, + + { "nQuickReject", "(IFFFFI)Z", (void*) android_view_GLES20Canvas_quickReject }, + { "nClipRect", "(IFFFF)Z", (void*) android_view_GLES20Canvas_clipRectF }, + { "nClipRect", "(IIIII)Z", (void*) android_view_GLES20Canvas_clipRect }, + + { "nTranslate", "(IFF)V", (void*) android_view_GLES20Canvas_translate }, + { "nRotate", "(IF)V", (void*) android_view_GLES20Canvas_rotate }, + { "nScale", "(IFF)V", (void*) android_view_GLES20Canvas_scale }, + + { "nSetMatrix", "(II)V", (void*) android_view_GLES20Canvas_setMatrix }, + { "nGetMatrix", "(II)V", (void*) android_view_GLES20Canvas_getMatrix }, + { "nConcatMatrix", "(II)V", (void*) android_view_GLES20Canvas_concatMatrix }, + + { "nDrawBitmap", "(IIFFIIII)V", (void*) android_view_GLES20Canvas_drawBitmap }, + { "nDrawBitmap", "(IIFFFFFFFFIIII)V", (void*) android_view_GLES20Canvas_drawBitmapRect }, + { "nDrawBitmap", "(IIIIIII)V", (void*) android_view_GLES20Canvas_drawBitmapMatrix }, + { "nDrawPatch", "(II[BFFFFIIII)V", (void*) android_view_GLES20Canvas_drawPatch }, + { "nDrawColor", "(III)V", (void*) android_view_GLES20Canvas_drawColor }, + { "nDrawRect", "(IFFFFI)V", (void*) android_view_GLES20Canvas_drawRect }, + + { "nGetClipBounds", "(ILandroid/graphics/Rect;)Z", + (void*) android_view_GLES20Canvas_getClipBounds }, +}; + +#define FIND_CLASS(var, className) \ + var = env->FindClass(className); \ + LOG_FATAL_IF(! var, "Unable to find class " className); \ + var = jclass(env->NewGlobalRef(var)); + +#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \ + var = env->GetMethodID(clazz, methodName, methodDescriptor); \ + LOG_FATAL_IF(! var, "Unable to find method " methodName); + +int register_android_view_GLES20Canvas(JNIEnv* env) { + FIND_CLASS(gRectClassInfo.clazz, "android/graphics/Rect"); + GET_METHOD_ID(gRectClassInfo.set, gRectClassInfo.clazz, "set", "(IIII)V"); + + return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)); +} + +}; diff --git a/core/jni/android_view_HardwareRenderer.cpp b/core/jni/android_view_HardwareRenderer.cpp new file mode 100644 index 0000000..abd788b --- /dev/null +++ b/core/jni/android_view_HardwareRenderer.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * 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. + */ + +#include <utils/SkGLCanvas.h> + +#include "jni.h" +#include <nativehelper/JNIHelp.h> +#include <android_runtime/AndroidRuntime.h> +#include <utils/misc.h> + +// ---------------------------------------------------------------------------- + +namespace android { + +static void android_view_HardwareRenderer_abandonGlCaches(JNIEnv* env, jobject) { + SkGLCanvas::AbandonAllTextures(); +} + +// ---------------------------------------------------------------------------- + +const char* const kClassPathName = "android/view/HardwareRenderer"; + +static JNINativeMethod gMethods[] = { + { "nativeAbandonGlCaches", "()V", + (void*)android_view_HardwareRenderer_abandonGlCaches }, +}; + +int register_android_view_HardwareRenderer(JNIEnv* env) { + return AndroidRuntime::registerNativeMethods(env, + kClassPathName, gMethods, NELEM(gMethods)); +} + +}; diff --git a/core/jni/android_view_ViewRoot.cpp b/core/jni/android_view_ViewRoot.cpp index 5173bb8..2988ae8 100644 --- a/core/jni/android_view_ViewRoot.cpp +++ b/core/jni/android_view_ViewRoot.cpp @@ -76,10 +76,6 @@ static void android_view_ViewRoot_showFPS(JNIEnv* env, jobject, jobject jcanvas, canvas->restore(); } -static void android_view_ViewRoot_abandonGlCaches(JNIEnv* env, jobject) { - SkGLCanvas::AbandonAllTextures(); -} - // ---------------------------------------------------------------------------- @@ -87,9 +83,7 @@ const char* const kClassPathName = "android/view/ViewRoot"; static JNINativeMethod gMethods[] = { { "nativeShowFPS", "(Landroid/graphics/Canvas;I)V", - (void*)android_view_ViewRoot_showFPS }, - { "nativeAbandonGlCaches", "()V", - (void*)android_view_ViewRoot_abandonGlCaches } + (void*)android_view_ViewRoot_showFPS } }; int register_android_view_ViewRoot(JNIEnv* env) { |