mirror of
https://github.com/fankes/termux-app.git
synced 2025-09-06 18:55:31 +08:00
Implement true (24-bit) color
This commit is contained in:
@@ -140,7 +140,7 @@ public final class TerminalBuffer {
|
|||||||
* @param newRows The number of rows the screen should have.
|
* @param newRows The number of rows the screen should have.
|
||||||
* @param cursor An int[2] containing the (column, row) cursor location.
|
* @param cursor An int[2] containing the (column, row) cursor location.
|
||||||
*/
|
*/
|
||||||
public void resize(int newColumns, int newRows, int newTotalRows, int[] cursor, int currentStyle, boolean altScreen) {
|
public void resize(int newColumns, int newRows, int newTotalRows, int[] cursor, long currentStyle, boolean altScreen) {
|
||||||
// newRows > mTotalRows should not normally happen since mTotalRows is TRANSCRIPT_ROWS (10000):
|
// newRows > mTotalRows should not normally happen since mTotalRows is TRANSCRIPT_ROWS (10000):
|
||||||
if (newColumns == mColumns && newRows <= mTotalRows) {
|
if (newColumns == mColumns && newRows <= mTotalRows) {
|
||||||
// Fast resize where just the rows changed.
|
// Fast resize where just the rows changed.
|
||||||
@@ -237,7 +237,7 @@ public final class TerminalBuffer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int currentOldCol = 0;
|
int currentOldCol = 0;
|
||||||
int styleAtCol = 0;
|
long styleAtCol = 0;
|
||||||
for (int i = 0; i < lastNonSpaceIndex; i++) {
|
for (int i = 0; i < lastNonSpaceIndex; i++) {
|
||||||
// Note that looping over java character, not cells.
|
// Note that looping over java character, not cells.
|
||||||
char c = oldLine.mText[i];
|
char c = oldLine.mText[i];
|
||||||
@@ -321,7 +321,7 @@ public final class TerminalBuffer {
|
|||||||
* @param bottomMargin One line after the last line that is scrolled.
|
* @param bottomMargin One line after the last line that is scrolled.
|
||||||
* @param style the style for the newly exposed line.
|
* @param style the style for the newly exposed line.
|
||||||
*/
|
*/
|
||||||
public void scrollDownOneLine(int topMargin, int bottomMargin, int style) {
|
public void scrollDownOneLine(int topMargin, int bottomMargin, long style) {
|
||||||
if (topMargin > bottomMargin - 1 || topMargin < 0 || bottomMargin > mScreenRows)
|
if (topMargin > bottomMargin - 1 || topMargin < 0 || bottomMargin > mScreenRows)
|
||||||
throw new IllegalArgumentException("topMargin=" + topMargin + ", bottomMargin=" + bottomMargin + ", mScreenRows=" + mScreenRows);
|
throw new IllegalArgumentException("topMargin=" + topMargin + ", bottomMargin=" + bottomMargin + ", mScreenRows=" + mScreenRows);
|
||||||
|
|
||||||
@@ -374,7 +374,7 @@ public final class TerminalBuffer {
|
|||||||
* InvalidParemeterException will be thrown. Typically this is called with a "val" argument of 32 to clear a block
|
* InvalidParemeterException will be thrown. Typically this is called with a "val" argument of 32 to clear a block
|
||||||
* of characters.
|
* of characters.
|
||||||
*/
|
*/
|
||||||
public void blockSet(int sx, int sy, int w, int h, int val, int style) {
|
public void blockSet(int sx, int sy, int w, int h, int val, long style) {
|
||||||
if (sx < 0 || sx + w > mColumns || sy < 0 || sy + h > mScreenRows) {
|
if (sx < 0 || sx + w > mColumns || sy < 0 || sy + h > mScreenRows) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"Illegal arguments! blockSet(" + sx + ", " + sy + ", " + w + ", " + h + ", " + val + ", " + mColumns + ", " + mScreenRows + ")");
|
"Illegal arguments! blockSet(" + sx + ", " + sy + ", " + w + ", " + h + ", " + val + ", " + mColumns + ", " + mScreenRows + ")");
|
||||||
@@ -388,14 +388,14 @@ public final class TerminalBuffer {
|
|||||||
return (mLines[row] == null) ? (mLines[row] = new TerminalRow(mColumns, 0)) : mLines[row];
|
return (mLines[row] == null) ? (mLines[row] = new TerminalRow(mColumns, 0)) : mLines[row];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setChar(int column, int row, int codePoint, int style) {
|
public void setChar(int column, int row, int codePoint, long style) {
|
||||||
if (row >= mScreenRows || column >= mColumns)
|
if (row >= mScreenRows || column >= mColumns)
|
||||||
throw new IllegalArgumentException("row=" + row + ", column=" + column + ", mScreenRows=" + mScreenRows + ", mColumns=" + mColumns);
|
throw new IllegalArgumentException("row=" + row + ", column=" + column + ", mScreenRows=" + mScreenRows + ", mColumns=" + mColumns);
|
||||||
row = externalToInternalRow(row);
|
row = externalToInternalRow(row);
|
||||||
allocateFullLineIfNecessary(row).setChar(column, codePoint, style);
|
allocateFullLineIfNecessary(row).setChar(column, codePoint, style);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getStyleAt(int externalRow, int column) {
|
public long getStyleAt(int externalRow, int column) {
|
||||||
return allocateFullLineIfNecessary(externalToInternalRow(externalRow)).getStyle(column);
|
return allocateFullLineIfNecessary(externalToInternalRow(externalRow)).getStyle(column);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -407,7 +407,7 @@ public final class TerminalBuffer {
|
|||||||
int startOfLine = (rectangular || y == top) ? left : leftMargin;
|
int startOfLine = (rectangular || y == top) ? left : leftMargin;
|
||||||
int endOfLine = (rectangular || y + 1 == bottom) ? right : rightMargin;
|
int endOfLine = (rectangular || y + 1 == bottom) ? right : rightMargin;
|
||||||
for (int x = startOfLine; x < endOfLine; x++) {
|
for (int x = startOfLine; x < endOfLine; x++) {
|
||||||
int currentStyle = line.getStyle(x);
|
long currentStyle = line.getStyle(x);
|
||||||
int foreColor = TextStyle.decodeForeColor(currentStyle);
|
int foreColor = TextStyle.decodeForeColor(currentStyle);
|
||||||
int backColor = TextStyle.decodeBackColor(currentStyle);
|
int backColor = TextStyle.decodeBackColor(currentStyle);
|
||||||
int effect = TextStyle.decodeEffect(currentStyle);
|
int effect = TextStyle.decodeEffect(currentStyle);
|
||||||
|
@@ -206,10 +206,15 @@ public final class TerminalEmulator {
|
|||||||
*/
|
*/
|
||||||
private boolean mAboutToAutoWrap;
|
private boolean mAboutToAutoWrap;
|
||||||
|
|
||||||
/** Foreground and background color indices, 0..255. */
|
/**
|
||||||
|
* Current foreground and background colors. Can either be a color index in [0,259] or a truecolor (24-bit) value.
|
||||||
|
* For a 24-bit value the top byte (0xff000000) is set.
|
||||||
|
*
|
||||||
|
* @see TextStyle
|
||||||
|
*/
|
||||||
int mForeColor, mBackColor;
|
int mForeColor, mBackColor;
|
||||||
|
|
||||||
/** Current TextStyle effect */
|
/** Current {@link TextStyle} effect. */
|
||||||
private int mEffect;
|
private int mEffect;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -611,7 +616,7 @@ public final class TerminalEmulator {
|
|||||||
int left = Math.min(getArg(argIndex++, 1, true) + effectiveLeftMargin, effectiveRightMargin + 1);
|
int left = Math.min(getArg(argIndex++, 1, true) + effectiveLeftMargin, effectiveRightMargin + 1);
|
||||||
int bottom = Math.min(getArg(argIndex++, mRows, true) + effectiveTopMargin, effectiveBottomMargin);
|
int bottom = Math.min(getArg(argIndex++, mRows, true) + effectiveTopMargin, effectiveBottomMargin);
|
||||||
int right = Math.min(getArg(argIndex, mColumns, true) + effectiveLeftMargin, effectiveRightMargin);
|
int right = Math.min(getArg(argIndex, mColumns, true) + effectiveLeftMargin, effectiveRightMargin);
|
||||||
int style = getStyle();
|
long style = getStyle();
|
||||||
for (int row = top - 1; row < bottom; row++)
|
for (int row = top - 1; row < bottom; row++)
|
||||||
for (int col = left - 1; col < right; col++)
|
for (int col = left - 1; col < right; col++)
|
||||||
if (!selective || (TextStyle.decodeEffect(mScreen.getStyleAt(row, col)) & TextStyle.CHARACTER_ATTRIBUTE_PROTECTED) == 0)
|
if (!selective || (TextStyle.decodeEffect(mScreen.getStyleAt(row, col)) & TextStyle.CHARACTER_ATTRIBUTE_PROTECTED) == 0)
|
||||||
@@ -953,7 +958,7 @@ public final class TerminalEmulator {
|
|||||||
unknownSequence(b);
|
unknownSequence(b);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
int style = getStyle();
|
long style = getStyle();
|
||||||
for (int row = startRow; row < endRow; row++) {
|
for (int row = startRow; row < endRow; row++) {
|
||||||
for (int col = startCol; col < endCol; col++) {
|
for (int col = startCol; col < endCol; col++) {
|
||||||
if ((TextStyle.decodeEffect(mScreen.getStyleAt(row, col)) & TextStyle.CHARACTER_ATTRIBUTE_PROTECTED) == 0)
|
if ((TextStyle.decodeEffect(mScreen.getStyleAt(row, col)) & TextStyle.CHARACTER_ATTRIBUTE_PROTECTED) == 0)
|
||||||
@@ -1687,11 +1692,10 @@ public final class TerminalEmulator {
|
|||||||
} else if (code >= 30 && code <= 37) {
|
} else if (code >= 30 && code <= 37) {
|
||||||
mForeColor = code - 30;
|
mForeColor = code - 30;
|
||||||
} else if (code == 38 || code == 48) {
|
} else if (code == 38 || code == 48) {
|
||||||
// ISO-8613-3 controls to set foreground (38) or background (48) colors.
|
// Extended set foreground(38)/background (48) color.
|
||||||
// P_s = (38|48) ; 2 ; P_r ; P_g ; P_b => Set to RGB value in range (0-255).
|
// This is followed by either "2;$R;$G;$B" to set a 24-bit color or
|
||||||
// P_s = (38|48) ; 5 ; P_s => Set to indexed color.
|
// "5;$INDEX" to set an indexed color.
|
||||||
if (i + 2 <= mArgIndex) {
|
if (i + 2 > mArgIndex) continue;
|
||||||
int color = -1;
|
|
||||||
int firstArg = mArgs[i + 1];
|
int firstArg = mArgs[i + 1];
|
||||||
if (firstArg == 2) {
|
if (firstArg == 2) {
|
||||||
if (i + 4 > mArgIndex) {
|
if (i + 4 > mArgIndex) {
|
||||||
@@ -1701,18 +1705,18 @@ public final class TerminalEmulator {
|
|||||||
if (red < 0 || green < 0 || blue < 0 || red > 255 || green > 255 || blue > 255) {
|
if (red < 0 || green < 0 || blue < 0 || red > 255 || green > 255 || blue > 255) {
|
||||||
finishSequenceAndLogError("Invalid RGB: " + red + "," + green + "," + blue);
|
finishSequenceAndLogError("Invalid RGB: " + red + "," + green + "," + blue);
|
||||||
} else {
|
} else {
|
||||||
// TODO: Implement 24 bit color.
|
int argbColor = 0xff000000 | (red << 16) | (green << 8) | blue;
|
||||||
finishSequenceAndLogError("Unimplemented RGB: " + red + "," + green + "," + blue);
|
if (code == 38) {
|
||||||
|
mForeColor = argbColor;
|
||||||
|
} else {
|
||||||
|
mBackColor = argbColor;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
i += 4; // "2;P_r;P_g;P_r"
|
i += 4; // "2;P_r;P_g;P_r"
|
||||||
}
|
}
|
||||||
} else if (firstArg == 5) {
|
} else if (firstArg == 5) {
|
||||||
color = mArgs[i + 2];
|
int color = mArgs[i + 2];
|
||||||
i += 2; // "5;P_s"
|
i += 2; // "5;P_s"
|
||||||
} else {
|
|
||||||
finishSequenceAndLogError("Invalid ISO-8613-3 SGR first argument: " + firstArg);
|
|
||||||
}
|
|
||||||
if (i != -1) {
|
|
||||||
if (color >= 0 && color < TextStyle.NUM_INDEXED_COLORS) {
|
if (color >= 0 && color < TextStyle.NUM_INDEXED_COLORS) {
|
||||||
if (code == 38) {
|
if (code == 38) {
|
||||||
mForeColor = color;
|
mForeColor = color;
|
||||||
@@ -1720,10 +1724,10 @@ public final class TerminalEmulator {
|
|||||||
mBackColor = color;
|
mBackColor = color;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (LOG_ESCAPE_SEQUENCES)
|
if (LOG_ESCAPE_SEQUENCES) Log.w(EmulatorDebug.LOG_TAG, "Invalid color index: " + color);
|
||||||
Log.w(EmulatorDebug.LOG_TAG, "Invalid color index: " + color);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
finishSequenceAndLogError("Invalid ISO-8613-3 SGR first argument: " + firstArg);
|
||||||
}
|
}
|
||||||
} else if (code == 39) { // Set default foreground color.
|
} else if (code == 39) { // Set default foreground color.
|
||||||
mForeColor = TextStyle.COLOR_INDEX_FOREGROUND;
|
mForeColor = TextStyle.COLOR_INDEX_FOREGROUND;
|
||||||
@@ -1924,7 +1928,7 @@ public final class TerminalEmulator {
|
|||||||
mScreen.blockSet(sx, sy, w, h, ' ', getStyle());
|
mScreen.blockSet(sx, sy, w, h, ' ', getStyle());
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getStyle() {
|
private long getStyle() {
|
||||||
return TextStyle.encode(mForeColor, mBackColor, mEffect);
|
return TextStyle.encode(mForeColor, mBackColor, mEffect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -20,13 +20,13 @@ public final class TerminalRow {
|
|||||||
/** If this row has been line wrapped due to text output at the end of line. */
|
/** If this row has been line wrapped due to text output at the end of line. */
|
||||||
boolean mLineWrap;
|
boolean mLineWrap;
|
||||||
/** The style bits of each cell in the row. See {@link TextStyle}. */
|
/** The style bits of each cell in the row. See {@link TextStyle}. */
|
||||||
final int[] mStyle;
|
final long[] mStyle;
|
||||||
|
|
||||||
/** Construct a blank row (containing only whitespace, ' ') with a specified style. */
|
/** Construct a blank row (containing only whitespace, ' ') with a specified style. */
|
||||||
public TerminalRow(int columns, int style) {
|
public TerminalRow(int columns, long style) {
|
||||||
mColumns = columns;
|
mColumns = columns;
|
||||||
mText = new char[(int) (SPARE_CAPACITY_FACTOR * columns)];
|
mText = new char[(int) (SPARE_CAPACITY_FACTOR * columns)];
|
||||||
mStyle = new int[columns];
|
mStyle = new long[columns];
|
||||||
clear(style);
|
clear(style);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,14 +112,14 @@ public final class TerminalRow {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clear(int style) {
|
public void clear(long style) {
|
||||||
Arrays.fill(mText, ' ');
|
Arrays.fill(mText, ' ');
|
||||||
Arrays.fill(mStyle, style);
|
Arrays.fill(mStyle, style);
|
||||||
mSpaceUsed = (short) mColumns;
|
mSpaceUsed = (short) mColumns;
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://github.com/steven676/Android-Terminal-Emulator/commit/9a47042620bec87617f0b4f5d50568535668fe26
|
// https://github.com/steven676/Android-Terminal-Emulator/commit/9a47042620bec87617f0b4f5d50568535668fe26
|
||||||
public void setChar(int columnToSet, int codePoint, int style) {
|
public void setChar(int columnToSet, int codePoint, long style) {
|
||||||
mStyle[columnToSet] = style;
|
mStyle[columnToSet] = style;
|
||||||
|
|
||||||
final int newCodePointDisplayWidth = WcWidth.width(codePoint);
|
final int newCodePointDisplayWidth = WcWidth.width(codePoint);
|
||||||
@@ -225,7 +225,7 @@ public final class TerminalRow {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final int getStyle(int column) {
|
public final long getStyle(int column) {
|
||||||
return mStyle[column];
|
return mStyle[column];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -173,7 +173,7 @@ public final class TerminalSession extends TerminalOutput {
|
|||||||
* @param rows The number of rows in the terminal window.
|
* @param rows The number of rows in the terminal window.
|
||||||
*/
|
*/
|
||||||
public void initializeEmulator(int columns, int rows) {
|
public void initializeEmulator(int columns, int rows) {
|
||||||
mEmulator = new TerminalEmulator(this, columns, rows, /* transcript= */5000);
|
mEmulator = new TerminalEmulator(this, columns, rows, /* transcript= */2000);
|
||||||
|
|
||||||
int[] processId = new int[1];
|
int[] processId = new int[1];
|
||||||
mTerminalFileDescriptor = JNI.createSubprocess(mShellPath, mCwd, mArgs, mEnv, processId, rows, columns);
|
mTerminalFileDescriptor = JNI.createSubprocess(mShellPath, mCwd, mArgs, mEnv, processId, rows, columns);
|
||||||
|
@@ -1,11 +1,13 @@
|
|||||||
package com.termux.terminal;
|
package com.termux.terminal;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encodes effects, foreground and background colors into a 32 bit integer, which are stored for each cell in a terminal
|
* Encodes effects, foreground and background colors into a 64 bit long, which are stored for each cell in a terminal
|
||||||
* row in {@link TerminalRow#mStyle}.
|
* row in {@link TerminalRow#mStyle}.
|
||||||
* <p/>
|
* <p/>
|
||||||
* The foreground and background colors take 9 bits each, leaving (32-9-9)=14 bits for effect flags. Using 9 for now
|
* The bit layout is:
|
||||||
* (the different CHARACTER_ATTRIBUTE_* bits).
|
* - 16 flags (11 currently used).
|
||||||
|
* - 24 for foreground color (only 9 first bits if a color index).
|
||||||
|
* - 24 for background color (only 9 first bits if a color index).
|
||||||
*/
|
*/
|
||||||
public final class TextStyle {
|
public final class TextStyle {
|
||||||
|
|
||||||
@@ -25,6 +27,10 @@ public final class TextStyle {
|
|||||||
public final static int CHARACTER_ATTRIBUTE_PROTECTED = 1 << 7;
|
public final static int CHARACTER_ATTRIBUTE_PROTECTED = 1 << 7;
|
||||||
/** Dim colors. Also known as faint or half intensity. */
|
/** Dim colors. Also known as faint or half intensity. */
|
||||||
public final static int CHARACTER_ATTRIBUTE_DIM = 1 << 8;
|
public final static int CHARACTER_ATTRIBUTE_DIM = 1 << 8;
|
||||||
|
/** If true (24-bit) color is used for the cell for foreground. */
|
||||||
|
private final static int CHARACTER_ATTRIBUTE_TRUECOLOR_FOREGROUND = 1 << 9;
|
||||||
|
/** If true (24-bit) color is used for the cell for foreground. */
|
||||||
|
private final static int CHARACTER_ATTRIBUTE_TRUECOLOR_BACKGROUND= 1 << 10;
|
||||||
|
|
||||||
public final static int COLOR_INDEX_FOREGROUND = 256;
|
public final static int COLOR_INDEX_FOREGROUND = 256;
|
||||||
public final static int COLOR_INDEX_BACKGROUND = 257;
|
public final static int COLOR_INDEX_BACKGROUND = 257;
|
||||||
@@ -34,22 +40,47 @@ public final class TextStyle {
|
|||||||
public final static int NUM_INDEXED_COLORS = 259;
|
public final static int NUM_INDEXED_COLORS = 259;
|
||||||
|
|
||||||
/** Normal foreground and background colors and no effects. */
|
/** Normal foreground and background colors and no effects. */
|
||||||
final static int NORMAL = encode(COLOR_INDEX_FOREGROUND, COLOR_INDEX_BACKGROUND, 0);
|
final static long NORMAL = encode(COLOR_INDEX_FOREGROUND, COLOR_INDEX_BACKGROUND, 0);
|
||||||
|
|
||||||
static int encode(int foreColor, int backColor, int effect) {
|
static long encode(int foreColor, int backColor, int effect) {
|
||||||
return ((effect & 0b111111111) << 18) | ((foreColor & 0b111111111) << 9) | (backColor & 0b111111111);
|
long result = effect & 0b111111111;
|
||||||
|
if ((0xff000000 & foreColor) == 0xff000000) {
|
||||||
|
// 24-bit color.
|
||||||
|
result |= CHARACTER_ATTRIBUTE_TRUECOLOR_FOREGROUND | (((long) foreColor & 0x00ffffffL) << 40L);
|
||||||
|
} else {
|
||||||
|
// Indexed color.
|
||||||
|
result |= (((long) foreColor) & 0b111111111L) << 40;
|
||||||
|
}
|
||||||
|
if ((0xff000000 & backColor) == 0xff000000) {
|
||||||
|
// 24-bit color.
|
||||||
|
result |= CHARACTER_ATTRIBUTE_TRUECOLOR_BACKGROUND | (((long) backColor & 0x00ffffffL) << 16L);
|
||||||
|
} else {
|
||||||
|
// Indexed color.
|
||||||
|
result |= (((long) backColor) & 0b111111111L) << 16L;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int decodeForeColor(int encodedColor) {
|
return result;
|
||||||
return (encodedColor >> 9) & 0b111111111;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int decodeBackColor(int encodedColor) {
|
public static int decodeForeColor(long style) {
|
||||||
return encodedColor & 0b111111111;
|
if ((style & CHARACTER_ATTRIBUTE_TRUECOLOR_FOREGROUND) == 0) {
|
||||||
}
|
return (int) ((style >>> 40) & 0b111111111L);
|
||||||
|
} else {
|
||||||
public static int decodeEffect(int encodedColor) {
|
return 0xff000000 | (int) ((style >>> 40) & 0x00ffffffL);
|
||||||
return (encodedColor >> 18) & 0b111111111;
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int decodeBackColor(long style) {
|
||||||
|
if ((style & CHARACTER_ATTRIBUTE_TRUECOLOR_BACKGROUND) == 0) {
|
||||||
|
return (int) ((style >>> 16) & 0b111111111L);
|
||||||
|
} else {
|
||||||
|
return 0xff000000 | (int) ((style >>> 16) & 0x00ffffffL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int decodeEffect(long style) {
|
||||||
|
return (int) (style & 0b11111111111);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -82,7 +82,7 @@ final class TerminalRenderer {
|
|||||||
final char[] line = lineObject.mText;
|
final char[] line = lineObject.mText;
|
||||||
final int charsUsedInLine = lineObject.getSpaceUsed();
|
final int charsUsedInLine = lineObject.getSpaceUsed();
|
||||||
|
|
||||||
int lastRunStyle = 0;
|
long lastRunStyle = 0;
|
||||||
boolean lastRunInsideCursor = false;
|
boolean lastRunInsideCursor = false;
|
||||||
int lastRunStartColumn = -1;
|
int lastRunStartColumn = -1;
|
||||||
int lastRunStartIndex = 0;
|
int lastRunStartIndex = 0;
|
||||||
@@ -97,7 +97,7 @@ final class TerminalRenderer {
|
|||||||
final int codePoint = charIsHighsurrogate ? Character.toCodePoint(charAtIndex, line[currentCharIndex + 1]) : charAtIndex;
|
final int codePoint = charIsHighsurrogate ? Character.toCodePoint(charAtIndex, line[currentCharIndex + 1]) : charAtIndex;
|
||||||
final int codePointWcWidth = WcWidth.width(codePoint);
|
final int codePointWcWidth = WcWidth.width(codePoint);
|
||||||
final boolean insideCursor = (column >= selx1 && column <= selx2) || (cursorX == column || (codePointWcWidth == 2 && cursorX == column + 1));
|
final boolean insideCursor = (column >= selx1 && column <= selx2) || (cursorX == column || (codePointWcWidth == 2 && cursorX == column + 1));
|
||||||
final int style = lineObject.getStyle(column);
|
final long style = lineObject.getStyle(column);
|
||||||
|
|
||||||
// Check if the measured text width for this code point is not the same as that expected by wcwidth().
|
// Check if the measured text width for this code point is not the same as that expected by wcwidth().
|
||||||
// This could happen for some fonts which are not truly monospace, or for more exotic characters such as
|
// This could happen for some fonts which are not truly monospace, or for more exotic characters such as
|
||||||
@@ -154,9 +154,17 @@ final class TerminalRenderer {
|
|||||||
* @param reverseVideo if the screen is rendered with the global reverse video flag set
|
* @param reverseVideo if the screen is rendered with the global reverse video flag set
|
||||||
*/
|
*/
|
||||||
private void drawTextRun(Canvas canvas, char[] text, int[] palette, float y, int startColumn, int runWidthColumns, int startCharIndex, int runWidthChars,
|
private void drawTextRun(Canvas canvas, char[] text, int[] palette, float y, int startColumn, int runWidthColumns, int startCharIndex, int runWidthChars,
|
||||||
float mes, boolean cursor, int textStyle, boolean reverseVideo) {
|
float mes, boolean cursor, long textStyle, boolean reverseVideo) {
|
||||||
int foreColor = TextStyle.decodeForeColor(textStyle);
|
int foreColor = TextStyle.decodeForeColor(textStyle);
|
||||||
int backColor = TextStyle.decodeBackColor(textStyle);
|
int backColor = TextStyle.decodeBackColor(textStyle);
|
||||||
|
|
||||||
|
int foreColorIndex = -1;
|
||||||
|
if ((foreColor & 0xff000000) != 0xff000000) {
|
||||||
|
foreColorIndex = foreColor;
|
||||||
|
foreColor = palette[foreColor];
|
||||||
|
}
|
||||||
|
if ((backColor & 0xff000000) != 0xff000000) backColor = palette[backColor];
|
||||||
|
|
||||||
final int effect = TextStyle.decodeEffect(textStyle);
|
final int effect = TextStyle.decodeEffect(textStyle);
|
||||||
float left = startColumn * mFontWidth;
|
float left = startColumn * mFontWidth;
|
||||||
float right = left + runWidthColumns * mFontWidth;
|
float right = left + runWidthColumns * mFontWidth;
|
||||||
@@ -180,9 +188,9 @@ final class TerminalRenderer {
|
|||||||
backColor = tmp;
|
backColor = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (backColor != TextStyle.COLOR_INDEX_BACKGROUND) {
|
if (backColor != palette[TextStyle.COLOR_INDEX_BACKGROUND]) {
|
||||||
// Only draw non-default background.
|
// Only draw non-default background.
|
||||||
mTextPaint.setColor(palette[backColor]);
|
mTextPaint.setColor(backColor);
|
||||||
canvas.drawRect(left, y - mFontLineSpacingAndAscent + mFontAscent, right, y, mTextPaint);
|
canvas.drawRect(left, y - mFontLineSpacingAndAscent + mFontAscent, right, y, mTextPaint);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,26 +203,25 @@ final class TerminalRenderer {
|
|||||||
final boolean dim = (effect & TextStyle.CHARACTER_ATTRIBUTE_DIM) != 0;
|
final boolean dim = (effect & TextStyle.CHARACTER_ATTRIBUTE_DIM) != 0;
|
||||||
|
|
||||||
// Let bold have bright colors if applicable (one of the first 8):
|
// Let bold have bright colors if applicable (one of the first 8):
|
||||||
final int actualForeColor = foreColor + (bold && foreColor < 8 ? 8 : 0);
|
if (bold && foreColorIndex >= 0 && foreColorIndex < 8) foreColor = palette[foreColorIndex + 8];
|
||||||
|
|
||||||
int foreColorARGB = palette[actualForeColor];
|
|
||||||
if (dim) {
|
if (dim) {
|
||||||
int red = (0xFF & (foreColorARGB >> 16));
|
int red = (0xFF & (foreColor >> 16));
|
||||||
int green = (0xFF & (foreColorARGB >> 8));
|
int green = (0xFF & (foreColor >> 8));
|
||||||
int blue = (0xFF & foreColorARGB);
|
int blue = (0xFF & foreColor);
|
||||||
// Dim color handling used by libvte which in turn took it from xterm
|
// Dim color handling used by libvte which in turn took it from xterm
|
||||||
// (https://bug735245.bugzilla-attachments.gnome.org/attachment.cgi?id=284267):
|
// (https://bug735245.bugzilla-attachments.gnome.org/attachment.cgi?id=284267):
|
||||||
red = red * 2 / 3;
|
red = red * 2 / 3;
|
||||||
green = green * 2 / 3;
|
green = green * 2 / 3;
|
||||||
blue = blue * 2 / 3;
|
blue = blue * 2 / 3;
|
||||||
foreColorARGB = 0xFF000000 + (red << 16) + (green << 8) + blue;
|
foreColor = 0xFF000000 + (red << 16) + (green << 8) + blue;
|
||||||
}
|
}
|
||||||
|
|
||||||
mTextPaint.setFakeBoldText(bold);
|
mTextPaint.setFakeBoldText(bold);
|
||||||
mTextPaint.setUnderlineText(underline);
|
mTextPaint.setUnderlineText(underline);
|
||||||
mTextPaint.setTextSkewX(italic ? -0.35f : 0.f);
|
mTextPaint.setTextSkewX(italic ? -0.35f : 0.f);
|
||||||
mTextPaint.setStrikeThruText(strikeThrough);
|
mTextPaint.setStrikeThruText(strikeThrough);
|
||||||
mTextPaint.setColor(foreColorARGB);
|
mTextPaint.setColor(foreColor);
|
||||||
|
|
||||||
// The text alignment is the default Paint.Align.LEFT.
|
// The text alignment is the default Paint.Align.LEFT.
|
||||||
canvas.drawText(text, startCharIndex, runWidthChars, left, y - mFontLineSpacingAndAscent, mTextPaint);
|
canvas.drawText(text, startCharIndex, runWidthChars, left, y - mFontLineSpacingAndAscent, mTextPaint);
|
||||||
|
@@ -18,7 +18,7 @@ public class CursorAndScreenTest extends TerminalTestCase {
|
|||||||
assertLinesAre("ABCDE", "FGHIJ", "KLMNO", "PQRST", "UVWXY");
|
assertLinesAre("ABCDE", "FGHIJ", "KLMNO", "PQRST", "UVWXY");
|
||||||
for (int row = 0; row < 5; row++) {
|
for (int row = 0; row < 5; row++) {
|
||||||
for (int col = 0; col < 5; col++) {
|
for (int col = 0; col < 5; col++) {
|
||||||
int s = getStyleAt(row, col);
|
long s = getStyleAt(row, col);
|
||||||
Assert.assertEquals(col, TextStyle.decodeForeColor(s));
|
Assert.assertEquals(col, TextStyle.decodeForeColor(s));
|
||||||
Assert.assertEquals(row, TextStyle.decodeBackColor(s));
|
Assert.assertEquals(row, TextStyle.decodeBackColor(s));
|
||||||
}
|
}
|
||||||
@@ -28,7 +28,7 @@ public class CursorAndScreenTest extends TerminalTestCase {
|
|||||||
assertLinesAre("KLMNO", "PQRST", "UVWXY", " ", " ");
|
assertLinesAre("KLMNO", "PQRST", "UVWXY", " ", " ");
|
||||||
for (int row = 0; row < 3; row++) {
|
for (int row = 0; row < 3; row++) {
|
||||||
for (int col = 0; col < 5; col++) {
|
for (int col = 0; col < 5; col++) {
|
||||||
int s = getStyleAt(row, col);
|
long s = getStyleAt(row, col);
|
||||||
Assert.assertEquals(col, TextStyle.decodeForeColor(s));
|
Assert.assertEquals(col, TextStyle.decodeForeColor(s));
|
||||||
Assert.assertEquals(row + 2, TextStyle.decodeBackColor(s));
|
Assert.assertEquals(row + 2, TextStyle.decodeBackColor(s));
|
||||||
}
|
}
|
||||||
@@ -43,7 +43,7 @@ public class CursorAndScreenTest extends TerminalTestCase {
|
|||||||
for (int col = 0; col < 5; col++) {
|
for (int col = 0; col < 5; col++) {
|
||||||
int wantedForeground = (row == 1 || row == 2) ? 98 : col;
|
int wantedForeground = (row == 1 || row == 2) ? 98 : col;
|
||||||
int wantedBackground = (row == 1 || row == 2) ? 99 : (row == 0 ? 2 : row);
|
int wantedBackground = (row == 1 || row == 2) ? 99 : (row == 0 ? 2 : row);
|
||||||
int s = getStyleAt(row, col);
|
long s = getStyleAt(row, col);
|
||||||
Assert.assertEquals(wantedForeground, TextStyle.decodeForeColor(s));
|
Assert.assertEquals(wantedForeground, TextStyle.decodeForeColor(s));
|
||||||
Assert.assertEquals(wantedBackground, TextStyle.decodeBackColor(s));
|
Assert.assertEquals(wantedBackground, TextStyle.decodeBackColor(s));
|
||||||
}
|
}
|
||||||
|
@@ -93,7 +93,7 @@ public class ResizeTest extends TerminalTestCase {
|
|||||||
enterString("\033[2J");
|
enterString("\033[2J");
|
||||||
for (int r = 0; r < rows; r++) {
|
for (int r = 0; r < rows; r++) {
|
||||||
for (int c = 0; c < cols; c++) {
|
for (int c = 0; c < cols; c++) {
|
||||||
int style = getStyleAt(r, c);
|
long style = getStyleAt(r, c);
|
||||||
assertEquals(119, TextStyle.decodeForeColor(style));
|
assertEquals(119, TextStyle.decodeForeColor(style));
|
||||||
assertEquals(129, TextStyle.decodeBackColor(style));
|
assertEquals(129, TextStyle.decodeBackColor(style));
|
||||||
}
|
}
|
||||||
@@ -105,7 +105,7 @@ public class ResizeTest extends TerminalTestCase {
|
|||||||
// After resize, screen should still be same color:
|
// After resize, screen should still be same color:
|
||||||
for (int r = 0; r < rows - 2; r++) {
|
for (int r = 0; r < rows - 2; r++) {
|
||||||
for (int c = 0; c < cols; c++) {
|
for (int c = 0; c < cols; c++) {
|
||||||
int style = getStyleAt(r, c);
|
long style = getStyleAt(r, c);
|
||||||
assertEquals(119, TextStyle.decodeForeColor(style));
|
assertEquals(119, TextStyle.decodeForeColor(style));
|
||||||
assertEquals(129, TextStyle.decodeBackColor(style));
|
assertEquals(129, TextStyle.decodeBackColor(style));
|
||||||
}
|
}
|
||||||
@@ -116,7 +116,7 @@ public class ResizeTest extends TerminalTestCase {
|
|||||||
resize(cols, rows);
|
resize(cols, rows);
|
||||||
for (int r = 0; r < rows; r++) {
|
for (int r = 0; r < rows; r++) {
|
||||||
for (int c = 0; c < cols; c++) {
|
for (int c = 0; c < cols; c++) {
|
||||||
int style = getStyleAt(r, c);
|
long style = getStyleAt(r, c);
|
||||||
assertEquals(119, TextStyle.decodeForeColor(style));
|
assertEquals(119, TextStyle.decodeForeColor(style));
|
||||||
assertEquals("wrong at row=" + r, r >= 3 ? 200 : 129, TextStyle.decodeBackColor(style));
|
assertEquals("wrong at row=" + r, r >= 3 ? 200 : 129, TextStyle.decodeBackColor(style));
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
package com.termux.terminal;
|
package com.termux.terminal;
|
||||||
|
|
||||||
public class ScreenBufferTest extends TerminalTest {
|
public class ScreenBufferTest extends TerminalTestCase {
|
||||||
|
|
||||||
public void testBasics() {
|
public void testBasics() {
|
||||||
TerminalBuffer screen = new TerminalBuffer(5, 3, 3);
|
TerminalBuffer screen = new TerminalBuffer(5, 3, 3);
|
||||||
|
@@ -147,7 +147,6 @@ public class TerminalTest extends TerminalTestCase {
|
|||||||
enterString("\033[38;5;119m");
|
enterString("\033[38;5;119m");
|
||||||
assertEquals(119, mTerminal.mForeColor);
|
assertEquals(119, mTerminal.mForeColor);
|
||||||
assertEquals(TextStyle.COLOR_INDEX_BACKGROUND, mTerminal.mBackColor);
|
assertEquals(TextStyle.COLOR_INDEX_BACKGROUND, mTerminal.mBackColor);
|
||||||
|
|
||||||
enterString("\033[48;5;129m");
|
enterString("\033[48;5;129m");
|
||||||
assertEquals(119, mTerminal.mForeColor);
|
assertEquals(119, mTerminal.mForeColor);
|
||||||
assertEquals(129, mTerminal.mBackColor);
|
assertEquals(129, mTerminal.mBackColor);
|
||||||
@@ -161,6 +160,30 @@ public class TerminalTest extends TerminalTestCase {
|
|||||||
enterString("\033[38;5;178;48;5;179;m");
|
enterString("\033[38;5;178;48;5;179;m");
|
||||||
assertEquals(178, mTerminal.mForeColor);
|
assertEquals(178, mTerminal.mForeColor);
|
||||||
assertEquals(179, mTerminal.mBackColor);
|
assertEquals(179, mTerminal.mBackColor);
|
||||||
|
|
||||||
|
// 24 bit colors:
|
||||||
|
enterString(("\033[0m")); // Reset fg and bg colors.
|
||||||
|
enterString("\033[38;2;255;127;2m");
|
||||||
|
int expectedForeground = 0xff000000 | (255 << 16) | (127 << 8) | 2;
|
||||||
|
assertEquals(expectedForeground, mTerminal.mForeColor);
|
||||||
|
assertEquals(TextStyle.COLOR_INDEX_BACKGROUND, mTerminal.mBackColor);
|
||||||
|
enterString("\033[48;2;1;2;254m");
|
||||||
|
int expectedBackground = 0xff000000 | (1 << 16) | (2 << 8) | 254;
|
||||||
|
assertEquals(expectedForeground, mTerminal.mForeColor);
|
||||||
|
assertEquals(expectedBackground, mTerminal.mBackColor);
|
||||||
|
|
||||||
|
// 24 bit colors, set fg and bg at once:
|
||||||
|
enterString(("\033[0m")); // Reset fg and bg colors.
|
||||||
|
assertEquals(TextStyle.COLOR_INDEX_FOREGROUND, mTerminal.mForeColor);
|
||||||
|
assertEquals(TextStyle.COLOR_INDEX_BACKGROUND, mTerminal.mBackColor);
|
||||||
|
enterString("\033[38;2;255;127;2;48;2;1;2;254m");
|
||||||
|
assertEquals(expectedForeground, mTerminal.mForeColor);
|
||||||
|
assertEquals(expectedBackground, mTerminal.mBackColor);
|
||||||
|
|
||||||
|
// 24 bit colors, invalid input:
|
||||||
|
enterString("\033[38;2;300;127;2;48;2;1;300;254m");
|
||||||
|
assertEquals(expectedForeground, mTerminal.mForeColor);
|
||||||
|
assertEquals(expectedBackground, mTerminal.mBackColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testBackgroundColorErase() {
|
public void testBackgroundColorErase() {
|
||||||
@@ -169,7 +192,7 @@ public class TerminalTest extends TerminalTestCase {
|
|||||||
withTerminalSized(cols, rows);
|
withTerminalSized(cols, rows);
|
||||||
for (int r = 0; r < rows; r++) {
|
for (int r = 0; r < rows; r++) {
|
||||||
for (int c = 0; c < cols; c++) {
|
for (int c = 0; c < cols; c++) {
|
||||||
int style = getStyleAt(r, c);
|
long style = getStyleAt(r, c);
|
||||||
assertEquals(TextStyle.COLOR_INDEX_FOREGROUND, TextStyle.decodeForeColor(style));
|
assertEquals(TextStyle.COLOR_INDEX_FOREGROUND, TextStyle.decodeForeColor(style));
|
||||||
assertEquals(TextStyle.COLOR_INDEX_BACKGROUND, TextStyle.decodeBackColor(style));
|
assertEquals(TextStyle.COLOR_INDEX_BACKGROUND, TextStyle.decodeBackColor(style));
|
||||||
}
|
}
|
||||||
@@ -182,7 +205,7 @@ public class TerminalTest extends TerminalTestCase {
|
|||||||
enterString("\033[2J");
|
enterString("\033[2J");
|
||||||
for (int r = 0; r < rows; r++) {
|
for (int r = 0; r < rows; r++) {
|
||||||
for (int c = 0; c < cols; c++) {
|
for (int c = 0; c < cols; c++) {
|
||||||
int style = getStyleAt(r, c);
|
long style = getStyleAt(r, c);
|
||||||
assertEquals(119, TextStyle.decodeForeColor(style));
|
assertEquals(119, TextStyle.decodeForeColor(style));
|
||||||
assertEquals(129, TextStyle.decodeBackColor(style));
|
assertEquals(129, TextStyle.decodeBackColor(style));
|
||||||
}
|
}
|
||||||
@@ -193,7 +216,7 @@ public class TerminalTest extends TerminalTestCase {
|
|||||||
enterString("\033[2L");
|
enterString("\033[2L");
|
||||||
for (int r = 0; r < rows; r++) {
|
for (int r = 0; r < rows; r++) {
|
||||||
for (int c = 0; c < cols; c++) {
|
for (int c = 0; c < cols; c++) {
|
||||||
int style = getStyleAt(r, c);
|
long style = getStyleAt(r, c);
|
||||||
assertEquals((r == 0 || r == 1) ? 139 : 129, TextStyle.decodeBackColor(style));
|
assertEquals((r == 0 || r == 1) ? 139 : 129, TextStyle.decodeBackColor(style));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -240,7 +240,7 @@ public abstract class TerminalTestCase extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** For testing only. Encoded style according to {@link TextStyle}. */
|
/** For testing only. Encoded style according to {@link TextStyle}. */
|
||||||
public int getStyleAt(int externalRow, int column) {
|
public long getStyleAt(int externalRow, int column) {
|
||||||
return mTerminal.getScreen().getStyleAt(externalRow, column);
|
return mTerminal.getScreen().getStyleAt(externalRow, column);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -296,7 +296,7 @@ public abstract class TerminalTestCase extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void assertForegroundColorAt(int externalRow, int column, int color) {
|
public void assertForegroundColorAt(int externalRow, int column, int color) {
|
||||||
int style = mTerminal.getScreen().mLines[mTerminal.getScreen().externalToInternalRow(externalRow)].getStyle(column);
|
long style = mTerminal.getScreen().mLines[mTerminal.getScreen().externalToInternalRow(externalRow)].getStyle(column);
|
||||||
assertEquals(color, TextStyle.decodeForeColor(style));
|
assertEquals(color, TextStyle.decodeForeColor(style));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -13,7 +13,7 @@ public class TextStyleTest extends TestCase {
|
|||||||
for (int fx : ALL_EFFECTS) {
|
for (int fx : ALL_EFFECTS) {
|
||||||
for (int fg = 0; fg < TextStyle.NUM_INDEXED_COLORS; fg++) {
|
for (int fg = 0; fg < TextStyle.NUM_INDEXED_COLORS; fg++) {
|
||||||
for (int bg = 0; bg < TextStyle.NUM_INDEXED_COLORS; bg++) {
|
for (int bg = 0; bg < TextStyle.NUM_INDEXED_COLORS; bg++) {
|
||||||
int encoded = TextStyle.encode(fg, bg, fx);
|
long encoded = TextStyle.encode(fg, bg, fx);
|
||||||
assertEquals(fg, TextStyle.decodeForeColor(encoded));
|
assertEquals(fg, TextStyle.decodeForeColor(encoded));
|
||||||
assertEquals(bg, TextStyle.decodeBackColor(encoded));
|
assertEquals(bg, TextStyle.decodeBackColor(encoded));
|
||||||
assertEquals(fx, TextStyle.decodeEffect(encoded));
|
assertEquals(fx, TextStyle.decodeEffect(encoded));
|
||||||
@@ -22,6 +22,22 @@ public class TextStyleTest extends TestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testEncoding24Bit() {
|
||||||
|
int[] values = {255, 240, 127, 1, 0};
|
||||||
|
for (int red : values) {
|
||||||
|
for (int green : values) {
|
||||||
|
for (int blue : values) {
|
||||||
|
int argb = 0xFF000000 | (red << 16) | (green << 8) | blue;
|
||||||
|
long encoded = TextStyle.encode(argb, 0, 0);
|
||||||
|
assertEquals(argb, TextStyle.decodeForeColor(encoded));
|
||||||
|
encoded = TextStyle.encode(0, argb, 0);
|
||||||
|
assertEquals(argb, TextStyle.decodeBackColor(encoded));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void testEncodingCombinations() {
|
public void testEncodingCombinations() {
|
||||||
for (int f1 : ALL_EFFECTS) {
|
for (int f1 : ALL_EFFECTS) {
|
||||||
for (int f2 : ALL_EFFECTS) {
|
for (int f2 : ALL_EFFECTS) {
|
||||||
@@ -32,13 +48,13 @@ public class TextStyleTest extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testEncodingStrikeThrough() {
|
public void testEncodingStrikeThrough() {
|
||||||
int encoded = TextStyle.encode(TextStyle.COLOR_INDEX_FOREGROUND, TextStyle.COLOR_INDEX_BACKGROUND,
|
long encoded = TextStyle.encode(TextStyle.COLOR_INDEX_FOREGROUND, TextStyle.COLOR_INDEX_BACKGROUND,
|
||||||
TextStyle.CHARACTER_ATTRIBUTE_STRIKETHROUGH);
|
TextStyle.CHARACTER_ATTRIBUTE_STRIKETHROUGH);
|
||||||
assertTrue((TextStyle.decodeEffect(encoded) & TextStyle.CHARACTER_ATTRIBUTE_STRIKETHROUGH) != 0);
|
assertTrue((TextStyle.decodeEffect(encoded) & TextStyle.CHARACTER_ATTRIBUTE_STRIKETHROUGH) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testEncodingProtected() {
|
public void testEncodingProtected() {
|
||||||
int encoded = TextStyle.encode(TextStyle.COLOR_INDEX_FOREGROUND, TextStyle.COLOR_INDEX_BACKGROUND,
|
long encoded = TextStyle.encode(TextStyle.COLOR_INDEX_FOREGROUND, TextStyle.COLOR_INDEX_BACKGROUND,
|
||||||
TextStyle.CHARACTER_ATTRIBUTE_STRIKETHROUGH);
|
TextStyle.CHARACTER_ATTRIBUTE_STRIKETHROUGH);
|
||||||
assertTrue((TextStyle.decodeEffect(encoded) & TextStyle.CHARACTER_ATTRIBUTE_PROTECTED) == 0);
|
assertTrue((TextStyle.decodeEffect(encoded) & TextStyle.CHARACTER_ATTRIBUTE_PROTECTED) == 0);
|
||||||
encoded = TextStyle.encode(TextStyle.COLOR_INDEX_FOREGROUND, TextStyle.COLOR_INDEX_BACKGROUND,
|
encoded = TextStyle.encode(TextStyle.COLOR_INDEX_FOREGROUND, TextStyle.COLOR_INDEX_BACKGROUND,
|
||||||
|
Reference in New Issue
Block a user