Allow reading font name from Windows `name` table entry.

This change adds support for reading font names from the TTF table from
both Mac/MacRoman and Windows/Unicode name entries. Before, only
Mac/MacRoman was supported.

Bug: pdfium:1427
Change-Id: I435265c43d4fb85664323d6a674244690e60cc21
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/62830
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fxcrt/widestring.cpp b/core/fxcrt/widestring.cpp
index 5a637cb..8da9e8d 100644
--- a/core/fxcrt/widestring.cpp
+++ b/core/fxcrt/widestring.cpp
@@ -947,6 +947,24 @@
   return result;
 }
 
+WideString WideString::FromUTF16BE(const unsigned short* wstr, size_t wlen) {
+  if (!wstr || wlen == 0)
+    return WideString();
+
+  WideString result;
+  {
+    // Span's lifetime must end before ReleaseBuffer() below.
+    pdfium::span<wchar_t> buf = result.GetBuffer(wlen);
+    for (size_t i = 0; i < wlen; i++) {
+      auto wch = wstr[i];
+      wch = (wch >> 8) | (wch << 8);
+      buf[i] = wch;
+    }
+  }
+  result.ReleaseBuffer(wlen);
+  return result;
+}
+
 void WideString::SetAt(size_t index, wchar_t c) {
   ASSERT(IsValidIndex(index));
   ReallocBeforeWrite(m_pData->m_nDataLength);
diff --git a/core/fxcrt/widestring.h b/core/fxcrt/widestring.h
index 2723e95..3373067 100644
--- a/core/fxcrt/widestring.h
+++ b/core/fxcrt/widestring.h
@@ -67,6 +67,8 @@
   static WideString FromUTF8(ByteStringView str) WARN_UNUSED_RESULT;
   static WideString FromUTF16LE(const unsigned short* str,
                                 size_t len) WARN_UNUSED_RESULT;
+  static WideString FromUTF16BE(const unsigned short* wstr,
+                                size_t wlen) WARN_UNUSED_RESULT;
 
   static size_t WStringLength(const unsigned short* str) WARN_UNUSED_RESULT;
 
diff --git a/core/fxge/fx_font.cpp b/core/fxge/fx_font.cpp
index fc47a33c..fe2d6b1 100644
--- a/core/fxge/fx_font.cpp
+++ b/core/fxge/fx_font.cpp
@@ -13,6 +13,12 @@
 
 namespace {
 
+// These numbers come from the OpenType name table specification.
+constexpr uint16_t kNamePlatformMac = 1;
+constexpr uint16_t kNameMacEncodingRoman = 0;
+constexpr uint16_t kNamePlatformWindows = 3;
+constexpr uint16_t kNameWindowsEncodingUnicode = 1;
+
 ByteString GetStringFromTable(pdfium::span<const uint8_t> string_span,
                               uint16_t offset,
                               uint16_t length) {
@@ -88,11 +94,31 @@
 
   for (uint32_t i = 0; i < name_count;
        i++, name_table = name_table.subspan(12)) {
-    if (GET_TT_SHORT(&name_table[6]) == name_id &&
-        GET_TT_SHORT(&name_table[0]) == 1 &&
-        GET_TT_SHORT(&name_table[2]) == 0) {
-      return GetStringFromTable(string_span, GET_TT_SHORT(&name_table[10]),
-                                GET_TT_SHORT(&name_table[8]));
+    if (GET_TT_SHORT(&name_table[6]) == name_id) {
+      const uint16_t platform_identifier = GET_TT_SHORT(name_table);
+      const uint16_t platform_encoding = GET_TT_SHORT(&name_table[2]);
+
+      if (platform_identifier == kNamePlatformMac &&
+          platform_encoding == kNameMacEncodingRoman) {
+        return GetStringFromTable(string_span, GET_TT_SHORT(&name_table[10]),
+                                  GET_TT_SHORT(&name_table[8]));
+      }
+      if (platform_identifier == kNamePlatformWindows &&
+          platform_encoding == kNameWindowsEncodingUnicode) {
+        // This name is always UTF16-BE and we have to convert it to UTF8.
+        ByteString utf16_be =
+            GetStringFromTable(string_span, GET_TT_SHORT(&name_table[10]),
+                               GET_TT_SHORT(&name_table[8]));
+        if (utf16_be.IsEmpty() || utf16_be.GetLength() % 2 != 0) {
+          return ByteString();
+        }
+
+        pdfium::span<const uint8_t> raw_span = utf16_be.raw_span();
+        return WideString::FromUTF16BE(
+                   reinterpret_cast<const uint16_t*>(raw_span.data()),
+                   raw_span.size() / 2)
+            .ToUTF8();
+      }
     }
   }
   return ByteString();
diff --git a/core/fxge/fx_font_unittest.cpp b/core/fxge/fx_font_unittest.cpp
index 1f98645..e550f0a 100644
--- a/core/fxge/fx_font_unittest.cpp
+++ b/core/fxge/fx_font_unittest.cpp
@@ -2,9 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <string>
+
+#include "core/fxge/cfx_folderfontinfo.h"
+#include "core/fxge/cfx_fontmapper.h"
 #include "core/fxge/fx_font.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
+#include "testing/utils/path_service.h"
 
 TEST(FXFontTest, PDF_AdobeNameFromUnicode) {
   EXPECT_STREQ("", PDF_AdobeNameFromUnicode(0x0000).c_str());
@@ -15,3 +20,25 @@
   EXPECT_STREQ("angkhankhuthai", PDF_AdobeNameFromUnicode(0x0e5a).c_str());
   EXPECT_STREQ("Euro", PDF_AdobeNameFromUnicode(0x20ac).c_str());
 }
+
+TEST(FXFontTest, ReadFontNameFromMicrosoftEntries) {
+  std::string test_data_dir;
+  PathService::GetTestDataDir(&test_data_dir);
+  ASSERT(!test_data_dir.empty());
+
+  CFX_FontMapper font_mapper(nullptr);
+
+  {
+    // |folder_font_info| has to be deallocated before the |font_mapper| or we
+    // run into UnownedPtr class issues with ASAN.
+    CFX_FolderFontInfo folder_font_info;
+    folder_font_info.AddPath(
+        (test_data_dir + PATH_SEPARATOR + "font_tests").c_str());
+
+    font_mapper.SetSystemFontInfo(SystemFontInfoIface::CreateDefault(nullptr));
+    ASSERT_TRUE(folder_font_info.EnumFontList(&font_mapper));
+  }
+
+  ASSERT_EQ(1, font_mapper.GetFaceSize());
+  ASSERT_EQ("Test", font_mapper.GetFaceName(0));
+}
diff --git a/testing/resources/font_tests/name_windows.ttf b/testing/resources/font_tests/name_windows.ttf
new file mode 100644
index 0000000..019ecef
--- /dev/null
+++ b/testing/resources/font_tests/name_windows.ttf
Binary files differ