From af1a266670d040d2f4083ff309d732d648afba2a Mon Sep 17 00:00:00 2001 From: Angelos Mouzakitis Date: Tue, 10 Oct 2023 14:33:42 +0000 Subject: Add submodule dependency files Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec --- .../MdeModulePkg/Universal/HiiDatabaseDxe/Image.c | 1563 ++++++++++++++++++++ 1 file changed, 1563 insertions(+) create mode 100644 roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/Image.c (limited to 'roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/Image.c') diff --git a/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/Image.c b/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/Image.c new file mode 100644 index 000000000..a108fc615 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/Image.c @@ -0,0 +1,1563 @@ +/** @file +Implementation for EFI_HII_IMAGE_PROTOCOL. + + +Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include "HiiDatabase.h" + +#define MAX_UINT24 0xFFFFFF + +/** + Get the imageid of last image block: EFI_HII_IIBT_END_BLOCK when input + ImageId is zero, otherwise return the address of the + corresponding image block with identifier specified by ImageId. + + This is a internal function. + + @param ImageBlocks Points to the beginning of a series of image blocks stored in order. + @param ImageId If input ImageId is 0, output the image id of the EFI_HII_IIBT_END_BLOCK; + else use this id to find its corresponding image block address. + + @return The image block address when input ImageId is not zero; otherwise return NULL. + +**/ +EFI_HII_IMAGE_BLOCK * +GetImageIdOrAddress ( + IN EFI_HII_IMAGE_BLOCK *ImageBlocks, + IN OUT EFI_IMAGE_ID *ImageId + ) +{ + EFI_IMAGE_ID ImageIdCurrent; + EFI_HII_IMAGE_BLOCK *CurrentImageBlock; + UINTN Length; + + ASSERT (ImageBlocks != NULL && ImageId != NULL); + CurrentImageBlock = ImageBlocks; + ImageIdCurrent = 1; + + while (CurrentImageBlock->BlockType != EFI_HII_IIBT_END) { + if (*ImageId != 0) { + if (*ImageId == ImageIdCurrent) { + // + // If the found image block is a duplicate block, update the ImageId to + // find the previous defined image block. + // + if (CurrentImageBlock->BlockType == EFI_HII_IIBT_DUPLICATE) { + *ImageId = ReadUnaligned16 ((VOID *) &((EFI_HII_IIBT_DUPLICATE_BLOCK *) CurrentImageBlock)->ImageId); + ASSERT (*ImageId != ImageIdCurrent); + ASSERT (*ImageId != 0); + CurrentImageBlock = ImageBlocks; + ImageIdCurrent = 1; + continue; + } + + return CurrentImageBlock; + } + if (*ImageId < ImageIdCurrent) { + // + // Can not find the specified image block in this image. + // + return NULL; + } + } + switch (CurrentImageBlock->BlockType) { + case EFI_HII_IIBT_EXT1: + Length = ((EFI_HII_IIBT_EXT1_BLOCK *) CurrentImageBlock)->Length; + break; + case EFI_HII_IIBT_EXT2: + Length = ReadUnaligned16 (&((EFI_HII_IIBT_EXT2_BLOCK *) CurrentImageBlock)->Length); + break; + case EFI_HII_IIBT_EXT4: + Length = ReadUnaligned32 ((VOID *) &((EFI_HII_IIBT_EXT4_BLOCK *) CurrentImageBlock)->Length); + break; + + case EFI_HII_IIBT_IMAGE_1BIT: + case EFI_HII_IIBT_IMAGE_1BIT_TRANS: + Length = sizeof (EFI_HII_IIBT_IMAGE_1BIT_BLOCK) - sizeof (UINT8) + + BITMAP_LEN_1_BIT ( + ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_1BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width), + ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_1BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height) + ); + ImageIdCurrent++; + break; + + case EFI_HII_IIBT_IMAGE_4BIT: + case EFI_HII_IIBT_IMAGE_4BIT_TRANS: + Length = sizeof (EFI_HII_IIBT_IMAGE_4BIT_BLOCK) - sizeof (UINT8) + + BITMAP_LEN_4_BIT ( + ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_4BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width), + ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_4BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height) + ); + ImageIdCurrent++; + break; + + case EFI_HII_IIBT_IMAGE_8BIT: + case EFI_HII_IIBT_IMAGE_8BIT_TRANS: + Length = sizeof (EFI_HII_IIBT_IMAGE_8BIT_BLOCK) - sizeof (UINT8) + + BITMAP_LEN_8_BIT ( + (UINT32) ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_8BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width), + ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_8BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height) + ); + ImageIdCurrent++; + break; + + case EFI_HII_IIBT_IMAGE_24BIT: + case EFI_HII_IIBT_IMAGE_24BIT_TRANS: + Length = sizeof (EFI_HII_IIBT_IMAGE_24BIT_BLOCK) - sizeof (EFI_HII_RGB_PIXEL) + + BITMAP_LEN_24_BIT ( + (UINT32) ReadUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width), + ReadUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height) + ); + ImageIdCurrent++; + break; + + case EFI_HII_IIBT_DUPLICATE: + Length = sizeof (EFI_HII_IIBT_DUPLICATE_BLOCK); + ImageIdCurrent++; + break; + + case EFI_HII_IIBT_IMAGE_JPEG: + Length = OFFSET_OF (EFI_HII_IIBT_JPEG_BLOCK, Data) + ReadUnaligned32 ((VOID *) &((EFI_HII_IIBT_JPEG_BLOCK *) CurrentImageBlock)->Size); + ImageIdCurrent++; + break; + + case EFI_HII_IIBT_IMAGE_PNG: + Length = OFFSET_OF (EFI_HII_IIBT_PNG_BLOCK, Data) + ReadUnaligned32 ((VOID *) &((EFI_HII_IIBT_PNG_BLOCK *) CurrentImageBlock)->Size); + ImageIdCurrent++; + break; + + case EFI_HII_IIBT_SKIP1: + Length = sizeof (EFI_HII_IIBT_SKIP1_BLOCK); + ImageIdCurrent += ((EFI_HII_IIBT_SKIP1_BLOCK *) CurrentImageBlock)->SkipCount; + break; + + case EFI_HII_IIBT_SKIP2: + Length = sizeof (EFI_HII_IIBT_SKIP2_BLOCK); + ImageIdCurrent += ReadUnaligned16 ((VOID *) &((EFI_HII_IIBT_SKIP2_BLOCK *) CurrentImageBlock)->SkipCount); + break; + + default: + // + // Unknown image blocks can not be skipped, processing halts. + // + ASSERT (FALSE); + Length = 0; + break; + } + + CurrentImageBlock = (EFI_HII_IMAGE_BLOCK *) ((UINT8 *) CurrentImageBlock + Length); + + } + + // + // When ImageId is zero, return the imageid of last image block: EFI_HII_IIBT_END_BLOCK. + // + if (*ImageId == 0) { + *ImageId = ImageIdCurrent; + return CurrentImageBlock; + } + + return NULL; +} + + + +/** + Convert pixels from EFI_GRAPHICS_OUTPUT_BLT_PIXEL to EFI_HII_RGB_PIXEL style. + + This is a internal function. + + + @param BitMapOut Pixels in EFI_HII_RGB_PIXEL format. + @param BitMapIn Pixels in EFI_GRAPHICS_OUTPUT_BLT_PIXEL format. + @param PixelNum The number of pixels to be converted. + + +**/ +VOID +CopyGopToRgbPixel ( + OUT EFI_HII_RGB_PIXEL *BitMapOut, + IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BitMapIn, + IN UINTN PixelNum + ) +{ + UINTN Index; + + ASSERT (BitMapOut != NULL && BitMapIn != NULL); + + for (Index = 0; Index < PixelNum; Index++) { + CopyMem (BitMapOut + Index, BitMapIn + Index, sizeof (EFI_HII_RGB_PIXEL)); + } +} + + +/** + Convert pixels from EFI_HII_RGB_PIXEL to EFI_GRAPHICS_OUTPUT_BLT_PIXEL style. + + This is a internal function. + + + @param BitMapOut Pixels in EFI_GRAPHICS_OUTPUT_BLT_PIXEL format. + @param BitMapIn Pixels in EFI_HII_RGB_PIXEL format. + @param PixelNum The number of pixels to be converted. + + +**/ +VOID +CopyRgbToGopPixel ( + OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BitMapOut, + IN EFI_HII_RGB_PIXEL *BitMapIn, + IN UINTN PixelNum + ) +{ + UINTN Index; + + ASSERT (BitMapOut != NULL && BitMapIn != NULL); + + for (Index = 0; Index < PixelNum; Index++) { + CopyMem (BitMapOut + Index, BitMapIn + Index, sizeof (EFI_HII_RGB_PIXEL)); + } +} + + +/** + Output pixels in "1 bit per pixel" format to an image. + + This is a internal function. + + + @param Image Points to the image which will store the pixels. + @param Data Stores the value of output pixels, 0 or 1. + @param PaletteInfo PaletteInfo which stores the color of the output + pixels. First entry corresponds to color 0 and + second one to color 1. + + +**/ +VOID +Output1bitPixel ( + IN OUT EFI_IMAGE_INPUT *Image, + IN UINT8 *Data, + IN EFI_HII_IMAGE_PALETTE_INFO *PaletteInfo + ) +{ + UINT16 Xpos; + UINT16 Ypos; + UINTN OffsetY; + UINT8 Index; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BitMapPtr; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL PaletteValue[2]; + EFI_HII_IMAGE_PALETTE_INFO *Palette; + UINTN PaletteSize; + UINT8 Byte; + + ASSERT (Image != NULL && Data != NULL && PaletteInfo != NULL); + + BitMapPtr = Image->Bitmap; + + // + // First entry corresponds to color 0 and second entry corresponds to color 1. + // + PaletteSize = 0; + CopyMem (&PaletteSize, PaletteInfo, sizeof (UINT16)); + PaletteSize += sizeof (UINT16); + Palette = AllocateZeroPool (PaletteSize); + ASSERT (Palette != NULL); + if (Palette == NULL) { + return; + } + CopyMem (Palette, PaletteInfo, PaletteSize); + + ZeroMem (PaletteValue, sizeof (PaletteValue)); + CopyRgbToGopPixel (&PaletteValue[0], &Palette->PaletteValue[0], 1); + CopyRgbToGopPixel (&PaletteValue[1], &Palette->PaletteValue[1], 1); + FreePool (Palette); + + // + // Convert the pixel from one bit to corresponding color. + // + for (Ypos = 0; Ypos < Image->Height; Ypos++) { + OffsetY = BITMAP_LEN_1_BIT (Image->Width, Ypos); + // + // All bits in these bytes are meaningful + // + for (Xpos = 0; Xpos < Image->Width / 8; Xpos++) { + Byte = *(Data + OffsetY + Xpos); + for (Index = 0; Index < 8; Index++) { + if ((Byte & (1 << Index)) != 0) { + BitMapPtr[Ypos * Image->Width + Xpos * 8 + (8 - Index - 1)] = PaletteValue[1]; + } else { + BitMapPtr[Ypos * Image->Width + Xpos * 8 + (8 - Index - 1)] = PaletteValue[0]; + } + } + } + + if (Image->Width % 8 != 0) { + // + // Padding bits in this byte should be ignored. + // + Byte = *(Data + OffsetY + Xpos); + for (Index = 0; Index < Image->Width % 8; Index++) { + if ((Byte & (1 << (8 - Index - 1))) != 0) { + BitMapPtr[Ypos * Image->Width + Xpos * 8 + Index] = PaletteValue[1]; + } else { + BitMapPtr[Ypos * Image->Width + Xpos * 8 + Index] = PaletteValue[0]; + } + } + } + } +} + + +/** + Output pixels in "4 bit per pixel" format to an image. + + This is a internal function. + + + @param Image Points to the image which will store the pixels. + @param Data Stores the value of output pixels, 0 ~ 15. + @param[in] PaletteInfo PaletteInfo which stores the color of the output + pixels. Each entry corresponds to a color within + [0, 15]. + + +**/ +VOID +Output4bitPixel ( + IN OUT EFI_IMAGE_INPUT *Image, + IN UINT8 *Data, + IN EFI_HII_IMAGE_PALETTE_INFO *PaletteInfo + ) +{ + UINT16 Xpos; + UINT16 Ypos; + UINTN OffsetY; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BitMapPtr; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL PaletteValue[16]; + EFI_HII_IMAGE_PALETTE_INFO *Palette; + UINTN PaletteSize; + UINT16 PaletteNum; + UINT8 Byte; + + ASSERT (Image != NULL && Data != NULL && PaletteInfo != NULL); + + BitMapPtr = Image->Bitmap; + + // + // The bitmap should allocate each color index starting from 0. + // + PaletteSize = 0; + CopyMem (&PaletteSize, PaletteInfo, sizeof (UINT16)); + PaletteSize += sizeof (UINT16); + Palette = AllocateZeroPool (PaletteSize); + ASSERT (Palette != NULL); + if (Palette == NULL) { + return; + } + CopyMem (Palette, PaletteInfo, PaletteSize); + PaletteNum = (UINT16)(Palette->PaletteSize / sizeof (EFI_HII_RGB_PIXEL)); + + ZeroMem (PaletteValue, sizeof (PaletteValue)); + CopyRgbToGopPixel (PaletteValue, Palette->PaletteValue, MIN (PaletteNum, ARRAY_SIZE (PaletteValue))); + FreePool (Palette); + + // + // Convert the pixel from 4 bit to corresponding color. + // + for (Ypos = 0; Ypos < Image->Height; Ypos++) { + OffsetY = BITMAP_LEN_4_BIT (Image->Width, Ypos); + // + // All bits in these bytes are meaningful + // + for (Xpos = 0; Xpos < Image->Width / 2; Xpos++) { + Byte = *(Data + OffsetY + Xpos); + BitMapPtr[Ypos * Image->Width + Xpos * 2] = PaletteValue[Byte >> 4]; + BitMapPtr[Ypos * Image->Width + Xpos * 2 + 1] = PaletteValue[Byte & 0x0F]; + } + + if (Image->Width % 2 != 0) { + // + // Padding bits in this byte should be ignored. + // + Byte = *(Data + OffsetY + Xpos); + BitMapPtr[Ypos * Image->Width + Xpos * 2] = PaletteValue[Byte >> 4]; + } + } +} + + +/** + Output pixels in "8 bit per pixel" format to an image. + + This is a internal function. + + + @param Image Points to the image which will store the pixels. + @param Data Stores the value of output pixels, 0 ~ 255. + @param[in] PaletteInfo PaletteInfo which stores the color of the output + pixels. Each entry corresponds to a color within + [0, 255]. + + +**/ +VOID +Output8bitPixel ( + IN OUT EFI_IMAGE_INPUT *Image, + IN UINT8 *Data, + IN EFI_HII_IMAGE_PALETTE_INFO *PaletteInfo + ) +{ + UINT16 Xpos; + UINT16 Ypos; + UINTN OffsetY; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BitMapPtr; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL PaletteValue[256]; + EFI_HII_IMAGE_PALETTE_INFO *Palette; + UINTN PaletteSize; + UINT16 PaletteNum; + UINT8 Byte; + + ASSERT (Image != NULL && Data != NULL && PaletteInfo != NULL); + + BitMapPtr = Image->Bitmap; + + // + // The bitmap should allocate each color index starting from 0. + // + PaletteSize = 0; + CopyMem (&PaletteSize, PaletteInfo, sizeof (UINT16)); + PaletteSize += sizeof (UINT16); + Palette = AllocateZeroPool (PaletteSize); + ASSERT (Palette != NULL); + if (Palette == NULL) { + return; + } + CopyMem (Palette, PaletteInfo, PaletteSize); + PaletteNum = (UINT16)(Palette->PaletteSize / sizeof (EFI_HII_RGB_PIXEL)); + ZeroMem (PaletteValue, sizeof (PaletteValue)); + CopyRgbToGopPixel (PaletteValue, Palette->PaletteValue, MIN (PaletteNum, ARRAY_SIZE (PaletteValue))); + FreePool (Palette); + + // + // Convert the pixel from 8 bits to corresponding color. + // + for (Ypos = 0; Ypos < Image->Height; Ypos++) { + OffsetY = BITMAP_LEN_8_BIT ((UINT32) Image->Width, Ypos); + // + // All bits are meaningful since the bitmap is 8 bits per pixel. + // + for (Xpos = 0; Xpos < Image->Width; Xpos++) { + Byte = *(Data + OffsetY + Xpos); + BitMapPtr[OffsetY + Xpos] = PaletteValue[Byte]; + } + } + +} + + +/** + Output pixels in "24 bit per pixel" format to an image. + + This is a internal function. + + + @param Image Points to the image which will store the pixels. + @param Data Stores the color of output pixels, allowing 16.8 + millions colors. + + +**/ +VOID +Output24bitPixel ( + IN OUT EFI_IMAGE_INPUT *Image, + IN EFI_HII_RGB_PIXEL *Data + ) +{ + UINT16 Ypos; + UINTN OffsetY; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BitMapPtr; + + ASSERT (Image != NULL && Data != NULL); + + BitMapPtr = Image->Bitmap; + + for (Ypos = 0; Ypos < Image->Height; Ypos++) { + OffsetY = BITMAP_LEN_8_BIT ((UINT32) Image->Width, Ypos); + CopyRgbToGopPixel (&BitMapPtr[OffsetY], &Data[OffsetY], Image->Width); + } + +} + + +/** + Convert the image from EFI_IMAGE_INPUT to EFI_IMAGE_OUTPUT format. + + This is a internal function. + + + @param BltBuffer Buffer points to bitmap data of incoming image. + @param BltX Specifies the offset from the left and top edge of + the output image of the first pixel in the image. + @param BltY Specifies the offset from the left and top edge of + the output image of the first pixel in the image. + @param Width Width of the incoming image, in pixels. + @param Height Height of the incoming image, in pixels. + @param Transparent If TRUE, all "off" pixels in the image will be + drawn using the pixel value from blt and all other + pixels will be copied. + @param Blt Buffer points to bitmap data of output image. + + @retval EFI_SUCCESS The image was successfully converted. + @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid. + +**/ +EFI_STATUS +ImageToBlt ( + IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, + IN UINTN BltX, + IN UINTN BltY, + IN UINTN Width, + IN UINTN Height, + IN BOOLEAN Transparent, + IN OUT EFI_IMAGE_OUTPUT **Blt + ) +{ + EFI_IMAGE_OUTPUT *ImageOut; + UINTN Xpos; + UINTN Ypos; + UINTN OffsetY1; // src buffer + UINTN OffsetY2; // dest buffer + EFI_GRAPHICS_OUTPUT_BLT_PIXEL SrcPixel; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL ZeroPixel; + + if (BltBuffer == NULL || Blt == NULL || *Blt == NULL) { + return EFI_INVALID_PARAMETER; + } + + ImageOut = *Blt; + + if (Width + BltX > ImageOut->Width) { + return EFI_INVALID_PARAMETER; + } + if (Height + BltY > ImageOut->Height) { + return EFI_INVALID_PARAMETER; + } + + ZeroMem (&ZeroPixel, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); + + for (Ypos = 0; Ypos < Height; Ypos++) { + OffsetY1 = Width * Ypos; + OffsetY2 = ImageOut->Width * (BltY + Ypos); + for (Xpos = 0; Xpos < Width; Xpos++) { + SrcPixel = BltBuffer[OffsetY1 + Xpos]; + if (Transparent) { + if (CompareMem (&SrcPixel, &ZeroPixel, 3) != 0) { + ImageOut->Image.Bitmap[OffsetY2 + BltX + Xpos] = SrcPixel; + } + } else { + ImageOut->Image.Bitmap[OffsetY2 + BltX + Xpos] = SrcPixel; + } + } + } + + return EFI_SUCCESS; +} + +/** + Return the HII package list identified by PackageList HII handle. + + @param Database Pointer to HII database list header. + @param PackageList HII handle of the package list to locate. + + @retval The HII package list instance. +**/ +HII_DATABASE_PACKAGE_LIST_INSTANCE * +LocatePackageList ( + IN LIST_ENTRY *Database, + IN EFI_HII_HANDLE PackageList + ) +{ + LIST_ENTRY *Link; + HII_DATABASE_RECORD *Record; + + // + // Get the specified package list and image package. + // + for (Link = GetFirstNode (Database); + !IsNull (Database, Link); + Link = GetNextNode (Database, Link) + ) { + Record = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE); + if (Record->Handle == PackageList) { + return Record->PackageList; + } + } + return NULL; +} + +/** + This function adds the image Image to the group of images owned by PackageList, and returns + a new image identifier (ImageId). + + @param This A pointer to the EFI_HII_IMAGE_PROTOCOL instance. + @param PackageList Handle of the package list where this image will + be added. + @param ImageId On return, contains the new image id, which is + unique within PackageList. + @param Image Points to the image. + + @retval EFI_SUCCESS The new image was added successfully. + @retval EFI_NOT_FOUND The specified PackageList could not be found in + database. + @retval EFI_OUT_OF_RESOURCES Could not add the image due to lack of resources. + @retval EFI_INVALID_PARAMETER Image is NULL or ImageId is NULL. + +**/ +EFI_STATUS +EFIAPI +HiiNewImage ( + IN CONST EFI_HII_IMAGE_PROTOCOL *This, + IN EFI_HII_HANDLE PackageList, + OUT EFI_IMAGE_ID *ImageId, + IN CONST EFI_IMAGE_INPUT *Image + ) +{ + HII_DATABASE_PRIVATE_DATA *Private; + HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode; + HII_IMAGE_PACKAGE_INSTANCE *ImagePackage; + EFI_HII_IMAGE_BLOCK *ImageBlocks; + UINT32 NewBlockSize; + + if (This == NULL || ImageId == NULL || Image == NULL || Image->Bitmap == NULL) { + return EFI_INVALID_PARAMETER; + } + + Private = HII_IMAGE_DATABASE_PRIVATE_DATA_FROM_THIS (This); + PackageListNode = LocatePackageList (&Private->DatabaseList, PackageList); + if (PackageListNode == NULL) { + return EFI_NOT_FOUND; + } + + EfiAcquireLock (&mHiiDatabaseLock); + + // + // Calcuate the size of new image. + // Make sure the size doesn't overflow UINT32. + // Note: 24Bit BMP occpuies 3 bytes per pixel. + // + NewBlockSize = (UINT32)Image->Width * Image->Height; + if (NewBlockSize > (MAX_UINT32 - (sizeof (EFI_HII_IIBT_IMAGE_24BIT_BLOCK) - sizeof (EFI_HII_RGB_PIXEL))) / 3) { + EfiReleaseLock (&mHiiDatabaseLock); + return EFI_OUT_OF_RESOURCES; + } + NewBlockSize = NewBlockSize * 3 + (sizeof (EFI_HII_IIBT_IMAGE_24BIT_BLOCK) - sizeof (EFI_HII_RGB_PIXEL)); + + // + // Get the image package in the package list, + // or create a new image package if image package does not exist. + // + if (PackageListNode->ImagePkg != NULL) { + ImagePackage = PackageListNode->ImagePkg; + + // + // Output the image id of the incoming image being inserted, which is the + // image id of the EFI_HII_IIBT_END block of old image package. + // + *ImageId = 0; + GetImageIdOrAddress (ImagePackage->ImageBlock, ImageId); + + // + // Update the package's image block by appending the new block to the end. + // + + // + // Make sure the final package length doesn't overflow. + // Length of the package header is represented using 24 bits. So MAX length is MAX_UINT24. + // + if (NewBlockSize > MAX_UINT24 - ImagePackage->ImagePkgHdr.Header.Length) { + EfiReleaseLock (&mHiiDatabaseLock); + return EFI_OUT_OF_RESOURCES; + } + // + // Because ImagePackage->ImageBlockSize < ImagePackage->ImagePkgHdr.Header.Length, + // So (ImagePackage->ImageBlockSize + NewBlockSize) <= MAX_UINT24 + // + ImageBlocks = AllocatePool (ImagePackage->ImageBlockSize + NewBlockSize); + if (ImageBlocks == NULL) { + EfiReleaseLock (&mHiiDatabaseLock); + return EFI_OUT_OF_RESOURCES; + } + // + // Copy the original content. + // + CopyMem ( + ImageBlocks, + ImagePackage->ImageBlock, + ImagePackage->ImageBlockSize - sizeof (EFI_HII_IIBT_END_BLOCK) + ); + FreePool (ImagePackage->ImageBlock); + ImagePackage->ImageBlock = ImageBlocks; + + // + // Point to the very last block. + // + ImageBlocks = (EFI_HII_IMAGE_BLOCK *) ( + (UINT8 *) ImageBlocks + ImagePackage->ImageBlockSize - sizeof (EFI_HII_IIBT_END_BLOCK) + ); + // + // Update the length record. + // + ImagePackage->ImageBlockSize += NewBlockSize; + ImagePackage->ImagePkgHdr.Header.Length += NewBlockSize; + PackageListNode->PackageListHdr.PackageLength += NewBlockSize; + + } else { + // + // Make sure the final package length doesn't overflow. + // Length of the package header is represented using 24 bits. So MAX length is MAX_UINT24. + // + if (NewBlockSize > MAX_UINT24 - (sizeof (EFI_HII_IMAGE_PACKAGE_HDR) + sizeof (EFI_HII_IIBT_END_BLOCK))) { + EfiReleaseLock (&mHiiDatabaseLock); + return EFI_OUT_OF_RESOURCES; + } + // + // The specified package list does not contain image package. + // Create one to add this image block. + // + ImagePackage = (HII_IMAGE_PACKAGE_INSTANCE *) AllocateZeroPool (sizeof (HII_IMAGE_PACKAGE_INSTANCE)); + if (ImagePackage == NULL) { + EfiReleaseLock (&mHiiDatabaseLock); + return EFI_OUT_OF_RESOURCES; + } + // + // Output the image id of the incoming image being inserted, which is the + // first image block so that id is initially to one. + // + *ImageId = 1; + // + // Fill in image package header. + // + ImagePackage->ImagePkgHdr.Header.Length = sizeof (EFI_HII_IMAGE_PACKAGE_HDR) + NewBlockSize + sizeof (EFI_HII_IIBT_END_BLOCK); + ImagePackage->ImagePkgHdr.Header.Type = EFI_HII_PACKAGE_IMAGES; + ImagePackage->ImagePkgHdr.ImageInfoOffset = sizeof (EFI_HII_IMAGE_PACKAGE_HDR); + ImagePackage->ImagePkgHdr.PaletteInfoOffset = 0; + + // + // Fill in palette info. + // + ImagePackage->PaletteBlock = NULL; + ImagePackage->PaletteInfoSize = 0; + + // + // Fill in image blocks. + // + ImagePackage->ImageBlockSize = NewBlockSize + sizeof (EFI_HII_IIBT_END_BLOCK); + ImagePackage->ImageBlock = AllocateZeroPool (NewBlockSize + sizeof (EFI_HII_IIBT_END_BLOCK)); + if (ImagePackage->ImageBlock == NULL) { + FreePool (ImagePackage); + EfiReleaseLock (&mHiiDatabaseLock); + return EFI_OUT_OF_RESOURCES; + } + ImageBlocks = ImagePackage->ImageBlock; + + // + // Insert this image package. + // + PackageListNode->ImagePkg = ImagePackage; + PackageListNode->PackageListHdr.PackageLength += ImagePackage->ImagePkgHdr.Header.Length; + } + + // + // Append the new block here + // + if (Image->Flags == EFI_IMAGE_TRANSPARENT) { + ImageBlocks->BlockType = EFI_HII_IIBT_IMAGE_24BIT_TRANS; + } else { + ImageBlocks->BlockType = EFI_HII_IIBT_IMAGE_24BIT; + } + WriteUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) ImageBlocks)->Bitmap.Width, Image->Width); + WriteUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) ImageBlocks)->Bitmap.Height, Image->Height); + CopyGopToRgbPixel (((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) ImageBlocks)->Bitmap.Bitmap, Image->Bitmap, (UINT32) Image->Width * Image->Height); + + // + // Append the block end + // + ImageBlocks = (EFI_HII_IMAGE_BLOCK *) ((UINT8 *) ImageBlocks + NewBlockSize); + ImageBlocks->BlockType = EFI_HII_IIBT_END; + + // + // Check whether need to get the contents of HiiDataBase. + // Only after ReadyToBoot to do the export. + // + if (gExportAfterReadyToBoot) { + HiiGetDatabaseInfo(&Private->HiiDatabase); + } + + EfiReleaseLock (&mHiiDatabaseLock); + + return EFI_SUCCESS; +} + + +/** + This function retrieves the image specified by ImageId which is associated with + the specified PackageList and copies it into the buffer specified by Image. + + @param Database A pointer to the database list header. + @param PackageList Handle of the package list where this image will + be searched. + @param ImageId The image's id,, which is unique within + PackageList. + @param Image Points to the image. + @param BitmapOnly TRUE to only return the bitmap type image. + FALSE to locate image decoder instance to decode image. + + @retval EFI_SUCCESS The new image was returned successfully. + @retval EFI_NOT_FOUND The image specified by ImageId is not in the + database. The specified PackageList is not in the database. + @retval EFI_BUFFER_TOO_SMALL The buffer specified by ImageSize is too small to + hold the image. + @retval EFI_INVALID_PARAMETER The Image or ImageSize was NULL. + @retval EFI_OUT_OF_RESOURCES The bitmap could not be retrieved because there was not + enough memory. +**/ +EFI_STATUS +IGetImage ( + IN LIST_ENTRY *Database, + IN EFI_HII_HANDLE PackageList, + IN EFI_IMAGE_ID ImageId, + OUT EFI_IMAGE_INPUT *Image, + IN BOOLEAN BitmapOnly + ) +{ + EFI_STATUS Status; + HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode; + HII_IMAGE_PACKAGE_INSTANCE *ImagePackage; + EFI_HII_IMAGE_BLOCK *CurrentImageBlock; + EFI_HII_IIBT_IMAGE_1BIT_BLOCK Iibt1bit; + UINT16 Width; + UINT16 Height; + UINTN ImageLength; + UINT8 *PaletteInfo; + UINT8 PaletteIndex; + UINT16 PaletteSize; + EFI_HII_IMAGE_DECODER_PROTOCOL *Decoder; + EFI_IMAGE_OUTPUT *ImageOut; + + if (Image == NULL || ImageId == 0) { + return EFI_INVALID_PARAMETER; + } + + PackageListNode = LocatePackageList (Database, PackageList); + if (PackageListNode == NULL) { + return EFI_NOT_FOUND; + } + ImagePackage = PackageListNode->ImagePkg; + if (ImagePackage == NULL) { + return EFI_NOT_FOUND; + } + + // + // Find the image block specified by ImageId + // + CurrentImageBlock = GetImageIdOrAddress (ImagePackage->ImageBlock, &ImageId); + if (CurrentImageBlock == NULL) { + return EFI_NOT_FOUND; + } + + Image->Flags = 0; + switch (CurrentImageBlock->BlockType) { + case EFI_HII_IIBT_IMAGE_JPEG: + case EFI_HII_IIBT_IMAGE_PNG: + if (BitmapOnly) { + return EFI_UNSUPPORTED; + } + + ImageOut = NULL; + Decoder = LocateHiiImageDecoder (CurrentImageBlock->BlockType); + if (Decoder == NULL) { + return EFI_UNSUPPORTED; + } + // + // Use the common block code since the definition of two structures is the same. + // + ASSERT (OFFSET_OF (EFI_HII_IIBT_JPEG_BLOCK, Data) == OFFSET_OF (EFI_HII_IIBT_PNG_BLOCK, Data)); + ASSERT (sizeof (((EFI_HII_IIBT_JPEG_BLOCK *) CurrentImageBlock)->Data) == + sizeof (((EFI_HII_IIBT_PNG_BLOCK *) CurrentImageBlock)->Data)); + ASSERT (OFFSET_OF (EFI_HII_IIBT_JPEG_BLOCK, Size) == OFFSET_OF (EFI_HII_IIBT_PNG_BLOCK, Size)); + ASSERT (sizeof (((EFI_HII_IIBT_JPEG_BLOCK *) CurrentImageBlock)->Size) == + sizeof (((EFI_HII_IIBT_PNG_BLOCK *) CurrentImageBlock)->Size)); + Status = Decoder->DecodeImage ( + Decoder, + ((EFI_HII_IIBT_JPEG_BLOCK *) CurrentImageBlock)->Data, + ((EFI_HII_IIBT_JPEG_BLOCK *) CurrentImageBlock)->Size, + &ImageOut, + FALSE + ); + + // + // Spec requires to use the first capable image decoder instance. + // The first image decoder instance may fail to decode the image. + // + if (!EFI_ERROR (Status)) { + Image->Bitmap = ImageOut->Image.Bitmap; + Image->Height = ImageOut->Height; + Image->Width = ImageOut->Width; + FreePool (ImageOut); + } + return Status; + + case EFI_HII_IIBT_IMAGE_1BIT_TRANS: + case EFI_HII_IIBT_IMAGE_4BIT_TRANS: + case EFI_HII_IIBT_IMAGE_8BIT_TRANS: + Image->Flags = EFI_IMAGE_TRANSPARENT; + // + // fall through + // + case EFI_HII_IIBT_IMAGE_1BIT: + case EFI_HII_IIBT_IMAGE_4BIT: + case EFI_HII_IIBT_IMAGE_8BIT: + // + // Use the common block code since the definition of these structures is the same. + // + CopyMem (&Iibt1bit, CurrentImageBlock, sizeof (EFI_HII_IIBT_IMAGE_1BIT_BLOCK)); + ImageLength = (UINTN) Iibt1bit.Bitmap.Width * Iibt1bit.Bitmap.Height; + if (ImageLength > MAX_UINTN / sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)) { + return EFI_OUT_OF_RESOURCES; + } + ImageLength *= sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL); + Image->Bitmap = AllocateZeroPool (ImageLength); + if (Image->Bitmap == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Image->Width = Iibt1bit.Bitmap.Width; + Image->Height = Iibt1bit.Bitmap.Height; + + PaletteInfo = ImagePackage->PaletteBlock + sizeof (EFI_HII_IMAGE_PALETTE_INFO_HEADER); + for (PaletteIndex = 1; PaletteIndex < Iibt1bit.PaletteIndex; PaletteIndex++) { + CopyMem (&PaletteSize, PaletteInfo, sizeof (UINT16)); + PaletteInfo += PaletteSize + sizeof (UINT16); + } + ASSERT (PaletteIndex == Iibt1bit.PaletteIndex); + + // + // Output bitmap data + // + if (CurrentImageBlock->BlockType == EFI_HII_IIBT_IMAGE_1BIT || + CurrentImageBlock->BlockType == EFI_HII_IIBT_IMAGE_1BIT_TRANS) { + Output1bitPixel ( + Image, + ((EFI_HII_IIBT_IMAGE_1BIT_BLOCK *) CurrentImageBlock)->Bitmap.Data, + (EFI_HII_IMAGE_PALETTE_INFO *) PaletteInfo + ); + } else if (CurrentImageBlock->BlockType == EFI_HII_IIBT_IMAGE_4BIT || + CurrentImageBlock->BlockType == EFI_HII_IIBT_IMAGE_4BIT_TRANS) { + Output4bitPixel ( + Image, + ((EFI_HII_IIBT_IMAGE_4BIT_BLOCK *) CurrentImageBlock)->Bitmap.Data, + (EFI_HII_IMAGE_PALETTE_INFO *) PaletteInfo + ); + } else { + Output8bitPixel ( + Image, + ((EFI_HII_IIBT_IMAGE_8BIT_BLOCK *) CurrentImageBlock)->Bitmap.Data, + (EFI_HII_IMAGE_PALETTE_INFO *) PaletteInfo + ); + } + + return EFI_SUCCESS; + + case EFI_HII_IIBT_IMAGE_24BIT_TRANS: + Image->Flags = EFI_IMAGE_TRANSPARENT; + // + // fall through + // + case EFI_HII_IIBT_IMAGE_24BIT: + Width = ReadUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width); + Height = ReadUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height); + ImageLength = (UINTN)Width * Height; + if (ImageLength > MAX_UINTN / sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)) { + return EFI_OUT_OF_RESOURCES; + } + ImageLength *= sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL); + Image->Bitmap = AllocateZeroPool (ImageLength); + if (Image->Bitmap == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Image->Width = Width; + Image->Height = Height; + + // + // Output the bitmap data directly. + // + Output24bitPixel ( + Image, + ((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) CurrentImageBlock)->Bitmap.Bitmap + ); + return EFI_SUCCESS; + + default: + return EFI_NOT_FOUND; + } +} + +/** + This function retrieves the image specified by ImageId which is associated with + the specified PackageList and copies it into the buffer specified by Image. + + @param This A pointer to the EFI_HII_IMAGE_PROTOCOL instance. + @param PackageList Handle of the package list where this image will + be searched. + @param ImageId The image's id,, which is unique within + PackageList. + @param Image Points to the image. + + @retval EFI_SUCCESS The new image was returned successfully. + @retval EFI_NOT_FOUND The image specified by ImageId is not in the + database. The specified PackageList is not in the database. + @retval EFI_BUFFER_TOO_SMALL The buffer specified by ImageSize is too small to + hold the image. + @retval EFI_INVALID_PARAMETER The Image or ImageSize was NULL. + @retval EFI_OUT_OF_RESOURCES The bitmap could not be retrieved because there was not + enough memory. + +**/ +EFI_STATUS +EFIAPI +HiiGetImage ( + IN CONST EFI_HII_IMAGE_PROTOCOL *This, + IN EFI_HII_HANDLE PackageList, + IN EFI_IMAGE_ID ImageId, + OUT EFI_IMAGE_INPUT *Image + ) +{ + HII_DATABASE_PRIVATE_DATA *Private; + Private = HII_IMAGE_DATABASE_PRIVATE_DATA_FROM_THIS (This); + return IGetImage (&Private->DatabaseList, PackageList, ImageId, Image, TRUE); +} + + +/** + This function updates the image specified by ImageId in the specified PackageListHandle to + the image specified by Image. + + @param This A pointer to the EFI_HII_IMAGE_PROTOCOL instance. + @param PackageList The package list containing the images. + @param ImageId The image's id,, which is unique within + PackageList. + @param Image Points to the image. + + @retval EFI_SUCCESS The new image was updated successfully. + @retval EFI_NOT_FOUND The image specified by ImageId is not in the + database. The specified PackageList is not in the database. + @retval EFI_INVALID_PARAMETER The Image was NULL. + +**/ +EFI_STATUS +EFIAPI +HiiSetImage ( + IN CONST EFI_HII_IMAGE_PROTOCOL *This, + IN EFI_HII_HANDLE PackageList, + IN EFI_IMAGE_ID ImageId, + IN CONST EFI_IMAGE_INPUT *Image + ) +{ + HII_DATABASE_PRIVATE_DATA *Private; + HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode; + HII_IMAGE_PACKAGE_INSTANCE *ImagePackage; + EFI_HII_IMAGE_BLOCK *CurrentImageBlock; + EFI_HII_IMAGE_BLOCK *ImageBlocks; + EFI_HII_IMAGE_BLOCK *NewImageBlock; + UINT32 NewBlockSize; + UINT32 OldBlockSize; + UINT32 Part1Size; + UINT32 Part2Size; + + if (This == NULL || Image == NULL || ImageId == 0 || Image->Bitmap == NULL) { + return EFI_INVALID_PARAMETER; + } + + Private = HII_IMAGE_DATABASE_PRIVATE_DATA_FROM_THIS (This); + PackageListNode = LocatePackageList (&Private->DatabaseList, PackageList); + if (PackageListNode == NULL) { + return EFI_NOT_FOUND; + } + ImagePackage = PackageListNode->ImagePkg; + if (ImagePackage == NULL) { + return EFI_NOT_FOUND; + } + + // + // Find the image block specified by ImageId + // + CurrentImageBlock = GetImageIdOrAddress (ImagePackage->ImageBlock, &ImageId); + if (CurrentImageBlock == NULL) { + return EFI_NOT_FOUND; + } + + EfiAcquireLock (&mHiiDatabaseLock); + + // + // Get the size of original image block. Use some common block code here + // since the definition of some structures is the same. + // + switch (CurrentImageBlock->BlockType) { + case EFI_HII_IIBT_IMAGE_JPEG: + OldBlockSize = OFFSET_OF (EFI_HII_IIBT_JPEG_BLOCK, Data) + ReadUnaligned32 ((VOID *) &((EFI_HII_IIBT_JPEG_BLOCK *) CurrentImageBlock)->Size); + break; + case EFI_HII_IIBT_IMAGE_PNG: + OldBlockSize = OFFSET_OF (EFI_HII_IIBT_PNG_BLOCK, Data) + ReadUnaligned32 ((VOID *) &((EFI_HII_IIBT_PNG_BLOCK *) CurrentImageBlock)->Size); + break; + case EFI_HII_IIBT_IMAGE_1BIT: + case EFI_HII_IIBT_IMAGE_1BIT_TRANS: + OldBlockSize = sizeof (EFI_HII_IIBT_IMAGE_1BIT_BLOCK) - sizeof (UINT8) + + BITMAP_LEN_1_BIT ( + ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_1BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width), + ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_1BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height) + ); + break; + case EFI_HII_IIBT_IMAGE_4BIT: + case EFI_HII_IIBT_IMAGE_4BIT_TRANS: + OldBlockSize = sizeof (EFI_HII_IIBT_IMAGE_4BIT_BLOCK) - sizeof (UINT8) + + BITMAP_LEN_4_BIT ( + ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_4BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width), + ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_4BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height) + ); + break; + case EFI_HII_IIBT_IMAGE_8BIT: + case EFI_HII_IIBT_IMAGE_8BIT_TRANS: + OldBlockSize = sizeof (EFI_HII_IIBT_IMAGE_8BIT_BLOCK) - sizeof (UINT8) + + BITMAP_LEN_8_BIT ( + (UINT32) ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_8BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width), + ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_8BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height) + ); + break; + case EFI_HII_IIBT_IMAGE_24BIT: + case EFI_HII_IIBT_IMAGE_24BIT_TRANS: + OldBlockSize = sizeof (EFI_HII_IIBT_IMAGE_24BIT_BLOCK) - sizeof (EFI_HII_RGB_PIXEL) + + BITMAP_LEN_24_BIT ( + (UINT32) ReadUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width), + ReadUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height) + ); + break; + default: + EfiReleaseLock (&mHiiDatabaseLock); + return EFI_NOT_FOUND; + } + + // + // Create the new image block according to input image. + // + + // + // Make sure the final package length doesn't overflow. + // Length of the package header is represented using 24 bits. So MAX length is MAX_UINT24. + // 24Bit BMP occpuies 3 bytes per pixel. + // + NewBlockSize = (UINT32)Image->Width * Image->Height; + if (NewBlockSize > (MAX_UINT32 - (sizeof (EFI_HII_IIBT_IMAGE_24BIT_BLOCK) - sizeof (EFI_HII_RGB_PIXEL))) / 3) { + EfiReleaseLock (&mHiiDatabaseLock); + return EFI_OUT_OF_RESOURCES; + } + NewBlockSize = NewBlockSize * 3 + (sizeof (EFI_HII_IIBT_IMAGE_24BIT_BLOCK) - sizeof (EFI_HII_RGB_PIXEL)); + if ((NewBlockSize > OldBlockSize) && + (NewBlockSize - OldBlockSize > MAX_UINT24 - ImagePackage->ImagePkgHdr.Header.Length) + ) { + EfiReleaseLock (&mHiiDatabaseLock); + return EFI_OUT_OF_RESOURCES; + } + + // + // Adjust the image package to remove the original block firstly then add the new block. + // + ImageBlocks = AllocateZeroPool (ImagePackage->ImageBlockSize + NewBlockSize - OldBlockSize); + if (ImageBlocks == NULL) { + EfiReleaseLock (&mHiiDatabaseLock); + return EFI_OUT_OF_RESOURCES; + } + + Part1Size = (UINT32) ((UINTN) CurrentImageBlock - (UINTN) ImagePackage->ImageBlock); + Part2Size = ImagePackage->ImageBlockSize - Part1Size - OldBlockSize; + CopyMem (ImageBlocks, ImagePackage->ImageBlock, Part1Size); + + // + // Set the new image block + // + NewImageBlock = (EFI_HII_IMAGE_BLOCK *) ((UINT8 *) ImageBlocks + Part1Size); + if ((Image->Flags & EFI_IMAGE_TRANSPARENT) == EFI_IMAGE_TRANSPARENT) { + NewImageBlock->BlockType= EFI_HII_IIBT_IMAGE_24BIT_TRANS; + } else { + NewImageBlock->BlockType = EFI_HII_IIBT_IMAGE_24BIT; + } + WriteUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) NewImageBlock)->Bitmap.Width, Image->Width); + WriteUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) NewImageBlock)->Bitmap.Height, Image->Height); + CopyGopToRgbPixel (((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) NewImageBlock)->Bitmap.Bitmap, + Image->Bitmap, (UINT32) Image->Width * Image->Height); + + CopyMem ((UINT8 *) NewImageBlock + NewBlockSize, (UINT8 *) CurrentImageBlock + OldBlockSize, Part2Size); + + FreePool (ImagePackage->ImageBlock); + ImagePackage->ImageBlock = ImageBlocks; + ImagePackage->ImageBlockSize += NewBlockSize - OldBlockSize; + ImagePackage->ImagePkgHdr.Header.Length += NewBlockSize - OldBlockSize; + PackageListNode->PackageListHdr.PackageLength += NewBlockSize - OldBlockSize; + + // + // Check whether need to get the contents of HiiDataBase. + // Only after ReadyToBoot to do the export. + // + if (gExportAfterReadyToBoot) { + HiiGetDatabaseInfo(&Private->HiiDatabase); + } + + EfiReleaseLock (&mHiiDatabaseLock); + return EFI_SUCCESS; + +} + + +/** + This function renders an image to a bitmap or the screen using the specified + color and options. It draws the image on an existing bitmap, allocates a new + bitmap or uses the screen. The images can be clipped. + + @param This A pointer to the EFI_HII_IMAGE_PROTOCOL instance. + @param Flags Describes how the image is to be drawn. + @param Image Points to the image to be displayed. + @param Blt If this points to a non-NULL on entry, this points + to the image, which is Width pixels wide and + Height pixels high. The image will be drawn onto + this image and EFI_HII_DRAW_FLAG_CLIP is implied. + If this points to a NULL on entry, then a buffer + will be allocated to hold the generated image and + the pointer updated on exit. It is the caller's + responsibility to free this buffer. + @param BltX Specifies the offset from the left and top edge of + the output image of the first pixel in the image. + @param BltY Specifies the offset from the left and top edge of + the output image of the first pixel in the image. + + @retval EFI_SUCCESS The image was successfully drawn. + @retval EFI_OUT_OF_RESOURCES Unable to allocate an output buffer for Blt. + @retval EFI_INVALID_PARAMETER The Image or Blt was NULL. + @retval EFI_INVALID_PARAMETER Any combination of Flags is invalid. + +**/ +EFI_STATUS +EFIAPI +HiiDrawImage ( + IN CONST EFI_HII_IMAGE_PROTOCOL *This, + IN EFI_HII_DRAW_FLAGS Flags, + IN CONST EFI_IMAGE_INPUT *Image, + IN OUT EFI_IMAGE_OUTPUT **Blt, + IN UINTN BltX, + IN UINTN BltY + ) +{ + EFI_STATUS Status; + HII_DATABASE_PRIVATE_DATA *Private; + BOOLEAN Transparent; + EFI_IMAGE_OUTPUT *ImageOut; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer; + UINTN BufferLen; + UINT16 Width; + UINT16 Height; + UINTN Xpos; + UINTN Ypos; + UINTN OffsetY1; + UINTN OffsetY2; + EFI_FONT_DISPLAY_INFO *FontInfo; + UINTN Index; + + if (This == NULL || Image == NULL || Blt == NULL) { + return EFI_INVALID_PARAMETER; + } + + if ((Flags & EFI_HII_DRAW_FLAG_CLIP) == EFI_HII_DRAW_FLAG_CLIP && *Blt == NULL) { + return EFI_INVALID_PARAMETER; + } + + if ((Flags & EFI_HII_DRAW_FLAG_TRANSPARENT) == EFI_HII_DRAW_FLAG_TRANSPARENT) { + return EFI_INVALID_PARAMETER; + } + + FontInfo = NULL; + + // + // Check whether the image will be drawn transparently or opaquely. + // + Transparent = FALSE; + if ((Flags & EFI_HII_DRAW_FLAG_TRANSPARENT) == EFI_HII_DRAW_FLAG_FORCE_TRANS) { + Transparent = TRUE; + } else if ((Flags & EFI_HII_DRAW_FLAG_TRANSPARENT) == EFI_HII_DRAW_FLAG_FORCE_OPAQUE){ + Transparent = FALSE; + } else { + // + // Now EFI_HII_DRAW_FLAG_DEFAULT is set, whether image will be drawn depending + // on the image's transparency setting. + // + if ((Image->Flags & EFI_IMAGE_TRANSPARENT) == EFI_IMAGE_TRANSPARENT) { + Transparent = TRUE; + } + } + + // + // Image cannot be drawn transparently if Blt points to NULL on entry. + // Currently output to Screen transparently is not supported, either. + // + if (Transparent) { + if (*Blt == NULL) { + return EFI_INVALID_PARAMETER; + } else if ((Flags & EFI_HII_DIRECT_TO_SCREEN) == EFI_HII_DIRECT_TO_SCREEN) { + return EFI_INVALID_PARAMETER; + } + } + + Private = HII_IMAGE_DATABASE_PRIVATE_DATA_FROM_THIS (This); + + // + // When Blt points to a non-NULL on entry, this image will be drawn onto + // this bitmap or screen pointed by "*Blt" and EFI_HII_DRAW_FLAG_CLIP is implied. + // Otherwise a new bitmap will be allocated to hold this image. + // + if (*Blt != NULL) { + // + // Make sure the BltX and BltY is inside the Blt area. + // + if ((BltX >= (*Blt)->Width) || (BltY >= (*Blt)->Height)) { + return EFI_INVALID_PARAMETER; + } + + // + // Clip the image by (Width, Height) + // + + Width = Image->Width; + Height = Image->Height; + + if (Width > (*Blt)->Width - (UINT16)BltX) { + Width = (*Blt)->Width - (UINT16)BltX; + } + if (Height > (*Blt)->Height - (UINT16)BltY) { + Height = (*Blt)->Height - (UINT16)BltY; + } + + // + // Prepare the buffer for the temporary image. + // Make sure the buffer size doesn't overflow UINTN. + // + BufferLen = Width * Height; + if (BufferLen > MAX_UINTN / sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)) { + return EFI_OUT_OF_RESOURCES; + } + BufferLen *= sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL); + BltBuffer = AllocateZeroPool (BufferLen); + if (BltBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + if (Width == Image->Width && Height == Image->Height) { + CopyMem (BltBuffer, Image->Bitmap, BufferLen); + } else { + for (Ypos = 0; Ypos < Height; Ypos++) { + OffsetY1 = Image->Width * Ypos; + OffsetY2 = Width * Ypos; + for (Xpos = 0; Xpos < Width; Xpos++) { + BltBuffer[OffsetY2 + Xpos] = Image->Bitmap[OffsetY1 + Xpos]; + } + } + } + + // + // Draw the image to existing bitmap or screen depending on flag. + // + if ((Flags & EFI_HII_DIRECT_TO_SCREEN) == EFI_HII_DIRECT_TO_SCREEN) { + // + // Caller should make sure the current UGA console is grarphic mode. + // + + // + // Write the image directly to the output device specified by Screen. + // + Status = (*Blt)->Image.Screen->Blt ( + (*Blt)->Image.Screen, + BltBuffer, + EfiBltBufferToVideo, + 0, + 0, + BltX, + BltY, + Width, + Height, + 0 + ); + } else { + // + // Draw the image onto the existing bitmap specified by Bitmap. + // + Status = ImageToBlt ( + BltBuffer, + BltX, + BltY, + Width, + Height, + Transparent, + Blt + ); + + } + + FreePool (BltBuffer); + return Status; + + } else { + // + // Allocate a new bitmap to hold the incoming image. + // + + // + // Make sure the final width and height doesn't overflow UINT16. + // + if ((BltX > (UINTN)MAX_UINT16 - Image->Width) || (BltY > (UINTN)MAX_UINT16 - Image->Height)) { + return EFI_INVALID_PARAMETER; + } + + Width = Image->Width + (UINT16)BltX; + Height = Image->Height + (UINT16)BltY; + + // + // Make sure the output image size doesn't overflow UINTN. + // + BufferLen = Width * Height; + if (BufferLen > MAX_UINTN / sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)) { + return EFI_OUT_OF_RESOURCES; + } + BufferLen *= sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL); + BltBuffer = AllocateZeroPool (BufferLen); + if (BltBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + ImageOut = (EFI_IMAGE_OUTPUT *) AllocateZeroPool (sizeof (EFI_IMAGE_OUTPUT)); + if (ImageOut == NULL) { + FreePool (BltBuffer); + return EFI_OUT_OF_RESOURCES; + } + ImageOut->Width = Width; + ImageOut->Height = Height; + ImageOut->Image.Bitmap = BltBuffer; + + // + // BUGBUG: Now all the "blank" pixels are filled with system default background + // color. Not sure if it need to be updated or not. + // + Status = GetSystemFont (Private, &FontInfo, NULL); + if (EFI_ERROR (Status)) { + FreePool (BltBuffer); + FreePool (ImageOut); + return Status; + } + ASSERT (FontInfo != NULL); + for (Index = 0; Index < (UINTN)Width * Height; Index++) { + BltBuffer[Index] = FontInfo->BackgroundColor; + } + FreePool (FontInfo); + + // + // Draw the incoming image to the new created image. + // + *Blt = ImageOut; + return ImageToBlt ( + Image->Bitmap, + BltX, + BltY, + Image->Width, + Image->Height, + Transparent, + Blt + ); + + } +} + + +/** + This function renders an image to a bitmap or the screen using the specified + color and options. It draws the image on an existing bitmap, allocates a new + bitmap or uses the screen. The images can be clipped. + + @param This A pointer to the EFI_HII_IMAGE_PROTOCOL instance. + @param Flags Describes how the image is to be drawn. + @param PackageList The package list in the HII database to search for + the specified image. + @param ImageId The image's id, which is unique within + PackageList. + @param Blt If this points to a non-NULL on entry, this points + to the image, which is Width pixels wide and + Height pixels high. The image will be drawn onto + this image and + EFI_HII_DRAW_FLAG_CLIP is implied. If this points + to a NULL on entry, then a buffer will be + allocated to hold the generated image and the + pointer updated on exit. It is the caller's + responsibility to free this buffer. + @param BltX Specifies the offset from the left and top edge of + the output image of the first pixel in the image. + @param BltY Specifies the offset from the left and top edge of + the output image of the first pixel in the image. + + @retval EFI_SUCCESS The image was successfully drawn. + @retval EFI_OUT_OF_RESOURCES Unable to allocate an output buffer for Blt. + @retval EFI_INVALID_PARAMETER The Blt was NULL. + @retval EFI_NOT_FOUND The image specified by ImageId is not in the database. + The specified PackageList is not in the database. + +**/ +EFI_STATUS +EFIAPI +HiiDrawImageId ( + IN CONST EFI_HII_IMAGE_PROTOCOL *This, + IN EFI_HII_DRAW_FLAGS Flags, + IN EFI_HII_HANDLE PackageList, + IN EFI_IMAGE_ID ImageId, + IN OUT EFI_IMAGE_OUTPUT **Blt, + IN UINTN BltX, + IN UINTN BltY + ) +{ + EFI_STATUS Status; + EFI_IMAGE_INPUT Image; + + // + // Check input parameter. + // + if (This == NULL || Blt == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Get the specified Image. + // + Status = HiiGetImage (This, PackageList, ImageId, &Image); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Draw this image. + // + Status = HiiDrawImage (This, Flags, &Image, Blt, BltX, BltY); + if (Image.Bitmap != NULL) { + FreePool (Image.Bitmap); + } + return Status; +} + -- cgit