Improve TrueType font fallback check for glyph ID 0.

Change the heuristics used to check for font fallback when drawing
TrueType fonts with glyph ID 0. In some cases, 0 means use glyph 0, and
in other cases, it means the glyph is invalid. Right now, the code tries
to use a fallback font, and if that fails, go back to the original font.
Instead of doing this back-and-forth, look at the heuristics and decide
one way or the other.

Bug: chromium:1271578
Change-Id: I71a0a6607162602d8e3fba07e80546ed3a1ce548
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/91831
Reviewed-by: Nigi <nigi@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/render/charposlist.cpp b/core/fpdfapi/render/charposlist.cpp
index 6c171d2..c07ddbe 100644
--- a/core/fpdfapi/render/charposlist.cpp
+++ b/core/fpdfapi/render/charposlist.cpp
@@ -12,6 +12,32 @@
 #include "core/fxge/cfx_substfont.h"
 #include "core/fxge/text_char_pos.h"
 
+namespace {
+
+bool ShouldUseExistingFont(const CPDF_Font* font,
+                           uint32_t glyph_id,
+                           bool has_to_unicode) {
+  // Check for invalid glyph ID.
+  if (glyph_id == static_cast<uint32_t>(-1))
+    return false;
+
+  if (!font->IsTrueTypeFont())
+    return true;
+
+  // For TrueType fonts, a glyph ID of 0 may be invalid.
+  //
+  // When a "ToUnicode" entry exists in the font dictionary, it indicates
+  // a "ToUnicode" mapping file is used to convert from CIDs (which
+  // begins at decimal 0) to Unicode code. (See ToUnicode Mapping File
+  // Tutorial - Adobe
+  // https://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/5411.ToUnicode.pdf
+  // and
+  // https://www.freetype.org/freetype2/docs/tutorial/step1.html#section-6)
+  return glyph_id != 0 || has_to_unicode;
+}
+
+}  // namespace
+
 std::vector<TextCharPos> GetCharPosList(pdfium::span<const uint32_t> char_codes,
                                         pdfium::span<const float> char_pos,
                                         CPDF_Font* font,
@@ -43,42 +69,19 @@
                    ? text_char_pos.m_ExtGID
                    : text_char_pos.m_GlyphIndex;
 #endif
-    bool is_invalid_glyph = glyph_id == static_cast<uint32_t>(-1);
-    bool is_true_type_zero_glyph = glyph_id == 0 && font->IsTrueTypeFont();
-    bool use_fallback_font = false;
-    if (is_invalid_glyph || is_true_type_zero_glyph) {
-      text_char_pos.m_FallbackFontPosition =
-          font->FallbackFontFromCharcode(char_code);
-      text_char_pos.m_GlyphIndex = font->FallbackGlyphFromCharcode(
-          text_char_pos.m_FallbackFontPosition, char_code);
-      if (is_true_type_zero_glyph &&
-          text_char_pos.m_GlyphIndex == static_cast<uint32_t>(-1)) {
-        // For a TrueType font character, when finding the glyph from the
-        // fallback font fails, switch back to using the original font.
-
-        // When keyword "ToUnicode" exists in the PDF file, it indicates
-        // a "ToUnicode" mapping file is used to convert from CIDs (which
-        // begins at decimal 0) to Unicode code. (See ToUnicode Mapping File
-        // Tutorial - Adobe
-        // https://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/5411.ToUnicode.pdf
-        // and
-        // https://www.freetype.org/freetype2/docs/tutorial/step1.html#section-6)
-        if (has_to_unicode)
-          text_char_pos.m_GlyphIndex = 0;
-      } else {
-        use_fallback_font = true;
-      }
-    }
     CFX_Font* current_font;
-    if (use_fallback_font) {
-      current_font =
-          font->GetFontFallback(text_char_pos.m_FallbackFontPosition);
+    if (ShouldUseExistingFont(font, glyph_id, has_to_unicode)) {
+      current_font = font->GetFont();
+      text_char_pos.m_FallbackFontPosition = -1;
+    } else {
+      int32_t fallback_position = font->FallbackFontFromCharcode(char_code);
+      current_font = font->GetFontFallback(fallback_position);
+      text_char_pos.m_FallbackFontPosition = fallback_position;
+      text_char_pos.m_GlyphIndex =
+          font->FallbackGlyphFromCharcode(fallback_position, char_code);
 #if BUILDFLAG(IS_APPLE)
       text_char_pos.m_ExtGID = text_char_pos.m_GlyphIndex;
 #endif
-    } else {
-      current_font = font->GetFont();
-      text_char_pos.m_FallbackFontPosition = -1;
     }
 
     if (!font->IsEmbedded() && !font->IsCIDFont())
diff --git a/testing/SUPPRESSIONS b/testing/SUPPRESSIONS
index a0840b1..ee548b2 100644
--- a/testing/SUPPRESSIONS
+++ b/testing/SUPPRESSIONS
@@ -334,9 +334,6 @@
 # TODO(pdfium:1747): Remove after associated bug is fixed
 bug_1258634.in * * * skia
 
-# TODO(chromium:1271578): Remove after associated bug is fixed
-bug_1271578.in * * * *
-
 # TODO(pdfium:1748): Remove after associated bug is fixed
 bug_1286.in * * * skia
 
diff --git a/testing/resources/pixel/bug_1271578_expected_mac.pdf.0.png b/testing/resources/pixel/bug_1271578_expected_mac.pdf.0.png
new file mode 100644
index 0000000..7318ef2
--- /dev/null
+++ b/testing/resources/pixel/bug_1271578_expected_mac.pdf.0.png
Binary files differ