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