2 This module provide help function for displaying unicode string.
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php.
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 #include "UefiLibInternal.h"
23 } UNICODE_WIDTH_ENTRY
;
25 #define NARROW_CHAR 0xFFF0
26 #define WIDE_CHAR 0xFFF1
28 GLOBAL_REMOVE_IF_UNREFERENCED CONST UNICODE_WIDTH_ENTRY mUnicodeWidthTable
[] = {
30 // General script area
34 * Merge the blocks and replace them with the above entry as they fall to
35 * the same category and they are all narrow glyph. This will reduce search
36 * time and table size. The merge will omit the reserved code.
38 * Remove the above item if below is un-commented.
40 {(CHAR16)0x007F, 1}, // C0 controls and basic Latin. 0x0000-0x007F
41 {(CHAR16)0x00FF, 1}, // C1 controls and Latin-1 support. 0x0080-0x00FF
42 {(CHAR16)0x017F, 1}, // Latin extended-A. 0x0100-0x017F
43 {(CHAR16)0x024F, 1}, // Latin extended-B. 0x0180-0x024F
44 {(CHAR16)0x02AF, 1}, // IPA extensions. 0x0250-0x02AF
45 {(CHAR16)0x02FF, 1}, // Spacing modifier letters. 0x02B0-0x02FF
46 {(CHAR16)0x036F, 1}, // Combining diacritical marks. 0x0300-0x036F
47 {(CHAR16)0x03FF, 1}, // Greek. 0x0370-0x03FF
48 {(CHAR16)0x04FF, 1}, // Cyrillic. 0x0400-0x04FF
49 {(CHAR16)0x052F, 0}, // Unassigned. As Armenian in ver3.0. 0x0500-0x052F
50 {(CHAR16)0x058F, 1}, // Armenian. 0x0530-0x058F
51 {(CHAR16)0x05FF, 1}, // Hebrew. 0x0590-0x05FF
52 {(CHAR16)0x06FF, 1}, // Arabic. 0x0600-0x06FF
53 {(CHAR16)0x08FF, 0}, // Unassigned. 0x0700-0x08FF
54 {(CHAR16)0x097F, 1}, // Devanagari. 0x0900-0x097F
55 {(CHAR16)0x09FF, 1}, // Bengali. 0x0980-0x09FF
56 {(CHAR16)0x0A7F, 1}, // Gurmukhi. 0x0A00-0x0A7F
57 {(CHAR16)0x0AFF, 1}, // Gujarati. 0x0A80-0x0AFF
58 {(CHAR16)0x0B7F, 1}, // Oriya. 0x0B00-0x0B7F
59 {(CHAR16)0x0BFF, 1}, // Tamil. (See page 7-92). 0x0B80-0x0BFF
60 {(CHAR16)0x0C7F, 1}, // Telugu. 0x0C00-0x0C7F
61 {(CHAR16)0x0CFF, 1}, // Kannada. (See page 7-100). 0x0C80-0x0CFF
62 {(CHAR16)0x0D7F, 1}, // Malayalam (See page 7-104). 0x0D00-0x0D7F
63 {(CHAR16)0x0DFF, 0}, // Unassigned. 0x0D80-0x0DFF
64 {(CHAR16)0x0E7F, 1}, // Thai. 0x0E00-0x0E7F
65 {(CHAR16)0x0EFF, 1}, // Lao. 0x0E80-0x0EFF
66 {(CHAR16)0x0FBF, 1}, // Tibetan. 0x0F00-0x0FBF
67 {(CHAR16)0x109F, 0}, // Unassigned. 0x0FC0-0x109F
68 {(CHAR16)0x10FF, 1}, // Georgian. 0x10A0-0x10FF
69 {(CHAR16)0x11FF, 1}, // Hangul Jamo. 0x1100-0x11FF
70 {(CHAR16)0x1DFF, 0}, // Unassigned. 0x1200-0x1DFF
71 {(CHAR16)0x1EFF, 1}, // Latin extended additional. 0x1E00-0x1EFF
72 {(CHAR16)0x1FFF, 1}, // Greek extended. 0x1F00-0x1FFF
81 * Merge the blocks and replace them with the above entry as they fall to
82 * the same category and they are all narrow glyph. This will reduce search
83 * time and table size. The merge will omit the reserved code.
85 * Remove the above item if below is un-commented.
87 {(CHAR16)0x206F, 1}, // General punctuation. (See page7-154). 0x200-0x206F
88 {(CHAR16)0x209F, 1}, // Superscripts and subscripts. 0x2070-0x209F
89 {(CHAR16)0x20CF, 1}, // Currency symbols. 0x20A0-0x20CF
90 {(CHAR16)0x20FF, 1}, // Combining diacritical marks for symbols. 0x20D0-0x20FF
91 {(CHAR16)0x214F, 1}, // Letterlike sympbols. 0x2100-0x214F
92 {(CHAR16)0x218F, 1}, // Number forms. 0x2150-0x218F
93 {(CHAR16)0x21FF, 1}, // Arrows. 0x2190-0x21FF
94 {(CHAR16)0x22FF, 1}, // Mathematical operators. 0x2200-0x22FF
95 {(CHAR16)0x23FF, 1}, // Miscellaneous technical. 0x2300-0x23FF
96 {(CHAR16)0x243F, 1}, // Control pictures. 0x2400-0x243F
97 {(CHAR16)0x245F, 1}, // Optical character recognition. 0x2440-0x245F
98 {(CHAR16)0x24FF, 1}, // Enclosed alphanumerics. 0x2460-0x24FF
99 {(CHAR16)0x257F, 1}, // Box drawing. 0x2500-0x257F
100 {(CHAR16)0x259F, 1}, // Block elements. 0x2580-0x259F
101 {(CHAR16)0x25FF, 1}, // Geometric shapes. 0x25A0-0x25FF
102 {(CHAR16)0x26FF, 1}, // Miscellaneous symbols. 0x2600-0x26FF
103 {(CHAR16)0x27BF, 1}, // Dingbats. 0x2700-0x27BF
104 {(CHAR16)0x2FFF, 0}, // Reserved. 0x27C0-0x2FFF
109 // CJK phonetics and symbol area
113 * Merge the blocks and replace them with the above entry as they fall to
114 * the same category and they are all wide glyph. This will reduce search
115 * time and table size. The merge will omit the reserved code.
117 * Remove the above item if below is un-commented.
119 {(CHAR16)0x303F, 2}, // CJK symbols and punctuation. 0x3000-0x303F
120 {(CHAR16)0x309F, 2}, // Hiragana. 0x3040-0x309F
121 {(CHAR16)0x30FF, 2}, // Katakana. 0x30A0-0x30FF
122 {(CHAR16)0x312F, 2}, // Bopomofo. 0x3100-0x312F
123 {(CHAR16)0x318F, 2}, // Hangul compatibility jamo. 0x3130-0x318F
124 {(CHAR16)0x319F, 2}, // Kanbun. 0x3190-0x319F
125 {(CHAR16)0x31FF, 0}, // Reserved. As Bopomofo extended in ver3.0. 0x31A0-0x31FF
126 {(CHAR16)0x32FF, 2}, // Enclosed CJK letters and months. 0x3200-0x32FF
127 {(CHAR16)0x33FF, 2}, // CJK compatibility. 0x3300-0x33FF
132 // CJK ideograph area
136 * Merge the blocks and replace them with the above entry as they fall to
137 * the same category and they are all wide glyph. This will reduce search
138 * time and table size. The merge will omit the reserved code.
140 * Remove the above item if below is un-commented.
142 {(CHAR16)0x4DFF, 0}, // Reserved. 0x3400-0x4DBF as CJK unified ideographs
143 // extension A in ver3.0. 0x3400-0x4DFF
144 {(CHAR16)0x9FFF, 2}, // CJK unified ideographs. 0x4E00-0x9FFF
151 {(CHAR16
)0xABFF, 0}, // Reserved. 0xA000-0xA490 as Yi syllables. 0xA490-0xA4D0
152 // as Yi radicals in ver3.0. 0xA000-0xABFF
158 * Merge the blocks and replace them with the above entry as they fall to
159 * the same category and they are all wide glyph. This will reduce search
160 * time and table size. The merge will omit the reserved code.
162 * Remove the above item if below is un-commented.
164 {(CHAR16)0xD7A3, 2}, // Hangul syllables. 0xAC00-0xD7A3
165 {(CHAR16)0xD7FF, 0}, // Reserved. 0xD7A3-0xD7FF
172 {(CHAR16
)0xDFFF, 0}, // Surrogates, not used now. 0xD800-0xDFFF
177 {(CHAR16
)0xF8FF, 0}, // Private use area. 0xE000-0xF8FF
180 // Compatibility area and specials
182 {(CHAR16
)0xFAFF, 2}, // CJK compatibility ideographs. 0xF900-0xFAFF
183 {(CHAR16
)0xFB4F, 1}, // Alphabetic presentation forms. 0xFB00-0xFB4F
184 {(CHAR16
)0xFDFF, 1}, // Arabic presentation forms-A. 0xFB50-0xFDFF
185 {(CHAR16
)0xFE1F, 0}, // Reserved. As variation selectors in ver3.0. 0xFE00-0xFE1F
186 {(CHAR16
)0xFE2F, 1}, // Combining half marks. 0xFE20-0xFE2F
187 {(CHAR16
)0xFE4F, 2}, // CJK compatibility forms. 0xFE30-0xFE4F
188 {(CHAR16
)0xFE6F, 1}, // Small Form Variants. 0xFE50-0xFE6F
189 {(CHAR16
)0xFEFF, 1}, // Arabic presentation forms-B. 0xFE70-0xFEFF
190 {(CHAR16
)0xFFEF, 1}, // Half width and full width forms. 0xFF00-0xFFEF
191 {(CHAR16
)0xFFFF, 0}, // Speicials. 0xFFF0-0xFFFF
195 Retrieves the width of a Unicode character.
197 This function computes and returns the width of the Unicode character specified
200 @param UnicodeChar A Unicode character.
202 @retval 0 The width if UnicodeChar could not be determined.
203 @retval 1 UnicodeChar is a narrow glyph.
204 @retval 2 UnicodeChar is a wide glyph.
210 IN CHAR16 UnicodeChar
216 CONST UNICODE_WIDTH_ENTRY
*Item
;
220 High
= (sizeof (mUnicodeWidthTable
)) / (sizeof (UNICODE_WIDTH_ENTRY
)) - 1;
221 while (Low
<= High
) {
222 Index
= (Low
+ High
) >> 1;
223 Item
= &(mUnicodeWidthTable
[Index
]);
225 if (UnicodeChar
<= Item
->WChar
) {
232 if (UnicodeChar
> Item
->WChar
) {
234 } else if (UnicodeChar
<= mUnicodeWidthTable
[Index
- 1].WChar
) {
238 // Index - 1 < UnicodeChar <= Index. Found
252 Computes the display length of a Null-terminated Unicode String.
254 This function computes and returns the display length of the Null-terminated
255 Unicode string specified by String. If String is NULL then 0 is returned. If
256 any of the widths of the Unicode characters in String can not be determined,
257 then 0 is returned. The display width of String can be computed by summing the
258 display widths of each Unicode character in String. Unicode characters that
259 are narrow glyphs have a width of 1, and Unicode characters that are width glyphs
260 have a width of 2. If String is not aligned on a 16-bit boundary, then ASSERT().
262 @param String A pointer to a Null-terminated Unicode string.
264 @return The display length of the Null-terminated Unicode string specified by String.
269 UnicodeStringDisplayLength (
270 IN CONST CHAR16
*String
276 if (String
== NULL
) {
281 while (*String
!= 0) {
282 Width
= GetGlyphWidth (*String
);
295 Count the storage space of a Unicode string.
297 This function handles the Unicode string with NARROW_CHAR
298 and WIDE_CHAR control characters. NARROW_HCAR and WIDE_CHAR
299 does not count in the resultant output. If a WIDE_CHAR is
300 hit, then 2 Unicode character will consume an output storage
301 space with size of CHAR16 till a NARROW_CHAR is hit.
303 @param String The input string to be counted.
304 @param LimitLen Whether need to limit the string length.
305 @param MaxWidth The max length this function supported.
306 @param Offset The max index of the string can be show out.
308 @return Storage space for the input string.
312 UefiLibGetStringWidth (
321 UINTN IncrementValue
;
323 if (String
== NULL
) {
333 // Advance to the null-terminator or to the first width directive
335 for (;(String
[Index
] != NARROW_CHAR
) && (String
[Index
] != WIDE_CHAR
) && (String
[Index
] != 0); Index
++) {
336 Count
= Count
+ IncrementValue
;
338 if (LimitLen
&& Count
> MaxWidth
) {
344 // We hit the null-terminator, we now have a count
346 if (String
[Index
] == 0) {
350 if (LimitLen
&& Count
> MaxWidth
) {
356 // We encountered a narrow directive - strip it from the size calculation since it doesn't get printed
357 // and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2)
359 if (String
[Index
] == NARROW_CHAR
) {
361 // Skip to the next character
367 // Skip to the next character
372 } while (String
[Index
] != 0);
374 return Count
* sizeof (CHAR16
);
378 Draws a dialog box to the console output device specified by
379 ConOut defined in the EFI_SYSTEM_TABLE and waits for a keystroke
380 from the console input device specified by ConIn defined in the
383 If there are no strings in the variable argument list, then ASSERT().
384 If all the strings in the variable argument list are empty, then ASSERT().
386 @param[in] Attribute Specifies the foreground and background color of the popup.
387 @param[out] Key A pointer to the EFI_KEY value of the key that was
388 pressed. This is an optional parameter that may be NULL.
389 If it is NULL then no wait for a keypress will be performed.
390 @param[in] ... The variable argument list that contains pointers to Null-
391 terminated Unicode strings to display in the dialog box.
392 The variable argument list is terminated by a NULL.
399 OUT EFI_INPUT_KEY
*Key
, OPTIONAL
405 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*ConOut
;
406 EFI_SIMPLE_TEXT_OUTPUT_MODE SavedConsoleMode
;
420 // Determine the length of the longest line in the popup and the the total
421 // number of lines in the popup
423 VA_START (Args
, Key
);
426 while ((String
= VA_ARG (Args
, CHAR16
*)) != NULL
) {
427 MaxLength
= MAX (MaxLength
, UefiLibGetStringWidth (String
, FALSE
, 0, NULL
) / 2);
433 // If the total number of lines in the popup is zero, then ASSERT()
435 ASSERT (NumberOfLines
!= 0);
438 // If the maximum length of all the strings is zero, then ASSERT()
440 ASSERT (MaxLength
!= 0);
443 // Cache a pointer to the Simple Text Output Protocol in the EFI System Table
445 ConOut
= gST
->ConOut
;
448 // Save the current console cursor position and attributes
450 CopyMem (&SavedConsoleMode
, ConOut
->Mode
, sizeof (SavedConsoleMode
));
453 // Retrieve the number of columns and rows in the current console mode
455 ConOut
->QueryMode (ConOut
, SavedConsoleMode
.Mode
, &Columns
, &Rows
);
458 // Disable cursor and set the foreground and background colors specified by Attribute
460 ConOut
->EnableCursor (ConOut
, FALSE
);
461 ConOut
->SetAttribute (ConOut
, Attribute
);
464 // Limit NumberOfLines to height of the screen minus 3 rows for the box itself
466 NumberOfLines
= MIN (NumberOfLines
, Rows
- 3);
469 // Limit MaxLength to width of the screen minus 2 columns for the box itself
471 MaxLength
= MIN (MaxLength
, Columns
- 2);
474 // Compute the starting row and starting column for the popup
476 Row
= (Rows
- (NumberOfLines
+ 3)) / 2;
477 Column
= (Columns
- (MaxLength
+ 2)) / 2;
480 // Allocate a buffer for a single line of the popup with borders and a Null-terminator
482 Line
= AllocateZeroPool ((MaxLength
+ 3) * sizeof (CHAR16
));
483 ASSERT (Line
!= NULL
);
486 // Draw top of popup box
488 SetMem16 (Line
, (MaxLength
+ 2) * 2, BOXDRAW_HORIZONTAL
);
489 Line
[0] = BOXDRAW_DOWN_RIGHT
;
490 Line
[MaxLength
+ 1] = BOXDRAW_DOWN_LEFT
;
491 Line
[MaxLength
+ 2] = L
'\0';
492 ConOut
->SetCursorPosition (ConOut
, Column
, Row
++);
493 ConOut
->OutputString (ConOut
, Line
);
496 // Draw middle of the popup with strings
498 VA_START (Args
, Key
);
499 while ((String
= VA_ARG (Args
, CHAR16
*)) != NULL
&& NumberOfLines
> 0) {
500 SetMem16 (Line
, (MaxLength
+ 2) * 2, L
' ');
501 Line
[0] = BOXDRAW_VERTICAL
;
502 Line
[MaxLength
+ 1] = BOXDRAW_VERTICAL
;
503 Line
[MaxLength
+ 2] = L
'\0';
504 ConOut
->SetCursorPosition (ConOut
, Column
, Row
);
505 ConOut
->OutputString (ConOut
, Line
);
506 Length
= UefiLibGetStringWidth (String
, FALSE
, 0, NULL
) / 2;
507 if (Length
<= MaxLength
) {
509 // Length <= MaxLength
511 ConOut
->SetCursorPosition (ConOut
, Column
+ 1 + (MaxLength
- Length
) / 2, Row
++);
512 ConOut
->OutputString (ConOut
, String
);
515 // Length > MaxLength
517 UefiLibGetStringWidth (String
, TRUE
, MaxLength
, &Length
);
518 TmpString
= AllocateZeroPool ((Length
+ 1) * sizeof (CHAR16
));
519 ASSERT (TmpString
!= NULL
);
520 StrnCpyS (TmpString
, Length
+ 1, String
, Length
- 3);
521 StrCatS (TmpString
, Length
+ 1, L
"...");
523 ConOut
->SetCursorPosition (ConOut
, Column
+ 1, Row
++);
524 ConOut
->OutputString (ConOut
, TmpString
);
525 FreePool (TmpString
);
532 // Draw bottom of popup box
534 SetMem16 (Line
, (MaxLength
+ 2) * 2, BOXDRAW_HORIZONTAL
);
535 Line
[0] = BOXDRAW_UP_RIGHT
;
536 Line
[MaxLength
+ 1] = BOXDRAW_UP_LEFT
;
537 Line
[MaxLength
+ 2] = L
'\0';
538 ConOut
->SetCursorPosition (ConOut
, Column
, Row
++);
539 ConOut
->OutputString (ConOut
, Line
);
542 // Free the allocated line buffer
547 // Restore the cursor visibility, position, and attributes
549 ConOut
->EnableCursor (ConOut
, SavedConsoleMode
.CursorVisible
);
550 ConOut
->SetCursorPosition (ConOut
, SavedConsoleMode
.CursorColumn
, SavedConsoleMode
.CursorRow
);
551 ConOut
->SetAttribute (ConOut
, SavedConsoleMode
.Attribute
);
554 // Wait for a keystroke
558 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, Key
);
559 if (!EFI_ERROR (Status
)) {
564 // If we encounter error, continue to read another key in.
566 if (Status
!= EFI_NOT_READY
) {
569 gBS
->WaitForEvent (1, &gST
->ConIn
->WaitForKey
, &EventIndex
);