1452 lines
32 KiB
C
1452 lines
32 KiB
C
/*++
|
||
|
||
Copyright (c) 1993 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
disp_gr.c
|
||
|
||
Abstract:
|
||
|
||
This file was created from \private\windows\setup\textmode\splib\ixdispj.c.
|
||
This file contains routines to display MBCS characters to the Graphics
|
||
VRAM.
|
||
|
||
Author:
|
||
|
||
v-junm (Compaq Japan)
|
||
hideyukn
|
||
tedm
|
||
|
||
Environment:
|
||
|
||
Kernel mode only.
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "bootx86.h"
|
||
#include "displayp.h"
|
||
#include "bootfont.h"
|
||
|
||
#include "vmode.h"
|
||
|
||
//
|
||
// Physical video attributes.
|
||
//
|
||
#define VIDEO_BUFFER_VA 0xa0000
|
||
#define VIDEO_BYTES_PER_SCAN_LINE 80
|
||
#define VIDEO_WIDTH_PIXELS 640
|
||
#define VIDEO_HEIGHT_SCAN_LINES 480
|
||
#define VIDEO_SIZE_BYTES (VIDEO_BYTES_PER_SCAN_LINE*VIDEO_HEIGHT_SCAN_LINES)
|
||
|
||
|
||
PUCHAR GrVp = (PUCHAR)VIDEO_BUFFER_VA;
|
||
|
||
//
|
||
// Screen width and height in half-character cells
|
||
// and macro to determine total number of characters
|
||
// displayed on the screen at once.
|
||
//
|
||
unsigned ScreenWidthCells,ScreenHeightCells;
|
||
#define SCREEN_SIZE_CELLS (ScreenWidthCells*ScreenHeightCells)
|
||
|
||
//
|
||
// Globals:
|
||
//
|
||
// CharacterCellHeight is the number of scan lines total in a character.
|
||
// It includes any top or bottom fill lines.
|
||
//
|
||
// CharacterImageHeight is the number of scan lines in the image of a character.
|
||
// This is dependent on the font. Characters may be padded top and bottom.
|
||
//
|
||
// NOTE: All of this code assumes the font's single-byte characters are 8 bits wide
|
||
// and the font's double-byte characters are 16 bits wide!
|
||
//
|
||
unsigned CharacterCellHeight;
|
||
unsigned CharacterImageHeight;
|
||
unsigned CharacterTopPad;
|
||
unsigned CharacterBottomPad;
|
||
|
||
#define VIDEO_BYTES_PER_TEXT_ROW (VIDEO_BYTES_PER_SCAN_LINE*CharacterCellHeight)
|
||
|
||
//
|
||
// Values describing the number of each type of character in the font,
|
||
// and pointers to the base of the glyphs.
|
||
//
|
||
unsigned SbcsCharCount;
|
||
unsigned DbcsCharCount;
|
||
PUCHAR SbcsImages;
|
||
PUCHAR DbcsImages;
|
||
|
||
//
|
||
// Values to be passed to GrDisplayMBCSChar
|
||
//
|
||
#define SBCSWIDTH 8
|
||
#define DBCSWIDTH 16
|
||
|
||
//
|
||
// Lead byte table. Read from bootfont.bin.
|
||
//
|
||
UCHAR LeadByteTable[2*(MAX_DBCS_RANGE+1)];
|
||
|
||
//
|
||
// keeps track as to whether to reset the
|
||
// display in TextGrTerminate().
|
||
//
|
||
BOOLEAN AllowGraphicsReset = TRUE;
|
||
|
||
|
||
VOID
|
||
GrDisplayMBCSChar(
|
||
IN PUCHAR image,
|
||
IN unsigned width,
|
||
IN UCHAR top,
|
||
IN UCHAR bottom
|
||
);
|
||
|
||
PUCHAR
|
||
GrGetDBCSFontImage(
|
||
USHORT Code
|
||
);
|
||
|
||
PUCHAR
|
||
GrGetSBCSFontImage(
|
||
UCHAR Code
|
||
);
|
||
|
||
|
||
VOID
|
||
GrWriteSBCSChar(
|
||
IN UCHAR c
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Displays a character at the current cursor position. ONLY SBCS
|
||
characters can be displayed using this routine.
|
||
|
||
Arguments:
|
||
|
||
c - character to display.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
unsigned u;
|
||
PUCHAR pImage;
|
||
UCHAR temp;
|
||
|
||
switch(c) {
|
||
|
||
case '\n':
|
||
if(TextRow == (ScreenHeightCells-1)) {
|
||
TextGrScrollDisplay();
|
||
TextSetCursorPosition(0,TextRow);
|
||
} else {
|
||
TextSetCursorPosition(0,TextRow+1);
|
||
}
|
||
break;
|
||
|
||
case '\r':
|
||
break; // ignore
|
||
|
||
case '\t':
|
||
temp = ' ';
|
||
u = 8 - (TextColumn % 8);
|
||
while(u--) {
|
||
TextGrCharOut(&temp);
|
||
}
|
||
TextSetCursorPosition(TextColumn+u,TextRow);
|
||
break;
|
||
|
||
default:
|
||
//
|
||
// Assume it's a valid SBCS character.
|
||
// Get font image for SBCS char.
|
||
//
|
||
pImage = GrGetSBCSFontImage(c);
|
||
|
||
//
|
||
// Display the SBCS char. Check for special graphics characters.
|
||
// Add top and bottom extra pixels accordingly (otherwise the grids
|
||
// don't connect properly, because of top and bottom spacing).
|
||
//
|
||
if ( c == 0x2 || c == 0x1 || c == 0x16 )
|
||
GrDisplayMBCSChar( pImage, SBCSWIDTH, 0x00, 0x66 );
|
||
else if ( c == 0x4 || c == 0x3 || c == 0x15 )
|
||
GrDisplayMBCSChar( pImage, SBCSWIDTH, 0x66, 0x00 );
|
||
else if ( c == 0x5 || c == 10 || c == 0x17 || c == 0x19 )
|
||
GrDisplayMBCSChar( pImage, SBCSWIDTH, 0x66, 0x66 );
|
||
else
|
||
GrDisplayMBCSChar( pImage, SBCSWIDTH, 0x00, 0x00 );
|
||
|
||
}
|
||
}
|
||
|
||
|
||
VOID
|
||
GrDisplayMBCSChar(
|
||
IN PUCHAR image,
|
||
IN unsigned width,
|
||
IN UCHAR top,
|
||
IN UCHAR bottom
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Displays a DBCS or a SBCS character at the current cursor
|
||
position.
|
||
|
||
Arguments:
|
||
|
||
image - SBCS or DBCS font image.
|
||
width - Width in bits of character image (must be SBCSWIDTH pr DBCSWIDTH).
|
||
top - Character to fill the top extra character line(s).
|
||
bottom- Character to fill the bottom extra character line(s).
|
||
|
||
Return Value:
|
||
|
||
FALSE if image points to NULL,
|
||
else TRUE.
|
||
|
||
--*/
|
||
|
||
{
|
||
unsigned i;
|
||
|
||
//
|
||
// Validate parameter
|
||
//
|
||
if(image == NULL) {
|
||
return;
|
||
}
|
||
|
||
|
||
//
|
||
// There are TOP_EXTRA lines at the top that we need to skip (background color).
|
||
//
|
||
for(i=0; i<CharacterTopPad; i++) {
|
||
|
||
//
|
||
// If DBCS char, we need to clear 2 bytes.
|
||
//
|
||
if(width == DBCSWIDTH) {
|
||
*GrVp++ = top;
|
||
}
|
||
*GrVp++ = top;
|
||
|
||
//
|
||
// Position pointer at next scan line
|
||
// for the font image.
|
||
//
|
||
GrVp += VIDEO_BYTES_PER_SCAN_LINE - (width/SBCSWIDTH);
|
||
}
|
||
|
||
//
|
||
// Display full height of DBCS or SBCS char.
|
||
//
|
||
for(i=0; i<CharacterImageHeight; i++) {
|
||
|
||
//
|
||
// If DBCS char, need to display 2 bytes,
|
||
// so display first byte here.
|
||
//
|
||
if(width == DBCSWIDTH) {
|
||
*GrVp++ = *image++;
|
||
}
|
||
|
||
//
|
||
// Display 2nd byte of DBCS char or the
|
||
// first and only byte of SBCS char.
|
||
//
|
||
*GrVp++ = *image++;
|
||
|
||
//
|
||
// Increment GrVP to display location of
|
||
// next row of font image.
|
||
//
|
||
GrVp += VIDEO_BYTES_PER_SCAN_LINE - (width/SBCSWIDTH);
|
||
}
|
||
|
||
//
|
||
// There are BOT_EXTRA lines at the bottom that we need to fill with the
|
||
// background color.
|
||
//
|
||
for(i=0; i<CharacterBottomPad; i++) {
|
||
|
||
//
|
||
// If DBCS char, need to clear 2 bytes
|
||
//
|
||
if(width == DBCSWIDTH) {
|
||
*GrVp++ = bottom;
|
||
}
|
||
*GrVp++ = bottom;
|
||
|
||
//
|
||
// Position pointer at next scan line
|
||
// for the font image.
|
||
//
|
||
GrVp += VIDEO_BYTES_PER_SCAN_LINE - (width/SBCSWIDTH);
|
||
}
|
||
|
||
//
|
||
// Increment cursor and video pointer
|
||
//
|
||
if(width == DBCSWIDTH) {
|
||
TextSetCursorPosition(TextColumn+2,TextRow);
|
||
} else {
|
||
TextSetCursorPosition(TextColumn+1,TextRow);
|
||
}
|
||
}
|
||
|
||
|
||
unsigned
|
||
GrWriteMBCSString(
|
||
IN PUCHAR String,
|
||
IN unsigned MaxChars
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Displays a mixed byte string at the current cursor
|
||
position.
|
||
|
||
Arguments:
|
||
|
||
String - supplies pointer to asciz string.
|
||
|
||
MaxBytes - supplies the maximum number of characters to be written.
|
||
|
||
Return Value:
|
||
|
||
Number of bytes written.
|
||
|
||
--*/
|
||
|
||
{
|
||
PUCHAR pImage;
|
||
USHORT DBCSChar;
|
||
unsigned BytesWritten;
|
||
|
||
BytesWritten = 0;
|
||
|
||
//
|
||
// While string is not NULL,
|
||
// get font image and display it.
|
||
//
|
||
while(*String && MaxChars--) {
|
||
|
||
//
|
||
// Determine if char is SBCS or DBCS, get the correct font image,
|
||
// and display it.
|
||
//
|
||
if(GrIsDBCSLeadByte(*String)) {
|
||
DBCSChar = *String++ << 8;
|
||
DBCSChar = DBCSChar | *String++;
|
||
pImage = GrGetDBCSFontImage(DBCSChar);
|
||
GrDisplayMBCSChar(pImage,DBCSWIDTH,0x00,0x00);
|
||
BytesWritten++;
|
||
} else {
|
||
GrWriteSBCSChar(*String++);
|
||
}
|
||
BytesWritten++;
|
||
}
|
||
|
||
return(BytesWritten);
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
GrIsDBCSLeadByte(
|
||
IN UCHAR c
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Checks to see if a char is a DBCS leadbyte.
|
||
|
||
Arguments:
|
||
|
||
c - char to check if leadbyte or not.
|
||
|
||
Return Value:
|
||
|
||
TRUE - Leadbyte.
|
||
FALSE - Non-Leadbyte.
|
||
|
||
--*/
|
||
|
||
{
|
||
int i;
|
||
|
||
//
|
||
// Check to see if char is in leadbyte range.
|
||
// Note if (CHAR)(0) is a valid leadbyte,
|
||
// this routine will fail.
|
||
//
|
||
|
||
for(i=0; LeadByteTable[i]; i+=2) {
|
||
if((LeadByteTable[i] <= c) && (LeadByteTable[i+1] >= c)) {
|
||
return(TRUE);
|
||
}
|
||
}
|
||
|
||
return(FALSE);
|
||
}
|
||
|
||
|
||
PUCHAR
|
||
GrGetDBCSFontImage(
|
||
USHORT Code
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Gets the font image for DBCS char.
|
||
|
||
Arguments:
|
||
|
||
Code - DBCS char code.
|
||
|
||
Return Value:
|
||
|
||
Pointer to font image, or else NULL.
|
||
|
||
--*/
|
||
|
||
{
|
||
int Min,Max,Mid;
|
||
int Multiplier;
|
||
int Index;
|
||
USHORT code;
|
||
|
||
Min = 0;
|
||
Max = DbcsCharCount;
|
||
// multiplier = 2 (for index) +
|
||
// 2 * height +
|
||
// 2 (for unicode encoding)
|
||
//
|
||
Multiplier = 2 + (2*CharacterImageHeight) + 2;
|
||
|
||
//
|
||
// Do a binary search for the image.
|
||
// Format of table:
|
||
// First 2 bytes contain the DBCS char code.
|
||
// Next (2 * CharacterImageHeight) bytes are the char image.
|
||
// Next 2 bytes are for unicode version.
|
||
//
|
||
while(Max >= Min) {
|
||
Mid = (Max + Min) / 2;
|
||
Index = Mid*Multiplier;
|
||
code = (DbcsImages[Index] << 8) | DbcsImages[Index+1];
|
||
|
||
if(Code == code) {
|
||
return(DbcsImages+Index+2);
|
||
}
|
||
|
||
if(Code < code) {
|
||
Max = Mid - 1;
|
||
} else {
|
||
Min = Mid + 1;
|
||
}
|
||
}
|
||
|
||
//
|
||
// ERROR: No image found.
|
||
//
|
||
return(NULL);
|
||
}
|
||
|
||
//
|
||
// This array is used to override a glyph returned by GrGetSBCSFontImage.
|
||
// Basically, if the user is asking for one of the first 6 glyphs from
|
||
// the SBCS map, we'll intercept the call and return the value from this
|
||
// array.
|
||
//
|
||
// This is because there was a previous assumption that the first 6 glyphs
|
||
// in an SBCS image were drawing characters. The same 6 drawing characters.
|
||
// That means we just introduced an external reliance on every bootfont.bin.
|
||
// Better to keep the dependence right here.
|
||
//
|
||
UCHAR SbcsRemapper[6][18] = {
|
||
// SBCS codes (16 bytes worth) Unicode value
|
||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x60, 0x60, 0x67, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x25, 0x54},
|
||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0xe6, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x25, 0x57},
|
||
{0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x67, 0x60, 0x60, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x5A},
|
||
{0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x06, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x5D},
|
||
{0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x25, 0x51},
|
||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x50}
|
||
};
|
||
|
||
|
||
PUCHAR
|
||
GrGetSBCSFontImage(
|
||
UCHAR Code
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Gets the font image for SBCS char.
|
||
|
||
Arguments:
|
||
|
||
Code - SBCS char code.
|
||
|
||
Return Value:
|
||
|
||
Pointer to font image, or else NULL.
|
||
|
||
--*/
|
||
|
||
{
|
||
int Max,Min,Mid;
|
||
int Multiplier;
|
||
int Index;
|
||
|
||
|
||
//
|
||
// WARNING: Nauseating hack!!
|
||
// We're going to special case some drawing characters here because
|
||
// these graphics characters may not exist in every locale. This is
|
||
// where we'll supercede some of the bootfont.bin lookups with the
|
||
// glyphs we really want.
|
||
//
|
||
// We're going to remap some low SBCS values to some specific drawing
|
||
// glyphs.
|
||
//
|
||
// 1: "top left corner" double-line. Corresponds to ANSI code 0xC9 and unicode 0x2554
|
||
// ----
|
||
// | --
|
||
// | |
|
||
// | |
|
||
//
|
||
//
|
||
// 2. "top right corner" double-line. Corresponds to ANSI code 0xBB and unicode 0x2557
|
||
// ----
|
||
// -- |
|
||
// | |
|
||
// | |
|
||
//
|
||
// 3. "bottom left corner". Corresponds to ANSI code 0xC8 and unicode 0x255A
|
||
// 4. "bottom right corner". Corresponds to ANSI code 0xBC and unicode 0x255D
|
||
// 5. "double verticl line". Corresponds to ANSI code 0xBA and unicode 0x2551
|
||
// 6. "double horizontal line". Corresponds to ANSI code 0xCD and unicode 0x2550
|
||
//
|
||
if( (Code >= 0x1) && (Code <= 0x6) ) {
|
||
return SbcsRemapper[Code-1];
|
||
}
|
||
|
||
|
||
Min = 0;
|
||
Max = SbcsCharCount;
|
||
// multiplier = 1 (for index) +
|
||
// height +
|
||
// 2 (for unicode encoding)
|
||
//
|
||
Multiplier = 1 + (CharacterImageHeight) + 2;
|
||
|
||
|
||
//
|
||
// Do a binary search for the image.
|
||
// Format of table:
|
||
// First byte contains the SBCS char code.
|
||
// Next (CharacterImageHeight) bytes are the char image.
|
||
// Next 2 bytes are for unicode version.
|
||
//
|
||
while(Max >= Min) {
|
||
Mid = (Max + Min) / 2;
|
||
Index = Mid*Multiplier;
|
||
|
||
if(Code == SbcsImages[Index]) {
|
||
return(SbcsImages+Index+1);
|
||
}
|
||
|
||
if(Code < SbcsImages[Index]) {
|
||
Max = Mid - 1;
|
||
} else {
|
||
Min = Mid + 1;
|
||
}
|
||
}
|
||
|
||
//
|
||
// ERROR: No image found.
|
||
//
|
||
return(NULL);
|
||
}
|
||
|
||
|
||
//
|
||
// Need to turn off optimization for this
|
||
// routine. Since the write and read to
|
||
// GVRAM seem useless to the compiler.
|
||
//
|
||
|
||
#pragma optimize( "", off )
|
||
|
||
VOID
|
||
TextGrSetCurrentAttribute(
|
||
IN UCHAR Attribute
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Sets the attribute by setting up various VGA registers.
|
||
The comments only say what registers are set to what, so
|
||
to understand the logic, follow the code while looking at
|
||
Figure 5-5 of PC&PS/2 Video Systems by Richard Wilton.
|
||
The book is published by Microsoft Press.
|
||
|
||
Arguments:
|
||
|
||
Attribute - New attribute to set to.
|
||
Attribute:
|
||
High nibble - background attribute.
|
||
Low nibble - foreground attribute.
|
||
|
||
Return Value:
|
||
|
||
Nothing.
|
||
|
||
--*/
|
||
|
||
{
|
||
UCHAR temp = 0;
|
||
|
||
//
|
||
// Address of GVRAM off the screen.
|
||
//
|
||
|
||
PUCHAR OffTheScreen = (PUCHAR)(0xa9600);
|
||
|
||
union WordOrByte {
|
||
struct Word { unsigned short ax; } x;
|
||
struct Byte { unsigned char al, ah; } h;
|
||
} regs;
|
||
|
||
//
|
||
// Reset Data Rotate/Function Select
|
||
// regisger.
|
||
//
|
||
|
||
outpw( 0x3ce, 0x3 ); // Need to reset Data Rotate/Function Select.
|
||
|
||
//
|
||
// Set Enable Set/Reset to
|
||
// all (0f).
|
||
//
|
||
|
||
outpw( 0x3ce, 0xf01 );
|
||
|
||
//
|
||
// Put background color into Set/Reset register.
|
||
// This is done to put the background color into
|
||
// the latches later.
|
||
//
|
||
|
||
regs.x.ax = (unsigned short)(Attribute & 0x0f0) << 4;
|
||
outpw( 0x3ce, regs.x.ax ); // Put BLUE color in Set/Reset register.
|
||
|
||
//
|
||
// Put Set/Reset register value into GVRAM
|
||
// off the screen.
|
||
//
|
||
|
||
*OffTheScreen = temp;
|
||
|
||
//
|
||
// Read from screen, so the latches will be
|
||
// updated with the background color.
|
||
//
|
||
|
||
temp = *OffTheScreen;
|
||
|
||
//
|
||
// Set Data Rotate/Function Select register
|
||
// to be XOR.
|
||
//
|
||
|
||
outpw( 0x3ce, 0x1803 );
|
||
|
||
//
|
||
// XOR the foreground and background color and
|
||
// put it in Set/Reset register.
|
||
//
|
||
|
||
regs.h.ah = (Attribute >> 4) ^ (Attribute & 0x0f);
|
||
regs.h.al = 0;
|
||
outpw( 0x3ce, regs.x.ax );
|
||
|
||
//
|
||
// Put Inverse(~) of the XOR of foreground and
|
||
// ground attribute into Enable Set/Reset register.
|
||
//
|
||
|
||
regs.x.ax = ~regs.x.ax & 0x0f01;
|
||
outpw( 0x3ce, regs.x.ax );
|
||
}
|
||
|
||
//
|
||
// Turn optimization on again.
|
||
//
|
||
|
||
#pragma optimize( "", on )
|
||
|
||
|
||
VOID
|
||
TextGrPositionCursor(
|
||
USHORT Row,
|
||
USHORT Column
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Sets the position of the soft cursor. That is, it doesn't move the
|
||
hardware cursor but sets the location of the next write to the
|
||
screen.
|
||
|
||
Arguments:
|
||
|
||
Row - Row coordinate of where character is to be written.
|
||
|
||
Column - Column coordinate of where character is to be written.
|
||
|
||
Returns:
|
||
|
||
Nothing.
|
||
|
||
--*/
|
||
|
||
{
|
||
if(Row >= ScreenHeightCells) {
|
||
Row = (USHORT)ScreenHeightCells-1;
|
||
}
|
||
|
||
if(Column >= ScreenWidthCells) {
|
||
Column = (USHORT)ScreenWidthCells-1;
|
||
}
|
||
|
||
GrVp = (PUCHAR)VIDEO_BUFFER_VA + (Row * VIDEO_BYTES_PER_TEXT_ROW) + Column;
|
||
}
|
||
|
||
|
||
VOID
|
||
TextGrStringOut(
|
||
IN PUCHAR String
|
||
)
|
||
{
|
||
GrWriteMBCSString(String,(unsigned)(-1));
|
||
}
|
||
|
||
|
||
PUCHAR
|
||
TextGrCharOut(
|
||
PUCHAR pc
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Writes a character on the display at the current position.
|
||
Newlines and tabs are interpreted and acted upon.
|
||
|
||
Arguments:
|
||
|
||
pc - pointer to mbcs character to write.
|
||
|
||
Returns:
|
||
|
||
pointer to next character
|
||
|
||
--*/
|
||
|
||
{
|
||
return(pc + GrWriteMBCSString(pc,1));
|
||
}
|
||
|
||
|
||
VOID
|
||
TextGrFillAttribute(
|
||
IN UCHAR Attribute,
|
||
IN ULONG Length
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Changes the screen attribute starting at the current cursor position.
|
||
The cursor is not moved.
|
||
|
||
Arguments:
|
||
|
||
Attribute - Supplies the new attribute
|
||
|
||
Length - Supplies the length of the area to change (in bytes)
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
UCHAR OldAttribute;
|
||
unsigned i;
|
||
ULONG x,y;
|
||
PUCHAR pImage;
|
||
|
||
//
|
||
// Save the current attribute and set the attribute to the
|
||
// character desired by the caller.
|
||
//
|
||
TextGetCursorPosition(&x,&y);
|
||
OldAttribute = TextCurrentAttribute;
|
||
TextSetCurrentAttribute(Attribute);
|
||
|
||
//
|
||
// Dirty hack: just write spaces into the area requested by the caller.
|
||
//
|
||
pImage = GrGetSBCSFontImage(' ');
|
||
for(i=0; i<Length; i++) {
|
||
GrDisplayMBCSChar(pImage,SBCSWIDTH,0x00,0x00);
|
||
}
|
||
|
||
//
|
||
// Restore the current attribute.
|
||
//
|
||
TextSetCurrentAttribute(OldAttribute);
|
||
TextSetCursorPosition(x,y);
|
||
}
|
||
|
||
|
||
VOID
|
||
TextGrClearToEndOfLine(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Clears from the current cursor position to the end of the line
|
||
by writing blanks with the current video attribute.
|
||
The cursor position is not changed.
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Returns:
|
||
|
||
Nothing
|
||
|
||
--*/
|
||
|
||
{
|
||
unsigned u;
|
||
ULONG OldX,OldY;
|
||
UCHAR temp;
|
||
|
||
//
|
||
// Fill with blanks up to char before cursor position.
|
||
//
|
||
temp = ' ';
|
||
TextGetCursorPosition(&OldX,&OldY);
|
||
for(u=TextColumn; u<ScreenWidthCells; u++) {
|
||
TextGrCharOut(&temp);
|
||
}
|
||
TextSetCursorPosition(OldX,OldY);
|
||
}
|
||
|
||
|
||
VOID
|
||
TextGrClearFromStartOfLine(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Clears from the start of the line to the current cursor position
|
||
by writing blanks with the current video attribute.
|
||
The cursor position is not changed.
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Returns:
|
||
|
||
Nothing
|
||
|
||
--*/
|
||
|
||
{
|
||
unsigned u;
|
||
ULONG OldX,OldY;
|
||
UCHAR temp = ' ';
|
||
|
||
//
|
||
// Fill with blanks up to char before cursor position.
|
||
//
|
||
TextGetCursorPosition(&OldX,&OldY);
|
||
TextSetCursorPosition(0,OldY);
|
||
for(u=0; u<TextColumn; u++) {
|
||
TextGrCharOut(&temp);
|
||
}
|
||
TextSetCursorPosition(OldX,OldY);
|
||
}
|
||
|
||
VOID
|
||
TextGrClearToEndOfDisplay(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Clears from the current cursor position to the end of the video
|
||
display by writing blanks with the current video attribute.
|
||
The cursor position is not changed.
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Returns:
|
||
|
||
Nothing
|
||
|
||
--*/
|
||
{
|
||
unsigned i;
|
||
//
|
||
// Clear current line
|
||
//
|
||
TextGrClearToEndOfLine();
|
||
|
||
//
|
||
// Clear the remaining lines
|
||
//
|
||
for(i=(TextRow+1)*VIDEO_BYTES_PER_TEXT_ROW; i<VIDEO_SIZE_BYTES; i++) {
|
||
((PUCHAR)VIDEO_BUFFER_VA)[i] = 0x00;
|
||
}
|
||
}
|
||
|
||
|
||
VOID
|
||
TextGrClearDisplay(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Clears the text-mode video display by writing blanks with
|
||
the current video attribute over the entire display.
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Returns:
|
||
|
||
Nothing
|
||
|
||
--*/
|
||
|
||
{
|
||
unsigned i;
|
||
|
||
//
|
||
// Clear screen.
|
||
//
|
||
for(i=0; i<VIDEO_SIZE_BYTES; i++) {
|
||
((PUCHAR)VIDEO_BUFFER_VA)[i] = 0x00;
|
||
}
|
||
}
|
||
|
||
|
||
VOID
|
||
TextGrScrollDisplay(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Scrolls the display up one line. The cursor position is not changed.
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Returns:
|
||
|
||
Nothing
|
||
|
||
--*/
|
||
|
||
{
|
||
PUCHAR Source,Dest;
|
||
unsigned n,i;
|
||
ULONG OldX,OldY;
|
||
UCHAR temp = ' ';
|
||
|
||
Source = (PUCHAR)(VIDEO_BUFFER_VA) + VIDEO_BYTES_PER_TEXT_ROW;
|
||
Dest = (PUCHAR)VIDEO_BUFFER_VA;
|
||
|
||
n = VIDEO_BYTES_PER_TEXT_ROW * (ScreenHeightCells-1);
|
||
|
||
for(i=0; i<n; i++) {
|
||
*Dest++ = *Source++;
|
||
}
|
||
|
||
//
|
||
// Write blanks in the bottom line, using the current attribute.
|
||
//
|
||
TextGetCursorPosition(&OldX,&OldY);
|
||
|
||
TextSetCursorPosition(0,ScreenHeightCells-1);
|
||
for(i=0; i<ScreenWidthCells; i++) {
|
||
TextGrCharOut(&temp);
|
||
}
|
||
|
||
TextSetCursorPosition(OldX,OldY);
|
||
}
|
||
|
||
|
||
UCHAR GrGraphicsChars[GraphicsCharMax] = { 1, 2, 3, 4, 5, 6 };
|
||
// UCHAR GrGraphicsChars[GraphicsCharMax] = { '<27>','<27>','<27>','<27>','<27>','<27>' };
|
||
|
||
UCHAR
|
||
TextGrGetGraphicsChar(
|
||
IN GraphicsChar WhichOne
|
||
)
|
||
{
|
||
return(GrGraphicsChars[WhichOne]);
|
||
}
|
||
|
||
|
||
VOID
|
||
TextGrInitialize(
|
||
IN ULONG DiskId,
|
||
OUT PULONG ImageLength
|
||
)
|
||
{
|
||
ULONG FileId;
|
||
ARC_STATUS Status;
|
||
PUCHAR FontImage;
|
||
ULONG BytesRead;
|
||
BOOTFONTBIN_HEADER FileHeader;
|
||
LARGE_INTEGER SeekOffset;
|
||
ULONG SbcsSize,DbcsSize;
|
||
|
||
if (ImageLength) {
|
||
*ImageLength = 0;
|
||
}
|
||
|
||
//
|
||
// Attempt to open bootfont.bin. If this fails, then boot in single-byte charset mode.
|
||
//
|
||
if (BlBootingFromNet
|
||
#if defined(REMOTE_BOOT)
|
||
&& NetworkBootRom
|
||
#endif // defined(REMOTE_BOOT)
|
||
) {
|
||
CHAR Buffer[129];
|
||
strcpy(Buffer, NetBootPath);
|
||
strcat(Buffer, "BOOTFONT.BIN");
|
||
Status = BlOpen(DiskId,Buffer,ArcOpenReadOnly,&FileId);
|
||
} else {
|
||
Status = BlOpen(DiskId,"\\BOOTFONT.BIN",ArcOpenReadOnly,&FileId);
|
||
}
|
||
if(Status != ESUCCESS) {
|
||
goto clean0;
|
||
}
|
||
|
||
//
|
||
// Read in the file header and check some values.
|
||
// We enforce the width of 8/16 here. If this is changed code all over the
|
||
// rest of this module must also be changed.
|
||
//
|
||
Status = BlRead(FileId,&FileHeader,sizeof(BOOTFONTBIN_HEADER),&BytesRead);
|
||
if((Status != ESUCCESS)
|
||
|| (BytesRead != sizeof(BOOTFONTBIN_HEADER))
|
||
|| (FileHeader.Signature != BOOTFONTBIN_SIGNATURE)
|
||
|| (FileHeader.CharacterImageSbcsWidth != 8)
|
||
|| (FileHeader.CharacterImageDbcsWidth != 16)
|
||
) {
|
||
goto clean1;
|
||
}
|
||
|
||
//
|
||
// Calculate the amount of memory needed to hold the sbcs and dbcs
|
||
// character entries. Each sbcs entry is 1 byte for the ascii value
|
||
// followed by n bytes for the image itself. We assume a width of 8 pixels.
|
||
// For dbcs chars each entry is 2 bytes for the codepoint and n bytes
|
||
// for the image itself. We assume a width of 16 pixels.
|
||
//
|
||
// Add in an extra 2 bytes per entry for the ending unicode value of the SBCS/DBCS
|
||
// character.
|
||
//
|
||
// Also perform further validation on the file by comparing the sizes
|
||
// given in the header against a size we calculate.
|
||
//
|
||
SbcsSize = FileHeader.NumSbcsChars * (FileHeader.CharacterImageHeight + 1 + 2);
|
||
DbcsSize = FileHeader.NumDbcsChars * ((2 * FileHeader.CharacterImageHeight) + 2 + 2);
|
||
|
||
if((SbcsSize != FileHeader.SbcsEntriesTotalSize)
|
||
|| (DbcsSize != FileHeader.DbcsEntriesTotalSize)) {
|
||
goto clean1;
|
||
}
|
||
|
||
//
|
||
// save off the image length argument if requested
|
||
//
|
||
if (ImageLength) {
|
||
(*ImageLength) = sizeof(BOOTFONTBIN_HEADER) + SbcsSize + DbcsSize;
|
||
}
|
||
|
||
//
|
||
// Allocate memory to hold the font. We use FwAllocatePool() because
|
||
// that routine uses a separate heap that was inititialized before the
|
||
// high-level Bl memory system was initialized, and thus is safe.
|
||
//
|
||
FontImage = FwAllocatePool(SbcsSize+DbcsSize);
|
||
if(!FontImage) {
|
||
goto clean1;
|
||
}
|
||
|
||
//
|
||
// The entries get read into the base of the region we carved out.
|
||
// The dbcs images get read in immediately after that.
|
||
//
|
||
SbcsImages = FontImage;
|
||
DbcsImages = SbcsImages + FileHeader.SbcsEntriesTotalSize;
|
||
|
||
//
|
||
// Read in the sbcs entries.
|
||
//
|
||
SeekOffset.HighPart = 0;
|
||
SeekOffset.LowPart = FileHeader.SbcsOffset;
|
||
if((BlSeek(FileId,&SeekOffset,SeekAbsolute) != ESUCCESS)
|
||
|| (BlRead(FileId,SbcsImages,FileHeader.SbcsEntriesTotalSize,&BytesRead) != ESUCCESS)
|
||
|| (BytesRead != FileHeader.SbcsEntriesTotalSize)) {
|
||
goto clean2;
|
||
}
|
||
|
||
//
|
||
// Read in the dbcs entries.
|
||
//
|
||
SeekOffset.HighPart = 0;
|
||
SeekOffset.LowPart = FileHeader.DbcsOffset;
|
||
if((BlSeek(FileId,&SeekOffset,SeekAbsolute) != ESUCCESS)
|
||
|| (BlRead(FileId,DbcsImages,FileHeader.DbcsEntriesTotalSize,&BytesRead) != ESUCCESS)
|
||
|| (BytesRead != FileHeader.DbcsEntriesTotalSize)) {
|
||
goto clean2;
|
||
}
|
||
|
||
//
|
||
// We're done with the file now.
|
||
//
|
||
BlClose(FileId);
|
||
|
||
//
|
||
// Set up various values used for displaying the font.
|
||
//
|
||
DbcsLangId = FileHeader.LanguageId;
|
||
CharacterImageHeight = FileHeader.CharacterImageHeight;
|
||
CharacterTopPad = FileHeader.CharacterTopPad;
|
||
CharacterBottomPad = FileHeader.CharacterBottomPad;
|
||
CharacterCellHeight = CharacterImageHeight + CharacterTopPad + CharacterBottomPad;
|
||
SbcsCharCount = FileHeader.NumSbcsChars;
|
||
DbcsCharCount = FileHeader.NumDbcsChars;
|
||
//
|
||
// throughout the file, row/columns are passed around as ushorts,
|
||
// and compared to ScreenHeight/Width.
|
||
// ensure ScreenWidth/Height are bounded by the size of a USHORT
|
||
//
|
||
ScreenWidthCells = TRUNCATE_SIZE_AT_USHORT_MAX(VIDEO_WIDTH_PIXELS / FileHeader.CharacterImageSbcsWidth);
|
||
ScreenHeightCells = TRUNCATE_SIZE_AT_USHORT_MAX(VIDEO_HEIGHT_SCAN_LINES / CharacterCellHeight);
|
||
|
||
RtlMoveMemory(LeadByteTable,FileHeader.DbcsLeadTable,(MAX_DBCS_RANGE+1)*2);
|
||
|
||
//
|
||
// Switch the display into 640x480 graphics mode and clear it.
|
||
// We're done.
|
||
//
|
||
HW_CURSOR(0x80000000,0x12);
|
||
TextClearDisplay();
|
||
return;
|
||
|
||
clean2:
|
||
//
|
||
// Want to free the memory we allocated but there's no routine to do it
|
||
//
|
||
//FwFreePool();
|
||
clean1:
|
||
//
|
||
// Close the font file.
|
||
//
|
||
BlClose(FileId);
|
||
clean0:
|
||
return;
|
||
}
|
||
|
||
|
||
VOID
|
||
TextGrTerminate(
|
||
VOID
|
||
)
|
||
{
|
||
if(DbcsLangId) {
|
||
DbcsLangId = 0;
|
||
//
|
||
// This command switches the display into 80x25 text mode
|
||
// if there is no bitmap logo displayed. The logo is common
|
||
// to the loader and bootvid, and in this case we don't want
|
||
// to switch to text mode and then back to graphics.
|
||
//
|
||
if(!GraphicsMode && AllowGraphicsReset)
|
||
HW_CURSOR(0x80000000,0x3);
|
||
}
|
||
}
|
||
|
||
|
||
VOID
|
||
UTF8Encode(
|
||
USHORT InputValue,
|
||
PUCHAR UTF8Encoding
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Generates the UTF8 translation for a 16-bit value.
|
||
|
||
Arguments:
|
||
|
||
InputValue - 16-bit value to be encoded.
|
||
UTF8Encoding - receives the UTF8-encoding of the 16-bit value
|
||
|
||
Return Value:
|
||
|
||
NONE.
|
||
--*/
|
||
{
|
||
|
||
//
|
||
// convert into UTF8 for actual transmission
|
||
//
|
||
// UTF-8 encodes 2-byte Unicode characters as follows:
|
||
// If the first nine bits are zero (00000000 0xxxxxxx), encode it as one byte 0xxxxxxx
|
||
// If the first five bits are zero (00000yyy yyxxxxxx), encode it as two bytes 110yyyyy 10xxxxxx
|
||
// Otherwise (zzzzyyyy yyxxxxxx), encode it as three bytes 1110zzzz 10yyyyyy 10xxxxxx
|
||
//
|
||
if( (InputValue & 0xFF80) == 0 ) {
|
||
//
|
||
// if the top 9 bits are zero, then just
|
||
// encode as 1 byte. (ASCII passes through unchanged).
|
||
//
|
||
UTF8Encoding[2] = (UCHAR)(InputValue & 0xFF);
|
||
} else if( (InputValue & 0xF800) == 0 ) {
|
||
//
|
||
// if the top 5 bits are zero, then encode as 2 bytes
|
||
//
|
||
UTF8Encoding[2] = (UCHAR)(InputValue & 0x3F) | 0x80;
|
||
UTF8Encoding[1] = (UCHAR)((InputValue >> 6) & 0x1F) | 0xC0;
|
||
} else {
|
||
//
|
||
// encode as 3 bytes
|
||
//
|
||
UTF8Encoding[2] = (UCHAR)(InputValue & 0x3F) | 0x80;
|
||
UTF8Encoding[1] = (UCHAR)((InputValue >> 6) & 0x3F) | 0x80;
|
||
UTF8Encoding[0] = (UCHAR)((InputValue >> 12) & 0xF) | 0xE0;
|
||
}
|
||
}
|
||
|
||
VOID
|
||
GetDBCSUtf8Translation(
|
||
PUCHAR InputChar,
|
||
PUCHAR UTF8Encoding
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Gets the UTF8 translation for a DBCS char.
|
||
|
||
Arguments:
|
||
|
||
InputChar - pointer to DBCS character code.
|
||
UTF8Encoding - receives the UTF8-encoding of the DBCS character code
|
||
|
||
Return Value:
|
||
|
||
NONE.
|
||
|
||
--*/
|
||
|
||
{
|
||
int Min,Max,Mid;
|
||
int Multiplier;
|
||
int Index;
|
||
USHORT code;
|
||
USHORT Code;
|
||
|
||
Code = *InputChar++ << 8;
|
||
Code = Code | *InputChar++;
|
||
|
||
|
||
// initialize our output.
|
||
for( Index = 0; Index < 3; Index++ ) {
|
||
UTF8Encoding[Index] = 0;
|
||
}
|
||
|
||
|
||
Min = 0;
|
||
Max = DbcsCharCount;
|
||
|
||
//
|
||
// multiplier = 2 (for index) +
|
||
// 2* height +
|
||
// 2 (for unicode encoding)
|
||
//
|
||
Multiplier = 2 + (2*CharacterImageHeight) + 2;
|
||
|
||
//
|
||
// Do a binary search for the image.
|
||
// Format of table:
|
||
// First 2 bytes contain the DBCS char code.
|
||
// Next (2 * CharacterImageHeight) bytes are the char image.
|
||
// Next 2 bytes are for unicode version.
|
||
//
|
||
while(Max >= Min) {
|
||
Mid = (Max + Min) / 2;
|
||
Index = Mid*Multiplier;
|
||
code = (DbcsImages[Index] << 8) | (DbcsImages[Index+1]);
|
||
|
||
if(Code == code) {
|
||
|
||
WCHAR UnicodeValue = L'\0';
|
||
PUCHAR Image = (PUCHAR)DbcsImages+Index+2;
|
||
|
||
|
||
//
|
||
// image is pointing to an array of uchars, which are
|
||
// a bitmap of the character we want to display. Right
|
||
// behind this array is the unicode encoding of the
|
||
// character. Here's what the structure looks like:
|
||
//
|
||
// index bitmap unicode encoding of 'index'
|
||
// ^ ^ ^
|
||
// | | |
|
||
// | | - we previously converted 'index' into
|
||
// | | its unicode equivilent.
|
||
// | |
|
||
// | - This is where 'image' is pointing. It's an array of characters
|
||
// | (2 * width in length), which represents the bitmap to be displayed
|
||
// | on the screen which will represent the value in 'index'
|
||
// |
|
||
// - This is either an 8-bit value (if we're messing with SBCS), or a 16-bit value
|
||
// (if we're dealing with DBCS), in which case 'width' will be DBCSWIDTH.
|
||
//
|
||
// We're going to jump over the bitmap and retrieve the unicode encoding. Then we'll
|
||
// encode it into UTF8, then spew it over the headless port.
|
||
//
|
||
UnicodeValue = (WCHAR)( (Image[DBCSWIDTH*2]) | (Image[(DBCSWIDTH*2) + 1] << 8) );
|
||
|
||
UTF8Encode( UnicodeValue,
|
||
UTF8Encoding );
|
||
|
||
return;
|
||
}
|
||
|
||
if(Code < code) {
|
||
Max = Mid - 1;
|
||
} else {
|
||
Min = Mid + 1;
|
||
}
|
||
}
|
||
|
||
//
|
||
// ERROR: No image found.
|
||
//
|
||
return;
|
||
}
|
||
|
||
|
||
VOID
|
||
GetSBCSUtf8Translation(
|
||
PUCHAR InputChar,
|
||
PUCHAR UTF8Encoding
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Gets the font image for SBCS char.
|
||
|
||
Arguments:
|
||
|
||
InputChar - pointer to SBCS character code.
|
||
UTF8Encoding - receives the UTF8-encoding of the SBCS character code
|
||
|
||
Return Value:
|
||
|
||
NONE.
|
||
|
||
--*/
|
||
|
||
{
|
||
int Index;
|
||
UCHAR Code = *InputChar;
|
||
PUCHAR SBCSImage = NULL;
|
||
WCHAR UnicodeValue;
|
||
|
||
// initialize our output.
|
||
for( Index = 0; Index < 3; Index++ ) {
|
||
UTF8Encoding[Index] = 0;
|
||
}
|
||
|
||
SBCSImage = GrGetSBCSFontImage( Code );
|
||
|
||
if( SBCSImage ) {
|
||
UnicodeValue = (WCHAR)( (SBCSImage[SBCSWIDTH*2]) | (SBCSImage[(SBCSWIDTH*2) + 1] << 8) );
|
||
|
||
UTF8Encode( UnicodeValue,
|
||
UTF8Encoding );
|
||
}
|
||
return;
|
||
}
|
||
|