2 This module provide help function for displaying unicode string.
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
12 #include "UefiLibInternal.h"
17 } UNICODE_WIDTH_ENTRY
;
19 #define NARROW_CHAR 0xFFF0
20 #define WIDE_CHAR 0xFFF1
22 GLOBAL_REMOVE_IF_UNREFERENCED CONST UNICODE_WIDTH_ENTRY mUnicodeWidthTable
[] = {
24 // General script area
28 * Merge the blocks and replace them with the above entry as they fall to
29 * the same category and they are all narrow glyph. This will reduce search
30 * time and table size. The merge will omit the reserved code.
32 * Remove the above item if below is un-commented.
34 {(CHAR16)0x007F, 1}, // C0 controls and basic Latin. 0x0000-0x007F
35 {(CHAR16)0x00FF, 1}, // C1 controls and Latin-1 support. 0x0080-0x00FF
36 {(CHAR16)0x017F, 1}, // Latin extended-A. 0x0100-0x017F
37 {(CHAR16)0x024F, 1}, // Latin extended-B. 0x0180-0x024F
38 {(CHAR16)0x02AF, 1}, // IPA extensions. 0x0250-0x02AF
39 {(CHAR16)0x02FF, 1}, // Spacing modifier letters. 0x02B0-0x02FF
40 {(CHAR16)0x036F, 1}, // Combining diacritical marks. 0x0300-0x036F
41 {(CHAR16)0x03FF, 1}, // Greek. 0x0370-0x03FF
42 {(CHAR16)0x04FF, 1}, // Cyrillic. 0x0400-0x04FF
43 {(CHAR16)0x052F, 0}, // Unassigned. As Armenian in ver3.0. 0x0500-0x052F
44 {(CHAR16)0x058F, 1}, // Armenian. 0x0530-0x058F
45 {(CHAR16)0x05FF, 1}, // Hebrew. 0x0590-0x05FF
46 {(CHAR16)0x06FF, 1}, // Arabic. 0x0600-0x06FF
47 {(CHAR16)0x08FF, 0}, // Unassigned. 0x0700-0x08FF
48 {(CHAR16)0x097F, 1}, // Devanagari. 0x0900-0x097F
49 {(CHAR16)0x09FF, 1}, // Bengali. 0x0980-0x09FF
50 {(CHAR16)0x0A7F, 1}, // Gurmukhi. 0x0A00-0x0A7F
51 {(CHAR16)0x0AFF, 1}, // Gujarati. 0x0A80-0x0AFF
52 {(CHAR16)0x0B7F, 1}, // Oriya. 0x0B00-0x0B7F
53 {(CHAR16)0x0BFF, 1}, // Tamil. (See page 7-92). 0x0B80-0x0BFF
54 {(CHAR16)0x0C7F, 1}, // Telugu. 0x0C00-0x0C7F
55 {(CHAR16)0x0CFF, 1}, // Kannada. (See page 7-100). 0x0C80-0x0CFF
56 {(CHAR16)0x0D7F, 1}, // Malayalam (See page 7-104). 0x0D00-0x0D7F
57 {(CHAR16)0x0DFF, 0}, // Unassigned. 0x0D80-0x0DFF
58 {(CHAR16)0x0E7F, 1}, // Thai. 0x0E00-0x0E7F
59 {(CHAR16)0x0EFF, 1}, // Lao. 0x0E80-0x0EFF
60 {(CHAR16)0x0FBF, 1}, // Tibetan. 0x0F00-0x0FBF
61 {(CHAR16)0x109F, 0}, // Unassigned. 0x0FC0-0x109F
62 {(CHAR16)0x10FF, 1}, // Georgian. 0x10A0-0x10FF
63 {(CHAR16)0x11FF, 1}, // Hangul Jamo. 0x1100-0x11FF
64 {(CHAR16)0x1DFF, 0}, // Unassigned. 0x1200-0x1DFF
65 {(CHAR16)0x1EFF, 1}, // Latin extended additional. 0x1E00-0x1EFF
66 {(CHAR16)0x1FFF, 1}, // Greek extended. 0x1F00-0x1FFF
75 * Merge the blocks and replace them with the above entry as they fall to
76 * the same category and they are all narrow glyph. This will reduce search
77 * time and table size. The merge will omit the reserved code.
79 * Remove the above item if below is un-commented.
81 {(CHAR16)0x206F, 1}, // General punctuation. (See page7-154). 0x200-0x206F
82 {(CHAR16)0x209F, 1}, // Superscripts and subscripts. 0x2070-0x209F
83 {(CHAR16)0x20CF, 1}, // Currency symbols. 0x20A0-0x20CF
84 {(CHAR16)0x20FF, 1}, // Combining diacritical marks for symbols. 0x20D0-0x20FF
85 {(CHAR16)0x214F, 1}, // Letterlike sympbols. 0x2100-0x214F
86 {(CHAR16)0x218F, 1}, // Number forms. 0x2150-0x218F
87 {(CHAR16)0x21FF, 1}, // Arrows. 0x2190-0x21FF
88 {(CHAR16)0x22FF, 1}, // Mathematical operators. 0x2200-0x22FF
89 {(CHAR16)0x23FF, 1}, // Miscellaneous technical. 0x2300-0x23FF
90 {(CHAR16)0x243F, 1}, // Control pictures. 0x2400-0x243F
91 {(CHAR16)0x245F, 1}, // Optical character recognition. 0x2440-0x245F
92 {(CHAR16)0x24FF, 1}, // Enclosed alphanumerics. 0x2460-0x24FF
93 {(CHAR16)0x257F, 1}, // Box drawing. 0x2500-0x257F
94 {(CHAR16)0x259F, 1}, // Block elements. 0x2580-0x259F
95 {(CHAR16)0x25FF, 1}, // Geometric shapes. 0x25A0-0x25FF
96 {(CHAR16)0x26FF, 1}, // Miscellaneous symbols. 0x2600-0x26FF
97 {(CHAR16)0x27BF, 1}, // Dingbats. 0x2700-0x27BF
98 {(CHAR16)0x2FFF, 0}, // Reserved. 0x27C0-0x2FFF
103 // CJK phonetics and symbol area
107 * Merge the blocks and replace them with the above entry as they fall to
108 * the same category and they are all wide glyph. This will reduce search
109 * time and table size. The merge will omit the reserved code.
111 * Remove the above item if below is un-commented.
113 {(CHAR16)0x303F, 2}, // CJK symbols and punctuation. 0x3000-0x303F
114 {(CHAR16)0x309F, 2}, // Hiragana. 0x3040-0x309F
115 {(CHAR16)0x30FF, 2}, // Katakana. 0x30A0-0x30FF
116 {(CHAR16)0x312F, 2}, // Bopomofo. 0x3100-0x312F
117 {(CHAR16)0x318F, 2}, // Hangul compatibility jamo. 0x3130-0x318F
118 {(CHAR16)0x319F, 2}, // Kanbun. 0x3190-0x319F
119 {(CHAR16)0x31FF, 0}, // Reserved. As Bopomofo extended in ver3.0. 0x31A0-0x31FF
120 {(CHAR16)0x32FF, 2}, // Enclosed CJK letters and months. 0x3200-0x32FF
121 {(CHAR16)0x33FF, 2}, // CJK compatibility. 0x3300-0x33FF
126 // CJK ideograph area
130 * Merge the blocks and replace them with the above entry as they fall to
131 * the same category and they are all wide glyph. This will reduce search
132 * time and table size. The merge will omit the reserved code.
134 * Remove the above item if below is un-commented.
136 {(CHAR16)0x4DFF, 0}, // Reserved. 0x3400-0x4DBF as CJK unified ideographs
137 // extension A in ver3.0. 0x3400-0x4DFF
138 {(CHAR16)0x9FFF, 2}, // CJK unified ideographs. 0x4E00-0x9FFF
145 {(CHAR16
)0xABFF, 0}, // Reserved. 0xA000-0xA490 as Yi syllables. 0xA490-0xA4D0
146 // as Yi radicals in ver3.0. 0xA000-0xABFF
152 * Merge the blocks and replace them with the above entry as they fall to
153 * the same category and they are all wide glyph. This will reduce search
154 * time and table size. The merge will omit the reserved code.
156 * Remove the above item if below is un-commented.
158 {(CHAR16)0xD7A3, 2}, // Hangul syllables. 0xAC00-0xD7A3
159 {(CHAR16)0xD7FF, 0}, // Reserved. 0xD7A3-0xD7FF
166 {(CHAR16
)0xDFFF, 0}, // Surrogates, not used now. 0xD800-0xDFFF
171 {(CHAR16
)0xF8FF, 0}, // Private use area. 0xE000-0xF8FF
174 // Compatibility area and specials
176 {(CHAR16
)0xFAFF, 2}, // CJK compatibility ideographs. 0xF900-0xFAFF
177 {(CHAR16
)0xFB4F, 1}, // Alphabetic presentation forms. 0xFB00-0xFB4F
178 {(CHAR16
)0xFDFF, 1}, // Arabic presentation forms-A. 0xFB50-0xFDFF
179 {(CHAR16
)0xFE1F, 0}, // Reserved. As variation selectors in ver3.0. 0xFE00-0xFE1F
180 {(CHAR16
)0xFE2F, 1}, // Combining half marks. 0xFE20-0xFE2F
181 {(CHAR16
)0xFE4F, 2}, // CJK compatibility forms. 0xFE30-0xFE4F
182 {(CHAR16
)0xFE6F, 1}, // Small Form Variants. 0xFE50-0xFE6F
183 {(CHAR16
)0xFEFF, 1}, // Arabic presentation forms-B. 0xFE70-0xFEFF
184 {(CHAR16
)0xFFEF, 1}, // Half width and full width forms. 0xFF00-0xFFEF
185 {(CHAR16
)0xFFFF, 0}, // Speicials. 0xFFF0-0xFFFF
189 Retrieves the width of a Unicode character.
191 This function computes and returns the width of the Unicode character specified
194 @param UnicodeChar A Unicode character.
196 @retval 0 The width if UnicodeChar could not be determined.
197 @retval 1 UnicodeChar is a narrow glyph.
198 @retval 2 UnicodeChar is a wide glyph.
204 IN CHAR16 UnicodeChar
210 CONST UNICODE_WIDTH_ENTRY
*Item
;
214 High
= (sizeof (mUnicodeWidthTable
)) / (sizeof (UNICODE_WIDTH_ENTRY
)) - 1;
215 while (Low
<= High
) {
216 Index
= (Low
+ High
) >> 1;
217 Item
= &(mUnicodeWidthTable
[Index
]);
219 if (UnicodeChar
<= Item
->WChar
) {
226 if (UnicodeChar
> Item
->WChar
) {
228 } else if (UnicodeChar
<= mUnicodeWidthTable
[Index
- 1].WChar
) {
232 // Index - 1 < UnicodeChar <= Index. Found
246 Computes the display length of a Null-terminated Unicode String.
248 This function computes and returns the display length of the Null-terminated
249 Unicode string specified by String. If String is NULL then 0 is returned. If
250 any of the widths of the Unicode characters in String can not be determined,
251 then 0 is returned. The display width of String can be computed by summing the
252 display widths of each Unicode character in String. Unicode characters that
253 are narrow glyphs have a width of 1, and Unicode characters that are width glyphs
254 have a width of 2. If String is not aligned on a 16-bit boundary, then ASSERT().
256 @param String A pointer to a Null-terminated Unicode string.
258 @return The display length of the Null-terminated Unicode string specified by String.
263 UnicodeStringDisplayLength (
264 IN CONST CHAR16
*String
270 if (String
== NULL
) {
275 while (*String
!= 0) {
276 Width
= GetGlyphWidth (*String
);
289 Count the storage space of a Unicode string.
291 This function handles the Unicode string with NARROW_CHAR
292 and WIDE_CHAR control characters. NARROW_HCAR and WIDE_CHAR
293 does not count in the resultant output. If a WIDE_CHAR is
294 hit, then 2 Unicode character will consume an output storage
295 space with size of CHAR16 till a NARROW_CHAR is hit.
297 @param String The input string to be counted.
298 @param LimitLen Whether need to limit the string length.
299 @param MaxWidth The max length this function supported.
300 @param Offset The max index of the string can be show out.
302 @return Storage space for the input string.
306 UefiLibGetStringWidth (
315 UINTN IncrementValue
;
317 if (String
== NULL
) {
327 // Advance to the null-terminator or to the first width directive
329 for (;(String
[Index
] != NARROW_CHAR
) && (String
[Index
] != WIDE_CHAR
) && (String
[Index
] != 0); Index
++) {
330 Count
= Count
+ IncrementValue
;
332 if (LimitLen
&& Count
> MaxWidth
) {
338 // We hit the null-terminator, we now have a count
340 if (String
[Index
] == 0) {
344 if (LimitLen
&& Count
> MaxWidth
) {
350 // We encountered a narrow directive - strip it from the size calculation since it doesn't get printed
351 // and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2)
353 if (String
[Index
] == NARROW_CHAR
) {
355 // Skip to the next character
361 // Skip to the next character
366 } while (String
[Index
] != 0);
368 return Count
* sizeof (CHAR16
);
372 Draws a dialog box to the console output device specified by
373 ConOut defined in the EFI_SYSTEM_TABLE and waits for a keystroke
374 from the console input device specified by ConIn defined in the
377 If there are no strings in the variable argument list, then ASSERT().
378 If all the strings in the variable argument list are empty, then ASSERT().
380 @param[in] Attribute Specifies the foreground and background color of the popup.
381 @param[out] Key A pointer to the EFI_KEY value of the key that was
382 pressed. This is an optional parameter that may be NULL.
383 If it is NULL then no wait for a keypress will be performed.
384 @param[in] ... The variable argument list that contains pointers to Null-
385 terminated Unicode strings to display in the dialog box.
386 The variable argument list is terminated by a NULL.
393 OUT EFI_INPUT_KEY
*Key
, OPTIONAL
399 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*ConOut
;
400 EFI_SIMPLE_TEXT_OUTPUT_MODE SavedConsoleMode
;
414 // Determine the length of the longest line in the popup and the the total
415 // number of lines in the popup
417 VA_START (Args
, Key
);
420 while ((String
= VA_ARG (Args
, CHAR16
*)) != NULL
) {
421 MaxLength
= MAX (MaxLength
, UefiLibGetStringWidth (String
, FALSE
, 0, NULL
) / 2);
427 // If the total number of lines in the popup is zero, then ASSERT()
429 ASSERT (NumberOfLines
!= 0);
432 // If the maximum length of all the strings is zero, then ASSERT()
434 ASSERT (MaxLength
!= 0);
437 // Cache a pointer to the Simple Text Output Protocol in the EFI System Table
439 ConOut
= gST
->ConOut
;
442 // Save the current console cursor position and attributes
444 CopyMem (&SavedConsoleMode
, ConOut
->Mode
, sizeof (SavedConsoleMode
));
447 // Retrieve the number of columns and rows in the current console mode
449 ConOut
->QueryMode (ConOut
, SavedConsoleMode
.Mode
, &Columns
, &Rows
);
452 // Disable cursor and set the foreground and background colors specified by Attribute
454 ConOut
->EnableCursor (ConOut
, FALSE
);
455 ConOut
->SetAttribute (ConOut
, Attribute
);
458 // Limit NumberOfLines to height of the screen minus 3 rows for the box itself
460 NumberOfLines
= MIN (NumberOfLines
, Rows
- 3);
463 // Limit MaxLength to width of the screen minus 2 columns for the box itself
465 MaxLength
= MIN (MaxLength
, Columns
- 2);
468 // Compute the starting row and starting column for the popup
470 Row
= (Rows
- (NumberOfLines
+ 3)) / 2;
471 Column
= (Columns
- (MaxLength
+ 2)) / 2;
474 // Allocate a buffer for a single line of the popup with borders and a Null-terminator
476 Line
= AllocateZeroPool ((MaxLength
+ 3) * sizeof (CHAR16
));
477 ASSERT (Line
!= NULL
);
480 // Draw top of popup box
482 SetMem16 (Line
, (MaxLength
+ 2) * 2, BOXDRAW_HORIZONTAL
);
483 Line
[0] = BOXDRAW_DOWN_RIGHT
;
484 Line
[MaxLength
+ 1] = BOXDRAW_DOWN_LEFT
;
485 Line
[MaxLength
+ 2] = L
'\0';
486 ConOut
->SetCursorPosition (ConOut
, Column
, Row
++);
487 ConOut
->OutputString (ConOut
, Line
);
490 // Draw middle of the popup with strings
492 VA_START (Args
, Key
);
493 while ((String
= VA_ARG (Args
, CHAR16
*)) != NULL
&& NumberOfLines
> 0) {
494 SetMem16 (Line
, (MaxLength
+ 2) * 2, L
' ');
495 Line
[0] = BOXDRAW_VERTICAL
;
496 Line
[MaxLength
+ 1] = BOXDRAW_VERTICAL
;
497 Line
[MaxLength
+ 2] = L
'\0';
498 ConOut
->SetCursorPosition (ConOut
, Column
, Row
);
499 ConOut
->OutputString (ConOut
, Line
);
500 Length
= UefiLibGetStringWidth (String
, FALSE
, 0, NULL
) / 2;
501 if (Length
<= MaxLength
) {
503 // Length <= MaxLength
505 ConOut
->SetCursorPosition (ConOut
, Column
+ 1 + (MaxLength
- Length
) / 2, Row
++);
506 ConOut
->OutputString (ConOut
, String
);
509 // Length > MaxLength
511 UefiLibGetStringWidth (String
, TRUE
, MaxLength
, &Length
);
512 TmpString
= AllocateZeroPool ((Length
+ 1) * sizeof (CHAR16
));
513 ASSERT (TmpString
!= NULL
);
514 StrnCpyS (TmpString
, Length
+ 1, String
, Length
- 3);
515 StrCatS (TmpString
, Length
+ 1, L
"...");
517 ConOut
->SetCursorPosition (ConOut
, Column
+ 1, Row
++);
518 ConOut
->OutputString (ConOut
, TmpString
);
519 FreePool (TmpString
);
526 // Draw bottom of popup box
528 SetMem16 (Line
, (MaxLength
+ 2) * 2, BOXDRAW_HORIZONTAL
);
529 Line
[0] = BOXDRAW_UP_RIGHT
;
530 Line
[MaxLength
+ 1] = BOXDRAW_UP_LEFT
;
531 Line
[MaxLength
+ 2] = L
'\0';
532 ConOut
->SetCursorPosition (ConOut
, Column
, Row
++);
533 ConOut
->OutputString (ConOut
, Line
);
536 // Free the allocated line buffer
541 // Restore the cursor visibility, position, and attributes
543 ConOut
->EnableCursor (ConOut
, SavedConsoleMode
.CursorVisible
);
544 ConOut
->SetCursorPosition (ConOut
, SavedConsoleMode
.CursorColumn
, SavedConsoleMode
.CursorRow
);
545 ConOut
->SetAttribute (ConOut
, SavedConsoleMode
.Attribute
);
548 // Wait for a keystroke
552 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, Key
);
553 if (!EFI_ERROR (Status
)) {
558 // If we encounter error, continue to read another key in.
560 if (Status
!= EFI_NOT_READY
) {
563 gBS
->WaitForEvent (1, &gST
->ConIn
->WaitForKey
, &EventIndex
);