/*
* $Id$
*
* Copyright (C) 2003-2015 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.driver.textscreen.x86;
import org.jnode.driver.textscreen.TextScreen;
import org.jnode.vm.Unsafe;
/**
* @author Ewout Prangsma (epr@users.sourceforge.net)
* @author Fabien DUMINY (fduminy at jnode.org)
*/
public abstract class AbstractPcBufferTextScreen extends AbstractPcTextScreen {
/**
* Actual content buffer
*/
private final char[] buffer;
/**
* Temporary buffer that includes the cursor. This goes to the video device.
* Slower, but more likely to be correct than a temporary pointer to the last character
* the cursor was over, as in previous versions.
*/
private final char[]screenBuffer;
private int cursorIndex = 0;
private boolean cursorVisible = true;
/**
* Initialize this instance.
*
* @param width
* @param height
*/
public AbstractPcBufferTextScreen(int width, int height) {
super(width, height);
this.buffer = new char[width * height];
this.screenBuffer = new char[buffer.length];
}
/**
* @see org.jnode.driver.textscreen.TextScreen#copyContent(int, int, int)
*/
@Override
public final void copyContent(int srcOffset, int destOffset, int length) {
System.arraycopy(buffer, srcOffset, buffer, destOffset, length);
}
/**
* @see org.jnode.driver.textscreen.TextScreen#getChar(int)
*/
@Override
public final char getChar(int offset) {
return (char) (buffer[offset] & 0xFF);
}
/**
* @see org.jnode.driver.textscreen.TextScreen#getColor(int)
*/
@Override
public final int getColor(int offset) {
return (char) ((buffer[offset] >> 8) & 0xFF);
}
/**
* @see org.jnode.driver.textscreen.TextScreen#set(int, char, int, int)
*/
@Override
public void set(int offset, char ch, int count, int color) {
final char v = (char) ((ch & 0xFF) | ((color & 0xFF) << 8));
count = Math.min(count, buffer.length - offset);
//todo apparently count is negative sometimes, investigate it
for (int i = 0; i < count; i++) {
buffer[offset + i] = v;
}
}
/**
* @see org.jnode.driver.textscreen.TextScreen#set(int, char[], int, int,
* int)
*/
@Override
public void set(final int offset, final char[] ch, final int chOfs, int length, int color) {
color = (color & 0xFF) << 8;
length = Math.min(length, buffer.length - offset);
int bufOffset = offset;
int chOffset = chOfs;
for (int i = 0; i < length; i++) {
buffer[bufOffset++] = (char) ((ch[chOffset++] & 0xFF) | color);
}
}
/**
* @see org.jnode.driver.textscreen.TextScreen#set(int, char[], int, int,
* int[], int)
*/
@Override
public void set(final int offset, char[] ch, final int chOfs, int length, int[] colors, int colorsOfs) {
length = Math.min(length, buffer.length - offset);
int bufOffset = offset;
int chOffset = chOfs;
int colorsOffset = colorsOfs;
for (int i = 0; i < length; i++) {
buffer[bufOffset++] = (char) ((ch[chOffset++] & 0xFF) | (colors[colorsOffset++] & 0xFF) << 8);
}
}
/**
* Copies the entire screen to the given destination. For this operation to
* succeed, the screens involved must be compatible.
*
* @param dst
*/
@Override
public final void copyTo(TextScreen dst, int offset, int length) {
if (dst instanceof AbstractPcTextScreen) {
char[] toScreen = buffer;
if (cursorVisible && cursorIndex < buffer.length && cursorIndex >= 0) {
System.arraycopy(buffer, 0, screenBuffer, 0, buffer.length);
char origValue = buffer[cursorIndex];
// origValue |= 0x7000;//from december 2003 jnode code.
// exchange the background with the foreground
int color = (origValue >> 8) & 0xFF;
color = ((color >> 4) & 0xF) | ((color << 4) & 0xF0);
origValue &= 0x00FF;
origValue |= (color << 8) & 0xFF00;
screenBuffer[cursorIndex] = origValue;
toScreen = screenBuffer;
}
((AbstractPcTextScreen) dst).copyFrom(toScreen, getTopOffset());
} else {
throw new IllegalArgumentException("Unknown destination type " +
dst.getClass().getName());
}
}
/**
* Return the offset in the buffer of the first visible row.
*
* @return the offset
*/
protected int getTopOffset() {
return 0;
}
/**
* Copy the content of the given rawData into this screen.
*
* @param rawData
* @param rawDataOffset
*/
@Override
public final void copyFrom(char[] rawData, final int rawDataOffset) {
if (rawDataOffset < 0) {
Unsafe.die("Buffer:rawDataOffset = " + rawDataOffset);
}
System.arraycopy(rawData, rawDataOffset, buffer, getTopOffset(), getWidth() * getHeight());
}
/**
* Synchronize the state with the actual device.
* @param offset
* @param length
*/
public abstract void sync(int offset, int length);
@Override
public final int setCursor(int x, int y) {
this.cursorIndex = getOffset(x, y);
setParentCursor(x, y);
return cursorIndex;
}
protected abstract void setParentCursor(int x, int y);
@Override
public final int setCursorVisible(boolean visible) {
this.cursorVisible = visible;
return cursorIndex;
}
}