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
9 #include "UefiLibInternal.h"
14 } UNICODE_WIDTH_ENTRY
;
16 #define NARROW_CHAR 0xFFF0
17 #define WIDE_CHAR 0xFFF1
19 GLOBAL_REMOVE_IF_UNREFERENCED CONST UNICODE_WIDTH_ENTRY mUnicodeWidthTable
[] = {
21 // General script area
23 { (CHAR16
)0x1FFF, 1 },
26 * Merge the blocks and replace them with the above entry as they fall to
27 * the same category and they are all narrow glyph. This will reduce search
28 * time and table size. The merge will omit the reserved code.
30 * Remove the above item if below is un-commented.
32 {(CHAR16)0x007F, 1}, // C0 controls and basic Latin. 0x0000-0x007F
33 {(CHAR16)0x00FF, 1}, // C1 controls and Latin-1 support. 0x0080-0x00FF
34 {(CHAR16)0x017F, 1}, // Latin extended-A. 0x0100-0x017F
35 {(CHAR16)0x024F, 1}, // Latin extended-B. 0x0180-0x024F
36 {(CHAR16)0x02AF, 1}, // IPA extensions. 0x0250-0x02AF
37 {(CHAR16)0x02FF, 1}, // Spacing modifier letters. 0x02B0-0x02FF
38 {(CHAR16)0x036F, 1}, // Combining diacritical marks. 0x0300-0x036F
39 {(CHAR16)0x03FF, 1}, // Greek. 0x0370-0x03FF
40 {(CHAR16)0x04FF, 1}, // Cyrillic. 0x0400-0x04FF
41 {(CHAR16)0x052F, 0}, // Unassigned. As Armenian in ver3.0. 0x0500-0x052F
42 {(CHAR16)0x058F, 1}, // Armenian. 0x0530-0x058F
43 {(CHAR16)0x05FF, 1}, // Hebrew. 0x0590-0x05FF
44 {(CHAR16)0x06FF, 1}, // Arabic. 0x0600-0x06FF
45 {(CHAR16)0x08FF, 0}, // Unassigned. 0x0700-0x08FF
46 {(CHAR16)0x097F, 1}, // Devanagari. 0x0900-0x097F
47 {(CHAR16)0x09FF, 1}, // Bengali. 0x0980-0x09FF
48 {(CHAR16)0x0A7F, 1}, // Gurmukhi. 0x0A00-0x0A7F
49 {(CHAR16)0x0AFF, 1}, // Gujarati. 0x0A80-0x0AFF
50 {(CHAR16)0x0B7F, 1}, // Oriya. 0x0B00-0x0B7F
51 {(CHAR16)0x0BFF, 1}, // Tamil. (See page 7-92). 0x0B80-0x0BFF
52 {(CHAR16)0x0C7F, 1}, // Telugu. 0x0C00-0x0C7F
53 {(CHAR16)0x0CFF, 1}, // Kannada. (See page 7-100). 0x0C80-0x0CFF
54 {(CHAR16)0x0D7F, 1}, // Malayalam (See page 7-104). 0x0D00-0x0D7F
55 {(CHAR16)0x0DFF, 0}, // Unassigned. 0x0D80-0x0DFF
56 {(CHAR16)0x0E7F, 1}, // Thai. 0x0E00-0x0E7F
57 {(CHAR16)0x0EFF, 1}, // Lao. 0x0E80-0x0EFF
58 {(CHAR16)0x0FBF, 1}, // Tibetan. 0x0F00-0x0FBF
59 {(CHAR16)0x109F, 0}, // Unassigned. 0x0FC0-0x109F
60 {(CHAR16)0x10FF, 1}, // Georgian. 0x10A0-0x10FF
61 {(CHAR16)0x11FF, 1}, // Hangul Jamo. 0x1100-0x11FF
62 {(CHAR16)0x1DFF, 0}, // Unassigned. 0x1200-0x1DFF
63 {(CHAR16)0x1EFF, 1}, // Latin extended additional. 0x1E00-0x1EFF
64 {(CHAR16)0x1FFF, 1}, // Greek extended. 0x1F00-0x1FFF
71 { (CHAR16
)0x2FFF, 1 },
74 * Merge the blocks and replace them with the above entry as they fall to
75 * the same category and they are all narrow glyph. This will reduce search
76 * time and table size. The merge will omit the reserved code.
78 * Remove the above item if below is un-commented.
80 {(CHAR16)0x206F, 1}, // General punctuation. (See page7-154). 0x200-0x206F
81 {(CHAR16)0x209F, 1}, // Superscripts and subscripts. 0x2070-0x209F
82 {(CHAR16)0x20CF, 1}, // Currency symbols. 0x20A0-0x20CF
83 {(CHAR16)0x20FF, 1}, // Combining diacritical marks for symbols. 0x20D0-0x20FF
84 {(CHAR16)0x214F, 1}, // Letterlike sympbols. 0x2100-0x214F
85 {(CHAR16)0x218F, 1}, // Number forms. 0x2150-0x218F
86 {(CHAR16)0x21FF, 1}, // Arrows. 0x2190-0x21FF
87 {(CHAR16)0x22FF, 1}, // Mathematical operators. 0x2200-0x22FF
88 {(CHAR16)0x23FF, 1}, // Miscellaneous technical. 0x2300-0x23FF
89 {(CHAR16)0x243F, 1}, // Control pictures. 0x2400-0x243F
90 {(CHAR16)0x245F, 1}, // Optical character recognition. 0x2440-0x245F
91 {(CHAR16)0x24FF, 1}, // Enclosed alphanumerics. 0x2460-0x24FF
92 {(CHAR16)0x257F, 1}, // Box drawing. 0x2500-0x257F
93 {(CHAR16)0x259F, 1}, // Block elements. 0x2580-0x259F
94 {(CHAR16)0x25FF, 1}, // Geometric shapes. 0x25A0-0x25FF
95 {(CHAR16)0x26FF, 1}, // Miscellaneous symbols. 0x2600-0x26FF
96 {(CHAR16)0x27BF, 1}, // Dingbats. 0x2700-0x27BF
97 {(CHAR16)0x2FFF, 0}, // Reserved. 0x27C0-0x2FFF
102 // CJK phonetics and symbol area
104 { (CHAR16
)0x33FF, 2 },
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
128 { (CHAR16
)0x9FFF, 2 },
131 * Merge the blocks and replace them with the above entry as they fall to
132 * the same category and they are all wide glyph. This will reduce search
133 * time and table size. The merge will omit the reserved code.
135 * Remove the above item if below is un-commented.
137 {(CHAR16)0x4DFF, 0}, // Reserved. 0x3400-0x4DBF as CJK unified ideographs
138 // extension A in ver3.0. 0x3400-0x4DFF
139 {(CHAR16)0x9FFF, 2}, // CJK unified ideographs. 0x4E00-0x9FFF
146 { (CHAR16
)0xABFF, 0 }, // Reserved. 0xA000-0xA490 as Yi syllables. 0xA490-0xA4D0
147 // as Yi radicals in ver3.0. 0xA000-0xABFF
151 { (CHAR16
)0xD7FF, 2 },
154 * Merge the blocks and replace them with the above entry as they fall to
155 * the same category and they are all wide glyph. This will reduce search
156 * time and table size. The merge will omit the reserved code.
158 * Remove the above item if below is un-commented.
160 {(CHAR16)0xD7A3, 2}, // Hangul syllables. 0xAC00-0xD7A3
161 {(CHAR16)0xD7FF, 0}, // Reserved. 0xD7A3-0xD7FF
168 { (CHAR16
)0xDFFF, 0 }, // Surrogates, not used now. 0xD800-0xDFFF
173 { (CHAR16
)0xF8FF, 0 }, // Private use area. 0xE000-0xF8FF
176 // Compatibility area and specials
178 { (CHAR16
)0xFAFF, 2 }, // CJK compatibility ideographs. 0xF900-0xFAFF
179 { (CHAR16
)0xFB4F, 1 }, // Alphabetic presentation forms. 0xFB00-0xFB4F
180 { (CHAR16
)0xFDFF, 1 }, // Arabic presentation forms-A. 0xFB50-0xFDFF
181 { (CHAR16
)0xFE1F, 0 }, // Reserved. As variation selectors in ver3.0. 0xFE00-0xFE1F
182 { (CHAR16
)0xFE2F, 1 }, // Combining half marks. 0xFE20-0xFE2F
183 { (CHAR16
)0xFE4F, 2 }, // CJK compatibility forms. 0xFE30-0xFE4F
184 { (CHAR16
)0xFE6F, 1 }, // Small Form Variants. 0xFE50-0xFE6F
185 { (CHAR16
)0xFEFF, 1 }, // Arabic presentation forms-B. 0xFE70-0xFEFF
186 { (CHAR16
)0xFFEF, 1 }, // Half width and full width forms. 0xFF00-0xFFEF
187 { (CHAR16
)0xFFFF, 0 }, // Speicials. 0xFFF0-0xFFFF
191 Retrieves the width of a Unicode character.
193 This function computes and returns the width of the Unicode character specified
196 @param UnicodeChar A Unicode character.
198 @retval 0 The width if UnicodeChar could not be determined.
199 @retval 1 UnicodeChar is a narrow glyph.
200 @retval 2 UnicodeChar is a wide glyph.
206 IN CHAR16 UnicodeChar
212 CONST UNICODE_WIDTH_ENTRY
*Item
;
216 High
= (sizeof (mUnicodeWidthTable
)) / (sizeof (UNICODE_WIDTH_ENTRY
)) - 1;
217 while (Low
<= High
) {
218 Index
= (Low
+ High
) >> 1;
219 Item
= &(mUnicodeWidthTable
[Index
]);
221 if (UnicodeChar
<= Item
->WChar
) {
228 if (UnicodeChar
> Item
->WChar
) {
230 } else if (UnicodeChar
<= mUnicodeWidthTable
[Index
- 1].WChar
) {
234 // Index - 1 < UnicodeChar <= Index. Found
248 Computes the display length of a Null-terminated Unicode String.
250 This function computes and returns the display length of the Null-terminated
251 Unicode string specified by String. If String is NULL then 0 is returned. If
252 any of the widths of the Unicode characters in String can not be determined,
253 then 0 is returned. The display width of String can be computed by summing the
254 display widths of each Unicode character in String. Unicode characters that
255 are narrow glyphs have a width of 1, and Unicode characters that are width glyphs
256 have a width of 2. If String is not aligned on a 16-bit boundary, then ASSERT().
258 @param String A pointer to a Null-terminated Unicode string.
260 @return The display length of the Null-terminated Unicode string specified by String.
265 UnicodeStringDisplayLength (
266 IN CONST CHAR16
*String
272 if (String
== NULL
) {
277 while (*String
!= 0) {
278 Width
= GetGlyphWidth (*String
);
291 Count the storage space of a Unicode string.
293 This function handles the Unicode string with NARROW_CHAR
294 and WIDE_CHAR control characters. NARROW_HCAR and WIDE_CHAR
295 does not count in the resultant output. If a WIDE_CHAR is
296 hit, then 2 Unicode character will consume an output storage
297 space with size of CHAR16 till a NARROW_CHAR is hit.
299 @param String The input string to be counted.
300 @param LimitLen Whether need to limit the string length.
301 @param MaxWidth The max length this function supported.
302 @param Offset The max index of the string can be show out.
304 @return Storage space for the input string.
308 UefiLibGetStringWidth (
317 UINTN IncrementValue
;
319 if (String
== NULL
) {
329 // Advance to the null-terminator or to the first width directive
331 for ( ; (String
[Index
] != NARROW_CHAR
) && (String
[Index
] != WIDE_CHAR
) && (String
[Index
] != 0); Index
++) {
332 Count
= Count
+ IncrementValue
;
334 if (LimitLen
&& (Count
> MaxWidth
)) {
340 // We hit the null-terminator, we now have a count
342 if (String
[Index
] == 0) {
346 if (LimitLen
&& (Count
> MaxWidth
)) {
352 // We encountered a narrow directive - strip it from the size calculation since it doesn't get printed
353 // and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2)
355 if (String
[Index
] == NARROW_CHAR
) {
357 // Skip to the next character
363 // Skip to the next character
368 } while (String
[Index
] != 0);
370 return Count
* sizeof (CHAR16
);
374 Draws a dialog box to the console output device specified by
375 ConOut defined in the EFI_SYSTEM_TABLE and waits for a keystroke
376 from the console input device specified by ConIn defined in the
379 If there are no strings in the variable argument list, then ASSERT().
380 If all the strings in the variable argument list are empty, then ASSERT().
382 @param[in] Attribute Specifies the foreground and background color of the popup.
383 @param[out] Key A pointer to the EFI_KEY value of the key that was
384 pressed. This is an optional parameter that may be NULL.
385 If it is NULL then no wait for a keypress will be performed.
386 @param[in] ... The variable argument list that contains pointers to Null-
387 terminated Unicode strings to display in the dialog box.
388 The variable argument list is terminated by a NULL.
395 OUT EFI_INPUT_KEY
*Key OPTIONAL
,
401 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*ConOut
;
402 EFI_SIMPLE_TEXT_OUTPUT_MODE SavedConsoleMode
;
416 // Determine the length of the longest line in the popup and the the total
417 // number of lines in the popup
419 VA_START (Args
, Key
);
422 while ((String
= VA_ARG (Args
, CHAR16
*)) != NULL
) {
423 MaxLength
= MAX (MaxLength
, UefiLibGetStringWidth (String
, FALSE
, 0, NULL
) / 2);
430 // If the total number of lines in the popup is zero, then ASSERT()
432 ASSERT (NumberOfLines
!= 0);
435 // If the maximum length of all the strings is zero, then ASSERT()
437 ASSERT (MaxLength
!= 0);
440 // Cache a pointer to the Simple Text Output Protocol in the EFI System Table
442 ConOut
= gST
->ConOut
;
445 // Save the current console cursor position and attributes
447 CopyMem (&SavedConsoleMode
, ConOut
->Mode
, sizeof (SavedConsoleMode
));
450 // Retrieve the number of columns and rows in the current console mode
452 ConOut
->QueryMode (ConOut
, SavedConsoleMode
.Mode
, &Columns
, &Rows
);
455 // Disable cursor and set the foreground and background colors specified by Attribute
457 ConOut
->EnableCursor (ConOut
, FALSE
);
458 ConOut
->SetAttribute (ConOut
, Attribute
);
461 // Limit NumberOfLines to height of the screen minus 3 rows for the box itself
463 NumberOfLines
= MIN (NumberOfLines
, Rows
- 3);
466 // Limit MaxLength to width of the screen minus 2 columns for the box itself
468 MaxLength
= MIN (MaxLength
, Columns
- 2);
471 // Compute the starting row and starting column for the popup
473 Row
= (Rows
- (NumberOfLines
+ 3)) / 2;
474 Column
= (Columns
- (MaxLength
+ 2)) / 2;
477 // Allocate a buffer for a single line of the popup with borders and a Null-terminator
479 Line
= AllocateZeroPool ((MaxLength
+ 3) * sizeof (CHAR16
));
480 ASSERT (Line
!= NULL
);
483 // Draw top of popup box
485 SetMem16 (Line
, (MaxLength
+ 2) * 2, BOXDRAW_HORIZONTAL
);
486 Line
[0] = BOXDRAW_DOWN_RIGHT
;
487 Line
[MaxLength
+ 1] = BOXDRAW_DOWN_LEFT
;
488 Line
[MaxLength
+ 2] = L
'\0';
489 ConOut
->SetCursorPosition (ConOut
, Column
, Row
++);
490 ConOut
->OutputString (ConOut
, Line
);
493 // Draw middle of the popup with strings
495 VA_START (Args
, Key
);
496 while ((String
= VA_ARG (Args
, CHAR16
*)) != NULL
&& NumberOfLines
> 0) {
497 SetMem16 (Line
, (MaxLength
+ 2) * 2, L
' ');
498 Line
[0] = BOXDRAW_VERTICAL
;
499 Line
[MaxLength
+ 1] = BOXDRAW_VERTICAL
;
500 Line
[MaxLength
+ 2] = L
'\0';
501 ConOut
->SetCursorPosition (ConOut
, Column
, Row
);
502 ConOut
->OutputString (ConOut
, Line
);
503 Length
= UefiLibGetStringWidth (String
, FALSE
, 0, NULL
) / 2;
504 if (Length
<= MaxLength
) {
506 // Length <= MaxLength
508 ConOut
->SetCursorPosition (ConOut
, Column
+ 1 + (MaxLength
- Length
) / 2, Row
++);
509 ConOut
->OutputString (ConOut
, String
);
512 // Length > MaxLength
514 UefiLibGetStringWidth (String
, TRUE
, MaxLength
, &Length
);
515 TmpString
= AllocateZeroPool ((Length
+ 1) * sizeof (CHAR16
));
516 ASSERT (TmpString
!= NULL
);
517 StrnCpyS (TmpString
, Length
+ 1, String
, Length
- 3);
518 StrCatS (TmpString
, Length
+ 1, L
"...");
520 ConOut
->SetCursorPosition (ConOut
, Column
+ 1, Row
++);
521 ConOut
->OutputString (ConOut
, TmpString
);
522 FreePool (TmpString
);
531 // Draw bottom of popup box
533 SetMem16 (Line
, (MaxLength
+ 2) * 2, BOXDRAW_HORIZONTAL
);
534 Line
[0] = BOXDRAW_UP_RIGHT
;
535 Line
[MaxLength
+ 1] = BOXDRAW_UP_LEFT
;
536 Line
[MaxLength
+ 2] = L
'\0';
537 ConOut
->SetCursorPosition (ConOut
, Column
, Row
++);
538 ConOut
->OutputString (ConOut
, Line
);
541 // Free the allocated line buffer
546 // Restore the cursor visibility, position, and attributes
548 ConOut
->EnableCursor (ConOut
, SavedConsoleMode
.CursorVisible
);
549 ConOut
->SetCursorPosition (ConOut
, SavedConsoleMode
.CursorColumn
, SavedConsoleMode
.CursorRow
);
550 ConOut
->SetAttribute (ConOut
, SavedConsoleMode
.Attribute
);
553 // Wait for a keystroke
557 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, Key
);
558 if (!EFI_ERROR (Status
)) {
563 // If we encounter error, continue to read another key in.
565 if (Status
!= EFI_NOT_READY
) {
569 gBS
->WaitForEvent (1, &gST
->ConIn
->WaitForKey
, &EventIndex
);