diff options
-rw-r--r-- | jni/com_android_terminal_Terminal.cpp | 72 | ||||
-rw-r--r-- | src/com/android/terminal/Terminal.java | 17 | ||||
-rw-r--r-- | src/com/android/terminal/TerminalView.java | 42 |
3 files changed, 92 insertions, 39 deletions
diff --git a/jni/com_android_terminal_Terminal.cpp b/jni/com_android_terminal_Terminal.cpp index 31589aa..4a3fecb 100644 --- a/jni/com_android_terminal_Terminal.cpp +++ b/jni/com_android_terminal_Terminal.cpp @@ -60,15 +60,15 @@ static jmethodID bellMethod; static jmethodID resizeMethod; /* - * Cell class + * CellRun class */ -static jclass cellClass; -static jfieldID cellCharsField; - +static jclass cellRunClass; +static jfieldID cellRunDataField; +static jfieldID cellRunDataSizeField; +static jfieldID cellRunColSizeField; /* * Terminal session */ - class Terminal { public: Terminal(jobject callbacks, int rows, int cols); @@ -344,6 +344,7 @@ int Terminal::readLoop() { int Terminal::resize(short unsigned int rows, short unsigned int cols) { ALOGD("resize(%d, %d)", rows, cols); + // TODO: wait for resize event to propegate back from shell? mRows = rows; mCols = cols; struct winsize size = { rows, cols, 0, 0 }; @@ -395,29 +396,52 @@ static jint com_android_terminal_Terminal_nativeResize(JNIEnv* env, return term->resize(rows, cols); } -static jint com_android_terminal_Terminal_nativeGetCell(JNIEnv* env, - jclass clazz, jint ptr, jint row, jint col, jobject cell) { +static jint com_android_terminal_Terminal_nativeGetCellRun(JNIEnv* env, + jclass clazz, jint ptr, jint row, jint col, jobject run) { Terminal* term = reinterpret_cast<Terminal*>(ptr); + jcharArray dataArray = (jcharArray) env->GetObjectField(run, cellRunDataField); + jchar* data = env->GetCharArrayElements(dataArray, 0); + int dataLen = env->GetArrayLength(dataArray); + + VTermScreenCell cell; + memset(&cell, 0, sizeof(VTermScreenCell)); + VTermPos pos = { .row = row, .col = col, }; - VTermScreenCell termCell; - memset(&termCell, 0, sizeof(VTermScreenCell)); - int res = term->getCell(pos, &termCell); + int dataSize = 0; + int colSize = 0; + while (pos.col < term->getCols()) { + int res = term->getCell(pos, &cell); - //ALOGD("getCell(%d, %d, %s)", row, col, termCell.chars); + // TODO: terminate this loop once text style changes - // TODO: support full UTF-32 characters - // for testing, 0x00020000 should become 0xD840 0xDC00 + // TODO: remove this once terminal is resized + if (cell.width == 0) { + cell.width = 1; + } + + // TODO: support full UTF-32 characters + // for testing, 0x00020000 should become 0xD840 0xDC00 + int size = 1; + + // Only include cell chars if they fit into run + if (dataSize + size <= dataLen) { + data[dataSize] = cell.chars[0]; + dataSize += size; + colSize += cell.width; + pos.col += cell.width; + } else { + break; + } + } - jintArray charsArray = (jintArray)env->GetObjectField(cell, cellCharsField); - jint *chars = env->GetIntArrayElements(charsArray, 0); - chars[0] = termCell.chars[0]; - chars[1] = 0x00; - env->ReleaseIntArrayElements(charsArray, chars, 0); + env->ReleaseCharArrayElements(dataArray, data, 0); + env->SetIntField(run, cellRunDataSizeField, dataSize); + env->SetIntField(run, cellRunColSizeField, colSize); return 0; } @@ -436,7 +460,7 @@ static JNINativeMethod gMethods[] = { { "nativeInit", "(Lcom/android/terminal/TerminalCallbacks;II)I", (void*)com_android_terminal_Terminal_nativeInit }, { "nativeReadLoop", "(I)I", (void*)com_android_terminal_Terminal_nativeReadLoop }, { "nativeResize", "(III)I", (void*)com_android_terminal_Terminal_nativeResize }, - { "nativeGetCell", "(IIILcom/android/terminal/Terminal$Cell;)I", (void*)com_android_terminal_Terminal_nativeGetCell }, + { "nativeGetCellRun", "(IIILcom/android/terminal/Terminal$CellRun;)I", (void*)com_android_terminal_Terminal_nativeGetCellRun }, { "nativeGetRows", "(I)I", (void*)com_android_terminal_Terminal_nativeGetRows }, { "nativeGetCols", "(I)I", (void*)com_android_terminal_Terminal_nativeGetCols }, }; @@ -463,10 +487,12 @@ int register_com_android_terminal_Terminal(JNIEnv* env) { android::bellMethod = env->GetMethodID(terminalCallbacksClass, "bell", "()I"); android::resizeMethod = env->GetMethodID(terminalCallbacksClass, "resize", "(II)I"); - ScopedLocalRef<jclass> cellLocal(env, - env->FindClass("com/android/terminal/Terminal$Cell")); - cellClass = reinterpret_cast<jclass>(env->NewGlobalRef(cellLocal.get())); - cellCharsField = env->GetFieldID(cellClass, "chars", "[C"); + ScopedLocalRef<jclass> cellRunLocal(env, + env->FindClass("com/android/terminal/Terminal$CellRun")); + cellRunClass = reinterpret_cast<jclass>(env->NewGlobalRef(cellRunLocal.get())); + cellRunDataField = env->GetFieldID(cellRunClass, "data", "[C"); + cellRunDataSizeField = env->GetFieldID(cellRunClass, "dataSize", "I"); + cellRunColSizeField = env->GetFieldID(cellRunClass, "colSize", "I"); env->GetJavaVM(&gJavaVM); diff --git a/src/com/android/terminal/Terminal.java b/src/com/android/terminal/Terminal.java index 7d4197c..dfd370b 100644 --- a/src/com/android/terminal/Terminal.java +++ b/src/com/android/terminal/Terminal.java @@ -26,9 +26,14 @@ public class Terminal { System.loadLibrary("jni_terminal"); } - public static class Cell { - char[] chars = new char[2]; - int width = 1; + /** + * Represents a run of one or more {@code VTermScreenCell} which all have + * the same formatting. + */ + public static class CellRun { + char[] data; + int dataSize; + int colSize; boolean bold; int underline; @@ -97,8 +102,8 @@ public class Terminal { return nativeGetCols(mNativePtr); } - public void getCell(int row, int col, Cell cell) { - if (nativeGetCell(mNativePtr, row, col, cell) != 0) { + public void getCellRun(int row, int col, CellRun run) { + if (nativeGetCellRun(mNativePtr, row, col, run) != 0) { throw new IllegalStateException("getCell failed"); } } @@ -106,7 +111,7 @@ public class Terminal { private static native int nativeInit(TerminalCallbacks callbacks, int rows, int cols); private static native int nativeReadLoop(int ptr); private static native int nativeResize(int ptr, int rows, int cols); - private static native int nativeGetCell(int ptr, int row, int col, Cell cell); + private static native int nativeGetCellRun(int ptr, int row, int col, CellRun run); private static native int nativeGetRows(int ptr); private static native int nativeGetCols(int ptr); } diff --git a/src/com/android/terminal/TerminalView.java b/src/com/android/terminal/TerminalView.java index adbb0a7..33b651b 100644 --- a/src/com/android/terminal/TerminalView.java +++ b/src/com/android/terminal/TerminalView.java @@ -20,6 +20,7 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; +import android.graphics.Typeface; import android.graphics.Paint.FontMetrics; import android.graphics.Rect; import android.view.View; @@ -93,6 +94,7 @@ public class TerminalView extends View { } public void setTextSize(float textSize) { + mTextPaint.setTypeface(Typeface.MONOSPACE); mTextPaint.setTextSize(textSize); // Read metrics to get exact pixel dimensions @@ -126,6 +128,8 @@ public class TerminalView extends View { updateTerminalSize(); } } + + private static final int MAX_RUN_LENGTH = 128; @Override protected void onDraw(Canvas canvas) { @@ -136,28 +140,46 @@ public class TerminalView extends View { // Only draw dirty region of console final Rect dirty = canvas.getClipBounds(); + final int rows = mTerm.getRows(); + final int cols = mTerm.getCols(); + final int startRow = dirty.top / mCharHeight; - final int endRow = dirty.bottom / mCharHeight; + final int endRow = Math.min(dirty.bottom / mCharHeight, rows - 1); final int startCol = dirty.left / mCharWidth; - final int endCol = dirty.right / mCharWidth; + final int endCol = Math.min(dirty.right / mCharWidth, cols - 1); + + final Terminal.CellRun run = new Terminal.CellRun(); + run.data = new char[MAX_RUN_LENGTH]; - final Terminal.Cell cell = new Terminal.Cell(); + // Positions of each possible cell + // TODO: make sure this works with surrogate pairs + final float[] pos = new float[MAX_RUN_LENGTH * 2]; + for (int i = 0; i < MAX_RUN_LENGTH; i++) { + pos[i * 2] = i * mCharWidth; + pos[(i * 2) + 1] = -mCharTop; + } for (int row = startRow; row <= endRow; row++) { for (int col = startCol; col <= endCol;) { - mTerm.getCell(row, col, cell); + mTerm.getCellRun(row, col, run); - mBgPaint.setColor(cell.bgColor); - mTextPaint.setColor(cell.fgColor); + mBgPaint.setColor(run.bgColor); + mTextPaint.setColor(run.fgColor); final int y = row * mCharHeight; final int x = col * mCharWidth; - final int xEnd = x + (cell.width * mCharWidth); + final int xEnd = x + (run.colSize * mCharWidth); + + canvas.save(Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG); + canvas.translate(x, y); + canvas.clipRect(0, 0, run.colSize * mCharWidth, mCharHeight); + + canvas.drawPaint(mBgPaint); + canvas.drawPosText(run.data, 0, run.dataSize, pos, mTextPaint); - canvas.drawRect(x, y, xEnd, y + mCharHeight, mBgPaint); - canvas.drawText(cell.chars, 0, cell.chars.length, x, y - mCharTop, mTextPaint); + canvas.restore(); - col += cell.width; + col += run.colSize; } } |