CloverBootloader/MdeModulePkg/Universal/HiiDatabaseDxe/Image.c
2019-09-03 12:58:42 +03:00

1564 lines
55 KiB
C

/** @file
Implementation for EFI_HII_IMAGE_PROTOCOL.
Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR>
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;
}