/*++ Copyright (c) 2013 Minoca Corp. All Rights Reserved Module Name: textvid.c Abstract: This module implements a fake firmware interface for ARM systems that have no firmware services layer. Author: Evan Green 30-Jan-2013 Environment: Boot and Kernel --*/ // // ------------------------------------------------------------------- Includes // #include "basevidp.h" // // --------------------------------------------------------------------- Macros // // // This routine converts a color value from software form into its physical // form. // #define TRANSLATE_COLOR(_Value, _Translation) \ (((SHIFT_COLOR(_Value, _Translation.RedShift) & _Translation.RedMask)) | \ ((SHIFT_COLOR(_Value, _Translation.GreenShift) & \ _Translation.GreenMask)) | \ ((SHIFT_COLOR(_Value, _Translation.BlueShift) & _Translation.BlueMask))) // // This routine shifts a value left by the given amount (right if the shift is // negative). // #define SHIFT_COLOR(_Value, _Shift) \ (((_Shift) >= 0) ? ((_Value) << (_Shift)) : ((_Value) >> -(_Shift))) // // This macro just flips red and blue. // #define SWIZZLE_RED_BLUE(_Value) \ ((((_Value) & 0x000000FF) << 16) | (((_Value) & 0x00FF0000) >> 16) | \ ((_Value) & 0x0000FF00)) // // This macro converts a foreground and background color into attributes // (upper 8 of 16 bits) for BIOS text mode. // #define BIOS_TEXT_ATTRIBUTES(_Foreground, _Background) \ ((((_Foreground) & 0xF) << 8) | (((_Background) & 0x7) << 12)) // // ---------------------------------------------------------------- Definitions // // // ----------------------------------------------- Internal Function Prototypes // VOID VidpConvertPalette ( PBASE_VIDEO_CONTEXT Context, PBASE_VIDEO_PALETTE Palette, PBASE_VIDEO_PALETTE PhysicalPalette ); VOID VidpPrintCharacter ( PBASE_VIDEO_CONTEXT Context, ULONG XCoordinate, ULONG YCoordinate, PBASE_VIDEO_CHARACTER Character ); VOID VidpConvertIntegerToString ( LONG Integer, PSTR String, ULONG Base ); ULONG VidpFindHighestBitSet ( ULONG Value ); // // ------------------------------------------------------ Data Type Definitions // typedef struct _COLOR_TRANSLATION { LONG RedShift; ULONG RedMask; LONG GreenShift; ULONG GreenMask; LONG BlueShift; ULONG BlueMask; } COLOR_TRANSLATION, *PCOLOR_TRANSLATION; // // -------------------------------------------------------------------- Globals // // // Store the default palette to use. // BASE_VIDEO_PALETTE VidDefaultPalette = { { BASE_VIDEO_COLOR_RGB(255, 240, 165), BASE_VIDEO_COLOR_RGB(0, 0, 0), BASE_VIDEO_COLOR_RGB(134, 37, 23), BASE_VIDEO_COLOR_RGB(37, 188, 36), BASE_VIDEO_COLOR_RGB(173, 173, 39), BASE_VIDEO_COLOR_RGB(50, 27, 184), BASE_VIDEO_COLOR_RGB(134, 30, 134), BASE_VIDEO_COLOR_RGB(47, 204, 197), BASE_VIDEO_COLOR_RGB(203, 204, 206), }, { BASE_VIDEO_COLOR_RGB(255, 255, 170), BASE_VIDEO_COLOR_RGB(142, 145, 149), BASE_VIDEO_COLOR_RGB(255, 120, 100), BASE_VIDEO_COLOR_RGB(49, 231, 34), BASE_VIDEO_COLOR_RGB(234, 236, 35), BASE_VIDEO_COLOR_RGB(70, 160, 255), BASE_VIDEO_COLOR_RGB(240, 100, 240), BASE_VIDEO_COLOR_RGB(20, 240, 240), BASE_VIDEO_COLOR_RGB(233, 235, 237), }, BASE_VIDEO_COLOR_RGB(19, 119, 61), BASE_VIDEO_COLOR_RGB(19, 119, 61), BASE_VIDEO_COLOR_RGB(255, 240, 165), BASE_VIDEO_COLOR_RGB(142, 40, 0), }; // // Store a pointer to the default font to use. // PBASE_VIDEO_FONT VidDefaultFont = &VidFontPs2Thin48x16; // // Store the conversion between ANSI colors and BIOS text attribute numbers. // const UCHAR VidTextModeColors[AnsiColorCount] = {7, 0, 4, 2, 6, 1, 5, 3, 7}; // // ------------------------------------------------------------------ Functions // KSTATUS VidInitialize ( PBASE_VIDEO_CONTEXT Context, PSYSTEM_RESOURCE_FRAME_BUFFER FrameBuffer ) /*++ Routine Description: This routine initializes the base video library. Arguments: Context - Supplies a pointer to the video context to initialize. FrameBuffer - Supplies a pointer to the frame buffer parameters. Return Value: Status code. --*/ { KSTATUS Status; Context->Mode = FrameBuffer->Mode; Context->FrameBuffer = FrameBuffer->Header.VirtualAddress; Context->Width = FrameBuffer->Width; Context->Height = FrameBuffer->Height; Context->PixelsPerScanLine = FrameBuffer->PixelsPerScanLine; Context->BitsPerPixel = FrameBuffer->BitsPerPixel; Context->RedMask = FrameBuffer->RedMask; Context->GreenMask = FrameBuffer->GreenMask; Context->BlueMask = FrameBuffer->BlueMask; ASSERT((Context->Mode != BaseVideoInvalidMode) && (Context->FrameBuffer != NULL) && (Context->Width != 0) && (Context->Height != 0) && (Context->PixelsPerScanLine >= Context->Width) && (Context->BitsPerPixel != 0)); ASSERT((Context->Mode != BaseVideoModeFrameBuffer) || ((Context->RedMask != 0) && (Context->GreenMask != 0) && (Context->BlueMask != 0))); RtlCopyMemory(&(Context->Palette), &VidDefaultPalette, sizeof(BASE_VIDEO_PALETTE)); VidpConvertPalette(Context, &VidDefaultPalette, &Context->PhysicalPalette); Context->Font = VidDefaultFont; ASSERT(Context->Font != NULL); if (Context->Mode == BaseVideoModeBiosText) { Context->Columns = Context->Width; Context->Rows = Context->Height; } else { Context->Columns = Context->Width / Context->Font->CellWidth; Context->Rows = Context->Height / Context->Font->CellHeight; } Status = STATUS_SUCCESS; return Status; } VOID VidClearScreen ( PBASE_VIDEO_CONTEXT Context, ULONG MinimumX, ULONG MinimumY, ULONG MaximumX, ULONG MaximumY ) /*++ Routine Description: This routine clears a region of the screen, filling it with the default fill character. If no frame buffer is present, this is a no-op. Arguments: Context - Supplies a pointer to the initialized base video context. MinimumX - Supplies the minimum X coordinate of the rectangle to clear, inclusive. MinimumY - Supplies the minimum Y coordinate of the rectangle to clear, inclusive. MaximumX - Supplies the maximum X coordinate of the rectangle to clear, exclusive. MaximumY - Supplies the maximum Y coordinate of the rectangle to clear, exclusive. Return Value: None. --*/ { BASE_VIDEO_CHARACTER Character; ULONG Color; ULONG HorizontalIndex; PULONG Pixel; PUSHORT Pixel16; PUCHAR Pixel8; ULONG VerticalIndex; if (Context->FrameBuffer == NULL) { return; } // // If either minimum value is off the screen, exit. // if (MinimumX >= Context->Width) { return; } if (MinimumY >= Context->Height) { return; } // // Truncate the maximum values. // if (MaximumX > Context->Width) { MaximumX = Context->Width; } if (MaximumY > Context->Height) { MaximumY = Context->Height; } // // Handle text mode by running around printing spaces. // if (Context->Mode == BaseVideoModeBiosText) { Character.Data.Character = ' '; Character.Data.Attributes = 0; for (VerticalIndex = MinimumY; VerticalIndex < MaximumY; VerticalIndex += 1) { for (HorizontalIndex = MinimumX; HorizontalIndex < MaximumX; HorizontalIndex += 1) { VidpPrintCharacter(Context, HorizontalIndex, VerticalIndex, &Character); } } return; } Color = Context->PhysicalPalette.DefaultBackground; // // Switch on the bits per pixel outside the hot inner loop. // switch (Context->BitsPerPixel) { case 8: for (VerticalIndex = MinimumY; VerticalIndex < MaximumY; VerticalIndex += 1) { Pixel = (PULONG)(Context->FrameBuffer + (((VerticalIndex * Context->PixelsPerScanLine) + MinimumX) * (Context->BitsPerPixel / BITS_PER_BYTE))); Pixel8 = (PUCHAR)Pixel; for (HorizontalIndex = MinimumX; HorizontalIndex < MaximumX; HorizontalIndex += 1) { *Pixel8 = (UCHAR)Color; Pixel8 += 1; } } break; case 16: for (VerticalIndex = MinimumY; VerticalIndex < MaximumY; VerticalIndex += 1) { Pixel = (PULONG)(Context->FrameBuffer + (((VerticalIndex * Context->PixelsPerScanLine) + MinimumX) * (Context->BitsPerPixel / BITS_PER_BYTE))); Pixel16 = (PUSHORT)Pixel; for (HorizontalIndex = MinimumX; HorizontalIndex < MaximumX; HorizontalIndex += 1) { *Pixel16 = (USHORT)Color; Pixel16 += 1; } } break; case 24: for (VerticalIndex = MinimumY; VerticalIndex < MaximumY; VerticalIndex += 1) { Pixel = (PULONG)(Context->FrameBuffer + (((VerticalIndex * Context->PixelsPerScanLine) + MinimumX) * (Context->BitsPerPixel / BITS_PER_BYTE))); Pixel8 = (PUCHAR)Pixel; for (HorizontalIndex = MinimumX; HorizontalIndex < MaximumX; HorizontalIndex += 1) { *Pixel8 = (UCHAR)Color; *(Pixel8 + 1) = (UCHAR)(Color >> 8); *(Pixel8 + 2) = (UCHAR)(Color >> 16); Pixel8 += 3; } } break; case 32: for (VerticalIndex = MinimumY; VerticalIndex < MaximumY; VerticalIndex += 1) { Pixel = (PULONG)(Context->FrameBuffer + (((VerticalIndex * Context->PixelsPerScanLine) + MinimumX) * (Context->BitsPerPixel / BITS_PER_BYTE))); for (HorizontalIndex = MinimumX; HorizontalIndex < MaximumX; HorizontalIndex += 1) { *Pixel = Color; Pixel += 1; } } break; default: ASSERT(FALSE); break; } return; } VOID VidPrintString ( PBASE_VIDEO_CONTEXT Context, ULONG XCoordinate, ULONG YCoordinate, PSTR String ) /*++ Routine Description: This routine prints a null-terminated string to the screen at the specified location. Arguments: Context - Supplies a pointer to the initialized base video context. XCoordinate - Supplies the X coordinate of the location on the screen to write to. YCoordinate - Supplies the Y cooordinate of the location on the screen to write to. String - Supplies the string to print. Return Value: None. --*/ { BASE_VIDEO_CHARACTER Character; ULONG Columns; ULONG Rows; if (Context->FrameBuffer == NULL) { return; } Columns = Context->Columns; Rows = Context->Rows; Character.AsUint32 = 0; while (*String != '\0') { Character.Data.Character = *String; VidpPrintCharacter(Context, XCoordinate, YCoordinate, &Character); XCoordinate += 1; if (XCoordinate >= Columns) { XCoordinate = 0; YCoordinate += 1; } if (YCoordinate >= Rows) { YCoordinate = 0; } String += 1; } return; } VOID VidPrintHexInteger ( PBASE_VIDEO_CONTEXT Context, ULONG XCoordinate, ULONG YCoordinate, ULONG Number ) /*++ Routine Description: This routine prints an integer to the screen in the specified location. Arguments: Context - Supplies a pointer to the initialized base video context. XCoordinate - Supplies the X coordinate of the location on the screen to write to. YCoordinate - Supplies the Y cooordinate of the location on the screen to write to. Number - Supplies the signed integer to print. Return Value: None. --*/ { CHAR StringBuffer[30]; VidpConvertIntegerToString(Number, StringBuffer, 16); VidPrintString(Context, XCoordinate, YCoordinate, StringBuffer); return; } VOID VidPrintInteger ( PBASE_VIDEO_CONTEXT Context, ULONG XCoordinate, ULONG YCoordinate, LONG Number ) /*++ Routine Description: This routine prints an integer to the screen in the specified location. Arguments: Context - Supplies a pointer to the initialized base video context. XCoordinate - Supplies the X coordinate of the location on the screen to write to. YCoordinate - Supplies the Y cooordinate of the location on the screen to write to. Number - Supplies the signed integer to print. Return Value: None. --*/ { CHAR StringBuffer[30]; VidpConvertIntegerToString(Number, StringBuffer, 10); VidPrintString(Context, XCoordinate, YCoordinate, StringBuffer); return; } VOID VidPrintCharacters ( PBASE_VIDEO_CONTEXT Context, ULONG XCoordinate, ULONG YCoordinate, PBASE_VIDEO_CHARACTER Characters, ULONG Count ) /*++ Routine Description: This routine prints a set of characters. Arguments: Context - Supplies a pointer to the initialized base video context. XCoordinate - Supplies the X coordinate of the location on the screen to write to. YCoordinate - Supplies the Y cooordinate of the location on the screen to write to. Characters - Supplies a pointer to the array of characters to write. Count - Supplies the number of characters in the array. Return Value: None. --*/ { ULONG Columns; ULONG Index; ULONG Rows; Columns = Context->Columns; Rows = Context->Rows; for (Index = 0; Index < Count; Index += 1) { VidpPrintCharacter(Context, XCoordinate, YCoordinate, Characters + Index); XCoordinate += 1; if (XCoordinate >= Columns) { XCoordinate = 0; YCoordinate += 1; } if (YCoordinate >= Rows) { YCoordinate = 0; } } return; } VOID VidSetPalette ( PBASE_VIDEO_CONTEXT Context, PBASE_VIDEO_PALETTE Palette, PBASE_VIDEO_PALETTE OldPalette ) /*++ Routine Description: This routine sets the current video palette. It is the caller's responsibility to synchronize both with printing and clearing the screen. Arguments: Context - Supplies a pointer to the initialized base video context. Palette - Supplies a pointer to the palette to set. This memory will be copied. OldPalette - Supplies an optional pointer where the old palette data will be returned. Return Value: None. --*/ { if (OldPalette != NULL) { RtlCopyMemory(OldPalette, &(Context->Palette), sizeof(BASE_VIDEO_PALETTE)); } RtlCopyMemory(&(Context->Palette), Palette, sizeof(BASE_VIDEO_PALETTE)); VidpConvertPalette(Context, &(Context->Palette), &(Context->PhysicalPalette)); return; } VOID VidSetPartialPalette ( PBASE_VIDEO_CONTEXT Context, PBASE_VIDEO_PARTIAL_PALETTE PartialPalette ) /*++ Routine Description: This routine sets the current video palette. It is the caller's responsibility to synchronize both with printing and clearing the screen. Arguments: Context - Supplies a pointer to the initialized base video context. PartialPalette - Supplies a pointer to the palette to set. This memory will be copied. Values in the palette not specified here will be left unchanged. Return Value: None. --*/ { BASE_VIDEO_PALETTE Palette; VidGetPalette(Context, &Palette); Palette.AnsiColor[AnsiColorDefault] = PartialPalette->DefaultForeground; Palette.BoldAnsiColor[AnsiColorDefault] = PartialPalette->DefaultBoldForeground; Palette.DefaultBackground = PartialPalette->DefaultBackground; Palette.DefaultBoldBackground = PartialPalette->DefaultBoldBackground; Palette.CursorText = PartialPalette->CursorText; Palette.CursorBackground = PartialPalette->CursorBackground; VidSetPalette(Context, &Palette, NULL); return; } VOID VidGetPalette ( PBASE_VIDEO_CONTEXT Context, PBASE_VIDEO_PALETTE Palette ) /*++ Routine Description: This routine gets the current video palette. It is the caller's responsibility to synchronize with anyone else that might be changing the palette. Arguments: Context - Supplies a pointer to the initialized base video context. Palette - Supplies a pointer where the palette will be returned. Return Value: None. --*/ { RtlCopyMemory(Palette, &(Context->Palette), sizeof(BASE_VIDEO_PALETTE)); return; } // // --------------------------------------------------------- Internal Functions // VOID VidpConvertPalette ( PBASE_VIDEO_CONTEXT Context, PBASE_VIDEO_PALETTE Palette, PBASE_VIDEO_PALETTE PhysicalPalette ) /*++ Routine Description: This routine converts the given palette into a physical palette that uses the native pixel format. Arguments: Context - Supplies a pointer to the initialized base video context. Palette - Supplies the natural palette to convert. PhysicalPalette - Supplies a pointer where the palette in native pixel format will be returned. Return Value: None. --*/ { ULONG BlueBit; ULONG BlueMask; ULONG ColorIndex; ULONG GreenBit; ULONG GreenMask; ULONG RedBit; ULONG RedMask; COLOR_TRANSLATION Translation; if (Context->Mode == BaseVideoModeBiosText) { for (ColorIndex = 0; ColorIndex < AnsiColorCount; ColorIndex += 1) { PhysicalPalette->AnsiColor[ColorIndex] = VidTextModeColors[ColorIndex]; PhysicalPalette->BoldAnsiColor[ColorIndex] = VidTextModeColors[ColorIndex] + 8; } PhysicalPalette->DefaultBackground = VidTextModeColors[AnsiColorBlack]; PhysicalPalette->DefaultBoldBackground = VidTextModeColors[AnsiColorWhite]; PhysicalPalette->CursorText = PhysicalPalette->DefaultBackground; PhysicalPalette->CursorBackground = PhysicalPalette->AnsiColor[AnsiColorDefault]; goto ConvertPaletteEnd; } ASSERT(Context->Mode == BaseVideoModeFrameBuffer); RedMask = Context->RedMask; GreenMask = Context->GreenMask; BlueMask = Context->BlueMask; ASSERT((RedMask != 0) && (GreenMask != 0) && (BlueMask != 0)); // // Handle some common cases. // if ((RedMask == 0x00FF0000) && (GreenMask == 0x0000FF00) && (BlueMask == 0x000000FF)) { RtlCopyMemory(PhysicalPalette, Palette, sizeof(BASE_VIDEO_PALETTE)); return; } else if ((RedMask == 0x000000FF) && (GreenMask == 0x0000FF00) && (BlueMask == 0x00FF0000)) { for (ColorIndex = 0; ColorIndex < AnsiColorCount; ColorIndex += 1) { PhysicalPalette->AnsiColor[ColorIndex] = SWIZZLE_RED_BLUE(Palette->AnsiColor[ColorIndex]); PhysicalPalette->BoldAnsiColor[ColorIndex] = SWIZZLE_RED_BLUE(Palette->BoldAnsiColor[ColorIndex]); } PhysicalPalette->DefaultBackground = SWIZZLE_RED_BLUE(Palette->DefaultBackground); PhysicalPalette->DefaultBoldBackground = SWIZZLE_RED_BLUE(Palette->DefaultBoldBackground); PhysicalPalette->CursorText = SWIZZLE_RED_BLUE(Palette->CursorText); PhysicalPalette->CursorBackground = SWIZZLE_RED_BLUE(Palette->CursorBackground); return; } // // Create the translation shift and mask. // Translation.RedMask = RedMask; Translation.GreenMask = GreenMask; Translation.BlueMask = BlueMask; RedBit = VidpFindHighestBitSet(Translation.RedMask) + 1; GreenBit = VidpFindHighestBitSet(Translation.GreenMask) + 1; BlueBit = VidpFindHighestBitSet(Translation.BlueMask) + 1; Translation.RedShift = RedBit - (3 * BITS_PER_BYTE); Translation.GreenShift = GreenBit - (2 * BITS_PER_BYTE); Translation.BlueShift = BlueBit - BITS_PER_BYTE; // // Translate all the colors in the palette. // for (ColorIndex = 0; ColorIndex < AnsiColorCount; ColorIndex += 1) { PhysicalPalette->AnsiColor[ColorIndex] = TRANSLATE_COLOR(Palette->AnsiColor[ColorIndex], Translation); PhysicalPalette->BoldAnsiColor[ColorIndex] = TRANSLATE_COLOR(Palette->BoldAnsiColor[ColorIndex], Translation); } PhysicalPalette->DefaultBackground = TRANSLATE_COLOR(Palette->DefaultBackground, Translation); PhysicalPalette->DefaultBoldBackground = TRANSLATE_COLOR(Palette->DefaultBoldBackground, Translation); PhysicalPalette->CursorText = TRANSLATE_COLOR(Palette->CursorText, Translation); PhysicalPalette->CursorBackground = TRANSLATE_COLOR(Palette->CursorBackground, Translation); ConvertPaletteEnd: return; } VOID VidpPrintCharacter ( PBASE_VIDEO_CONTEXT Context, ULONG XCoordinate, ULONG YCoordinate, PBASE_VIDEO_CHARACTER Character ) /*++ Routine Description: This routine prints a character to the screen in the specified location. Arguments: Context - Supplies a pointer to the initialized base video context. XCoordinate - Supplies the column to write to. YCoordinate - Supplies the row to write to. Character - Supplies a pointer to the character to print. Return Value: None. --*/ { USHORT Attributes; ANSI_COLOR BackgroundAnsiColor; ULONG BitIndex; ULONG ByteIndex; ULONG ColorOff; ULONG ColorOn; ULONG ColumnIndex; PUCHAR Data; PUSHORT Destination16; PULONG Destination32; PBYTE Destination8; PBASE_VIDEO_FONT Font; ANSI_COLOR ForegroundAnsiColor; ULONG HorizontalIndex; ULONG LineSize; PVOID LineStart; UCHAR RotateBuffer[8]; ULONG RowIndex; BYTE Source; ULONG SourceIndex; ULONG SwapColor; ULONG VerticalIndex; ULONG YPixel; // // Get the colors to use. // ColorOn = Context->PhysicalPalette.AnsiColor[AnsiColorDefault]; ColorOff = Context->PhysicalPalette.DefaultBackground; if (Character->Data.Attributes != 0) { Attributes = Character->Data.Attributes; if ((Attributes & BASE_VIDEO_CURSOR) != 0) { ColorOn = Context->PhysicalPalette.CursorText; ColorOff = Context->PhysicalPalette.CursorBackground; } else { BackgroundAnsiColor = (Attributes >> BASE_VIDEO_BACKGROUND_SHIFT) & BASE_VIDEO_COLOR_MASK; ForegroundAnsiColor = Attributes & BASE_VIDEO_COLOR_MASK; ColorOn = Context->PhysicalPalette.AnsiColor[ForegroundAnsiColor]; if ((Attributes & BASE_VIDEO_FOREGROUND_BOLD) != 0) { ColorOn = Context->PhysicalPalette.BoldAnsiColor[ForegroundAnsiColor]; } if (BackgroundAnsiColor != AnsiColorDefault) { ColorOff = Context->PhysicalPalette.AnsiColor[BackgroundAnsiColor]; } if ((Attributes & BASE_VIDEO_BACKGROUND_BOLD) != 0) { ColorOff = Context->PhysicalPalette.BoldAnsiColor[BackgroundAnsiColor]; if (BackgroundAnsiColor == AnsiColorDefault) { ColorOff = Context->PhysicalPalette.DefaultBoldBackground; } } if ((Attributes & BASE_VIDEO_NEGATIVE) != 0) { SwapColor = ColorOn; ColorOn = ColorOff; ColorOff = SwapColor; } } } // // Handle text mode differently. // if (Context->Mode == BaseVideoModeBiosText) { Destination16 = Context->FrameBuffer; Destination16 += (YCoordinate * Context->Width) + XCoordinate; *Destination16 = BIOS_TEXT_ATTRIBUTES(ColorOn, ColorOff) | (UCHAR)(Character->Data.Character); return; } // // Get the glyph data for that character. // Font = Context->Font; if ((Character->Data.Character < Font->FirstAsciiCode) || (Character->Data.Character >= Font->FirstAsciiCode + Font->GlyphCount)) { ASSERT(Font->FirstAsciiCode <= ' '); SourceIndex = ' ' - Font->FirstAsciiCode; } else { SourceIndex = Character->Data.Character - Font->FirstAsciiCode; } // // Rotate the character if needed. For those wondering, this code takes // about 185 bytes on x86, and the rotated data storage saves about 192 // bytes for the 5x7 and 4x6 fonts each. // if ((Font->Flags & BASE_VIDEO_FONT_ROTATED) != 0) { SourceIndex *= Font->GlyphBytesWidth * Font->GlyphWidth; Data = (PUCHAR)&(Font->Data[SourceIndex]); ASSERT((Font->GlyphWidth < sizeof(RotateBuffer)) && (Font->GlyphHeight < sizeof(RotateBuffer)) && (sizeof(RotateBuffer) <= BITS_PER_BYTE)); // // The normal data format runs horizontally. Build it a horizontal // row at a time (assuming there will be left than 8). // for (RowIndex = 0; RowIndex < Font->GlyphHeight; RowIndex += 1) { Source = 0; // // The row's data is spread out since the data is stored a column // at a time. It's always the same bit (row) for each column. // for (ColumnIndex = 0; ColumnIndex < Font->GlyphWidth; ColumnIndex += 1) { BitIndex = RowIndex; if ((Data[ColumnIndex] & (1 << BitIndex)) != 0) { Source |= 1 << (BITS_PER_BYTE - 1 - ColumnIndex); } } RotateBuffer[RowIndex] = Source; } Data = RotateBuffer; } else { SourceIndex *= Font->GlyphBytesWidth * Font->GlyphHeight; Data = (PUCHAR)&(Font->Data[SourceIndex]); } // // Compute the starting address on the frame buffer. // YPixel = (YCoordinate * Font->CellHeight) * Context->PixelsPerScanLine; LineStart = Context->FrameBuffer + ((YPixel + (XCoordinate * Font->CellWidth)) * (Context->BitsPerPixel / BITS_PER_BYTE)); LineSize = Context->PixelsPerScanLine * (Context->BitsPerPixel / BITS_PER_BYTE); // // Separate write loops for different pixel widths does mean more code, // but it skips conditionals in the inner loops, which are very hot. // switch (Context->BitsPerPixel) { case 8: for (VerticalIndex = 0; VerticalIndex < Font->GlyphHeight; VerticalIndex += 1) { Destination8 = LineStart; HorizontalIndex = 0; for (ByteIndex = 0; ByteIndex < Font->GlyphBytesWidth; ByteIndex += 1) { Source = *Data; BitIndex = 0; while ((BitIndex < BITS_PER_BYTE) && (HorizontalIndex < Font->GlyphWidth)) { if ((Source & 0x80) != 0) { *Destination8 = (UCHAR)ColorOn; } else { *Destination8 = (UCHAR)ColorOff; } Destination8 += 1; HorizontalIndex += 1; Source <<= 1; BitIndex += 1; } Data += 1; } while (HorizontalIndex < Font->CellWidth) { *Destination8 = (UCHAR)ColorOff; Destination8 += 1; HorizontalIndex += 1; } LineStart += LineSize; } while (VerticalIndex < Font->CellHeight) { Destination8 = LineStart; for (HorizontalIndex = 0; HorizontalIndex < Font->CellWidth; HorizontalIndex += 1) { *Destination8 = (UCHAR)ColorOff; Destination8 += 1; } LineStart += LineSize; VerticalIndex += 1; } break; case 16: for (VerticalIndex = 0; VerticalIndex < Font->GlyphHeight; VerticalIndex += 1) { Destination16 = LineStart; HorizontalIndex = 0; for (ByteIndex = 0; ByteIndex < Font->GlyphBytesWidth; ByteIndex += 1) { Source = *Data; BitIndex = 0; while ((BitIndex < BITS_PER_BYTE) && (HorizontalIndex < Font->GlyphWidth)) { if ((Source & 0x80) != 0) { *Destination16 = (USHORT)ColorOn; } else { *Destination16 = (USHORT)ColorOff; } Destination16 += 1; HorizontalIndex += 1; Source <<= 1; BitIndex += 1; } Data += 1; } while (HorizontalIndex < Font->CellWidth) { *Destination16 = (USHORT)ColorOff; Destination16 += 1; HorizontalIndex += 1; } LineStart += LineSize; } while (VerticalIndex < Font->CellHeight) { Destination16 = LineStart; for (HorizontalIndex = 0; HorizontalIndex < Font->CellWidth; HorizontalIndex += 1) { *Destination16 = (USHORT)ColorOff; Destination16 += 1; } LineStart += LineSize; VerticalIndex += 1; } break; case 24: for (VerticalIndex = 0; VerticalIndex < Font->GlyphHeight; VerticalIndex += 1) { Destination8 = LineStart; HorizontalIndex = 0; for (ByteIndex = 0; ByteIndex < Font->GlyphBytesWidth; ByteIndex += 1) { Source = *Data; BitIndex = 0; while ((BitIndex < BITS_PER_BYTE) && (HorizontalIndex < Font->GlyphWidth)) { if ((Source & 0x80) != 0) { *Destination8 = (UCHAR)ColorOn; *(Destination8 + 1) = (UCHAR)(ColorOn >> 8); *(Destination8 + 2) = (UCHAR)(ColorOn >> 16); } else { *Destination8 = (UCHAR)ColorOff; *(Destination8 + 1) = (UCHAR)(ColorOff >> 8); *(Destination8 + 2) = (UCHAR)(ColorOff >> 16); } Destination8 += 3; HorizontalIndex += 1; Source <<= 1; BitIndex += 1; } Data += 1; } while (HorizontalIndex < Font->CellWidth) { *Destination8 = (UCHAR)ColorOff; *(Destination8 + 1) = (UCHAR)(ColorOff >> 8); *(Destination8 + 2) = (UCHAR)(ColorOff >> 16); Destination8 += 3; HorizontalIndex += 1; } LineStart += LineSize; } while (VerticalIndex < Font->CellHeight) { Destination8 = LineStart; for (HorizontalIndex = 0; HorizontalIndex < Font->CellWidth; HorizontalIndex += 1) { *Destination8 = (UCHAR)ColorOff; *(Destination8 + 1) = (UCHAR)(ColorOff >> 8); *(Destination8 + 2) = (UCHAR)(ColorOff >> 16); Destination8 += 3; } LineStart += LineSize; VerticalIndex += 1; } break; case 32: for (VerticalIndex = 0; VerticalIndex < Font->GlyphHeight; VerticalIndex += 1) { Destination32 = LineStart; HorizontalIndex = 0; for (ByteIndex = 0; ByteIndex < Font->GlyphBytesWidth; ByteIndex += 1) { Source = *Data; BitIndex = 0; while ((BitIndex < BITS_PER_BYTE) && (HorizontalIndex < Font->GlyphWidth)) { if ((Source & 0x80) != 0) { *Destination32 = ColorOn; } else { *Destination32 = ColorOff; } Destination32 += 1; HorizontalIndex += 1; Source <<= 1; BitIndex += 1; } Data += 1; } while (HorizontalIndex < Font->CellWidth) { *Destination32 = ColorOff; Destination32 += 1; HorizontalIndex += 1; } LineStart += LineSize; } while (VerticalIndex < Font->CellHeight) { Destination32 = LineStart; for (HorizontalIndex = 0; HorizontalIndex < Font->CellWidth; HorizontalIndex += 1) { *Destination32 = ColorOff; Destination32 += 1; } LineStart += LineSize; VerticalIndex += 1; } break; default: ASSERT(FALSE); break; } return; } VOID VidpConvertIntegerToString ( LONG Integer, PSTR String, ULONG Base ) /*++ Routine Description: This routine converts an integer to a string. Arguments: Integer - Supplies the signed integer to convert to string format. String - Supplies a pointer to the allocated buffer where the string will be written. Base - Supplies the base of the number to print, from 2 to 16. Return Value: None. --*/ { ULONG CurrentPosition; BOOL Positive; CurrentPosition = 0; Positive = TRUE; // // Parameter checking. // if (String == NULL) { return; } if ((Base < 2) || (Base > 16)) { *String = '\0'; return; } // // Only deal with positive numbers, but remember if the number was negative. // if ((Integer < 0) && (Base == 10)) { Positive = FALSE; Integer = -Integer; } // // Loop over the integer, getting the least significant digit each // iteration. Note that this causes the string to come out backwards, which // is why the string is reversed before it is returned. // do { String[CurrentPosition] = (Integer % Base) + '0'; if (String[CurrentPosition] > '9') { String[CurrentPosition] = (Integer % Base) - 10 + 'A'; } CurrentPosition += 1; Integer = Integer / Base; } while (Integer > 0); // // Print out the negative sign at the end. // if (Positive == FALSE) { String[CurrentPosition] = '-'; CurrentPosition += 1; } // // Pad spaces to at least 8. // while (CurrentPosition < 8) { String[CurrentPosition] = ' '; CurrentPosition += 1; } // // Null terminate and reverse the string. // String[CurrentPosition] = '\0'; RtlStringReverse(String, String + CurrentPosition); return; } ULONG VidpFindHighestBitSet ( ULONG Value ) /*++ Routine Description: This routine finds the highest bit set in the given 32-bit integer. Arguments: Value - Supplies the value to find the highest bit number of. Return Value: Returns the index of the highest bit set. --*/ { ULONG Index; Index = (sizeof(ULONG) * BITS_PER_BYTE) - 1; while (TRUE) { if ((Value & (1 << Index)) != 0) { return Index; } if (Index == 0) { break; } Index -= 1; } return Index; }