/*++ 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= 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> 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; }