blob: db81b4cdd768d9c7a0af86e4aa0bdb5c06729c76 [file] [log] [blame]
lijuangc9d156e2016-07-27 18:31:00 +08001/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the distribution.
12 * * Neither the name of The Linux Foundation, Inc. nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <Uefi.h>
30#include <Library/BaseLib.h>
31#include <Library/UefiBootServicesTableLib.h>
32#include <Library/BaseMemoryLib.h>
33#include <Library/DebugLib.h>
34#include <Library/MemoryAllocationLib.h>
35#include <Library/UefiHiiServicesLib.h>
36#include <Library/Fonts.h>
37#include <Library/DrawUI.h>
38#include <Library/UpdateDeviceTree.h>
39#include <Protocol/GraphicsOutput.h>
40
41CONST EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutputProtocol = NULL;
42
43STATIC CHAR16 *mFactorName[] = {
44 [2] = SYSFONT_2x,
45 [3] = SYSFONT_3x,
46 [4] = SYSFONT_4x,
47 [5] = SYSFONT_5x,
48 [6] = SYSFONT_6x,
49 [7] = SYSFONT_7x,
50 [8] = SYSFONT_8x,
51};
52
53STATIC EFI_GRAPHICS_OUTPUT_BLT_PIXEL mColors[] = {
54 [BGR_WHITE] = {0xff, 0xff, 0xff, 0x00},
55 [BGR_BLACK] = {0x00, 0x00, 0x00, 0x00},
56 [BGR_ORANGE] = {0x00, 0xa5, 0xff, 0x00},
57 [BGR_YELLOW] = {0x00, 0xff, 0xff, 0x00},
58 [BGR_RED] = {0x00, 0x00, 0x98, 0x00},
59 [BGR_GREEN] = {0x00, 0xff, 0x00, 0x00},
60 [BGR_BLUE] = {0xff, 0x00, 0x00, 0x00},
61 [BGR_CYAN] = {0xff, 0xff, 0x00, 0x00},
62 [BGR_SILVER] = {0xc0, 0xc0, 0xc0, 0x00},
63};
64
65STATIC UINT32 GetResolutionWidth()
66{
67 STATIC UINT32 Width;
68 EFI_HANDLE ConsoleHandle = (EFI_HANDLE)NULL;
69
70 /* Get the width from the protocal at the first time */
71 if (Width)
72 return Width;
73
74 if (GraphicsOutputProtocol == NULL) {
75 ConsoleHandle = gST->ConsoleOutHandle;
lijuang4734bc82016-08-16 16:13:19 +080076 if (ConsoleHandle == NULL) {
77 DEBUG((EFI_D_ERROR, "Failed to get the handle for the active console input device.\n"));
78 return 0;
79 }
lijuangc9d156e2016-07-27 18:31:00 +080080
81 gBS->HandleProtocol (
82 ConsoleHandle,
83 &gEfiGraphicsOutputProtocolGuid,
84 (VOID **) &GraphicsOutputProtocol
85 );
lijuang4734bc82016-08-16 16:13:19 +080086 if (GraphicsOutputProtocol == NULL) {
87 DEBUG((EFI_D_ERROR, "Failed to get the graphics output protocol.\n"));
88 return 0;
89 }
lijuangc9d156e2016-07-27 18:31:00 +080090 }
91 Width = GraphicsOutputProtocol->Mode->Info->HorizontalResolution;
lijuang4734bc82016-08-16 16:13:19 +080092 if (!Width)
93 DEBUG((EFI_D_ERROR, "Failed to get the width of the screen.\n"));
lijuangc9d156e2016-07-27 18:31:00 +080094
95 return Width;
96}
97
98STATIC UINT32 GetResolutionHeight()
99{
100 STATIC UINT32 Height;
101 EFI_HANDLE ConsoleHandle = (EFI_HANDLE)NULL;
102
103 /* Get the height from the protocal at the first time */
104 if (Height)
105 return Height;
106
107 if (GraphicsOutputProtocol == NULL) {
108 ConsoleHandle = gST->ConsoleOutHandle;
lijuang4734bc82016-08-16 16:13:19 +0800109 if (ConsoleHandle == NULL) {
110 DEBUG((EFI_D_ERROR, "Failed to get the handle for the active console input device.\n"));
111 return 0;
112 }
lijuangc9d156e2016-07-27 18:31:00 +0800113
114 gBS->HandleProtocol (
115 ConsoleHandle,
116 &gEfiGraphicsOutputProtocolGuid,
117 (VOID **) &GraphicsOutputProtocol
118 );
lijuang4734bc82016-08-16 16:13:19 +0800119 if (GraphicsOutputProtocol == NULL) {
120 DEBUG((EFI_D_ERROR, "Failed to get the graphics output protocol.\n"));
121 return 0;
122 }
lijuangc9d156e2016-07-27 18:31:00 +0800123 }
124 Height = GraphicsOutputProtocol->Mode->Info->VerticalResolution;
lijuang4734bc82016-08-16 16:13:19 +0800125 if (!Height)
126 DEBUG((EFI_D_ERROR, "Failed to get the height of the screen.\n"));
lijuangc9d156e2016-07-27 18:31:00 +0800127
128 return Height;
129}
130
131/* Get Max font count per row */
132STATIC UINT32 GetMaxFontCount()
133{
134 EFI_STATUS Status;
135 UINT32 FontBaseWidth = EFI_GLYPH_WIDTH;
136 UINT32 max_count = 0;
137 EFI_IMAGE_OUTPUT *Blt = NULL;
138
139 Status = gHiiFont->GetGlyph(gHiiFont, "a", NULL, &Blt, NULL);
140 if (!EFI_ERROR (Status) && (Status != EFI_WARN_UNKNOWN_GLYPH)) {
141 if (Blt)
142 FontBaseWidth = Blt->Width;
143 }
144 max_count = GetResolutionWidth()/FontBaseWidth;
145 return max_count;
146}
147
148/**
149 Get Font's scale factor
150 @param[in] ScaleFactorType The type of the scale factor.
151 @retval ScaleFactor Get the suitable scale factor base on the
152 scale factor's type.
153 **/
154STATIC UINT32 GetFontScaleFactor(UINT32 ScaleFactorType)
155{
156 UINT32 scalefactor = GetMaxFontCount()/CHAR_NUM_PERROW;
157
158 if (scalefactor < 2)
159 scalefactor = 2;
160 else if (scalefactor > ((ARRAY_SIZE(mFactorName) - 1)/MAX_FACTORTYPE))
161 scalefactor = (ARRAY_SIZE(mFactorName) - 1)/MAX_FACTORTYPE;
162
163 return scalefactor*ScaleFactorType;
164}
165
166/* Get factor name base on the scale factor type */
167STATIC CHAR16 *GetFontFactorName(UINT32 ScaleFactorType)
168{
169 UINT32 ScaleFactor = GetFontScaleFactor(ScaleFactorType);
170
171 if (ScaleFactor <= (ARRAY_SIZE(mFactorName) -1)) {
172 return mFactorName[ScaleFactor];
173 } else {
174 return SYSFONT_3x;
175 }
176}
177
178STATIC VOID SetBltBuffer(EFI_IMAGE_OUTPUT *BltBuffer)
179{
180 BltBuffer->Width = (UINT16) GetResolutionWidth();
181 BltBuffer->Height = (UINT16) GetResolutionHeight();
182 BltBuffer->Image.Screen = GraphicsOutputProtocol;
183}
184
185STATIC VOID SetDisplayInfo(MENU_MSG_INFO *TargetMenu,
186 EFI_FONT_DISPLAY_INFO *FontDisplayInfo)
187{
188 /* Foreground */
189 FontDisplayInfo->ForegroundColor.Blue = mColors[TargetMenu->FgColor].Blue;
190 FontDisplayInfo->ForegroundColor.Green = mColors[TargetMenu->FgColor].Green;
191 FontDisplayInfo->ForegroundColor.Red = mColors[TargetMenu->FgColor].Red;
192 /* Background */
193 FontDisplayInfo->BackgroundColor.Blue = mColors[TargetMenu->BgColor].Blue;
194 FontDisplayInfo->BackgroundColor.Green = mColors[TargetMenu->BgColor].Green;
195 FontDisplayInfo->BackgroundColor.Red = mColors[TargetMenu->BgColor].Red;
196
197 /* Set font name */
198 FontDisplayInfo->FontInfoMask = EFI_FONT_INFO_ANY_SIZE | EFI_FONT_INFO_ANY_STYLE;
199 CopyMem(&FontDisplayInfo->FontInfo.FontName, GetFontFactorName(TargetMenu->ScaleFactorType),
200 StrSize(GetFontFactorName(TargetMenu->ScaleFactorType)));
201}
202
203STATIC VOID StrAlignRight(CHAR8* Msg, CHAR8* FilledChar, UINT32 ScaleFactorType) {
204 UINT32 i = 0;
205 UINT32 diff = 0;
206 CHAR8 StrSourceTemp[MAX_MSG_SIZE];
207 UINT32 Max_x = GetMaxFontCount();
208 UINT32 factor = GetFontScaleFactor(ScaleFactorType);
209
210 SetMem(StrSourceTemp, sizeof(StrSourceTemp), 0);
211 if (Max_x/factor > AsciiStrLen(Msg)) {
212 diff = Max_x/factor - AsciiStrLen(Msg);
213 for (i = 0; i < diff; i++) {
214 AsciiStrnCat(StrSourceTemp, FilledChar, Max_x/factor);
215 }
216 AsciiStrnCat(StrSourceTemp, Msg, Max_x/factor);
217 CopyMem(Msg, StrSourceTemp, AsciiStrSize(StrSourceTemp));
218 }
219}
220
221STATIC VOID StrAlignLeft(CHAR8* Msg, CHAR8* FilledChar, UINT32 ScaleFactorType) {
222 UINT32 i = 0;
223 UINT32 diff = 0;
224 CHAR8 StrSourceTemp[MAX_MSG_SIZE];
225 UINT32 Max_x = GetMaxFontCount();
226 UINT32 factor = GetFontScaleFactor(ScaleFactorType);
227
228 SetMem(StrSourceTemp, sizeof(StrSourceTemp), 0);
229 if (Max_x/factor > AsciiStrLen(Msg)) {
230 diff = Max_x/factor - AsciiStrLen(Msg);
231 for (i = 0; i < diff; i++) {
232 AsciiStrnCat(StrSourceTemp, FilledChar, Max_x/factor);
233 }
234 AsciiStrnCat(Msg, StrSourceTemp, Max_x/factor);
235 }
236}
237
238/* Message string manipulation base on the attribute of the message
239 * LINEATION: Fill a string with "_", for drawing a line
240 * ALIGN_RIGHT: String align right and fill this string with " "
241 * ALIGN_LEFT: String align left and fill this string with " "
242 * OPTION_ITEM: String align left and fill this string with " ",
243 * for updating the whole line's background
244 */
245STATIC VOID ManipulateMenuMsg(MENU_MSG_INFO *TargetMenu) {
246 switch (TargetMenu->Attribute) {
247 case LINEATION:
248 StrAlignLeft(TargetMenu->Msg, "_", TargetMenu->ScaleFactorType);
249 break;
250 case ALIGN_RIGHT:
251 StrAlignRight(TargetMenu->Msg, " ", TargetMenu->ScaleFactorType);
252 break;
253 case ALIGN_LEFT:
254 case OPTION_ITEM:
255 StrAlignLeft(TargetMenu->Msg, " ", TargetMenu->ScaleFactorType);
256 break;
257 }
258}
259
260/**
261 Draw menu on the screen
262 @param[in] TargetMenu The message info.
263 @param[in, out] pHeight The Pointer for increased height.
264 @retval EFI_SUCCESS The entry point is executed successfully.
265 @retval other Some error occurs when executing this entry point.
266**/
267EFI_STATUS DrawMenu(MENU_MSG_INFO *TargetMenu, UINT32 *pHeight)
268{
269 EFI_STATUS Status = EFI_SUCCESS;
270 EFI_FONT_DISPLAY_INFO *FontDisplayInfo = NULL;
271 EFI_IMAGE_OUTPUT *BltBuffer = NULL;
272 EFI_HII_ROW_INFO *RowInfoArray = NULL;
273 UINTN RowInfoArraySize;
274 CHAR16 FontMessage[MAX_MSG_SIZE];
lijuang31edca62016-09-01 16:36:41 +0800275 UINT32 Height = GetResolutionHeight();
276 UINT32 Width = GetResolutionWidth();
lijuangc9d156e2016-07-27 18:31:00 +0800277
lijuang31edca62016-09-01 16:36:41 +0800278 if (!Height || !Width) {
lijuang4734bc82016-08-16 16:13:19 +0800279 Status = EFI_OUT_OF_RESOURCES;
280 goto Exit;
281 }
282
lijuang31edca62016-09-01 16:36:41 +0800283 if (TargetMenu->Location >= Height) {
284 DEBUG((EFI_D_ERROR, "The Y-axis of the message is larger than the Y-max of the screen\n"));
285 Status = EFI_ABORTED;
286 goto Exit;
287 }
288
lijuangc9d156e2016-07-27 18:31:00 +0800289 BltBuffer = AllocateZeroPool (sizeof (EFI_IMAGE_OUTPUT));
290 if (BltBuffer == NULL) {
291 DEBUG((EFI_D_ERROR, "Failed to allocate zero pool for BltBuffer.\n"));
292 Status = EFI_OUT_OF_RESOURCES;
293 goto Exit;
294 }
295 SetBltBuffer(BltBuffer);
296
297 FontDisplayInfo = AllocateZeroPool(sizeof (EFI_FONT_DISPLAY_INFO) + 100);
298 if (FontDisplayInfo == NULL) {
299 DEBUG((EFI_D_ERROR, "Failed to allocate zero pool for FontDisplayInfo.\n"));
300 Status = EFI_OUT_OF_RESOURCES;
301 goto Exit;
302 }
303 SetDisplayInfo(TargetMenu, FontDisplayInfo);
304
305 ManipulateMenuMsg(TargetMenu);
306 AsciiStrToUnicodeStr(TargetMenu->Msg, FontMessage);
307 if (FontMessage == NULL) {
308 DEBUG((EFI_D_ERROR, "Failed to get font message.\n"));
309 Status = EFI_OUT_OF_RESOURCES;
310 goto Exit;
311 }
312
313 Status = gHiiFont->StringToImage(
314 gHiiFont,
315 /* Set to 0 for Bitmap mode */
316 EFI_HII_DIRECT_TO_SCREEN | EFI_HII_OUT_FLAG_WRAP,
317 FontMessage,
318 FontDisplayInfo,
319 &BltBuffer,
320 0, /* BltX */
321 TargetMenu->Location, /* BltY */
322 &RowInfoArray,
323 &RowInfoArraySize,
324 NULL
325 );
lijuang4734bc82016-08-16 16:13:19 +0800326 if (Status != EFI_SUCCESS) {
327 DEBUG((EFI_D_ERROR, "Failed to render a string to the display: %r\n", Status));
328 goto Exit;
329 }
lijuangc9d156e2016-07-27 18:31:00 +0800330
lijuang31edca62016-09-01 16:36:41 +0800331 if (pHeight && RowInfoArraySize && RowInfoArray) {
lijuangc9d156e2016-07-27 18:31:00 +0800332 *pHeight = RowInfoArraySize * RowInfoArray[0].LineHeight;
333 }
334
335 /* For Bitmap mode, use EfiBltBufferToVideo, and set DestX,DestY as needed */
336 GraphicsOutputProtocol->Blt(
337 GraphicsOutputProtocol,
338 BltBuffer->Image.Bitmap,
339 EfiBltVideoToVideo,
340 0, /* SrcX */
341 0, /* SrcY */
342 0, /* DestX */
343 0, /* DestY */
344 BltBuffer->Width,
345 BltBuffer->Height,
346 BltBuffer->Width * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
347 );
348
lijuang31edca62016-09-01 16:36:41 +0800349Exit:
350 if (RowInfoArray) {
351 FreePool(RowInfoArray);
352 BltBuffer = NULL;
353 }
lijuangc9d156e2016-07-27 18:31:00 +0800354
lijuang31edca62016-09-01 16:36:41 +0800355 if (BltBuffer) {
356 FreePool(BltBuffer);
357 BltBuffer = NULL;
358 }
359
360 if (FontDisplayInfo) {
361 FreePool(FontDisplayInfo);
362 FontDisplayInfo = NULL;
363 }
364 return Status;
lijuangc9d156e2016-07-27 18:31:00 +0800365}
366
367/**
368 Set the message info
369 @param[in] Msg Message.
370 @param[in] ScaleFactorType The scale factor type of the message.
371 @param[in] FgColor The foreground color of the message.
372 @param[in] BgColor The background color of the message.
373 @param[in] Attribute The attribute of the message.
374 @param[in] Location The location of the message.
375 @param[in] Action The action of the message.
376 @param[out] MenuMsgInfo The message info.
377**/
378VOID SetMenuMsgInfo(MENU_MSG_INFO *MenuMsgInfo, CHAR8* Msg, UINT32 ScaleFactorType,
379 UINT32 FgColor, UINT32 BgColor, UINT32 Attribute, UINT32 Location, UINT32 Action)
380{
381 CopyMem(&MenuMsgInfo->Msg, Msg, AsciiStrSize(Msg));
382 MenuMsgInfo->ScaleFactorType = ScaleFactorType;
383 MenuMsgInfo->FgColor = FgColor;
384 MenuMsgInfo->BgColor = BgColor;
385 MenuMsgInfo->Attribute = Attribute;
386 MenuMsgInfo->Location = Location;
387 MenuMsgInfo->Action = Action;
388}
389
390/**
391 Update the background color of the message
392 @param[in] MenuMsgInfo The message info.
393 @param[in] NewBgColor The new background color of the message.
394 @retval EFI_SUCCESS The entry point is executed successfully.
395 @retval other Some error occurs when executing this entry point.
396**/
397EFI_STATUS UpdateMsgBackground(MENU_MSG_INFO *MenuMsgInfo, UINT32 NewBgColor)
398{
399 MENU_MSG_INFO *target_msg_info = NULL;
400
401 target_msg_info = AllocateZeroPool(sizeof(MENU_MSG_INFO));
402 if (target_msg_info == NULL) {
403 DEBUG((EFI_D_ERROR, "Failed to allocate zero pool for message info.\n"));
404 return EFI_OUT_OF_RESOURCES;
405 }
406
407 SetMenuMsgInfo(target_msg_info, MenuMsgInfo->Msg,
408 MenuMsgInfo->ScaleFactorType,
409 MenuMsgInfo->FgColor,
410 NewBgColor,
411 MenuMsgInfo->Attribute,
412 MenuMsgInfo->Location,
413 MenuMsgInfo->Action);
414 DrawMenu(target_msg_info, 0);
415
416 if (target_msg_info) {
417 FreePool(target_msg_info);
418 target_msg_info = NULL;
419 }
420 return EFI_SUCCESS;
421}