Home | History | Annotate | Download | only in FrameworkUefiLib
      1 /** @file
      2   This module provide help function for displaying unicode string.
      3 
      4   Copyright (c) 2006 - 2012, 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
      9 
     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.
     12 
     13 **/
     14 
     15 
     16 
     17 
     18 #include "UefiLibInternal.h"
     19 
     20 typedef struct {
     21   CHAR16  WChar;
     22   UINT32  Width;
     23 } UNICODE_WIDTH_ENTRY;
     24 
     25 GLOBAL_REMOVE_IF_UNREFERENCED CONST UNICODE_WIDTH_ENTRY mUnicodeWidthTable[] = {
     26   //
     27   // General script area
     28   //
     29   {(CHAR16)0x1FFF,  1},
     30   /*
     31    * Merge the blocks and replace them with the above entry as they fall to
     32    * the same category and they are all narrow glyph. This will reduce search
     33    * time and table size. The merge will omit the reserved code.
     34    *
     35    * Remove the above item if below is un-commented.
     36    *
     37   {(CHAR16)0x007F,  1},       // C0 controls and basic Latin. 0x0000-0x007F
     38   {(CHAR16)0x00FF,  1},       // C1 controls and Latin-1 support. 0x0080-0x00FF
     39   {(CHAR16)0x017F,  1},       // Latin extended-A. 0x0100-0x017F
     40   {(CHAR16)0x024F,  1},       // Latin extended-B. 0x0180-0x024F
     41   {(CHAR16)0x02AF,  1},       // IPA extensions. 0x0250-0x02AF
     42   {(CHAR16)0x02FF,  1},       // Spacing modifier letters. 0x02B0-0x02FF
     43   {(CHAR16)0x036F,  1},       // Combining diacritical marks. 0x0300-0x036F
     44   {(CHAR16)0x03FF,  1},       // Greek. 0x0370-0x03FF
     45   {(CHAR16)0x04FF,  1},       // Cyrillic. 0x0400-0x04FF
     46   {(CHAR16)0x052F,  0},       // Unassigned. As Armenian in ver3.0. 0x0500-0x052F
     47   {(CHAR16)0x058F,  1},       // Armenian. 0x0530-0x058F
     48   {(CHAR16)0x05FF,  1},       // Hebrew. 0x0590-0x05FF
     49   {(CHAR16)0x06FF,  1},       // Arabic. 0x0600-0x06FF
     50   {(CHAR16)0x08FF,  0},       // Unassigned. 0x0700-0x08FF
     51   {(CHAR16)0x097F,  1},       // Devanagari. 0x0900-0x097F
     52   {(CHAR16)0x09FF,  1},       // Bengali. 0x0980-0x09FF
     53   {(CHAR16)0x0A7F,  1},       // Gurmukhi. 0x0A00-0x0A7F
     54   {(CHAR16)0x0AFF,  1},       // Gujarati. 0x0A80-0x0AFF
     55   {(CHAR16)0x0B7F,  1},       // Oriya. 0x0B00-0x0B7F
     56   {(CHAR16)0x0BFF,  1},       // Tamil. (See page 7-92). 0x0B80-0x0BFF
     57   {(CHAR16)0x0C7F,  1},       // Telugu. 0x0C00-0x0C7F
     58   {(CHAR16)0x0CFF,  1},       // Kannada. (See page 7-100). 0x0C80-0x0CFF
     59   {(CHAR16)0x0D7F,  1},       // Malayalam (See page 7-104). 0x0D00-0x0D7F
     60   {(CHAR16)0x0DFF,  0},       // Unassigned. 0x0D80-0x0DFF
     61   {(CHAR16)0x0E7F,  1},       // Thai. 0x0E00-0x0E7F
     62   {(CHAR16)0x0EFF,  1},       // Lao. 0x0E80-0x0EFF
     63   {(CHAR16)0x0FBF,  1},       // Tibetan. 0x0F00-0x0FBF
     64   {(CHAR16)0x109F,  0},       // Unassigned. 0x0FC0-0x109F
     65   {(CHAR16)0x10FF,  1},       // Georgian. 0x10A0-0x10FF
     66   {(CHAR16)0x11FF,  1},       // Hangul Jamo. 0x1100-0x11FF
     67   {(CHAR16)0x1DFF,  0},       // Unassigned. 0x1200-0x1DFF
     68   {(CHAR16)0x1EFF,  1},       // Latin extended additional. 0x1E00-0x1EFF
     69   {(CHAR16)0x1FFF,  1},       // Greek extended. 0x1F00-0x1FFF
     70   *
     71   */
     72 
     73   //
     74   // Symbol area
     75   //
     76   {(CHAR16)0x2FFF,  1},
     77   /*
     78    * Merge the blocks and replace them with the above entry as they fall to
     79    * the same category and they are all narrow glyph. This will reduce search
     80    * time and table size. The merge will omit the reserved code.
     81    *
     82    * Remove the above item if below is un-commented.
     83    *
     84   {(CHAR16)0x206F,  1},       // General punctuation. (See page7-154). 0x200-0x206F
     85   {(CHAR16)0x209F,  1},       // Superscripts and subscripts. 0x2070-0x209F
     86   {(CHAR16)0x20CF,  1},       // Currency symbols. 0x20A0-0x20CF
     87   {(CHAR16)0x20FF,  1},       // Combining diacritical marks for symbols. 0x20D0-0x20FF
     88   {(CHAR16)0x214F,  1},       // Letterlike sympbols. 0x2100-0x214F
     89   {(CHAR16)0x218F,  1},       // Number forms. 0x2150-0x218F
     90   {(CHAR16)0x21FF,  1},       // Arrows. 0x2190-0x21FF
     91   {(CHAR16)0x22FF,  1},       // Mathematical operators. 0x2200-0x22FF
     92   {(CHAR16)0x23FF,  1},       // Miscellaneous technical. 0x2300-0x23FF
     93   {(CHAR16)0x243F,  1},       // Control pictures. 0x2400-0x243F
     94   {(CHAR16)0x245F,  1},       // Optical character recognition. 0x2440-0x245F
     95   {(CHAR16)0x24FF,  1},       // Enclosed alphanumerics. 0x2460-0x24FF
     96   {(CHAR16)0x257F,  1},       // Box drawing. 0x2500-0x257F
     97   {(CHAR16)0x259F,  1},       // Block elements. 0x2580-0x259F
     98   {(CHAR16)0x25FF,  1},       // Geometric shapes. 0x25A0-0x25FF
     99   {(CHAR16)0x26FF,  1},       // Miscellaneous symbols. 0x2600-0x26FF
    100   {(CHAR16)0x27BF,  1},       // Dingbats. 0x2700-0x27BF
    101   {(CHAR16)0x2FFF,  0},       // Reserved. 0x27C0-0x2FFF
    102   *
    103   */
    104 
    105   //
    106   // CJK phonetics and symbol area
    107   //
    108   {(CHAR16)0x33FF,  2},
    109   /*
    110    * Merge the blocks and replace them with the above entry as they fall to
    111    * the same category and they are all wide glyph. This will reduce search
    112    * time and table size. The merge will omit the reserved code.
    113    *
    114    * Remove the above item if below is un-commented.
    115    *
    116   {(CHAR16)0x303F,  2},       // CJK symbols and punctuation. 0x3000-0x303F
    117   {(CHAR16)0x309F,  2},       // Hiragana. 0x3040-0x309F
    118   {(CHAR16)0x30FF,  2},       // Katakana. 0x30A0-0x30FF
    119   {(CHAR16)0x312F,  2},       // Bopomofo. 0x3100-0x312F
    120   {(CHAR16)0x318F,  2},       // Hangul compatibility jamo. 0x3130-0x318F
    121   {(CHAR16)0x319F,  2},       // Kanbun. 0x3190-0x319F
    122   {(CHAR16)0x31FF,  0},       // Reserved. As Bopomofo extended in ver3.0. 0x31A0-0x31FF
    123   {(CHAR16)0x32FF,  2},       // Enclosed CJK letters and months. 0x3200-0x32FF
    124   {(CHAR16)0x33FF,  2},       // CJK compatibility. 0x3300-0x33FF
    125   *
    126   */
    127 
    128   //
    129   // CJK ideograph area
    130   //
    131   {(CHAR16)0x9FFF,  2},
    132   /*
    133    * Merge the blocks and replace them with the above entry as they fall to
    134    * the same category and they are all wide glyph. This will reduce search
    135    * time and table size. The merge will omit the reserved code.
    136    *
    137    * Remove the above item if below is un-commented.
    138    *
    139   {(CHAR16)0x4DFF,  0},       // Reserved. 0x3400-0x4DBF as CJK unified ideographs
    140                       // extension A in ver3.0. 0x3400-0x4DFF
    141   {(CHAR16)0x9FFF,  2},       // CJK unified ideographs. 0x4E00-0x9FFF
    142   *
    143   */
    144 
    145   //
    146   // Reserved
    147   //
    148   {(CHAR16)0xABFF,  0},       // Reserved. 0xA000-0xA490 as Yi syllables. 0xA490-0xA4D0
    149   // as Yi radicals in ver3.0. 0xA000-0xABFF
    150   //
    151   // Hangul syllables
    152   //
    153   {(CHAR16)0xD7FF,  2},
    154   /*
    155    * Merge the blocks and replace them with the above entry as they fall to
    156    * the same category and they are all wide glyph. This will reduce search
    157    * time and table size. The merge will omit the reserved code.
    158    *
    159    * Remove the above item if below is un-commented.
    160    *
    161   {(CHAR16)0xD7A3,  2},       // Hangul syllables. 0xAC00-0xD7A3
    162   {(CHAR16)0xD7FF,  0},       // Reserved. 0xD7A3-0xD7FF
    163   *
    164   */
    165 
    166   //
    167   // Surrogates area
    168   //
    169   {(CHAR16)0xDFFF,  0},       // Surrogates, not used now. 0xD800-0xDFFF
    170 
    171   //
    172   // Private use area
    173   //
    174   {(CHAR16)0xF8FF,  0},       // Private use area. 0xE000-0xF8FF
    175 
    176   //
    177   // Compatibility area and specials
    178   //
    179   {(CHAR16)0xFAFF,  2},       // CJK compatibility ideographs. 0xF900-0xFAFF
    180   {(CHAR16)0xFB4F,  1},       // Alphabetic presentation forms. 0xFB00-0xFB4F
    181   {(CHAR16)0xFDFF,  1},       // Arabic presentation forms-A. 0xFB50-0xFDFF
    182   {(CHAR16)0xFE1F,  0},       // Reserved. As variation selectors in ver3.0. 0xFE00-0xFE1F
    183   {(CHAR16)0xFE2F,  1},       // Combining half marks. 0xFE20-0xFE2F
    184   {(CHAR16)0xFE4F,  2},       // CJK compatibility forms. 0xFE30-0xFE4F
    185   {(CHAR16)0xFE6F,  1},       // Small Form Variants. 0xFE50-0xFE6F
    186   {(CHAR16)0xFEFF,  1},       // Arabic presentation forms-B. 0xFE70-0xFEFF
    187   {(CHAR16)0xFFEF,  1},       // Half width and full width forms. 0xFF00-0xFFEF
    188   {(CHAR16)0xFFFF,  0},       // Speicials. 0xFFF0-0xFFFF
    189 };
    190 
    191 /**
    192   Retrieves the width of a Unicode character.
    193 
    194   This function computes and returns the width of the Unicode character specified
    195   by UnicodeChar.
    196 
    197   @param  UnicodeChar   A Unicode character.
    198 
    199   @retval 0             The width if UnicodeChar could not be determined.
    200   @retval 1             UnicodeChar is a narrow glyph.
    201   @retval 2             UnicodeChar is a wide glyph.
    202 
    203 **/
    204 UINTN
    205 EFIAPI
    206 GetGlyphWidth (
    207   IN CHAR16                         UnicodeChar
    208   )
    209 {
    210   UINTN                             Index;
    211   UINTN                             Low;
    212   UINTN                             High;
    213   CONST UNICODE_WIDTH_ENTRY         *Item;
    214 
    215   Item  = NULL;
    216   Low   = 0;
    217   High  = (sizeof (mUnicodeWidthTable)) / (sizeof (UNICODE_WIDTH_ENTRY)) - 1;
    218   while (Low <= High) {
    219     Index = (Low + High) >> 1;
    220     Item  = &(mUnicodeWidthTable[Index]);
    221     if (Index == 0) {
    222       if (UnicodeChar <= Item->WChar) {
    223         break;
    224       }
    225 
    226       return 0;
    227     }
    228 
    229     if (UnicodeChar > Item->WChar) {
    230       Low = Index + 1;
    231     } else if (UnicodeChar <= mUnicodeWidthTable[Index - 1].WChar) {
    232       High = Index - 1;
    233     } else {
    234       //
    235       // Index - 1 < UnicodeChar <= Index. Found
    236       //
    237       break;
    238     }
    239   }
    240 
    241   if (Low <= High) {
    242     return Item->Width;
    243   }
    244 
    245   return 0;
    246 }
    247 
    248 /**
    249   Computes the display length of a Null-terminated Unicode String.
    250 
    251   This function computes and returns the display length of the Null-terminated Unicode
    252   string specified by String.  If String is NULL then 0 is returned. If any of the widths
    253   of the Unicode characters in String can not be determined, then 0 is returned. The display
    254   width of String can be computed by summing the display widths of each Unicode character
    255   in String.  Unicode characters that are narrow glyphs have a width of 1, and Unicode
    256   characters that are width glyphs have a width of 2.
    257   If String is not aligned on a 16-bit boundary, then ASSERT().
    258 
    259   @param  String   A pointer to a Null-terminated Unicode string.
    260 
    261   @return          The display length of the Null-terminated Unicode string specified by String.
    262 
    263 **/
    264 UINTN
    265 EFIAPI
    266 UnicodeStringDisplayLength (
    267   IN CONST CHAR16                   *String
    268   )
    269 {
    270   UINTN                             Length;
    271   UINTN                             Width;
    272 
    273   if (String == NULL) {
    274     return 0;
    275   }
    276 
    277   Length = 0;
    278   while (*String != 0) {
    279     Width = GetGlyphWidth (*String);
    280     if (Width == 0) {
    281       return 0;
    282     }
    283 
    284     Length += Width;
    285     String++;
    286   }
    287 
    288   return Length;
    289 }
    290 
    291 /**
    292   Draws a dialog box to the console output device specified by
    293   ConOut defined in the EFI_SYSTEM_TABLE and waits for a keystroke
    294   from the console input device specified by ConIn defined in the
    295   EFI_SYSTEM_TABLE.
    296 
    297   If there are no strings in the variable argument list, then ASSERT().
    298   If all the strings in the variable argument list are empty, then ASSERT().
    299 
    300   @param[in]   Attribute  Specifies the foreground and background color of the popup.
    301   @param[out]  Key        A pointer to the EFI_KEY value of the key that was
    302                           pressed.  This is an optional parameter that may be NULL.
    303                           If it is NULL then no wait for a keypress will be performed.
    304   @param[in]  ...         The variable argument list that contains pointers to Null-
    305                           terminated Unicode strings to display in the dialog box.
    306                           The variable argument list is terminated by a NULL.
    307 
    308 **/
    309 VOID
    310 EFIAPI
    311 CreatePopUp (
    312   IN  UINTN          Attribute,
    313   OUT EFI_INPUT_KEY  *Key,      OPTIONAL
    314   ...
    315   )
    316 {
    317   EFI_STATUS                       Status;
    318   VA_LIST                          Args;
    319   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *ConOut;
    320   EFI_SIMPLE_TEXT_OUTPUT_MODE      SavedConsoleMode;
    321   UINTN                            Columns;
    322   UINTN                            Rows;
    323   UINTN                            Column;
    324   UINTN                            Row;
    325   UINTN                            NumberOfLines;
    326   UINTN                            MaxLength;
    327   CHAR16                           *String;
    328   UINTN                            Length;
    329   CHAR16                           *Line;
    330   UINTN                            EventIndex;
    331 
    332   //
    333   // Determine the length of the longest line in the popup and the the total
    334   // number of lines in the popup
    335   //
    336   VA_START (Args, Key);
    337   MaxLength = 0;
    338   NumberOfLines = 0;
    339   while ((String = VA_ARG (Args, CHAR16 *)) != NULL) {
    340     MaxLength = MAX (MaxLength, StrLen (String));
    341     NumberOfLines++;
    342   }
    343   VA_END (Args);
    344 
    345   //
    346   // If the total number of lines in the popup is zero, then ASSERT()
    347   //
    348   ASSERT (NumberOfLines != 0);
    349 
    350   //
    351   // If the maximum length of all the strings is zero, then ASSERT()
    352   //
    353   ASSERT (MaxLength != 0);
    354 
    355   //
    356   // Cache a pointer to the Simple Text Output Protocol in the EFI System Table
    357   //
    358   ConOut = gST->ConOut;
    359 
    360   //
    361   // Save the current console cursor position and attributes
    362   //
    363   CopyMem (&SavedConsoleMode, ConOut->Mode, sizeof (SavedConsoleMode));
    364 
    365   //
    366   // Retrieve the number of columns and rows in the current console mode
    367   //
    368   ConOut->QueryMode (ConOut, SavedConsoleMode.Mode, &Columns, &Rows);
    369 
    370   //
    371   // Disable cursor and set the foreground and background colors specified by Attribute
    372   //
    373   ConOut->EnableCursor (ConOut, FALSE);
    374   ConOut->SetAttribute (ConOut, Attribute);
    375 
    376   //
    377   // Limit NumberOfLines to height of the screen minus 3 rows for the box itself
    378   //
    379   NumberOfLines = MIN (NumberOfLines, Rows - 3);
    380 
    381   //
    382   // Limit MaxLength to width of the screen minus 2 columns for the box itself
    383   //
    384   MaxLength = MIN (MaxLength, Columns - 2);
    385 
    386   //
    387   // Compute the starting row and starting column for the popup
    388   //
    389   Row    = (Rows - (NumberOfLines + 3)) / 2;
    390   Column = (Columns - (MaxLength + 2)) / 2;
    391 
    392   //
    393   // Allocate a buffer for a single line of the popup with borders and a Null-terminator
    394   //
    395   Line = AllocateZeroPool ((MaxLength + 3) * sizeof (CHAR16));
    396   ASSERT (Line != NULL);
    397 
    398   //
    399   // Draw top of popup box
    400   //
    401   SetMem16 (Line, (MaxLength + 2) * 2, BOXDRAW_HORIZONTAL);
    402   Line[0]             = BOXDRAW_DOWN_RIGHT;
    403   Line[MaxLength + 1] = BOXDRAW_DOWN_LEFT;
    404   Line[MaxLength + 2] = L'\0';
    405   ConOut->SetCursorPosition (ConOut, Column, Row++);
    406   ConOut->OutputString (ConOut, Line);
    407 
    408   //
    409   // Draw middle of the popup with strings
    410   //
    411   VA_START (Args, Key);
    412   while ((String = VA_ARG (Args, CHAR16 *)) != NULL && NumberOfLines > 0) {
    413     Length = StrLen (String);
    414     SetMem16 (Line, (MaxLength + 2) * 2, L' ');
    415     if (Length <= MaxLength) {
    416       //
    417       // Length <= MaxLength
    418       //
    419       CopyMem (Line + 1 + (MaxLength - Length) / 2, String , Length * sizeof (CHAR16));
    420     } else {
    421       //
    422       // Length > MaxLength
    423       //
    424       CopyMem (Line + 1, String + (Length - MaxLength) / 2 , MaxLength * sizeof (CHAR16));
    425     }
    426     Line[0]             = BOXDRAW_VERTICAL;
    427     Line[MaxLength + 1] = BOXDRAW_VERTICAL;
    428     Line[MaxLength + 2] = L'\0';
    429     ConOut->SetCursorPosition (ConOut, Column, Row++);
    430     ConOut->OutputString (ConOut, Line);
    431     NumberOfLines--;
    432   }
    433   VA_END (Args);
    434 
    435   //
    436   // Draw bottom of popup box
    437   //
    438   SetMem16 (Line, (MaxLength + 2) * 2, BOXDRAW_HORIZONTAL);
    439   Line[0]             = BOXDRAW_UP_RIGHT;
    440   Line[MaxLength + 1] = BOXDRAW_UP_LEFT;
    441   Line[MaxLength + 2] = L'\0';
    442   ConOut->SetCursorPosition (ConOut, Column, Row++);
    443   ConOut->OutputString (ConOut, Line);
    444 
    445   //
    446   // Free the allocated line buffer
    447   //
    448   FreePool (Line);
    449 
    450   //
    451   // Restore the cursor visibility, position, and attributes
    452   //
    453   ConOut->EnableCursor      (ConOut, SavedConsoleMode.CursorVisible);
    454   ConOut->SetCursorPosition (ConOut, SavedConsoleMode.CursorColumn, SavedConsoleMode.CursorRow);
    455   ConOut->SetAttribute      (ConOut, SavedConsoleMode.Attribute);
    456 
    457   //
    458   // Wait for a keystroke
    459   //
    460   if (Key != NULL) {
    461     while (TRUE) {
    462       Status = gST->ConIn->ReadKeyStroke (gST->ConIn, Key);
    463       if (!EFI_ERROR (Status)) {
    464         break;
    465       }
    466 
    467       //
    468       // If we encounter error, continue to read another key in.
    469       //
    470       if (Status != EFI_NOT_READY) {
    471         continue;
    472       }
    473       gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
    474     }
    475   }
    476 }
    477