]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/HiiDatabaseDxe/Image.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Universal / HiiDatabaseDxe / Image.c
1 /** @file
2 Implementation for EFI_HII_IMAGE_PROTOCOL.
3
4
5 Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10
11 #include "HiiDatabase.h"
12
13 #define MAX_UINT24 0xFFFFFF
14
15 /**
16 Get the imageid of last image block: EFI_HII_IIBT_END_BLOCK when input
17 ImageId is zero, otherwise return the address of the
18 corresponding image block with identifier specified by ImageId.
19
20 This is a internal function.
21
22 @param ImageBlocks Points to the beginning of a series of image blocks stored in order.
23 @param ImageId If input ImageId is 0, output the image id of the EFI_HII_IIBT_END_BLOCK;
24 else use this id to find its corresponding image block address.
25
26 @return The image block address when input ImageId is not zero; otherwise return NULL.
27
28 **/
29 EFI_HII_IMAGE_BLOCK *
30 GetImageIdOrAddress (
31 IN EFI_HII_IMAGE_BLOCK *ImageBlocks,
32 IN OUT EFI_IMAGE_ID *ImageId
33 )
34 {
35 EFI_IMAGE_ID ImageIdCurrent;
36 EFI_HII_IMAGE_BLOCK *CurrentImageBlock;
37 UINTN Length;
38
39 ASSERT (ImageBlocks != NULL && ImageId != NULL);
40 CurrentImageBlock = ImageBlocks;
41 ImageIdCurrent = 1;
42
43 while (CurrentImageBlock->BlockType != EFI_HII_IIBT_END) {
44 if (*ImageId != 0) {
45 if (*ImageId == ImageIdCurrent) {
46 //
47 // If the found image block is a duplicate block, update the ImageId to
48 // find the previous defined image block.
49 //
50 if (CurrentImageBlock->BlockType == EFI_HII_IIBT_DUPLICATE) {
51 *ImageId = ReadUnaligned16 ((VOID *) &((EFI_HII_IIBT_DUPLICATE_BLOCK *) CurrentImageBlock)->ImageId);
52 ASSERT (*ImageId != ImageIdCurrent);
53 ASSERT (*ImageId != 0);
54 CurrentImageBlock = ImageBlocks;
55 ImageIdCurrent = 1;
56 continue;
57 }
58
59 return CurrentImageBlock;
60 }
61 if (*ImageId < ImageIdCurrent) {
62 //
63 // Can not find the specified image block in this image.
64 //
65 return NULL;
66 }
67 }
68 switch (CurrentImageBlock->BlockType) {
69 case EFI_HII_IIBT_EXT1:
70 Length = ((EFI_HII_IIBT_EXT1_BLOCK *) CurrentImageBlock)->Length;
71 break;
72 case EFI_HII_IIBT_EXT2:
73 Length = ReadUnaligned16 (&((EFI_HII_IIBT_EXT2_BLOCK *) CurrentImageBlock)->Length);
74 break;
75 case EFI_HII_IIBT_EXT4:
76 Length = ReadUnaligned32 ((VOID *) &((EFI_HII_IIBT_EXT4_BLOCK *) CurrentImageBlock)->Length);
77 break;
78
79 case EFI_HII_IIBT_IMAGE_1BIT:
80 case EFI_HII_IIBT_IMAGE_1BIT_TRANS:
81 Length = sizeof (EFI_HII_IIBT_IMAGE_1BIT_BLOCK) - sizeof (UINT8) +
82 BITMAP_LEN_1_BIT (
83 ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_1BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width),
84 ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_1BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height)
85 );
86 ImageIdCurrent++;
87 break;
88
89 case EFI_HII_IIBT_IMAGE_4BIT:
90 case EFI_HII_IIBT_IMAGE_4BIT_TRANS:
91 Length = sizeof (EFI_HII_IIBT_IMAGE_4BIT_BLOCK) - sizeof (UINT8) +
92 BITMAP_LEN_4_BIT (
93 ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_4BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width),
94 ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_4BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height)
95 );
96 ImageIdCurrent++;
97 break;
98
99 case EFI_HII_IIBT_IMAGE_8BIT:
100 case EFI_HII_IIBT_IMAGE_8BIT_TRANS:
101 Length = sizeof (EFI_HII_IIBT_IMAGE_8BIT_BLOCK) - sizeof (UINT8) +
102 BITMAP_LEN_8_BIT (
103 (UINT32) ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_8BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width),
104 ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_8BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height)
105 );
106 ImageIdCurrent++;
107 break;
108
109 case EFI_HII_IIBT_IMAGE_24BIT:
110 case EFI_HII_IIBT_IMAGE_24BIT_TRANS:
111 Length = sizeof (EFI_HII_IIBT_IMAGE_24BIT_BLOCK) - sizeof (EFI_HII_RGB_PIXEL) +
112 BITMAP_LEN_24_BIT (
113 (UINT32) ReadUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width),
114 ReadUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height)
115 );
116 ImageIdCurrent++;
117 break;
118
119 case EFI_HII_IIBT_DUPLICATE:
120 Length = sizeof (EFI_HII_IIBT_DUPLICATE_BLOCK);
121 ImageIdCurrent++;
122 break;
123
124 case EFI_HII_IIBT_IMAGE_JPEG:
125 Length = OFFSET_OF (EFI_HII_IIBT_JPEG_BLOCK, Data) + ReadUnaligned32 ((VOID *) &((EFI_HII_IIBT_JPEG_BLOCK *) CurrentImageBlock)->Size);
126 ImageIdCurrent++;
127 break;
128
129 case EFI_HII_IIBT_IMAGE_PNG:
130 Length = OFFSET_OF (EFI_HII_IIBT_PNG_BLOCK, Data) + ReadUnaligned32 ((VOID *) &((EFI_HII_IIBT_PNG_BLOCK *) CurrentImageBlock)->Size);
131 ImageIdCurrent++;
132 break;
133
134 case EFI_HII_IIBT_SKIP1:
135 Length = sizeof (EFI_HII_IIBT_SKIP1_BLOCK);
136 ImageIdCurrent += ((EFI_HII_IIBT_SKIP1_BLOCK *) CurrentImageBlock)->SkipCount;
137 break;
138
139 case EFI_HII_IIBT_SKIP2:
140 Length = sizeof (EFI_HII_IIBT_SKIP2_BLOCK);
141 ImageIdCurrent += ReadUnaligned16 ((VOID *) &((EFI_HII_IIBT_SKIP2_BLOCK *) CurrentImageBlock)->SkipCount);
142 break;
143
144 default:
145 //
146 // Unknown image blocks can not be skipped, processing halts.
147 //
148 ASSERT (FALSE);
149 Length = 0;
150 break;
151 }
152
153 CurrentImageBlock = (EFI_HII_IMAGE_BLOCK *) ((UINT8 *) CurrentImageBlock + Length);
154
155 }
156
157 //
158 // When ImageId is zero, return the imageid of last image block: EFI_HII_IIBT_END_BLOCK.
159 //
160 if (*ImageId == 0) {
161 *ImageId = ImageIdCurrent;
162 return CurrentImageBlock;
163 }
164
165 return NULL;
166 }
167
168
169
170 /**
171 Convert pixels from EFI_GRAPHICS_OUTPUT_BLT_PIXEL to EFI_HII_RGB_PIXEL style.
172
173 This is a internal function.
174
175
176 @param BitMapOut Pixels in EFI_HII_RGB_PIXEL format.
177 @param BitMapIn Pixels in EFI_GRAPHICS_OUTPUT_BLT_PIXEL format.
178 @param PixelNum The number of pixels to be converted.
179
180
181 **/
182 VOID
183 CopyGopToRgbPixel (
184 OUT EFI_HII_RGB_PIXEL *BitMapOut,
185 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BitMapIn,
186 IN UINTN PixelNum
187 )
188 {
189 UINTN Index;
190
191 ASSERT (BitMapOut != NULL && BitMapIn != NULL);
192
193 for (Index = 0; Index < PixelNum; Index++) {
194 CopyMem (BitMapOut + Index, BitMapIn + Index, sizeof (EFI_HII_RGB_PIXEL));
195 }
196 }
197
198
199 /**
200 Convert pixels from EFI_HII_RGB_PIXEL to EFI_GRAPHICS_OUTPUT_BLT_PIXEL style.
201
202 This is a internal function.
203
204
205 @param BitMapOut Pixels in EFI_GRAPHICS_OUTPUT_BLT_PIXEL format.
206 @param BitMapIn Pixels in EFI_HII_RGB_PIXEL format.
207 @param PixelNum The number of pixels to be converted.
208
209
210 **/
211 VOID
212 CopyRgbToGopPixel (
213 OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BitMapOut,
214 IN EFI_HII_RGB_PIXEL *BitMapIn,
215 IN UINTN PixelNum
216 )
217 {
218 UINTN Index;
219
220 ASSERT (BitMapOut != NULL && BitMapIn != NULL);
221
222 for (Index = 0; Index < PixelNum; Index++) {
223 CopyMem (BitMapOut + Index, BitMapIn + Index, sizeof (EFI_HII_RGB_PIXEL));
224 }
225 }
226
227
228 /**
229 Output pixels in "1 bit per pixel" format to an image.
230
231 This is a internal function.
232
233
234 @param Image Points to the image which will store the pixels.
235 @param Data Stores the value of output pixels, 0 or 1.
236 @param PaletteInfo PaletteInfo which stores the color of the output
237 pixels. First entry corresponds to color 0 and
238 second one to color 1.
239
240
241 **/
242 VOID
243 Output1bitPixel (
244 IN OUT EFI_IMAGE_INPUT *Image,
245 IN UINT8 *Data,
246 IN EFI_HII_IMAGE_PALETTE_INFO *PaletteInfo
247 )
248 {
249 UINT16 Xpos;
250 UINT16 Ypos;
251 UINTN OffsetY;
252 UINT8 Index;
253 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BitMapPtr;
254 EFI_GRAPHICS_OUTPUT_BLT_PIXEL PaletteValue[2];
255 EFI_HII_IMAGE_PALETTE_INFO *Palette;
256 UINTN PaletteSize;
257 UINT8 Byte;
258
259 ASSERT (Image != NULL && Data != NULL && PaletteInfo != NULL);
260
261 BitMapPtr = Image->Bitmap;
262
263 //
264 // First entry corresponds to color 0 and second entry corresponds to color 1.
265 //
266 PaletteSize = 0;
267 CopyMem (&PaletteSize, PaletteInfo, sizeof (UINT16));
268 PaletteSize += sizeof (UINT16);
269 Palette = AllocateZeroPool (PaletteSize);
270 ASSERT (Palette != NULL);
271 if (Palette == NULL) {
272 return;
273 }
274 CopyMem (Palette, PaletteInfo, PaletteSize);
275
276 ZeroMem (PaletteValue, sizeof (PaletteValue));
277 CopyRgbToGopPixel (&PaletteValue[0], &Palette->PaletteValue[0], 1);
278 CopyRgbToGopPixel (&PaletteValue[1], &Palette->PaletteValue[1], 1);
279 FreePool (Palette);
280
281 //
282 // Convert the pixel from one bit to corresponding color.
283 //
284 for (Ypos = 0; Ypos < Image->Height; Ypos++) {
285 OffsetY = BITMAP_LEN_1_BIT (Image->Width, Ypos);
286 //
287 // All bits in these bytes are meaningful
288 //
289 for (Xpos = 0; Xpos < Image->Width / 8; Xpos++) {
290 Byte = *(Data + OffsetY + Xpos);
291 for (Index = 0; Index < 8; Index++) {
292 if ((Byte & (1 << Index)) != 0) {
293 BitMapPtr[Ypos * Image->Width + Xpos * 8 + (8 - Index - 1)] = PaletteValue[1];
294 } else {
295 BitMapPtr[Ypos * Image->Width + Xpos * 8 + (8 - Index - 1)] = PaletteValue[0];
296 }
297 }
298 }
299
300 if (Image->Width % 8 != 0) {
301 //
302 // Padding bits in this byte should be ignored.
303 //
304 Byte = *(Data + OffsetY + Xpos);
305 for (Index = 0; Index < Image->Width % 8; Index++) {
306 if ((Byte & (1 << (8 - Index - 1))) != 0) {
307 BitMapPtr[Ypos * Image->Width + Xpos * 8 + Index] = PaletteValue[1];
308 } else {
309 BitMapPtr[Ypos * Image->Width + Xpos * 8 + Index] = PaletteValue[0];
310 }
311 }
312 }
313 }
314 }
315
316
317 /**
318 Output pixels in "4 bit per pixel" format to an image.
319
320 This is a internal function.
321
322
323 @param Image Points to the image which will store the pixels.
324 @param Data Stores the value of output pixels, 0 ~ 15.
325 @param[in] PaletteInfo PaletteInfo which stores the color of the output
326 pixels. Each entry corresponds to a color within
327 [0, 15].
328
329
330 **/
331 VOID
332 Output4bitPixel (
333 IN OUT EFI_IMAGE_INPUT *Image,
334 IN UINT8 *Data,
335 IN EFI_HII_IMAGE_PALETTE_INFO *PaletteInfo
336 )
337 {
338 UINT16 Xpos;
339 UINT16 Ypos;
340 UINTN OffsetY;
341 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BitMapPtr;
342 EFI_GRAPHICS_OUTPUT_BLT_PIXEL PaletteValue[16];
343 EFI_HII_IMAGE_PALETTE_INFO *Palette;
344 UINTN PaletteSize;
345 UINT16 PaletteNum;
346 UINT8 Byte;
347
348 ASSERT (Image != NULL && Data != NULL && PaletteInfo != NULL);
349
350 BitMapPtr = Image->Bitmap;
351
352 //
353 // The bitmap should allocate each color index starting from 0.
354 //
355 PaletteSize = 0;
356 CopyMem (&PaletteSize, PaletteInfo, sizeof (UINT16));
357 PaletteSize += sizeof (UINT16);
358 Palette = AllocateZeroPool (PaletteSize);
359 ASSERT (Palette != NULL);
360 if (Palette == NULL) {
361 return;
362 }
363 CopyMem (Palette, PaletteInfo, PaletteSize);
364 PaletteNum = (UINT16)(Palette->PaletteSize / sizeof (EFI_HII_RGB_PIXEL));
365
366 ZeroMem (PaletteValue, sizeof (PaletteValue));
367 CopyRgbToGopPixel (PaletteValue, Palette->PaletteValue, MIN (PaletteNum, ARRAY_SIZE (PaletteValue)));
368 FreePool (Palette);
369
370 //
371 // Convert the pixel from 4 bit to corresponding color.
372 //
373 for (Ypos = 0; Ypos < Image->Height; Ypos++) {
374 OffsetY = BITMAP_LEN_4_BIT (Image->Width, Ypos);
375 //
376 // All bits in these bytes are meaningful
377 //
378 for (Xpos = 0; Xpos < Image->Width / 2; Xpos++) {
379 Byte = *(Data + OffsetY + Xpos);
380 BitMapPtr[Ypos * Image->Width + Xpos * 2] = PaletteValue[Byte >> 4];
381 BitMapPtr[Ypos * Image->Width + Xpos * 2 + 1] = PaletteValue[Byte & 0x0F];
382 }
383
384 if (Image->Width % 2 != 0) {
385 //
386 // Padding bits in this byte should be ignored.
387 //
388 Byte = *(Data + OffsetY + Xpos);
389 BitMapPtr[Ypos * Image->Width + Xpos * 2] = PaletteValue[Byte >> 4];
390 }
391 }
392 }
393
394
395 /**
396 Output pixels in "8 bit per pixel" format to an image.
397
398 This is a internal function.
399
400
401 @param Image Points to the image which will store the pixels.
402 @param Data Stores the value of output pixels, 0 ~ 255.
403 @param[in] PaletteInfo PaletteInfo which stores the color of the output
404 pixels. Each entry corresponds to a color within
405 [0, 255].
406
407
408 **/
409 VOID
410 Output8bitPixel (
411 IN OUT EFI_IMAGE_INPUT *Image,
412 IN UINT8 *Data,
413 IN EFI_HII_IMAGE_PALETTE_INFO *PaletteInfo
414 )
415 {
416 UINT16 Xpos;
417 UINT16 Ypos;
418 UINTN OffsetY;
419 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BitMapPtr;
420 EFI_GRAPHICS_OUTPUT_BLT_PIXEL PaletteValue[256];
421 EFI_HII_IMAGE_PALETTE_INFO *Palette;
422 UINTN PaletteSize;
423 UINT16 PaletteNum;
424 UINT8 Byte;
425
426 ASSERT (Image != NULL && Data != NULL && PaletteInfo != NULL);
427
428 BitMapPtr = Image->Bitmap;
429
430 //
431 // The bitmap should allocate each color index starting from 0.
432 //
433 PaletteSize = 0;
434 CopyMem (&PaletteSize, PaletteInfo, sizeof (UINT16));
435 PaletteSize += sizeof (UINT16);
436 Palette = AllocateZeroPool (PaletteSize);
437 ASSERT (Palette != NULL);
438 if (Palette == NULL) {
439 return;
440 }
441 CopyMem (Palette, PaletteInfo, PaletteSize);
442 PaletteNum = (UINT16)(Palette->PaletteSize / sizeof (EFI_HII_RGB_PIXEL));
443 ZeroMem (PaletteValue, sizeof (PaletteValue));
444 CopyRgbToGopPixel (PaletteValue, Palette->PaletteValue, MIN (PaletteNum, ARRAY_SIZE (PaletteValue)));
445 FreePool (Palette);
446
447 //
448 // Convert the pixel from 8 bits to corresponding color.
449 //
450 for (Ypos = 0; Ypos < Image->Height; Ypos++) {
451 OffsetY = BITMAP_LEN_8_BIT ((UINT32) Image->Width, Ypos);
452 //
453 // All bits are meaningful since the bitmap is 8 bits per pixel.
454 //
455 for (Xpos = 0; Xpos < Image->Width; Xpos++) {
456 Byte = *(Data + OffsetY + Xpos);
457 BitMapPtr[OffsetY + Xpos] = PaletteValue[Byte];
458 }
459 }
460
461 }
462
463
464 /**
465 Output pixels in "24 bit per pixel" format to an image.
466
467 This is a internal function.
468
469
470 @param Image Points to the image which will store the pixels.
471 @param Data Stores the color of output pixels, allowing 16.8
472 millions colors.
473
474
475 **/
476 VOID
477 Output24bitPixel (
478 IN OUT EFI_IMAGE_INPUT *Image,
479 IN EFI_HII_RGB_PIXEL *Data
480 )
481 {
482 UINT16 Ypos;
483 UINTN OffsetY;
484 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BitMapPtr;
485
486 ASSERT (Image != NULL && Data != NULL);
487
488 BitMapPtr = Image->Bitmap;
489
490 for (Ypos = 0; Ypos < Image->Height; Ypos++) {
491 OffsetY = BITMAP_LEN_8_BIT ((UINT32) Image->Width, Ypos);
492 CopyRgbToGopPixel (&BitMapPtr[OffsetY], &Data[OffsetY], Image->Width);
493 }
494
495 }
496
497
498 /**
499 Convert the image from EFI_IMAGE_INPUT to EFI_IMAGE_OUTPUT format.
500
501 This is a internal function.
502
503
504 @param BltBuffer Buffer points to bitmap data of incoming image.
505 @param BltX Specifies the offset from the left and top edge of
506 the output image of the first pixel in the image.
507 @param BltY Specifies the offset from the left and top edge of
508 the output image of the first pixel in the image.
509 @param Width Width of the incoming image, in pixels.
510 @param Height Height of the incoming image, in pixels.
511 @param Transparent If TRUE, all "off" pixels in the image will be
512 drawn using the pixel value from blt and all other
513 pixels will be copied.
514 @param Blt Buffer points to bitmap data of output image.
515
516 @retval EFI_SUCCESS The image was successfully converted.
517 @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.
518
519 **/
520 EFI_STATUS
521 ImageToBlt (
522 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer,
523 IN UINTN BltX,
524 IN UINTN BltY,
525 IN UINTN Width,
526 IN UINTN Height,
527 IN BOOLEAN Transparent,
528 IN OUT EFI_IMAGE_OUTPUT **Blt
529 )
530 {
531 EFI_IMAGE_OUTPUT *ImageOut;
532 UINTN Xpos;
533 UINTN Ypos;
534 UINTN OffsetY1; // src buffer
535 UINTN OffsetY2; // dest buffer
536 EFI_GRAPHICS_OUTPUT_BLT_PIXEL SrcPixel;
537 EFI_GRAPHICS_OUTPUT_BLT_PIXEL ZeroPixel;
538
539 if (BltBuffer == NULL || Blt == NULL || *Blt == NULL) {
540 return EFI_INVALID_PARAMETER;
541 }
542
543 ImageOut = *Blt;
544
545 if (Width + BltX > ImageOut->Width) {
546 return EFI_INVALID_PARAMETER;
547 }
548 if (Height + BltY > ImageOut->Height) {
549 return EFI_INVALID_PARAMETER;
550 }
551
552 ZeroMem (&ZeroPixel, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
553
554 for (Ypos = 0; Ypos < Height; Ypos++) {
555 OffsetY1 = Width * Ypos;
556 OffsetY2 = ImageOut->Width * (BltY + Ypos);
557 for (Xpos = 0; Xpos < Width; Xpos++) {
558 SrcPixel = BltBuffer[OffsetY1 + Xpos];
559 if (Transparent) {
560 if (CompareMem (&SrcPixel, &ZeroPixel, 3) != 0) {
561 ImageOut->Image.Bitmap[OffsetY2 + BltX + Xpos] = SrcPixel;
562 }
563 } else {
564 ImageOut->Image.Bitmap[OffsetY2 + BltX + Xpos] = SrcPixel;
565 }
566 }
567 }
568
569 return EFI_SUCCESS;
570 }
571
572 /**
573 Return the HII package list identified by PackageList HII handle.
574
575 @param Database Pointer to HII database list header.
576 @param PackageList HII handle of the package list to locate.
577
578 @retval The HII package list instance.
579 **/
580 HII_DATABASE_PACKAGE_LIST_INSTANCE *
581 LocatePackageList (
582 IN LIST_ENTRY *Database,
583 IN EFI_HII_HANDLE PackageList
584 )
585 {
586 LIST_ENTRY *Link;
587 HII_DATABASE_RECORD *Record;
588
589 //
590 // Get the specified package list and image package.
591 //
592 for (Link = GetFirstNode (Database);
593 !IsNull (Database, Link);
594 Link = GetNextNode (Database, Link)
595 ) {
596 Record = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
597 if (Record->Handle == PackageList) {
598 return Record->PackageList;
599 }
600 }
601 return NULL;
602 }
603
604 /**
605 This function adds the image Image to the group of images owned by PackageList, and returns
606 a new image identifier (ImageId).
607
608 @param This A pointer to the EFI_HII_IMAGE_PROTOCOL instance.
609 @param PackageList Handle of the package list where this image will
610 be added.
611 @param ImageId On return, contains the new image id, which is
612 unique within PackageList.
613 @param Image Points to the image.
614
615 @retval EFI_SUCCESS The new image was added successfully.
616 @retval EFI_NOT_FOUND The specified PackageList could not be found in
617 database.
618 @retval EFI_OUT_OF_RESOURCES Could not add the image due to lack of resources.
619 @retval EFI_INVALID_PARAMETER Image is NULL or ImageId is NULL.
620
621 **/
622 EFI_STATUS
623 EFIAPI
624 HiiNewImage (
625 IN CONST EFI_HII_IMAGE_PROTOCOL *This,
626 IN EFI_HII_HANDLE PackageList,
627 OUT EFI_IMAGE_ID *ImageId,
628 IN CONST EFI_IMAGE_INPUT *Image
629 )
630 {
631 HII_DATABASE_PRIVATE_DATA *Private;
632 HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode;
633 HII_IMAGE_PACKAGE_INSTANCE *ImagePackage;
634 EFI_HII_IMAGE_BLOCK *ImageBlocks;
635 UINT32 NewBlockSize;
636
637 if (This == NULL || ImageId == NULL || Image == NULL || Image->Bitmap == NULL) {
638 return EFI_INVALID_PARAMETER;
639 }
640
641 Private = HII_IMAGE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
642 PackageListNode = LocatePackageList (&Private->DatabaseList, PackageList);
643 if (PackageListNode == NULL) {
644 return EFI_NOT_FOUND;
645 }
646
647 EfiAcquireLock (&mHiiDatabaseLock);
648
649 //
650 // Calcuate the size of new image.
651 // Make sure the size doesn't overflow UINT32.
652 // Note: 24Bit BMP occpuies 3 bytes per pixel.
653 //
654 NewBlockSize = (UINT32)Image->Width * Image->Height;
655 if (NewBlockSize > (MAX_UINT32 - (sizeof (EFI_HII_IIBT_IMAGE_24BIT_BLOCK) - sizeof (EFI_HII_RGB_PIXEL))) / 3) {
656 return EFI_OUT_OF_RESOURCES;
657 }
658 NewBlockSize = NewBlockSize * 3 + (sizeof (EFI_HII_IIBT_IMAGE_24BIT_BLOCK) - sizeof (EFI_HII_RGB_PIXEL));
659
660 //
661 // Get the image package in the package list,
662 // or create a new image package if image package does not exist.
663 //
664 if (PackageListNode->ImagePkg != NULL) {
665 ImagePackage = PackageListNode->ImagePkg;
666
667 //
668 // Output the image id of the incoming image being inserted, which is the
669 // image id of the EFI_HII_IIBT_END block of old image package.
670 //
671 *ImageId = 0;
672 GetImageIdOrAddress (ImagePackage->ImageBlock, ImageId);
673
674 //
675 // Update the package's image block by appending the new block to the end.
676 //
677
678 //
679 // Make sure the final package length doesn't overflow.
680 // Length of the package header is represented using 24 bits. So MAX length is MAX_UINT24.
681 //
682 if (NewBlockSize > MAX_UINT24 - ImagePackage->ImagePkgHdr.Header.Length) {
683 return EFI_OUT_OF_RESOURCES;
684 }
685 //
686 // Because ImagePackage->ImageBlockSize < ImagePackage->ImagePkgHdr.Header.Length,
687 // So (ImagePackage->ImageBlockSize + NewBlockSize) <= MAX_UINT24
688 //
689 ImageBlocks = AllocatePool (ImagePackage->ImageBlockSize + NewBlockSize);
690 if (ImageBlocks == NULL) {
691 EfiReleaseLock (&mHiiDatabaseLock);
692 return EFI_OUT_OF_RESOURCES;
693 }
694 //
695 // Copy the original content.
696 //
697 CopyMem (
698 ImageBlocks,
699 ImagePackage->ImageBlock,
700 ImagePackage->ImageBlockSize - sizeof (EFI_HII_IIBT_END_BLOCK)
701 );
702 FreePool (ImagePackage->ImageBlock);
703 ImagePackage->ImageBlock = ImageBlocks;
704
705 //
706 // Point to the very last block.
707 //
708 ImageBlocks = (EFI_HII_IMAGE_BLOCK *) (
709 (UINT8 *) ImageBlocks + ImagePackage->ImageBlockSize - sizeof (EFI_HII_IIBT_END_BLOCK)
710 );
711 //
712 // Update the length record.
713 //
714 ImagePackage->ImageBlockSize += NewBlockSize;
715 ImagePackage->ImagePkgHdr.Header.Length += NewBlockSize;
716 PackageListNode->PackageListHdr.PackageLength += NewBlockSize;
717
718 } else {
719 //
720 // Make sure the final package length doesn't overflow.
721 // Length of the package header is represented using 24 bits. So MAX length is MAX_UINT24.
722 //
723 if (NewBlockSize > MAX_UINT24 - (sizeof (EFI_HII_IMAGE_PACKAGE_HDR) + sizeof (EFI_HII_IIBT_END_BLOCK))) {
724 return EFI_OUT_OF_RESOURCES;
725 }
726 //
727 // The specified package list does not contain image package.
728 // Create one to add this image block.
729 //
730 ImagePackage = (HII_IMAGE_PACKAGE_INSTANCE *) AllocateZeroPool (sizeof (HII_IMAGE_PACKAGE_INSTANCE));
731 if (ImagePackage == NULL) {
732 EfiReleaseLock (&mHiiDatabaseLock);
733 return EFI_OUT_OF_RESOURCES;
734 }
735 //
736 // Output the image id of the incoming image being inserted, which is the
737 // first image block so that id is initially to one.
738 //
739 *ImageId = 1;
740 //
741 // Fill in image package header.
742 //
743 ImagePackage->ImagePkgHdr.Header.Length = sizeof (EFI_HII_IMAGE_PACKAGE_HDR) + NewBlockSize + sizeof (EFI_HII_IIBT_END_BLOCK);
744 ImagePackage->ImagePkgHdr.Header.Type = EFI_HII_PACKAGE_IMAGES;
745 ImagePackage->ImagePkgHdr.ImageInfoOffset = sizeof (EFI_HII_IMAGE_PACKAGE_HDR);
746 ImagePackage->ImagePkgHdr.PaletteInfoOffset = 0;
747
748 //
749 // Fill in palette info.
750 //
751 ImagePackage->PaletteBlock = NULL;
752 ImagePackage->PaletteInfoSize = 0;
753
754 //
755 // Fill in image blocks.
756 //
757 ImagePackage->ImageBlockSize = NewBlockSize + sizeof (EFI_HII_IIBT_END_BLOCK);
758 ImagePackage->ImageBlock = AllocateZeroPool (NewBlockSize + sizeof (EFI_HII_IIBT_END_BLOCK));
759 if (ImagePackage->ImageBlock == NULL) {
760 FreePool (ImagePackage);
761 EfiReleaseLock (&mHiiDatabaseLock);
762 return EFI_OUT_OF_RESOURCES;
763 }
764 ImageBlocks = ImagePackage->ImageBlock;
765
766 //
767 // Insert this image package.
768 //
769 PackageListNode->ImagePkg = ImagePackage;
770 PackageListNode->PackageListHdr.PackageLength += ImagePackage->ImagePkgHdr.Header.Length;
771 }
772
773 //
774 // Append the new block here
775 //
776 if (Image->Flags == EFI_IMAGE_TRANSPARENT) {
777 ImageBlocks->BlockType = EFI_HII_IIBT_IMAGE_24BIT_TRANS;
778 } else {
779 ImageBlocks->BlockType = EFI_HII_IIBT_IMAGE_24BIT;
780 }
781 WriteUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) ImageBlocks)->Bitmap.Width, Image->Width);
782 WriteUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) ImageBlocks)->Bitmap.Height, Image->Height);
783 CopyGopToRgbPixel (((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) ImageBlocks)->Bitmap.Bitmap, Image->Bitmap, (UINT32) Image->Width * Image->Height);
784
785 //
786 // Append the block end
787 //
788 ImageBlocks = (EFI_HII_IMAGE_BLOCK *) ((UINT8 *) ImageBlocks + NewBlockSize);
789 ImageBlocks->BlockType = EFI_HII_IIBT_END;
790
791 //
792 // Check whether need to get the contents of HiiDataBase.
793 // Only after ReadyToBoot to do the export.
794 //
795 if (gExportAfterReadyToBoot) {
796 HiiGetDatabaseInfo(&Private->HiiDatabase);
797 }
798
799 EfiReleaseLock (&mHiiDatabaseLock);
800
801 return EFI_SUCCESS;
802 }
803
804
805 /**
806 This function retrieves the image specified by ImageId which is associated with
807 the specified PackageList and copies it into the buffer specified by Image.
808
809 @param Database A pointer to the database list header.
810 @param PackageList Handle of the package list where this image will
811 be searched.
812 @param ImageId The image's id,, which is unique within
813 PackageList.
814 @param Image Points to the image.
815 @param BitmapOnly TRUE to only return the bitmap type image.
816 FALSE to locate image decoder instance to decode image.
817
818 @retval EFI_SUCCESS The new image was returned successfully.
819 @retval EFI_NOT_FOUND The image specified by ImageId is not in the
820 database. The specified PackageList is not in the database.
821 @retval EFI_BUFFER_TOO_SMALL The buffer specified by ImageSize is too small to
822 hold the image.
823 @retval EFI_INVALID_PARAMETER The Image or ImageSize was NULL.
824 @retval EFI_OUT_OF_RESOURCES The bitmap could not be retrieved because there was not
825 enough memory.
826 **/
827 EFI_STATUS
828 IGetImage (
829 IN LIST_ENTRY *Database,
830 IN EFI_HII_HANDLE PackageList,
831 IN EFI_IMAGE_ID ImageId,
832 OUT EFI_IMAGE_INPUT *Image,
833 IN BOOLEAN BitmapOnly
834 )
835 {
836 EFI_STATUS Status;
837 HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode;
838 HII_IMAGE_PACKAGE_INSTANCE *ImagePackage;
839 EFI_HII_IMAGE_BLOCK *CurrentImageBlock;
840 EFI_HII_IIBT_IMAGE_1BIT_BLOCK Iibt1bit;
841 UINT16 Width;
842 UINT16 Height;
843 UINTN ImageLength;
844 UINT8 *PaletteInfo;
845 UINT8 PaletteIndex;
846 UINT16 PaletteSize;
847 EFI_HII_IMAGE_DECODER_PROTOCOL *Decoder;
848 EFI_IMAGE_OUTPUT *ImageOut;
849
850 if (Image == NULL || ImageId == 0) {
851 return EFI_INVALID_PARAMETER;
852 }
853
854 PackageListNode = LocatePackageList (Database, PackageList);
855 if (PackageListNode == NULL) {
856 return EFI_NOT_FOUND;
857 }
858 ImagePackage = PackageListNode->ImagePkg;
859 if (ImagePackage == NULL) {
860 return EFI_NOT_FOUND;
861 }
862
863 //
864 // Find the image block specified by ImageId
865 //
866 CurrentImageBlock = GetImageIdOrAddress (ImagePackage->ImageBlock, &ImageId);
867 if (CurrentImageBlock == NULL) {
868 return EFI_NOT_FOUND;
869 }
870
871 Image->Flags = 0;
872 switch (CurrentImageBlock->BlockType) {
873 case EFI_HII_IIBT_IMAGE_JPEG:
874 case EFI_HII_IIBT_IMAGE_PNG:
875 if (BitmapOnly) {
876 return EFI_UNSUPPORTED;
877 }
878
879 ImageOut = NULL;
880 Decoder = LocateHiiImageDecoder (CurrentImageBlock->BlockType);
881 if (Decoder == NULL) {
882 return EFI_UNSUPPORTED;
883 }
884 //
885 // Use the common block code since the definition of two structures is the same.
886 //
887 ASSERT (OFFSET_OF (EFI_HII_IIBT_JPEG_BLOCK, Data) == OFFSET_OF (EFI_HII_IIBT_PNG_BLOCK, Data));
888 ASSERT (sizeof (((EFI_HII_IIBT_JPEG_BLOCK *) CurrentImageBlock)->Data) ==
889 sizeof (((EFI_HII_IIBT_PNG_BLOCK *) CurrentImageBlock)->Data));
890 ASSERT (OFFSET_OF (EFI_HII_IIBT_JPEG_BLOCK, Size) == OFFSET_OF (EFI_HII_IIBT_PNG_BLOCK, Size));
891 ASSERT (sizeof (((EFI_HII_IIBT_JPEG_BLOCK *) CurrentImageBlock)->Size) ==
892 sizeof (((EFI_HII_IIBT_PNG_BLOCK *) CurrentImageBlock)->Size));
893 Status = Decoder->DecodeImage (
894 Decoder,
895 ((EFI_HII_IIBT_JPEG_BLOCK *) CurrentImageBlock)->Data,
896 ((EFI_HII_IIBT_JPEG_BLOCK *) CurrentImageBlock)->Size,
897 &ImageOut,
898 FALSE
899 );
900
901 //
902 // Spec requires to use the first capable image decoder instance.
903 // The first image decoder instance may fail to decode the image.
904 //
905 if (!EFI_ERROR (Status)) {
906 Image->Bitmap = ImageOut->Image.Bitmap;
907 Image->Height = ImageOut->Height;
908 Image->Width = ImageOut->Width;
909 FreePool (ImageOut);
910 }
911 return Status;
912
913 case EFI_HII_IIBT_IMAGE_1BIT_TRANS:
914 case EFI_HII_IIBT_IMAGE_4BIT_TRANS:
915 case EFI_HII_IIBT_IMAGE_8BIT_TRANS:
916 Image->Flags = EFI_IMAGE_TRANSPARENT;
917 //
918 // fall through
919 //
920 case EFI_HII_IIBT_IMAGE_1BIT:
921 case EFI_HII_IIBT_IMAGE_4BIT:
922 case EFI_HII_IIBT_IMAGE_8BIT:
923 //
924 // Use the common block code since the definition of these structures is the same.
925 //
926 CopyMem (&Iibt1bit, CurrentImageBlock, sizeof (EFI_HII_IIBT_IMAGE_1BIT_BLOCK));
927 ImageLength = (UINTN) Iibt1bit.Bitmap.Width * Iibt1bit.Bitmap.Height;
928 if (ImageLength > MAX_UINTN / sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)) {
929 return EFI_OUT_OF_RESOURCES;
930 }
931 ImageLength *= sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
932 Image->Bitmap = AllocateZeroPool (ImageLength);
933 if (Image->Bitmap == NULL) {
934 return EFI_OUT_OF_RESOURCES;
935 }
936
937 Image->Width = Iibt1bit.Bitmap.Width;
938 Image->Height = Iibt1bit.Bitmap.Height;
939
940 PaletteInfo = ImagePackage->PaletteBlock + sizeof (EFI_HII_IMAGE_PALETTE_INFO_HEADER);
941 for (PaletteIndex = 1; PaletteIndex < Iibt1bit.PaletteIndex; PaletteIndex++) {
942 CopyMem (&PaletteSize, PaletteInfo, sizeof (UINT16));
943 PaletteInfo += PaletteSize + sizeof (UINT16);
944 }
945 ASSERT (PaletteIndex == Iibt1bit.PaletteIndex);
946
947 //
948 // Output bitmap data
949 //
950 if (CurrentImageBlock->BlockType == EFI_HII_IIBT_IMAGE_1BIT ||
951 CurrentImageBlock->BlockType == EFI_HII_IIBT_IMAGE_1BIT_TRANS) {
952 Output1bitPixel (
953 Image,
954 ((EFI_HII_IIBT_IMAGE_1BIT_BLOCK *) CurrentImageBlock)->Bitmap.Data,
955 (EFI_HII_IMAGE_PALETTE_INFO *) PaletteInfo
956 );
957 } else if (CurrentImageBlock->BlockType == EFI_HII_IIBT_IMAGE_4BIT ||
958 CurrentImageBlock->BlockType == EFI_HII_IIBT_IMAGE_4BIT_TRANS) {
959 Output4bitPixel (
960 Image,
961 ((EFI_HII_IIBT_IMAGE_4BIT_BLOCK *) CurrentImageBlock)->Bitmap.Data,
962 (EFI_HII_IMAGE_PALETTE_INFO *) PaletteInfo
963 );
964 } else {
965 Output8bitPixel (
966 Image,
967 ((EFI_HII_IIBT_IMAGE_8BIT_BLOCK *) CurrentImageBlock)->Bitmap.Data,
968 (EFI_HII_IMAGE_PALETTE_INFO *) PaletteInfo
969 );
970 }
971
972 return EFI_SUCCESS;
973
974 case EFI_HII_IIBT_IMAGE_24BIT_TRANS:
975 Image->Flags = EFI_IMAGE_TRANSPARENT;
976 //
977 // fall through
978 //
979 case EFI_HII_IIBT_IMAGE_24BIT:
980 Width = ReadUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width);
981 Height = ReadUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height);
982 ImageLength = (UINTN)Width * Height;
983 if (ImageLength > MAX_UINTN / sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)) {
984 return EFI_OUT_OF_RESOURCES;
985 }
986 ImageLength *= sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
987 Image->Bitmap = AllocateZeroPool (ImageLength);
988 if (Image->Bitmap == NULL) {
989 return EFI_OUT_OF_RESOURCES;
990 }
991
992 Image->Width = Width;
993 Image->Height = Height;
994
995 //
996 // Output the bitmap data directly.
997 //
998 Output24bitPixel (
999 Image,
1000 ((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) CurrentImageBlock)->Bitmap.Bitmap
1001 );
1002 return EFI_SUCCESS;
1003
1004 default:
1005 return EFI_NOT_FOUND;
1006 }
1007 }
1008
1009 /**
1010 This function retrieves the image specified by ImageId which is associated with
1011 the specified PackageList and copies it into the buffer specified by Image.
1012
1013 @param This A pointer to the EFI_HII_IMAGE_PROTOCOL instance.
1014 @param PackageList Handle of the package list where this image will
1015 be searched.
1016 @param ImageId The image's id,, which is unique within
1017 PackageList.
1018 @param Image Points to the image.
1019
1020 @retval EFI_SUCCESS The new image was returned successfully.
1021 @retval EFI_NOT_FOUND The image specified by ImageId is not in the
1022 database. The specified PackageList is not in the database.
1023 @retval EFI_BUFFER_TOO_SMALL The buffer specified by ImageSize is too small to
1024 hold the image.
1025 @retval EFI_INVALID_PARAMETER The Image or ImageSize was NULL.
1026 @retval EFI_OUT_OF_RESOURCES The bitmap could not be retrieved because there was not
1027 enough memory.
1028
1029 **/
1030 EFI_STATUS
1031 EFIAPI
1032 HiiGetImage (
1033 IN CONST EFI_HII_IMAGE_PROTOCOL *This,
1034 IN EFI_HII_HANDLE PackageList,
1035 IN EFI_IMAGE_ID ImageId,
1036 OUT EFI_IMAGE_INPUT *Image
1037 )
1038 {
1039 HII_DATABASE_PRIVATE_DATA *Private;
1040 Private = HII_IMAGE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
1041 return IGetImage (&Private->DatabaseList, PackageList, ImageId, Image, TRUE);
1042 }
1043
1044
1045 /**
1046 This function updates the image specified by ImageId in the specified PackageListHandle to
1047 the image specified by Image.
1048
1049 @param This A pointer to the EFI_HII_IMAGE_PROTOCOL instance.
1050 @param PackageList The package list containing the images.
1051 @param ImageId The image's id,, which is unique within
1052 PackageList.
1053 @param Image Points to the image.
1054
1055 @retval EFI_SUCCESS The new image was updated successfully.
1056 @retval EFI_NOT_FOUND The image specified by ImageId is not in the
1057 database. The specified PackageList is not in the database.
1058 @retval EFI_INVALID_PARAMETER The Image was NULL.
1059
1060 **/
1061 EFI_STATUS
1062 EFIAPI
1063 HiiSetImage (
1064 IN CONST EFI_HII_IMAGE_PROTOCOL *This,
1065 IN EFI_HII_HANDLE PackageList,
1066 IN EFI_IMAGE_ID ImageId,
1067 IN CONST EFI_IMAGE_INPUT *Image
1068 )
1069 {
1070 HII_DATABASE_PRIVATE_DATA *Private;
1071 HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode;
1072 HII_IMAGE_PACKAGE_INSTANCE *ImagePackage;
1073 EFI_HII_IMAGE_BLOCK *CurrentImageBlock;
1074 EFI_HII_IMAGE_BLOCK *ImageBlocks;
1075 EFI_HII_IMAGE_BLOCK *NewImageBlock;
1076 UINT32 NewBlockSize;
1077 UINT32 OldBlockSize;
1078 UINT32 Part1Size;
1079 UINT32 Part2Size;
1080
1081 if (This == NULL || Image == NULL || ImageId == 0 || Image->Bitmap == NULL) {
1082 return EFI_INVALID_PARAMETER;
1083 }
1084
1085 Private = HII_IMAGE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
1086 PackageListNode = LocatePackageList (&Private->DatabaseList, PackageList);
1087 if (PackageListNode == NULL) {
1088 return EFI_NOT_FOUND;
1089 }
1090 ImagePackage = PackageListNode->ImagePkg;
1091 if (ImagePackage == NULL) {
1092 return EFI_NOT_FOUND;
1093 }
1094
1095 //
1096 // Find the image block specified by ImageId
1097 //
1098 CurrentImageBlock = GetImageIdOrAddress (ImagePackage->ImageBlock, &ImageId);
1099 if (CurrentImageBlock == NULL) {
1100 return EFI_NOT_FOUND;
1101 }
1102
1103 EfiAcquireLock (&mHiiDatabaseLock);
1104
1105 //
1106 // Get the size of original image block. Use some common block code here
1107 // since the definition of some structures is the same.
1108 //
1109 switch (CurrentImageBlock->BlockType) {
1110 case EFI_HII_IIBT_IMAGE_JPEG:
1111 OldBlockSize = OFFSET_OF (EFI_HII_IIBT_JPEG_BLOCK, Data) + ReadUnaligned32 ((VOID *) &((EFI_HII_IIBT_JPEG_BLOCK *) CurrentImageBlock)->Size);
1112 break;
1113 case EFI_HII_IIBT_IMAGE_PNG:
1114 OldBlockSize = OFFSET_OF (EFI_HII_IIBT_PNG_BLOCK, Data) + ReadUnaligned32 ((VOID *) &((EFI_HII_IIBT_PNG_BLOCK *) CurrentImageBlock)->Size);
1115 break;
1116 case EFI_HII_IIBT_IMAGE_1BIT:
1117 case EFI_HII_IIBT_IMAGE_1BIT_TRANS:
1118 OldBlockSize = sizeof (EFI_HII_IIBT_IMAGE_1BIT_BLOCK) - sizeof (UINT8) +
1119 BITMAP_LEN_1_BIT (
1120 ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_1BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width),
1121 ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_1BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height)
1122 );
1123 break;
1124 case EFI_HII_IIBT_IMAGE_4BIT:
1125 case EFI_HII_IIBT_IMAGE_4BIT_TRANS:
1126 OldBlockSize = sizeof (EFI_HII_IIBT_IMAGE_4BIT_BLOCK) - sizeof (UINT8) +
1127 BITMAP_LEN_4_BIT (
1128 ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_4BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width),
1129 ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_4BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height)
1130 );
1131 break;
1132 case EFI_HII_IIBT_IMAGE_8BIT:
1133 case EFI_HII_IIBT_IMAGE_8BIT_TRANS:
1134 OldBlockSize = sizeof (EFI_HII_IIBT_IMAGE_8BIT_BLOCK) - sizeof (UINT8) +
1135 BITMAP_LEN_8_BIT (
1136 (UINT32) ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_8BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width),
1137 ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_8BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height)
1138 );
1139 break;
1140 case EFI_HII_IIBT_IMAGE_24BIT:
1141 case EFI_HII_IIBT_IMAGE_24BIT_TRANS:
1142 OldBlockSize = sizeof (EFI_HII_IIBT_IMAGE_24BIT_BLOCK) - sizeof (EFI_HII_RGB_PIXEL) +
1143 BITMAP_LEN_24_BIT (
1144 (UINT32) ReadUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width),
1145 ReadUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height)
1146 );
1147 break;
1148 default:
1149 EfiReleaseLock (&mHiiDatabaseLock);
1150 return EFI_NOT_FOUND;
1151 }
1152
1153 //
1154 // Create the new image block according to input image.
1155 //
1156
1157 //
1158 // Make sure the final package length doesn't overflow.
1159 // Length of the package header is represented using 24 bits. So MAX length is MAX_UINT24.
1160 // 24Bit BMP occpuies 3 bytes per pixel.
1161 //
1162 NewBlockSize = (UINT32)Image->Width * Image->Height;
1163 if (NewBlockSize > (MAX_UINT32 - (sizeof (EFI_HII_IIBT_IMAGE_24BIT_BLOCK) - sizeof (EFI_HII_RGB_PIXEL))) / 3) {
1164 return EFI_OUT_OF_RESOURCES;
1165 }
1166 NewBlockSize = NewBlockSize * 3 + (sizeof (EFI_HII_IIBT_IMAGE_24BIT_BLOCK) - sizeof (EFI_HII_RGB_PIXEL));
1167 if ((NewBlockSize > OldBlockSize) &&
1168 (NewBlockSize - OldBlockSize > MAX_UINT24 - ImagePackage->ImagePkgHdr.Header.Length)
1169 ) {
1170 return EFI_OUT_OF_RESOURCES;
1171 }
1172
1173 //
1174 // Adjust the image package to remove the original block firstly then add the new block.
1175 //
1176 ImageBlocks = AllocateZeroPool (ImagePackage->ImageBlockSize + NewBlockSize - OldBlockSize);
1177 if (ImageBlocks == NULL) {
1178 EfiReleaseLock (&mHiiDatabaseLock);
1179 return EFI_OUT_OF_RESOURCES;
1180 }
1181
1182 Part1Size = (UINT32) ((UINTN) CurrentImageBlock - (UINTN) ImagePackage->ImageBlock);
1183 Part2Size = ImagePackage->ImageBlockSize - Part1Size - OldBlockSize;
1184 CopyMem (ImageBlocks, ImagePackage->ImageBlock, Part1Size);
1185
1186 //
1187 // Set the new image block
1188 //
1189 NewImageBlock = (EFI_HII_IMAGE_BLOCK *) ((UINT8 *) ImageBlocks + Part1Size);
1190 if ((Image->Flags & EFI_IMAGE_TRANSPARENT) == EFI_IMAGE_TRANSPARENT) {
1191 NewImageBlock->BlockType= EFI_HII_IIBT_IMAGE_24BIT_TRANS;
1192 } else {
1193 NewImageBlock->BlockType = EFI_HII_IIBT_IMAGE_24BIT;
1194 }
1195 WriteUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) NewImageBlock)->Bitmap.Width, Image->Width);
1196 WriteUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) NewImageBlock)->Bitmap.Height, Image->Height);
1197 CopyGopToRgbPixel (((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) NewImageBlock)->Bitmap.Bitmap,
1198 Image->Bitmap, (UINT32) Image->Width * Image->Height);
1199
1200 CopyMem ((UINT8 *) NewImageBlock + NewBlockSize, (UINT8 *) CurrentImageBlock + OldBlockSize, Part2Size);
1201
1202 FreePool (ImagePackage->ImageBlock);
1203 ImagePackage->ImageBlock = ImageBlocks;
1204 ImagePackage->ImageBlockSize += NewBlockSize - OldBlockSize;
1205 ImagePackage->ImagePkgHdr.Header.Length += NewBlockSize - OldBlockSize;
1206 PackageListNode->PackageListHdr.PackageLength += NewBlockSize - OldBlockSize;
1207
1208 //
1209 // Check whether need to get the contents of HiiDataBase.
1210 // Only after ReadyToBoot to do the export.
1211 //
1212 if (gExportAfterReadyToBoot) {
1213 HiiGetDatabaseInfo(&Private->HiiDatabase);
1214 }
1215
1216 EfiReleaseLock (&mHiiDatabaseLock);
1217 return EFI_SUCCESS;
1218
1219 }
1220
1221
1222 /**
1223 This function renders an image to a bitmap or the screen using the specified
1224 color and options. It draws the image on an existing bitmap, allocates a new
1225 bitmap or uses the screen. The images can be clipped.
1226
1227 @param This A pointer to the EFI_HII_IMAGE_PROTOCOL instance.
1228 @param Flags Describes how the image is to be drawn.
1229 @param Image Points to the image to be displayed.
1230 @param Blt If this points to a non-NULL on entry, this points
1231 to the image, which is Width pixels wide and
1232 Height pixels high. The image will be drawn onto
1233 this image and EFI_HII_DRAW_FLAG_CLIP is implied.
1234 If this points to a NULL on entry, then a buffer
1235 will be allocated to hold the generated image and
1236 the pointer updated on exit. It is the caller's
1237 responsibility to free this buffer.
1238 @param BltX Specifies the offset from the left and top edge of
1239 the output image of the first pixel in the image.
1240 @param BltY Specifies the offset from the left and top edge of
1241 the output image of the first pixel in the image.
1242
1243 @retval EFI_SUCCESS The image was successfully drawn.
1244 @retval EFI_OUT_OF_RESOURCES Unable to allocate an output buffer for Blt.
1245 @retval EFI_INVALID_PARAMETER The Image or Blt was NULL.
1246 @retval EFI_INVALID_PARAMETER Any combination of Flags is invalid.
1247
1248 **/
1249 EFI_STATUS
1250 EFIAPI
1251 HiiDrawImage (
1252 IN CONST EFI_HII_IMAGE_PROTOCOL *This,
1253 IN EFI_HII_DRAW_FLAGS Flags,
1254 IN CONST EFI_IMAGE_INPUT *Image,
1255 IN OUT EFI_IMAGE_OUTPUT **Blt,
1256 IN UINTN BltX,
1257 IN UINTN BltY
1258 )
1259 {
1260 EFI_STATUS Status;
1261 HII_DATABASE_PRIVATE_DATA *Private;
1262 BOOLEAN Transparent;
1263 EFI_IMAGE_OUTPUT *ImageOut;
1264 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
1265 UINTN BufferLen;
1266 UINT16 Width;
1267 UINT16 Height;
1268 UINTN Xpos;
1269 UINTN Ypos;
1270 UINTN OffsetY1;
1271 UINTN OffsetY2;
1272 EFI_FONT_DISPLAY_INFO *FontInfo;
1273 UINTN Index;
1274
1275 if (This == NULL || Image == NULL || Blt == NULL) {
1276 return EFI_INVALID_PARAMETER;
1277 }
1278
1279 if ((Flags & EFI_HII_DRAW_FLAG_CLIP) == EFI_HII_DRAW_FLAG_CLIP && *Blt == NULL) {
1280 return EFI_INVALID_PARAMETER;
1281 }
1282
1283 if ((Flags & EFI_HII_DRAW_FLAG_TRANSPARENT) == EFI_HII_DRAW_FLAG_TRANSPARENT) {
1284 return EFI_INVALID_PARAMETER;
1285 }
1286
1287 FontInfo = NULL;
1288
1289 //
1290 // Check whether the image will be drawn transparently or opaquely.
1291 //
1292 Transparent = FALSE;
1293 if ((Flags & EFI_HII_DRAW_FLAG_TRANSPARENT) == EFI_HII_DRAW_FLAG_FORCE_TRANS) {
1294 Transparent = TRUE;
1295 } else if ((Flags & EFI_HII_DRAW_FLAG_TRANSPARENT) == EFI_HII_DRAW_FLAG_FORCE_OPAQUE){
1296 Transparent = FALSE;
1297 } else {
1298 //
1299 // Now EFI_HII_DRAW_FLAG_DEFAULT is set, whether image will be drawn depending
1300 // on the image's transparency setting.
1301 //
1302 if ((Image->Flags & EFI_IMAGE_TRANSPARENT) == EFI_IMAGE_TRANSPARENT) {
1303 Transparent = TRUE;
1304 }
1305 }
1306
1307 //
1308 // Image cannot be drawn transparently if Blt points to NULL on entry.
1309 // Currently output to Screen transparently is not supported, either.
1310 //
1311 if (Transparent) {
1312 if (*Blt == NULL) {
1313 return EFI_INVALID_PARAMETER;
1314 } else if ((Flags & EFI_HII_DIRECT_TO_SCREEN) == EFI_HII_DIRECT_TO_SCREEN) {
1315 return EFI_INVALID_PARAMETER;
1316 }
1317 }
1318
1319 Private = HII_IMAGE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
1320
1321 //
1322 // When Blt points to a non-NULL on entry, this image will be drawn onto
1323 // this bitmap or screen pointed by "*Blt" and EFI_HII_DRAW_FLAG_CLIP is implied.
1324 // Otherwise a new bitmap will be allocated to hold this image.
1325 //
1326 if (*Blt != NULL) {
1327 //
1328 // Make sure the BltX and BltY is inside the Blt area.
1329 //
1330 if ((BltX >= (*Blt)->Width) || (BltY >= (*Blt)->Height)) {
1331 return EFI_INVALID_PARAMETER;
1332 }
1333
1334 //
1335 // Clip the image by (Width, Height)
1336 //
1337
1338 Width = Image->Width;
1339 Height = Image->Height;
1340
1341 if (Width > (*Blt)->Width - (UINT16)BltX) {
1342 Width = (*Blt)->Width - (UINT16)BltX;
1343 }
1344 if (Height > (*Blt)->Height - (UINT16)BltY) {
1345 Height = (*Blt)->Height - (UINT16)BltY;
1346 }
1347
1348 //
1349 // Prepare the buffer for the temporary image.
1350 // Make sure the buffer size doesn't overflow UINTN.
1351 //
1352 BufferLen = Width * Height;
1353 if (BufferLen > MAX_UINTN / sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)) {
1354 return EFI_OUT_OF_RESOURCES;
1355 }
1356 BufferLen *= sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
1357 BltBuffer = AllocateZeroPool (BufferLen);
1358 if (BltBuffer == NULL) {
1359 return EFI_OUT_OF_RESOURCES;
1360 }
1361
1362 if (Width == Image->Width && Height == Image->Height) {
1363 CopyMem (BltBuffer, Image->Bitmap, BufferLen);
1364 } else {
1365 for (Ypos = 0; Ypos < Height; Ypos++) {
1366 OffsetY1 = Image->Width * Ypos;
1367 OffsetY2 = Width * Ypos;
1368 for (Xpos = 0; Xpos < Width; Xpos++) {
1369 BltBuffer[OffsetY2 + Xpos] = Image->Bitmap[OffsetY1 + Xpos];
1370 }
1371 }
1372 }
1373
1374 //
1375 // Draw the image to existing bitmap or screen depending on flag.
1376 //
1377 if ((Flags & EFI_HII_DIRECT_TO_SCREEN) == EFI_HII_DIRECT_TO_SCREEN) {
1378 //
1379 // Caller should make sure the current UGA console is grarphic mode.
1380 //
1381
1382 //
1383 // Write the image directly to the output device specified by Screen.
1384 //
1385 Status = (*Blt)->Image.Screen->Blt (
1386 (*Blt)->Image.Screen,
1387 BltBuffer,
1388 EfiBltBufferToVideo,
1389 0,
1390 0,
1391 BltX,
1392 BltY,
1393 Width,
1394 Height,
1395 0
1396 );
1397 } else {
1398 //
1399 // Draw the image onto the existing bitmap specified by Bitmap.
1400 //
1401 Status = ImageToBlt (
1402 BltBuffer,
1403 BltX,
1404 BltY,
1405 Width,
1406 Height,
1407 Transparent,
1408 Blt
1409 );
1410
1411 }
1412
1413 FreePool (BltBuffer);
1414 return Status;
1415
1416 } else {
1417 //
1418 // Allocate a new bitmap to hold the incoming image.
1419 //
1420
1421 //
1422 // Make sure the final width and height doesn't overflow UINT16.
1423 //
1424 if ((BltX > (UINTN)MAX_UINT16 - Image->Width) || (BltY > (UINTN)MAX_UINT16 - Image->Height)) {
1425 return EFI_INVALID_PARAMETER;
1426 }
1427
1428 Width = Image->Width + (UINT16)BltX;
1429 Height = Image->Height + (UINT16)BltY;
1430
1431 //
1432 // Make sure the output image size doesn't overflow UINTN.
1433 //
1434 BufferLen = Width * Height;
1435 if (BufferLen > MAX_UINTN / sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)) {
1436 return EFI_OUT_OF_RESOURCES;
1437 }
1438 BufferLen *= sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
1439 BltBuffer = AllocateZeroPool (BufferLen);
1440 if (BltBuffer == NULL) {
1441 return EFI_OUT_OF_RESOURCES;
1442 }
1443
1444 ImageOut = (EFI_IMAGE_OUTPUT *) AllocateZeroPool (sizeof (EFI_IMAGE_OUTPUT));
1445 if (ImageOut == NULL) {
1446 FreePool (BltBuffer);
1447 return EFI_OUT_OF_RESOURCES;
1448 }
1449 ImageOut->Width = Width;
1450 ImageOut->Height = Height;
1451 ImageOut->Image.Bitmap = BltBuffer;
1452
1453 //
1454 // BUGBUG: Now all the "blank" pixels are filled with system default background
1455 // color. Not sure if it need to be updated or not.
1456 //
1457 Status = GetSystemFont (Private, &FontInfo, NULL);
1458 if (EFI_ERROR (Status)) {
1459 FreePool (BltBuffer);
1460 FreePool (ImageOut);
1461 return Status;
1462 }
1463 ASSERT (FontInfo != NULL);
1464 for (Index = 0; Index < (UINTN)Width * Height; Index++) {
1465 BltBuffer[Index] = FontInfo->BackgroundColor;
1466 }
1467 FreePool (FontInfo);
1468
1469 //
1470 // Draw the incoming image to the new created image.
1471 //
1472 *Blt = ImageOut;
1473 return ImageToBlt (
1474 Image->Bitmap,
1475 BltX,
1476 BltY,
1477 Image->Width,
1478 Image->Height,
1479 Transparent,
1480 Blt
1481 );
1482
1483 }
1484 }
1485
1486
1487 /**
1488 This function renders an image to a bitmap or the screen using the specified
1489 color and options. It draws the image on an existing bitmap, allocates a new
1490 bitmap or uses the screen. The images can be clipped.
1491
1492 @param This A pointer to the EFI_HII_IMAGE_PROTOCOL instance.
1493 @param Flags Describes how the image is to be drawn.
1494 @param PackageList The package list in the HII database to search for
1495 the specified image.
1496 @param ImageId The image's id, which is unique within
1497 PackageList.
1498 @param Blt If this points to a non-NULL on entry, this points
1499 to the image, which is Width pixels wide and
1500 Height pixels high. The image will be drawn onto
1501 this image and
1502 EFI_HII_DRAW_FLAG_CLIP is implied. If this points
1503 to a NULL on entry, then a buffer will be
1504 allocated to hold the generated image and the
1505 pointer updated on exit. It is the caller's
1506 responsibility to free this buffer.
1507 @param BltX Specifies the offset from the left and top edge of
1508 the output image of the first pixel in the image.
1509 @param BltY Specifies the offset from the left and top edge of
1510 the output image of the first pixel in the image.
1511
1512 @retval EFI_SUCCESS The image was successfully drawn.
1513 @retval EFI_OUT_OF_RESOURCES Unable to allocate an output buffer for Blt.
1514 @retval EFI_INVALID_PARAMETER The Blt was NULL.
1515 @retval EFI_NOT_FOUND The image specified by ImageId is not in the database.
1516 The specified PackageList is not in the database.
1517
1518 **/
1519 EFI_STATUS
1520 EFIAPI
1521 HiiDrawImageId (
1522 IN CONST EFI_HII_IMAGE_PROTOCOL *This,
1523 IN EFI_HII_DRAW_FLAGS Flags,
1524 IN EFI_HII_HANDLE PackageList,
1525 IN EFI_IMAGE_ID ImageId,
1526 IN OUT EFI_IMAGE_OUTPUT **Blt,
1527 IN UINTN BltX,
1528 IN UINTN BltY
1529 )
1530 {
1531 EFI_STATUS Status;
1532 EFI_IMAGE_INPUT Image;
1533
1534 //
1535 // Check input parameter.
1536 //
1537 if (This == NULL || Blt == NULL) {
1538 return EFI_INVALID_PARAMETER;
1539 }
1540
1541 //
1542 // Get the specified Image.
1543 //
1544 Status = HiiGetImage (This, PackageList, ImageId, &Image);
1545 if (EFI_ERROR (Status)) {
1546 return Status;
1547 }
1548
1549 //
1550 // Draw this image.
1551 //
1552 Status = HiiDrawImage (This, Flags, &Image, Blt, BltX, BltY);
1553 if (Image.Bitmap != NULL) {
1554 FreePool (Image.Bitmap);
1555 }
1556 return Status;
1557 }
1558