/** @file\r
This module provide help function for displaying unicode string.\r
\r
- Copyright (c) 2006, Intel Corporation<BR>\r
- All rights reserved. This program and the accompanying materials \r
- are licensed and made available under the terms and conditions of the BSD License \r
- which accompanies this distribution. The full text of the license may be found at \r
- http://opensource.org/licenses/bsd-license.php \r
-\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
\r
\r
-//\r
-// Include common header file for this module.\r
-//\r
+\r
#include "UefiLibInternal.h"\r
\r
typedef struct {\r
UINT32 Width;\r
} UNICODE_WIDTH_ENTRY;\r
\r
+#define NARROW_CHAR 0xFFF0\r
+#define WIDE_CHAR 0xFFF1\r
+\r
GLOBAL_REMOVE_IF_UNREFERENCED CONST UNICODE_WIDTH_ENTRY mUnicodeWidthTable[] = {\r
//\r
// General script area\r
//\r
{(CHAR16)0x1FFF, 1},\r
/*\r
- * Merge the blocks and replace them with the above entry as they fall to \r
+ * Merge the blocks and replace them with the above entry as they fall to\r
* the same category and they are all narrow glyph. This will reduce search\r
* time and table size. The merge will omit the reserved code.\r
*\r
//\r
{(CHAR16)0x2FFF, 1},\r
/*\r
- * Merge the blocks and replace them with the above entry as they fall to \r
+ * Merge the blocks and replace them with the above entry as they fall to\r
* the same category and they are all narrow glyph. This will reduce search\r
* time and table size. The merge will omit the reserved code.\r
*\r
//\r
{(CHAR16)0x33FF, 2},\r
/*\r
- * Merge the blocks and replace them with the above entry as they fall to \r
+ * Merge the blocks and replace them with the above entry as they fall to\r
* the same category and they are all wide glyph. This will reduce search\r
* time and table size. The merge will omit the reserved code.\r
*\r
//\r
{(CHAR16)0x9FFF, 2},\r
/*\r
- * Merge the blocks and replace them with the above entry as they fall to \r
+ * Merge the blocks and replace them with the above entry as they fall to\r
* the same category and they are all wide glyph. This will reduce search\r
* time and table size. The merge will omit the reserved code.\r
*\r
* Remove the above item if below is un-commented.\r
*\r
- {(CHAR16)0x4DFF, 0}, // Reserved. 0x3400-0x4DBF as CJK unified ideographs \r
+ {(CHAR16)0x4DFF, 0}, // Reserved. 0x3400-0x4DBF as CJK unified ideographs\r
// extension A in ver3.0. 0x3400-0x4DFF\r
{(CHAR16)0x9FFF, 2}, // CJK unified ideographs. 0x4E00-0x9FFF\r
*\r
//\r
{(CHAR16)0xD7FF, 2},\r
/*\r
- * Merge the blocks and replace them with the above entry as they fall to \r
+ * Merge the blocks and replace them with the above entry as they fall to\r
* the same category and they are all wide glyph. This will reduce search\r
* time and table size. The merge will omit the reserved code.\r
*\r
};\r
\r
/**\r
- This function computes and returns the width of the Unicode character \r
- specified by UnicodeChar.\r
+ Retrieves the width of a Unicode character.\r
+\r
+ This function computes and returns the width of the Unicode character specified\r
+ by UnicodeChar.\r
\r
@param UnicodeChar A Unicode character.\r
\r
}\r
\r
/**\r
- This function computes and returns the display length of\r
- the Null-terminated Unicode string specified by String.\r
- If String is NULL, then 0 is returned.\r
- If any of the widths of the Unicode characters in String\r
- can not be determined, then 0 is returned.\r
+ Computes the display length of a Null-terminated Unicode String.\r
+\r
+ This function computes and returns the display length of the Null-terminated\r
+ Unicode string specified by String. If String is NULL then 0 is returned. If\r
+ any of the widths of the Unicode characters in String can not be determined,\r
+ then 0 is returned. The display width of String can be computed by summing the\r
+ display widths of each Unicode character in String. Unicode characters that\r
+ are narrow glyphs have a width of 1, and Unicode characters that are width glyphs\r
+ have a width of 2. If String is not aligned on a 16-bit boundary, then ASSERT().\r
\r
@param String A pointer to a Null-terminated Unicode string.\r
\r
@return The display length of the Null-terminated Unicode string specified by String.\r
- \r
+\r
**/\r
UINTN\r
EFIAPI\r
\r
return Length;\r
}\r
+\r
+/**\r
+ Count the storage space of a Unicode string.\r
+\r
+ This function handles the Unicode string with NARROW_CHAR\r
+ and WIDE_CHAR control characters. NARROW_HCAR and WIDE_CHAR\r
+ does not count in the resultant output. If a WIDE_CHAR is\r
+ hit, then 2 Unicode character will consume an output storage\r
+ space with size of CHAR16 till a NARROW_CHAR is hit.\r
+\r
+ @param String The input string to be counted.\r
+ @param LimitLen Whether need to limit the string length.\r
+ @param MaxWidth The max length this function supported.\r
+ @param Offset The max index of the string can be show out.\r
+\r
+ @return Storage space for the input string.\r
+\r
+**/\r
+UINTN\r
+UefiLibGetStringWidth (\r
+ IN CHAR16 *String,\r
+ IN BOOLEAN LimitLen,\r
+ IN UINTN MaxWidth,\r
+ OUT UINTN *Offset\r
+ )\r
+{\r
+ UINTN Index;\r
+ UINTN Count;\r
+ UINTN IncrementValue;\r
+\r
+ if (String == NULL) {\r
+ return 0;\r
+ }\r
+\r
+ Index = 0;\r
+ Count = 0;\r
+ IncrementValue = 1;\r
+\r
+ do {\r
+ //\r
+ // Advance to the null-terminator or to the first width directive\r
+ //\r
+ for (;(String[Index] != NARROW_CHAR) && (String[Index] != WIDE_CHAR) && (String[Index] != 0); Index++) {\r
+ Count = Count + IncrementValue;\r
+\r
+ if (LimitLen && Count > MaxWidth) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ //\r
+ // We hit the null-terminator, we now have a count\r
+ //\r
+ if (String[Index] == 0) {\r
+ break;\r
+ }\r
+\r
+ if (LimitLen && Count > MaxWidth) {\r
+ *Offset = Index;\r
+ break;\r
+ }\r
+\r
+ //\r
+ // We encountered a narrow directive - strip it from the size calculation since it doesn't get printed\r
+ // and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2)\r
+ //\r
+ if (String[Index] == NARROW_CHAR) {\r
+ //\r
+ // Skip to the next character\r
+ //\r
+ Index++;\r
+ IncrementValue = 1;\r
+ } else {\r
+ //\r
+ // Skip to the next character\r
+ //\r
+ Index++;\r
+ IncrementValue = 2;\r
+ }\r
+ } while (String[Index] != 0);\r
+\r
+ return Count * sizeof (CHAR16);\r
+}\r
+\r
+/**\r
+ Draws a dialog box to the console output device specified by\r
+ ConOut defined in the EFI_SYSTEM_TABLE and waits for a keystroke\r
+ from the console input device specified by ConIn defined in the\r
+ EFI_SYSTEM_TABLE.\r
+\r
+ If there are no strings in the variable argument list, then ASSERT().\r
+ If all the strings in the variable argument list are empty, then ASSERT().\r
+\r
+ @param[in] Attribute Specifies the foreground and background color of the popup.\r
+ @param[out] Key A pointer to the EFI_KEY value of the key that was\r
+ pressed. This is an optional parameter that may be NULL.\r
+ If it is NULL then no wait for a keypress will be performed.\r
+ @param[in] ... The variable argument list that contains pointers to Null-\r
+ terminated Unicode strings to display in the dialog box.\r
+ The variable argument list is terminated by a NULL.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+CreatePopUp (\r
+ IN UINTN Attribute,\r
+ OUT EFI_INPUT_KEY *Key, OPTIONAL\r
+ ...\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ VA_LIST Args;\r
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;\r
+ EFI_SIMPLE_TEXT_OUTPUT_MODE SavedConsoleMode;\r
+ UINTN Columns;\r
+ UINTN Rows;\r
+ UINTN Column;\r
+ UINTN Row;\r
+ UINTN NumberOfLines;\r
+ UINTN MaxLength;\r
+ CHAR16 *String;\r
+ UINTN Length;\r
+ CHAR16 *Line;\r
+ UINTN EventIndex;\r
+ CHAR16 *TmpString;\r
+\r
+ //\r
+ // Determine the length of the longest line in the popup and the the total\r
+ // number of lines in the popup\r
+ //\r
+ VA_START (Args, Key);\r
+ MaxLength = 0;\r
+ NumberOfLines = 0;\r
+ while ((String = VA_ARG (Args, CHAR16 *)) != NULL) {\r
+ MaxLength = MAX (MaxLength, UefiLibGetStringWidth (String, FALSE, 0, NULL) / 2);\r
+ NumberOfLines++;\r
+ }\r
+ VA_END (Args);\r
+\r
+ //\r
+ // If the total number of lines in the popup is zero, then ASSERT()\r
+ //\r
+ ASSERT (NumberOfLines != 0);\r
+\r
+ //\r
+ // If the maximum length of all the strings is zero, then ASSERT()\r
+ //\r
+ ASSERT (MaxLength != 0);\r
+\r
+ //\r
+ // Cache a pointer to the Simple Text Output Protocol in the EFI System Table\r
+ //\r
+ ConOut = gST->ConOut;\r
+\r
+ //\r
+ // Save the current console cursor position and attributes\r
+ //\r
+ CopyMem (&SavedConsoleMode, ConOut->Mode, sizeof (SavedConsoleMode));\r
+\r
+ //\r
+ // Retrieve the number of columns and rows in the current console mode\r
+ //\r
+ ConOut->QueryMode (ConOut, SavedConsoleMode.Mode, &Columns, &Rows);\r
+\r
+ //\r
+ // Disable cursor and set the foreground and background colors specified by Attribute\r
+ //\r
+ ConOut->EnableCursor (ConOut, FALSE);\r
+ ConOut->SetAttribute (ConOut, Attribute);\r
+\r
+ //\r
+ // Limit NumberOfLines to height of the screen minus 3 rows for the box itself\r
+ //\r
+ NumberOfLines = MIN (NumberOfLines, Rows - 3);\r
+\r
+ //\r
+ // Limit MaxLength to width of the screen minus 2 columns for the box itself\r
+ //\r
+ MaxLength = MIN (MaxLength, Columns - 2);\r
+\r
+ //\r
+ // Compute the starting row and starting column for the popup\r
+ //\r
+ Row = (Rows - (NumberOfLines + 3)) / 2;\r
+ Column = (Columns - (MaxLength + 2)) / 2;\r
+\r
+ //\r
+ // Allocate a buffer for a single line of the popup with borders and a Null-terminator\r
+ //\r
+ Line = AllocateZeroPool ((MaxLength + 3) * sizeof (CHAR16));\r
+ ASSERT (Line != NULL);\r
+\r
+ //\r
+ // Draw top of popup box\r
+ //\r
+ SetMem16 (Line, (MaxLength + 2) * 2, BOXDRAW_HORIZONTAL);\r
+ Line[0] = BOXDRAW_DOWN_RIGHT;\r
+ Line[MaxLength + 1] = BOXDRAW_DOWN_LEFT;\r
+ Line[MaxLength + 2] = L'\0';\r
+ ConOut->SetCursorPosition (ConOut, Column, Row++);\r
+ ConOut->OutputString (ConOut, Line);\r
+\r
+ //\r
+ // Draw middle of the popup with strings\r
+ //\r
+ VA_START (Args, Key);\r
+ while ((String = VA_ARG (Args, CHAR16 *)) != NULL && NumberOfLines > 0) {\r
+ SetMem16 (Line, (MaxLength + 2) * 2, L' ');\r
+ Line[0] = BOXDRAW_VERTICAL;\r
+ Line[MaxLength + 1] = BOXDRAW_VERTICAL;\r
+ Line[MaxLength + 2] = L'\0';\r
+ ConOut->SetCursorPosition (ConOut, Column, Row);\r
+ ConOut->OutputString (ConOut, Line);\r
+ Length = UefiLibGetStringWidth (String, FALSE, 0, NULL) / 2;\r
+ if (Length <= MaxLength) {\r
+ //\r
+ // Length <= MaxLength\r
+ //\r
+ ConOut->SetCursorPosition (ConOut, Column + 1 + (MaxLength - Length) / 2, Row++);\r
+ ConOut->OutputString (ConOut, String);\r
+ } else {\r
+ //\r
+ // Length > MaxLength\r
+ //\r
+ UefiLibGetStringWidth (String, TRUE, MaxLength, &Length);\r
+ TmpString = AllocateZeroPool ((Length + 1) * sizeof (CHAR16));\r
+ ASSERT (TmpString != NULL);\r
+ StrnCpyS (TmpString, Length + 1, String, Length - 3);\r
+ StrCatS (TmpString, Length + 1, L"...");\r
+\r
+ ConOut->SetCursorPosition (ConOut, Column + 1, Row++);\r
+ ConOut->OutputString (ConOut, TmpString);\r
+ FreePool (TmpString);\r
+ }\r
+ NumberOfLines--;\r
+ }\r
+ VA_END (Args);\r
+\r
+ //\r
+ // Draw bottom of popup box\r
+ //\r
+ SetMem16 (Line, (MaxLength + 2) * 2, BOXDRAW_HORIZONTAL);\r
+ Line[0] = BOXDRAW_UP_RIGHT;\r
+ Line[MaxLength + 1] = BOXDRAW_UP_LEFT;\r
+ Line[MaxLength + 2] = L'\0';\r
+ ConOut->SetCursorPosition (ConOut, Column, Row++);\r
+ ConOut->OutputString (ConOut, Line);\r
+\r
+ //\r
+ // Free the allocated line buffer\r
+ //\r
+ FreePool (Line);\r
+\r
+ //\r
+ // Restore the cursor visibility, position, and attributes\r
+ //\r
+ ConOut->EnableCursor (ConOut, SavedConsoleMode.CursorVisible);\r
+ ConOut->SetCursorPosition (ConOut, SavedConsoleMode.CursorColumn, SavedConsoleMode.CursorRow);\r
+ ConOut->SetAttribute (ConOut, SavedConsoleMode.Attribute);\r
+\r
+ //\r
+ // Wait for a keystroke\r
+ //\r
+ if (Key != NULL) {\r
+ while (TRUE) {\r
+ Status = gST->ConIn->ReadKeyStroke (gST->ConIn, Key);\r
+ if (!EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // If we encounter error, continue to read another key in.\r
+ //\r
+ if (Status != EFI_NOT_READY) {\r
+ continue;\r
+ }\r
+ gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);\r
+ }\r
+ }\r
+}\r