Use CPDF_DefaultAppearance instead of custom parsing

This CL moves code over to using CPDF_DefaultAppearance instead of
calling the CPDF_SimpleParser directly. This means the code for finding
a specific tag start can move into CPDF_DefaultAppearance directly.

Change-Id: I1dc64e54aedd03d059b963121d466f3eb75c17db
Reviewed-on: https://pdfium-review.googlesource.com/28410
Reviewed-by: Henrique Nakashima <hnakashima@chromium.org>
Commit-Queue: dsinclair <dsinclair@chromium.org>
diff --git a/BUILD.gn b/BUILD.gn
index a62b028..c6aee5c 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -2885,6 +2885,7 @@
     "core/fpdfapi/parser/cpdf_simple_parser_unittest.cpp",
     "core/fpdfapi/parser/cpdf_syntax_parser_unittest.cpp",
     "core/fpdfapi/parser/fpdf_parser_decode_unittest.cpp",
+    "core/fpdfdoc/cpdf_defaultappearance_unittest.cpp",
     "core/fpdfdoc/cpdf_dest_unittest.cpp",
     "core/fpdfdoc/cpdf_filespec_unittest.cpp",
     "core/fpdfdoc/cpdf_formfield_unittest.cpp",
diff --git a/core/fpdfapi/parser/cpdf_simple_parser.cpp b/core/fpdfapi/parser/cpdf_simple_parser.cpp
index 47ce1ad..45ea0d4 100644
--- a/core/fpdfapi/parser/cpdf_simple_parser.cpp
+++ b/core/fpdfapi/parser/cpdf_simple_parser.cpp
@@ -6,8 +6,6 @@
 
 #include "core/fpdfapi/parser/cpdf_simple_parser.h"
 
-#include <vector>
-
 #include "core/fpdfapi/parser/fpdf_parser_utility.h"
 
 CPDF_SimpleParser::CPDF_SimpleParser(const ByteStringView& str) : data_(str) {}
@@ -129,35 +127,3 @@
   }
   return data_.Mid(start_pos, dwSize);
 }
-
-bool CPDF_SimpleParser::FindTagParamFromStart(const ByteStringView& token,
-                                              int nParams) {
-  nParams++;
-
-  std::vector<uint32_t> pBuf(nParams);
-  int buf_index = 0;
-  int buf_count = 0;
-  cur_pos_ = 0;
-  while (1) {
-    pBuf[buf_index++] = cur_pos_;
-    if (buf_index == nParams)
-      buf_index = 0;
-
-    buf_count++;
-    if (buf_count > nParams)
-      buf_count = nParams;
-
-    ByteStringView word = GetWord();
-    if (word.IsEmpty())
-      return false;
-
-    if (word == token) {
-      if (buf_count < nParams)
-        continue;
-
-      cur_pos_ = pBuf[buf_index];
-      return true;
-    }
-  }
-  return false;
-}
diff --git a/core/fpdfapi/parser/cpdf_simple_parser.h b/core/fpdfapi/parser/cpdf_simple_parser.h
index f02a58c..8a07323 100644
--- a/core/fpdfapi/parser/cpdf_simple_parser.h
+++ b/core/fpdfapi/parser/cpdf_simple_parser.h
@@ -19,11 +19,8 @@
 
   ByteStringView GetWord();
 
-  // Find the token and its |nParams| parameters from the start of data,
-  // and move the current position to the start of those parameters.
-  bool FindTagParamFromStart(const ByteStringView& token, int nParams);
-
-  uint32_t GetCurPosForTest() const { return cur_pos_; }
+  void SetCurPos(uint32_t pos) { cur_pos_ = pos; }
+  uint32_t GetCurPos() const { return cur_pos_; }
 
  private:
   const ByteStringView data_;
diff --git a/core/fpdfapi/parser/cpdf_simple_parser_unittest.cpp b/core/fpdfapi/parser/cpdf_simple_parser_unittest.cpp
index b53b6c6..2fb50f1 100644
--- a/core/fpdfapi/parser/cpdf_simple_parser_unittest.cpp
+++ b/core/fpdfapi/parser/cpdf_simple_parser_unittest.cpp
@@ -59,39 +59,3 @@
         << " for case " << i;
   }
 }
-
-TEST(SimpleParserTest, FindTagParamFromStart) {
-  static const struct FindTagTestStruct {
-    const unsigned char* input;
-    unsigned int input_size;
-    const char* token;
-    int num_params;
-    bool result;
-    unsigned int result_pos;
-  } test_data[] = {
-      // Empty strings.
-      STR_IN_TEST_CASE("", "Tj", 1, false, 0),
-      STR_IN_TEST_CASE("", "", 1, false, 0),
-      // Empty token.
-      STR_IN_TEST_CASE("  T j", "", 1, false, 5),
-      // No parameter.
-      STR_IN_TEST_CASE("Tj", "Tj", 1, false, 2),
-      STR_IN_TEST_CASE("(Tj", "Tj", 1, false, 3),
-      // Partial token match.
-      STR_IN_TEST_CASE("\r12\t34  56 78Tj", "Tj", 1, false, 15),
-      // Regular cases with various parameters.
-      STR_IN_TEST_CASE("\r\0abd Tj", "Tj", 1, true, 0),
-      STR_IN_TEST_CASE("12 4 Tj 3 46 Tj", "Tj", 1, true, 2),
-      STR_IN_TEST_CASE("er^ 2 (34) (5667) Tj", "Tj", 2, true, 5),
-      STR_IN_TEST_CASE("<344> (232)\t343.4\n12 45 Tj", "Tj", 3, true, 11),
-      STR_IN_TEST_CASE("1 2 3 4 5 6 7 8 cm", "cm", 6, true, 3),
-  };
-  for (size_t i = 0; i < FX_ArraySize(test_data); ++i) {
-    const FindTagTestStruct& data = test_data[i];
-    CPDF_SimpleParser parser(ByteStringView(data.input, data.input_size));
-    EXPECT_EQ(data.result,
-              parser.FindTagParamFromStart(data.token, data.num_params))
-        << " for case " << i;
-    EXPECT_EQ(data.result_pos, parser.GetCurPosForTest()) << " for case " << i;
-  }
-}
diff --git a/core/fpdfdoc/cpdf_defaultappearance.cpp b/core/fpdfdoc/cpdf_defaultappearance.cpp
index cae553a..8878dc0 100644
--- a/core/fpdfdoc/cpdf_defaultappearance.cpp
+++ b/core/fpdfdoc/cpdf_defaultappearance.cpp
@@ -7,17 +7,58 @@
 #include "core/fpdfdoc/cpdf_defaultappearance.h"
 
 #include <algorithm>
+#include <vector>
 
 #include "core/fpdfapi/parser/cpdf_simple_parser.h"
 #include "core/fpdfapi/parser/fpdf_parser_decode.h"
 #include "core/fxge/cfx_color.h"
 
+namespace {
+
+// Find the token and its |nParams| parameters from the start of data,
+// and move the current position to the start of those parameters.
+bool FindTagParamFromStart(CPDF_SimpleParser* parser,
+                           const ByteStringView& token,
+                           int nParams) {
+  nParams++;
+
+  std::vector<uint32_t> pBuf(nParams);
+  int buf_index = 0;
+  int buf_count = 0;
+
+  parser->SetCurPos(0);
+  while (1) {
+    pBuf[buf_index++] = parser->GetCurPos();
+    if (buf_index == nParams)
+      buf_index = 0;
+
+    buf_count++;
+    if (buf_count > nParams)
+      buf_count = nParams;
+
+    ByteStringView word = parser->GetWord();
+    if (word.IsEmpty())
+      return false;
+
+    if (word == token) {
+      if (buf_count < nParams)
+        continue;
+
+      parser->SetCurPos(pBuf[buf_index]);
+      return true;
+    }
+  }
+  return false;
+}
+
+}  // namespace
+
 bool CPDF_DefaultAppearance::HasFont() {
   if (m_csDA.IsEmpty())
     return false;
 
   CPDF_SimpleParser syntax(m_csDA.AsStringView());
-  return syntax.FindTagParamFromStart("Tf", 2);
+  return FindTagParamFromStart(&syntax, "Tf", 2);
 }
 
 ByteString CPDF_DefaultAppearance::GetFont(float* fFontSize) {
@@ -27,7 +68,7 @@
 
   ByteString csFontNameTag;
   CPDF_SimpleParser syntax(m_csDA.AsStringView());
-  if (syntax.FindTagParamFromStart("Tf", 2)) {
+  if (FindTagParamFromStart(&syntax, "Tf", 2)) {
     csFontNameTag = ByteString(syntax.GetWord());
     csFontNameTag.Delete(0, 1);
     *fFontSize = FX_atof(syntax.GetWord());
@@ -40,11 +81,11 @@
     return false;
 
   CPDF_SimpleParser syntax(m_csDA.AsStringView());
-  if (syntax.FindTagParamFromStart("g", 1))
+  if (FindTagParamFromStart(&syntax, "g", 1))
     return true;
-  if (syntax.FindTagParamFromStart("rg", 3))
+  if (FindTagParamFromStart(&syntax, "rg", 3))
     return true;
-  return syntax.FindTagParamFromStart("k", 4);
+  return FindTagParamFromStart(&syntax, "k", 4);
 }
 
 void CPDF_DefaultAppearance::GetColor(int& iColorType, float fc[4]) {
@@ -56,19 +97,19 @@
     return;
 
   CPDF_SimpleParser syntax(m_csDA.AsStringView());
-  if (syntax.FindTagParamFromStart("g", 1)) {
+  if (FindTagParamFromStart(&syntax, "g", 1)) {
     iColorType = CFX_Color::kGray;
     fc[0] = FX_atof(syntax.GetWord());
     return;
   }
-  if (syntax.FindTagParamFromStart("rg", 3)) {
+  if (FindTagParamFromStart(&syntax, "rg", 3)) {
     iColorType = CFX_Color::kRGB;
     fc[0] = FX_atof(syntax.GetWord());
     fc[1] = FX_atof(syntax.GetWord());
     fc[2] = FX_atof(syntax.GetWord());
     return;
   }
-  if (syntax.FindTagParamFromStart("k", 4)) {
+  if (FindTagParamFromStart(&syntax, "k", 4)) {
     iColorType = CFX_Color::kCMYK;
     fc[0] = FX_atof(syntax.GetWord());
     fc[1] = FX_atof(syntax.GetWord());
@@ -104,4 +145,12 @@
                        static_cast<int>(g * 255 + 0.5f),
                        static_cast<int>(b * 255 + 0.5f));
   }
+  NOTREACHED();
+}
+
+bool CPDF_DefaultAppearance::FindTagParamFromStartForTesting(
+    CPDF_SimpleParser* parser,
+    const ByteStringView& token,
+    int nParams) {
+  return FindTagParamFromStart(parser, token, nParams);
 }
diff --git a/core/fpdfdoc/cpdf_defaultappearance.h b/core/fpdfdoc/cpdf_defaultappearance.h
index af13a3f..79ad0bb 100644
--- a/core/fpdfdoc/cpdf_defaultappearance.h
+++ b/core/fpdfdoc/cpdf_defaultappearance.h
@@ -7,6 +7,7 @@
 #ifndef CORE_FPDFDOC_CPDF_DEFAULTAPPEARANCE_H_
 #define CORE_FPDFDOC_CPDF_DEFAULTAPPEARANCE_H_
 
+#include "core/fpdfapi/parser/cpdf_simple_parser.h"
 #include "core/fpdfdoc/cpdf_defaultappearance.h"
 #include "core/fxcrt/fx_coordinates.h"
 #include "core/fxcrt/fx_string.h"
@@ -29,6 +30,10 @@
   void GetColor(int& iColorType, float fc[4]);
   void GetColor(FX_ARGB& color, int& iColorType);
 
+  bool FindTagParamFromStartForTesting(CPDF_SimpleParser* parser,
+                                       const ByteStringView& token,
+                                       int nParams);
+
  private:
   ByteString m_csDA;
 };
diff --git a/core/fpdfdoc/cpdf_defaultappearance_unittest.cpp b/core/fpdfdoc/cpdf_defaultappearance_unittest.cpp
new file mode 100644
index 0000000..031fa8c
--- /dev/null
+++ b/core/fpdfdoc/cpdf_defaultappearance_unittest.cpp
@@ -0,0 +1,47 @@
+// Copyright 2018 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/fpdfdoc/cpdf_defaultappearance.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/test_support.h"
+
+TEST(CPDFDefaultAppearanceTest, FindTagParamFromStart) {
+  static const struct FindTagTestStruct {
+    const unsigned char* input;
+    unsigned int input_size;
+    const char* token;
+    int num_params;
+    bool result;
+    unsigned int result_pos;
+  } test_data[] = {
+      // Empty strings.
+      STR_IN_TEST_CASE("", "Tj", 1, false, 0),
+      STR_IN_TEST_CASE("", "", 1, false, 0),
+      // Empty token.
+      STR_IN_TEST_CASE("  T j", "", 1, false, 5),
+      // No parameter.
+      STR_IN_TEST_CASE("Tj", "Tj", 1, false, 2),
+      STR_IN_TEST_CASE("(Tj", "Tj", 1, false, 3),
+      // Partial token match.
+      STR_IN_TEST_CASE("\r12\t34  56 78Tj", "Tj", 1, false, 15),
+      // Regular cases with various parameters.
+      STR_IN_TEST_CASE("\r\0abd Tj", "Tj", 1, true, 0),
+      STR_IN_TEST_CASE("12 4 Tj 3 46 Tj", "Tj", 1, true, 2),
+      STR_IN_TEST_CASE("er^ 2 (34) (5667) Tj", "Tj", 2, true, 5),
+      STR_IN_TEST_CASE("<344> (232)\t343.4\n12 45 Tj", "Tj", 3, true, 11),
+      STR_IN_TEST_CASE("1 2 3 4 5 6 7 8 cm", "cm", 6, true, 3),
+  };
+
+  CPDF_DefaultAppearance da;
+  for (size_t i = 0; i < FX_ArraySize(test_data); ++i) {
+    CPDF_SimpleParser parser(
+        ByteStringView(test_data[i].input, test_data[i].input_size));
+    EXPECT_EQ(test_data[i].result,
+              da.FindTagParamFromStartForTesting(&parser, test_data[i].token,
+                                                 test_data[i].num_params))
+        << " for case " << i;
+    EXPECT_EQ(test_data[i].result_pos, parser.GetCurPos()) << " for case " << i;
+  }
+}
diff --git a/core/fpdfdoc/cpdf_formfield.cpp b/core/fpdfdoc/cpdf_formfield.cpp
index 679acd1..f3dcac2 100644
--- a/core/fpdfdoc/cpdf_formfield.cpp
+++ b/core/fpdfdoc/cpdf_formfield.cpp
@@ -15,9 +15,9 @@
 #include "core/fpdfapi/parser/cpdf_document.h"
 #include "core/fpdfapi/parser/cpdf_name.h"
 #include "core/fpdfapi/parser/cpdf_number.h"
-#include "core/fpdfapi/parser/cpdf_simple_parser.h"
 #include "core/fpdfapi/parser/cpdf_string.h"
 #include "core/fpdfapi/parser/fpdf_parser_decode.h"
+#include "core/fpdfdoc/cpdf_defaultappearance.h"
 #include "core/fpdfdoc/cpdf_formcontrol.h"
 #include "core/fpdfdoc/cpdf_interform.h"
 #include "core/fpdfdoc/cpvt_generateap.h"
@@ -914,15 +914,16 @@
   if (!pFont)
     return;
 
-  CPDF_SimpleParser syntax(DA.AsStringView());
-  syntax.FindTagParamFromStart("Tf", 2);
-  ByteString font_name(syntax.GetWord());
+  CPDF_DefaultAppearance appearance(DA);
+  if (!appearance.HasFont())
+    return;
+
+  ByteString font_name = appearance.GetFont(&m_FontSize);
   CPDF_Dictionary* pFontDict = pFont->GetDictFor(font_name);
   if (!pFontDict)
     return;
 
   m_pFont = m_pForm->GetDocument()->LoadFont(pFontDict);
-  m_FontSize = FX_atof(syntax.GetWord());
 }
 
 bool CPDF_FormField::NotifyBeforeSelectionChange(const WideString& value) {
diff --git a/core/fpdfdoc/cpvt_generateap.cpp b/core/fpdfdoc/cpvt_generateap.cpp
index 4138b21..a6a64aa 100644
--- a/core/fpdfdoc/cpvt_generateap.cpp
+++ b/core/fpdfdoc/cpvt_generateap.cpp
@@ -19,11 +19,11 @@
 #include "core/fpdfapi/parser/cpdf_name.h"
 #include "core/fpdfapi/parser/cpdf_number.h"
 #include "core/fpdfapi/parser/cpdf_reference.h"
-#include "core/fpdfapi/parser/cpdf_simple_parser.h"
 #include "core/fpdfapi/parser/cpdf_stream.h"
 #include "core/fpdfapi/parser/cpdf_string.h"
 #include "core/fpdfapi/parser/fpdf_parser_decode.h"
 #include "core/fpdfdoc/cpdf_annot.h"
+#include "core/fpdfdoc/cpdf_defaultappearance.h"
 #include "core/fpdfdoc/cpdf_formfield.h"
 #include "core/fpdfdoc/cpvt_fontmap.h"
 #include "core/fpdfdoc/cpvt_word.h"
@@ -922,14 +922,17 @@
   if (DA.IsEmpty())
     return;
 
-  CPDF_SimpleParser syntax(DA.AsStringView());
-  syntax.FindTagParamFromStart("Tf", 2);
-  ByteString sFontName(syntax.GetWord());
-  sFontName = PDF_NameDecode(sFontName.AsStringView());
+  CPDF_DefaultAppearance appearance(DA);
+  if (!appearance.HasFont())
+    return;
+
+  ASSERT(appearance.HasFont());
+  float fFontSize = 0;
+  ByteString sFontName =
+      PDF_NameDecode(appearance.GetFont(&fFontSize).AsStringView());
   if (sFontName.IsEmpty())
     return;
 
-  float fFontSize = FX_atof(syntax.GetWord());
   CFX_Color crText = CFX_Color::ParseColor(DA);
   CPDF_Dictionary* pDRDict = pFormDict->GetDictFor("DR");
   if (!pDRDict)
diff --git a/core/fxge/cfx_color.cpp b/core/fxge/cfx_color.cpp
index 42ab39d..5175adc 100644
--- a/core/fxge/cfx_color.cpp
+++ b/core/fxge/cfx_color.cpp
@@ -9,7 +9,7 @@
 #include <algorithm>
 
 #include "core/fpdfapi/parser/cpdf_array.h"
-#include "core/fpdfapi/parser/cpdf_simple_parser.h"
+#include "core/fpdfdoc/cpdf_defaultappearance.h"
 
 namespace {
 
@@ -84,23 +84,25 @@
 
 // Static.
 CFX_Color CFX_Color::ParseColor(const ByteString& str) {
-  CPDF_SimpleParser syntax(str.AsStringView());
-  if (syntax.FindTagParamFromStart("g", 1))
-    return CFX_Color(CFX_Color::kGray, FX_atof(syntax.GetWord()));
+  CPDF_DefaultAppearance appearance(str);
+  ASSERT(appearance.HasColor());
 
-  if (syntax.FindTagParamFromStart("rg", 3)) {
-    float f1 = FX_atof(syntax.GetWord());
-    float f2 = FX_atof(syntax.GetWord());
-    float f3 = FX_atof(syntax.GetWord());
-    return CFX_Color(CFX_Color::kRGB, f1, f2, f3);
+  int color_type;
+  float values[4];
+  appearance.GetColor(color_type, values);
+
+  if (color_type == CFX_Color::kTransparent)
+    return CFX_Color(CFX_Color::kTransparent);
+  if (color_type == CFX_Color::kGray)
+    return CFX_Color(CFX_Color::kGray, values[0]);
+  if (color_type == CFX_Color::kRGB)
+    return CFX_Color(CFX_Color::kRGB, values[0], values[1], values[2]);
+  if (color_type == CFX_Color::kCMYK) {
+    return CFX_Color(CFX_Color::kCMYK, values[0], values[1], values[2],
+                     values[3]);
   }
-  if (syntax.FindTagParamFromStart("k", 4)) {
-    float f1 = FX_atof(syntax.GetWord());
-    float f2 = FX_atof(syntax.GetWord());
-    float f3 = FX_atof(syntax.GetWord());
-    float f4 = FX_atof(syntax.GetWord());
-    return CFX_Color(CFX_Color::kCMYK, f1, f2, f3, f4);
-  }
+
+  NOTREACHED();
   return CFX_Color(CFX_Color::kTransparent);
 }
 
diff --git a/fpdfsdk/formfiller/cba_fontmap.cpp b/fpdfsdk/formfiller/cba_fontmap.cpp
index 8e4ac46..b7e14b4 100644
--- a/fpdfsdk/formfiller/cba_fontmap.cpp
+++ b/fpdfsdk/formfiller/cba_fontmap.cpp
@@ -12,9 +12,9 @@
 #include "core/fpdfapi/page/cpdf_page.h"
 #include "core/fpdfapi/parser/cpdf_document.h"
 #include "core/fpdfapi/parser/cpdf_reference.h"
-#include "core/fpdfapi/parser/cpdf_simple_parser.h"
 #include "core/fpdfapi/parser/cpdf_stream.h"
 #include "core/fpdfapi/parser/fpdf_parser_decode.h"
+#include "core/fpdfdoc/cpdf_defaultappearance.h"
 #include "core/fpdfdoc/cpdf_formfield.h"
 #include "core/fxge/cfx_substfont.h"
 #include "fpdfsdk/cpdfsdk_annot.h"
@@ -216,10 +216,12 @@
   if (sDA.IsEmpty())
     return nullptr;
 
-  CPDF_SimpleParser syntax(sDA.AsStringView());
-  syntax.FindTagParamFromStart("Tf", 2);
+  CPDF_DefaultAppearance appearance(sDA);
+  ASSERT(appearance.HasFont());
 
-  ByteString sDecodedFontName = PDF_NameDecode(syntax.GetWord());
+  float font_size;
+  ByteString sDecodedFontName =
+      PDF_NameDecode(appearance.GetFont(&font_size).AsStringView());
   *sAlias = sDecodedFontName.Right(sDecodedFontName.GetLength() - 1);
 
   CPDF_Dictionary* pFontDict = nullptr;