]> git.proxmox.com Git - mirror_edk2.git/blobdiff - EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/ProcessOptions.c
Fix the issue of Wide char help strings cannot break into multiple lines correctly
[mirror_edk2.git] / EdkModulePkg / Universal / UserInterface / SetupBrowser / Dxe / ProcessOptions.c
index a2aa50fbd517127ddcdd0059e37e9b0a346d852e..2306714537a6bcc54211c08e68b234ac73804b1d 100644 (file)
@@ -1,6 +1,7 @@
-/*++\r
-\r
-Copyright (c) 2006, Intel Corporation                                                         \r
+/**@file\r
+       Implementation for handling the User Interface option processing.\r
+       \r
+Copyright (c) 2006 - 2007 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
@@ -9,17 +10,7 @@ http://opensource.org/licenses/bsd-license.php
 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
 \r
-Module Name:\r
-\r
-  ProcessOptions.c\r
-\r
-Abstract:\r
-  \r
-  Implementation for handling the User Interface option processing.\r
-\r
-Revision History\r
-\r
---*/\r
+**/\r
 \r
 #include "Setup.h"\r
 #include "Ui.h"\r
@@ -1201,203 +1192,215 @@ ProcessOptions (
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  Split StringPtr to several lines of strings stored in FormattedString and the glyph width of \r
+  each line cannot exceed gHelpBlockWidth.\r
+\r
+  @param StringPtr          The pointer of string\r
+  @param FormattedString    The pointer of format string\r
+  @param RowCount           The count of row \r
+  \r
+**/\r
 VOID\r
 ProcessHelpString (\r
-  IN  CHAR16                      *StringPtr,\r
-  OUT CHAR16                      **FormattedString,\r
-  IN  UINTN                       RowCount\r
+  IN  CHAR16  *StringPtr,\r
+  OUT CHAR16  **FormattedString,\r
+  IN  UINTN   RowCount\r
   )\r
 {\r
+  CONST UINTN BlockWidth = (UINTN) gHelpBlockWidth - 1;\r
+  UINTN AllocateSize;\r
+  //\r
+  // [PrevCurrIndex, CurrIndex) forms a range of a screen-line\r
+  //\r
   UINTN CurrIndex;\r
-  UINTN PrevIndex;\r
-  UINTN SearchIndex;\r
-  UINTN PrevSearchIndex;\r
-  UINTN StringCount;\r
-  UINTN PageCount;\r
-\r
-  StringCount = 0;\r
-  PrevIndex   = 0;\r
-  CurrIndex   = gHelpBlockWidth - 1;\r
-\r
-  if (*FormattedString != NULL) {\r
-    gBS->FreePool (*FormattedString);\r
-    *FormattedString = NULL;\r
-  }\r
-\r
-  for (; CurrIndex > PrevIndex; CurrIndex--) {\r
-    //\r
-    // In the case where the string ended and a new one is immediately after it\r
-    // we need to check for the null-terminator and reset the CurrIndex\r
-    //\r
-    SearchIndex     = CurrIndex;\r
-    PrevSearchIndex = PrevIndex;\r
-\r
-    for (; SearchIndex > PrevSearchIndex; PrevSearchIndex++) {\r
-      if ((StringPtr[PrevSearchIndex] == CHAR_NULL) || (StringPtr[PrevSearchIndex] == CHAR_LINEFEED)) {\r
-        CurrIndex = PrevSearchIndex;\r
-        break;\r
-      }\r
-\r
-      if (StringPtr[PrevSearchIndex] == CHAR_CARRIAGE_RETURN) {\r
-        if (StringPtr[PrevSearchIndex + 1] == CHAR_LINEFEED) {\r
-          //\r
-          // Found a "\n",advance to the next new line.\r
-          //\r
-          CurrIndex = PrevSearchIndex + 1;\r
-          break;\r
-        } else {\r
-          //\r
-          // Found a "\r",return to the start of the current line.\r
-          //\r
-          PrevIndex = PrevSearchIndex + 1;\r
-          CurrIndex = PrevSearchIndex + gHelpBlockWidth;\r
-          continue;\r
-        }\r
-      }\r
-    }\r
-\r
-    //\r
-    // End of the string, thus stop counting.\r
-    //\r
-    if (StringPtr[CurrIndex] == CHAR_NULL) {\r
-      StringCount++;\r
-      break;\r
-    }\r
-    //\r
-    // The premise is that for every HELP_BLOCK_WIDTH we rewind\r
-    // until we find the first space.  That is the delimiter for\r
-    // the string, and we will then advance our CurrIndex another\r
-    // HELP_BLOCK_WIDTH and continue the process breaking the larger\r
-    // string into chunks that fit within the HELP_BLOCK_WIDTH requirements.\r
-    //\r
-    if (StringPtr[CurrIndex] == CHAR_SPACE) {\r
-      //\r
-      // How many strings have been found?\r
-      //\r
-      StringCount++;\r
-      PrevIndex = CurrIndex + 1;\r
-      CurrIndex = CurrIndex + gHelpBlockWidth;\r
-    }\r
-    //\r
-    // Found a Linefeed, advance to the next line.\r
-    //\r
-    if (StringPtr[CurrIndex] == CHAR_LINEFEED) {\r
-      StringCount++;\r
-      PrevIndex = CurrIndex + 1;\r
-      CurrIndex = CurrIndex + gHelpBlockWidth;\r
-    }\r
-  }\r
+  UINTN PrevCurrIndex;\r
+  UINTN LineCount;\r
+  UINTN VirtualLineCount;\r
   //\r
-  // endfor\r
+  // GlyphOffset stores glyph width of current screen-line\r
   //\r
-  // Round the value up one (doesn't hurt)\r
+  UINTN GlyphOffset;\r
   //\r
-  StringCount++;\r
-\r
+  // GlyphWidth equals to 2 if we meet width directive\r
   //\r
-  // Determine the number of pages this help string occupies\r
+  UINTN GlyphWidth;\r
   //\r
-  PageCount = StringCount / RowCount;\r
-  if (StringCount % RowCount > 0) {\r
-    PageCount++;\r
-  }\r
+  // during scanning, we remember the position of last space character\r
+  // in case that if next word cannot put in current line, we could restore back to the position\r
+  // of last space character\r
+  // while we should also remmeber the glyph width of the last space character for restoring\r
   //\r
-  // Convert the PageCount into lines so we can allocate the correct buffer size\r
+  UINTN LastSpaceIndex;\r
+  UINTN LastSpaceGlyphWidth;\r
   //\r
-  StringCount = PageCount * RowCount;\r
+  // every time we begin to form a new screen-line, we should remember glyph width of single character\r
+  // of last line\r
+  //\r
+  UINTN LineStartGlyphWidth;\r
+  UINTN *IndexArray;\r
+  UINTN *OldIndexArray;\r
 \r
   //\r
-  // We now know how many strings we will have, so we can allocate the\r
-  // space required for the array or strings.\r
+  // every three elements of IndexArray form a screen-line of string:[ IndexArray[i*3], IndexArray[i*3+1] )\r
+  // IndexArray[i*3+2] stores the initial glyph width of single character. to save this is because we want\r
+  // to bring the width directive of the last line to current screen-line.\r
+  // e.g.: "\wideabcde ... fghi", if "fghi" also has width directive but is splitted to the next screen-line \r
+  // different from that of "\wideabcde", we should remember the width directive.\r
   //\r
-  *FormattedString = AllocateZeroPool ((StringCount) * (gHelpBlockWidth + 1) * 2);\r
-  ASSERT (*FormattedString);\r
+  AllocateSize  = 0x20;\r
+  IndexArray    = AllocatePool (AllocateSize * sizeof (UINTN) * 3);\r
 \r
-  StringCount = 0;\r
-  PrevIndex   = 0;\r
-  CurrIndex   = gHelpBlockWidth - 1;\r
+  if (*FormattedString != NULL) {\r
+    FreePool (*FormattedString);\r
+    *FormattedString = NULL;\r
+  }\r
 \r
-  for (; CurrIndex > PrevIndex; CurrIndex--) {\r
-    //\r
-    // In the case where the string ended and a new one is immediately after it\r
-    // we need to check for the null-terminator and reset the CurrIndex\r
-    //\r
-    SearchIndex     = CurrIndex;\r
-    PrevSearchIndex = PrevIndex;\r
+  for (PrevCurrIndex = 0, CurrIndex  = 0, LineCount   = 0, LastSpaceIndex = 0, \r
+       IndexArray[0] = 0, GlyphWidth = 1, GlyphOffset = 0, LastSpaceGlyphWidth = 1, LineStartGlyphWidth = 1; \r
+       (StringPtr[CurrIndex] != CHAR_NULL); \r
+       CurrIndex ++) {\r
+\r
+    if (LineCount == AllocateSize) {\r
+      AllocateSize   += 0x10;\r
+      OldIndexArray  =  IndexArray;\r
+      IndexArray     =  AllocatePool (AllocateSize * sizeof (UINTN) * 3);\r
+      CopyMem (IndexArray, OldIndexArray, LineCount * sizeof (UINTN) * 3);\r
+      if (OldIndexArray != NULL) {\r
+        FreePool (OldIndexArray);\r
+      }\r
+    }\r
 \r
-    for (; SearchIndex > PrevSearchIndex; PrevSearchIndex++) {\r
-      if ((StringPtr[PrevSearchIndex] == CHAR_NULL) || (StringPtr[PrevSearchIndex] == CHAR_LINEFEED)) {\r
-        CurrIndex = PrevSearchIndex;\r
+    switch (StringPtr[CurrIndex]) {\r
+    \r
+      case NARROW_CHAR:\r
+      case WIDE_CHAR:\r
+        GlyphWidth = ((StringPtr[CurrIndex] == WIDE_CHAR) ? 2 : 1);\r
+        if (CurrIndex == 0) {\r
+          LineStartGlyphWidth = GlyphWidth;\r
+        }\r
         break;\r
-      }\r
 \r
-      if (StringPtr[PrevSearchIndex] == CHAR_CARRIAGE_RETURN) {\r
-        if (StringPtr[PrevSearchIndex + 1] == CHAR_LINEFEED) {\r
-          //\r
-          // Found a "\n",advance to the next new line.\r
-          //\r
-          CurrIndex = PrevSearchIndex + 1;\r
-          break;\r
-        } else {\r
+      //\r
+      // char is '\n'\r
+      // "\r\n" isn't handled here, handled by case CHAR_CARRIAGE_RETURN\r
+      //\r
+      case CHAR_LINEFEED:\r
+        //\r
+        // Store a range of string as a line\r
+        //\r
+        IndexArray[LineCount*3]   = PrevCurrIndex;\r
+        IndexArray[LineCount*3+1] = CurrIndex;\r
+        IndexArray[LineCount*3+2] = LineStartGlyphWidth;\r
+        LineCount ++;\r
+        //\r
+        // Reset offset and save begin position of line\r
+        //\r
+        GlyphOffset = 0;\r
+        LineStartGlyphWidth = GlyphWidth;\r
+        PrevCurrIndex = CurrIndex + 1;\r
+        break;\r
+\r
+      //\r
+      // char is '\r'\r
+      // "\r\n" and "\r" both are handled here\r
+      //\r
+      case CHAR_CARRIAGE_RETURN:\r
+        if (StringPtr[CurrIndex + 1] == CHAR_LINEFEED) {\r
           //\r
-          // Found a "\r",return to the start of the current line.\r
+          // next char is '\n'\r
           //\r
-          PrevIndex = PrevSearchIndex + 1;\r
-          CurrIndex = PrevSearchIndex + gHelpBlockWidth;\r
-          continue;\r
+          IndexArray[LineCount*3]   = PrevCurrIndex;\r
+          IndexArray[LineCount*3+1] = CurrIndex;\r
+          IndexArray[LineCount*3+2] = LineStartGlyphWidth;\r
+          LineCount ++;\r
+          CurrIndex ++;\r
         }\r
-      }\r
-    }\r
+        GlyphOffset = 0;\r
+        LineStartGlyphWidth = GlyphWidth;\r
+        PrevCurrIndex = CurrIndex + 1;\r
+        break;\r
 \r
-    //\r
-    // End of the string, thus stop counting.\r
-    //\r
-    if (StringPtr[CurrIndex] == CHAR_NULL) {\r
       //\r
-      // Copy the fragment to the FormattedString buffer\r
+      // char is space or other char\r
       //\r
-      StrnCpy ((FormattedString[0] + StringCount * gHelpBlockWidth), &StringPtr[PrevIndex], CurrIndex - PrevIndex);\r
-      StringCount++;\r
-      break;\r
+      default:\r
+        GlyphOffset     += GlyphWidth;\r
+        if (GlyphOffset >= BlockWidth) {\r
+          if (LastSpaceIndex > PrevCurrIndex) {\r
+            //\r
+            // LastSpaceIndex points to space inside current screen-line,\r
+            // restore to LastSpaceIndex\r
+            // (Otherwise the word is too long to fit one screen-line, just cut it)\r
+            //\r
+            CurrIndex  = LastSpaceIndex;\r
+            GlyphWidth = LastSpaceGlyphWidth;\r
+          } else if (GlyphOffset > BlockWidth) {\r
+            //\r
+            // the word is too long to fit one screen-line and we don't get the chance \r
+            // of GlyphOffset == BlockWidth because GlyphWidth = 2\r
+            //\r
+            CurrIndex --;\r
+          }\r
+          \r
+          IndexArray[LineCount*3]   = PrevCurrIndex;\r
+          IndexArray[LineCount*3+1] = CurrIndex + 1;\r
+          IndexArray[LineCount*3+2] = LineStartGlyphWidth;\r
+          LineStartGlyphWidth = GlyphWidth;\r
+          LineCount ++;\r
+          //\r
+          // Reset offset and save begin position of line\r
+          //\r
+          GlyphOffset                 = 0;\r
+          PrevCurrIndex               = CurrIndex + 1;\r
+        }\r
+\r
+        //\r
+        // LastSpaceIndex: remember position of last space\r
+        //\r
+        if (StringPtr[CurrIndex] == CHAR_SPACE) {\r
+          LastSpaceIndex      = CurrIndex;\r
+          LastSpaceGlyphWidth = GlyphWidth;\r
+        }\r
+        break;\r
     }\r
+  }\r
+\r
+  if (GlyphOffset > 0) {\r
+    IndexArray[LineCount*3]   = PrevCurrIndex;\r
+    IndexArray[LineCount*3+1] = CurrIndex;\r
+    IndexArray[LineCount*3+2] = GlyphWidth;\r
+    LineCount ++;\r
+  }\r
+\r
+  if (LineCount == 0) {\r
     //\r
-    // The premise is that for every HELP_BLOCK_WIDTH we rewind\r
-    // until we find the first space.  That is the delimiter for\r
-    // the string, and we will then advance our CurrIndex another\r
-    // HELP_BLOCK_WIDTH and continue the process breaking the larger\r
-    // string into chunks that fit within the HELP_BLOCK_WIDTH requirements.\r
+    // in case we meet null string\r
     //\r
-    if (StringPtr[CurrIndex] == CHAR_SPACE) {\r
-      //\r
-      // Copy the fragment to the FormattedString buffer\r
-      //\r
-      StrnCpy ((FormattedString[0] + StringCount * gHelpBlockWidth), &StringPtr[PrevIndex], CurrIndex - PrevIndex);\r
-      StringCount++;\r
-      PrevIndex = CurrIndex + 1;\r
-      CurrIndex = CurrIndex + gHelpBlockWidth;\r
-    }\r
+    IndexArray[0] = 0;\r
+    IndexArray[1] = 1;\r
     //\r
-    // Found a LineFeed, advance to the next line.\r
+    // we assume null string's glyph width is 1\r
     //\r
-    if (StringPtr[CurrIndex] == CHAR_LINEFEED) {\r
-      StringPtr[CurrIndex] = CHAR_SPACE;\r
-      //\r
-      // "\n" is represented as CHAR_CARRIAGE_RETURN + CHAR_LINEFEED,check this.\r
-      //\r
-      if (StringPtr[CurrIndex - 1] == CHAR_CARRIAGE_RETURN) {\r
-        StringPtr[CurrIndex - 1] = CHAR_SPACE;\r
-      }\r
+    IndexArray[1] = 1;\r
+    LineCount ++;\r
+  }\r
 \r
-      StrnCpy ((FormattedString[0] + StringCount * gHelpBlockWidth), &StringPtr[PrevIndex], CurrIndex - PrevIndex);\r
-      StringCount++;\r
-      PrevIndex = CurrIndex + 1;\r
-      CurrIndex = CurrIndex + gHelpBlockWidth;\r
-    }\r
+  VirtualLineCount = RowCount * (LineCount / RowCount + (LineCount % RowCount > 0));\r
+  *FormattedString = AllocateZeroPool (VirtualLineCount * (BlockWidth + 1) * sizeof (CHAR16) * 2);\r
+\r
+  for (CurrIndex = 0; CurrIndex < LineCount; CurrIndex ++) {\r
+    *(*FormattedString + CurrIndex * 2 * (BlockWidth + 1)) = (IndexArray[CurrIndex*3+2] == 2) ? WIDE_CHAR : NARROW_CHAR;\r
+    StrnCpy (\r
+      *FormattedString + CurrIndex * 2 * (BlockWidth + 1) + 1, \r
+      StringPtr + IndexArray[CurrIndex*3], \r
+      IndexArray[CurrIndex*3+1]-IndexArray[CurrIndex*3]\r
+      );\r
+  }\r
+\r
+  if (IndexArray != NULL) {\r
+    FreePool (IndexArray);\r
   }\r
-  //\r
-  // endfor\r
-  //\r
-  return ;\r
 }\r
 \r
 VOID\r
@@ -1484,11 +1487,16 @@ IfrToFormTag (
     break;\r
 \r
   case EFI_IFR_STRING_OP:\r
+    //\r
+    // Convert EFI_IFR_STRING.MinSize and EFI_IFR_STRING.MaxSize to actual minimum and maximum bytes\r
+    // and store to EFI_TAG.Minimum and EFI_TAG.Maximum\r
+    //\r
     TempValue = 0;\r
     CopyMem (&TempValue, &((EFI_IFR_STRING *) FormData)->MinSize, sizeof (UINT8));\r
     TempValue = (UINT16) (TempValue * 2);\r
     CopyMem (&TargetTag->Minimum, &TempValue, sizeof (UINT16));\r
 \r
+    TempValue = 0;\r
     CopyMem (&TempValue, &((EFI_IFR_STRING *) FormData)->MaxSize, sizeof (UINT8));\r
     TempValue = (UINT16) (TempValue * 2);\r
     CopyMem (&TargetTag->Maximum, &TempValue, sizeof (UINT16));\r
@@ -1505,6 +1513,7 @@ IfrToFormTag (
     TempValue = (UINT16) (TempValue * 2);\r
     CopyMem (&TargetTag->Minimum, &TempValue, sizeof (UINT16));\r
 \r
+    TempValue = 0;\r
     CopyMem (&TempValue, &((EFI_IFR_PASSWORD *) FormData)->MaxSize, sizeof (UINT8));\r
     TempValue = (UINT16) (TempValue * 2);\r
     CopyMem (&TargetTag->Maximum, &TempValue, sizeof (UINT16));\r