Snap for 13632198 from 103bfa7b57a068fc1ce83cd259dafb05eeaa67c3 to 25Q4-release

Change-Id: I3f97f05f08be8f27b6bcc25e0a534d47286e7cab
diff --git a/core/fpdfdoc/cpdf_bafontmap.cpp b/core/fpdfdoc/cpdf_bafontmap.cpp
index 694778c..ea67a8f 100644
--- a/core/fpdfdoc/cpdf_bafontmap.cpp
+++ b/core/fpdfdoc/cpdf_bafontmap.cpp
@@ -252,9 +252,12 @@
     return nullptr;
 
   CPDF_DefaultAppearance appearance(sDA);
-  float font_size;
-  std::optional<ByteString> font = appearance.GetFont(&font_size);
-  *sAlias = font.value_or(ByteString());
+  auto maybe_font_name_and_size = appearance.GetFont();
+  if (maybe_font_name_and_size.has_value()) {
+    *sAlias = maybe_font_name_and_size.value().name;
+  } else {
+    sAlias->clear();
+  }
 
   RetainPtr<CPDF_Dictionary> pFontDict;
   if (RetainPtr<CPDF_Dictionary> pAPDict =
diff --git a/core/fpdfdoc/cpdf_defaultappearance.cpp b/core/fpdfdoc/cpdf_defaultappearance.cpp
index cb8e6e5..9edcdb0 100644
--- a/core/fpdfdoc/cpdf_defaultappearance.cpp
+++ b/core/fpdfdoc/cpdf_defaultappearance.cpp
@@ -9,14 +9,30 @@
 #include <algorithm>
 #include <vector>
 
+#include "core/fpdfapi/parser/cpdf_dictionary.h"
 #include "core/fpdfapi/parser/cpdf_simple_parser.h"
 #include "core/fpdfapi/parser/fpdf_parser_utility.h"
+#include "core/fpdfdoc/cpdf_formfield.h"
 #include "core/fxcrt/fx_string.h"
 #include "core/fxcrt/notreached.h"
 #include "core/fxge/cfx_color.h"
 
 namespace {
 
+ByteString GetDefaultAppearanceString(const CPDF_Dictionary* annot_dict,
+                                          const CPDF_Dictionary* acroform_dict) {
+  ByteString default_appearance_string;
+  RetainPtr<const CPDF_Object> default_appearance_object =
+          CPDF_FormField::GetFieldAttrForDict(annot_dict, "DA");
+  if (default_appearance_object) {
+    default_appearance_string = default_appearance_object->GetString();
+  }
+  if (default_appearance_string.IsEmpty() && acroform_dict) {
+    default_appearance_string = acroform_dict->GetByteStringFor("DA");
+  }
+  return default_appearance_string;
+}
+
 // 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,
@@ -58,24 +74,37 @@
     : m_csDA(csDA) {}
 
 CPDF_DefaultAppearance::CPDF_DefaultAppearance(
-    const CPDF_DefaultAppearance& cDA) = default;
+    const CPDF_Dictionary* annot_dict,
+    const CPDF_Dictionary* acroform_dict)
+    : CPDF_DefaultAppearance(
+       GetDefaultAppearanceString(annot_dict, acroform_dict)) {}
 
 CPDF_DefaultAppearance::~CPDF_DefaultAppearance() = default;
 
-std::optional<ByteString> CPDF_DefaultAppearance::GetFont(
-    float* fFontSize) const {
-  *fFontSize = 0.0f;
+std::optional<CPDF_DefaultAppearance::FontNameAndSize>
+CPDF_DefaultAppearance::GetFont() const {
   if (m_csDA.IsEmpty())
-    return std::nullopt;
+     return std::nullopt;
 
-  ByteString csFontNameTag;
   CPDF_SimpleParser syntax(m_csDA.AsStringView().unsigned_span());
-  if (FindTagParamFromStart(&syntax, "Tf", 2)) {
-    csFontNameTag = ByteString(syntax.GetWord());
-    csFontNameTag.Delete(0, 1);
-    *fFontSize = StringToFloat(syntax.GetWord());
+  if (!FindTagParamFromStart(&syntax, "Tf", 2)) {
+    return FontNameAndSize();
   }
-  return PDF_NameDecode(csFontNameTag.AsStringView());
+
+  // Deliberately using separate statements here to ensure the correct
+  // evaluation order.
+  FontNameAndSize result;
+  result.name = PDF_NameDecode(syntax.GetWord().Substr(1));
+  result.size = StringToFloat(syntax.GetWord());
+  return result;
+}
+
+float CPDF_DefaultAppearance::GetFontSizeOrZero() const {
+  auto maybe_font_name_and_size = GetFont();
+  if (!maybe_font_name_and_size.has_value()) {
+    return 0;
+  }
+  return maybe_font_name_and_size.value().size;
 }
 
 std::optional<CFX_Color> CPDF_DefaultAppearance::GetColor() const {
diff --git a/core/fpdfdoc/cpdf_defaultappearance.h b/core/fpdfdoc/cpdf_defaultappearance.h
index 78180ad..a177e0f 100644
--- a/core/fpdfdoc/cpdf_defaultappearance.h
+++ b/core/fpdfdoc/cpdf_defaultappearance.h
@@ -12,15 +12,25 @@
 #include "core/fxcrt/bytestring.h"
 #include "core/fxge/cfx_color.h"
 
+
+class CPDF_Dictionary;
 class CPDF_SimpleParser;
 
 class CPDF_DefaultAppearance {
  public:
+  struct FontNameAndSize {
+    ByteString name;
+    float size = 0;  // Defaults to 0 if not found.
+  };
   explicit CPDF_DefaultAppearance(const ByteString& csDA);
-  CPDF_DefaultAppearance(const CPDF_DefaultAppearance& cDA);
+  CPDF_DefaultAppearance(const CPDF_Dictionary* annot_dict,
+                         const CPDF_Dictionary* acroform_dict);
+  CPDF_DefaultAppearance(const CPDF_DefaultAppearance&) = delete;
+  CPDF_DefaultAppearance& operator=(const CPDF_DefaultAppearance&) = delete;
   ~CPDF_DefaultAppearance();
 
-  std::optional<ByteString> GetFont(float* fFontSize) const;
+  std::optional<FontNameAndSize> GetFont() const;
+  float GetFontSizeOrZero() const;
 
   std::optional<CFX_Color> GetColor() const;
   std::optional<CFX_Color::TypeAndARGB> GetColorARGB() const;
diff --git a/core/fpdfdoc/cpdf_formcontrol.cpp b/core/fpdfdoc/cpdf_formcontrol.cpp
index ef81603..a7bae23 100644
--- a/core/fpdfdoc/cpdf_formcontrol.cpp
+++ b/core/fpdfdoc/cpdf_formcontrol.cpp
@@ -203,19 +203,20 @@
 }
 
 RetainPtr<CPDF_Font> CPDF_FormControl::GetDefaultControlFont() const {
-  float fFontSize;
-  CPDF_DefaultAppearance cDA = GetDefaultAppearance();
-  std::optional<ByteString> csFontNameTag = cDA.GetFont(&fFontSize);
-  if (!csFontNameTag.has_value() || csFontNameTag->IsEmpty())
+  CPDF_DefaultAppearance default_appearance = GetDefaultAppearance();
+  auto maybe_font_name_and_size = default_appearance.GetFont();
+  if (!maybe_font_name_and_size.has_value() ||
+      maybe_font_name_and_size.value().name.IsEmpty()) {
     return nullptr;
-
+  }
+  const ByteString &font_name = maybe_font_name_and_size.value().name;
   RetainPtr<CPDF_Dictionary> pDRDict = ToDictionary(
-      CPDF_FormField::GetMutableFieldAttrForDict(m_pWidgetDict.Get(), "DR"));
+ CPDF_FormField::GetMutableFieldAttrForDict(m_pWidgetDict.Get(), "DR"));
   if (pDRDict) {
     RetainPtr<CPDF_Dictionary> pFonts = pDRDict->GetMutableDictFor("Font");
     if (ValidateFontResourceDict(pFonts.Get())) {
       RetainPtr<CPDF_Dictionary> pElement =
-          pFonts->GetMutableDictFor(csFontNameTag.value());
+          pFonts->GetMutableDictFor(font_name);
       if (pElement) {
         RetainPtr<CPDF_Font> pFont =
             m_pForm->GetFontForElement(std::move(pElement));
@@ -224,13 +225,13 @@
       }
     }
   }
-  RetainPtr<CPDF_Font> pFormFont = m_pForm->GetFormFont(csFontNameTag.value());
+  RetainPtr<CPDF_Font> pFormFont = m_pForm->GetFormFont(font_name);
   if (pFormFont)
     return pFormFont;
 
   RetainPtr<CPDF_Dictionary> pPageDict = m_pWidgetDict->GetMutableDictFor("P");
   RetainPtr<CPDF_Dictionary> pDict = ToDictionary(
-      CPDF_FormField::GetMutableFieldAttrForDict(pPageDict.Get(), "Resources"));
+  CPDF_FormField::GetMutableFieldAttrForDict(pPageDict.Get(), "Resources"));
   if (!pDict)
     return nullptr;
 
@@ -238,8 +239,7 @@
   if (!ValidateFontResourceDict(pFonts.Get()))
     return nullptr;
 
-  RetainPtr<CPDF_Dictionary> pElement =
-      pFonts->GetMutableDictFor(csFontNameTag.value());
+  RetainPtr<CPDF_Dictionary> pElement = pFonts->GetMutableDictFor(font_name);
   if (!pElement)
     return nullptr;
 
diff --git a/core/fpdfdoc/cpdf_generateap.cpp b/core/fpdfdoc/cpdf_generateap.cpp
index 568fc2c..0b1b2d6 100644
--- a/core/fpdfdoc/cpdf_generateap.cpp
+++ b/core/fpdfdoc/cpdf_generateap.cpp
@@ -92,18 +92,24 @@
   return PDF_EncodeString(words) + " Tj\n";
 }
 
+ByteString StringFromFontNameAndSize(const ByteString& font_name,
+                                     float font_size) {
+  fxcrt::ostringstream font_stream;
+  if (font_name.GetLength() > 0 && font_size > 0) {
+    font_stream << "/" << font_name << " ";
+    WriteFloat(font_stream, font_size) << " Tf\n";
+  }
+  return ByteString(font_stream);
+}
+
 ByteString GetFontSetString(IPVT_FontMap* font_map,
                             int32_t font_index,
                             float font_size) {
-  fxcrt::ostringstream font_stream;
-  if (font_map) {
-    ByteString font_alias = font_map->GetPDFFontAlias(font_index);
-    if (font_alias.GetLength() > 0 && font_size > 0) {
-      font_stream << "/" << font_alias << " ";
-      WriteFloat(font_stream, font_size) << " Tf\n";
-    }
+  if (!font_map) {
+    return ByteString();
   }
-  return ByteString(font_stream);
+  return StringFromFontNameAndSize(font_map->GetPDFFontAlias(font_index),
+                                   font_size);
 }
 
 void SetVtFontSize(float font_size, CPVT_VariableText& vt) {
@@ -246,20 +252,6 @@
   };
 }
 
-ByteString GetDefaultAppearanceString(CPDF_Dictionary* annot_dict,
-                                      CPDF_Dictionary* form_dict) {
-  ByteString default_appearance_string;
-  RetainPtr<const CPDF_Object> default_appearance_object =
-      CPDF_FormField::GetFieldAttrForDict(annot_dict, "DA");
-  if (default_appearance_object) {
-    default_appearance_string = default_appearance_object->GetString();
-  }
-  if (default_appearance_string.IsEmpty()) {
-    default_appearance_string = form_dict->GetByteStringFor("DA");
-  }
-  return default_appearance_string;
-}
-
 struct DefaultAppearanceInfo {
   ByteString font_name;
   float font_size;
@@ -267,22 +259,17 @@
 };
 
 std::optional<DefaultAppearanceInfo> GetDefaultAppearanceInfo(
-    const ByteString& default_appearance_string) {
-  if (default_appearance_string.IsEmpty()) {
-    return std::nullopt;
-  }
-
-  CPDF_DefaultAppearance appearance(default_appearance_string);
-
-  float font_size = 0;
-  std::optional<ByteString> font = appearance.GetFont(&font_size);
-  if (!font.has_value()) {
+    const CPDF_Dictionary* annot_dict,
+    const CPDF_Dictionary* acroform_dict) {
+  CPDF_DefaultAppearance appearance(annot_dict, acroform_dict);
+  auto maybe_font_name_and_size = appearance.GetFont();
+  if (!maybe_font_name_and_size.has_value()) {
     return std::nullopt;
   }
 
   return DefaultAppearanceInfo{
-      .font_name = font.value(),
-      .font_size = font_size,
+      .font_name = maybe_font_name_and_size.value().name,
+      .font_size = maybe_font_name_and_size.value().size,
       .text_color = appearance.GetColor().value_or(CFX_Color())};
 }
 
@@ -1057,8 +1044,7 @@
   }
 
   std::optional<DefaultAppearanceInfo> default_appearance_info =
-      GetDefaultAppearanceInfo(
-          GetDefaultAppearanceString(annot_dict, form_dict));
+      GetDefaultAppearanceInfo(annot_dict, form_dict);
   if (!default_appearance_info.has_value()) {
     return false;
   }
@@ -1459,8 +1445,7 @@
   }
 
   std::optional<DefaultAppearanceInfo> default_appearance_info =
-      GetDefaultAppearanceInfo(
-          GetDefaultAppearanceString(annot_dict, form_dict));
+      GetDefaultAppearanceInfo(annot_dict, form_dict);
   if (!default_appearance_info.has_value()) {
     return;
   }
@@ -1620,4 +1605,48 @@
     default:
       return false;
   }
+}
+
+// static
+bool CPDF_GenerateAP::GenerateDefaultAppearanceWithColor(
+    CPDF_Document* doc,
+    CPDF_Dictionary* annot_dict,
+    const CFX_Color& color) {
+  CHECK(doc);
+  CHECK(annot_dict);
+
+  RetainPtr<CPDF_Dictionary> root_dict = doc->GetMutableRoot();
+  if (!root_dict) {
+    return false;
+  }
+
+  RetainPtr<CPDF_Dictionary> acroform_dict =
+      root_dict->GetMutableDictFor("AcroForm");
+  if (!acroform_dict) {
+    acroform_dict = CPDF_InteractiveForm::InitAcroFormDict(doc);
+    CHECK(acroform_dict);
+  }
+
+  CPDF_DefaultAppearance default_appearance(annot_dict, acroform_dict);
+  auto maybe_font_name_and_size = default_appearance.GetFont();
+  if (!maybe_font_name_and_size.has_value()) {
+    return false;
+  }
+
+  ByteString new_default_appearance_font_name_and_size =
+      StringFromFontNameAndSize(maybe_font_name_and_size.value().name,
+                                maybe_font_name_and_size.value().size);
+  if (new_default_appearance_font_name_and_size.IsEmpty()) {
+    return false;
+  }
+
+  ByteString new_default_appearance_color =
+      GenerateColorAP(color, PaintOperation::kFill);
+  CHECK(!new_default_appearance_color.IsEmpty());
+  annot_dict->SetNewFor<CPDF_String>(
+      "DA",
+      new_default_appearance_font_name_and_size + new_default_appearance_color);
+
+  // TODO(thestig): Call GenerateAnnotAP();
+  return true;
 }
\ No newline at end of file
diff --git a/core/fpdfdoc/cpdf_generateap.h b/core/fpdfdoc/cpdf_generateap.h
index 520ce4f..60b158b 100644
--- a/core/fpdfdoc/cpdf_generateap.h
+++ b/core/fpdfdoc/cpdf_generateap.h
@@ -11,6 +11,7 @@
 
 class CPDF_Dictionary;
 class CPDF_Document;
+struct CFX_Color;
 
 class CPDF_GenerateAP {
  public:
@@ -26,6 +27,10 @@
                               CPDF_Dictionary* pAnnotDict,
                               CPDF_Annot::Subtype subtype);
 
+  static bool GenerateDefaultAppearanceWithColor(CPDF_Document* doc,
+                                                 CPDF_Dictionary* annot_dict,
+                                                 const CFX_Color& color);
+
   CPDF_GenerateAP() = delete;
   CPDF_GenerateAP(const CPDF_GenerateAP&) = delete;
   CPDF_GenerateAP& operator=(const CPDF_GenerateAP&) = delete;
diff --git a/core/fpdfdoc/cpdf_interactiveform.h b/core/fpdfdoc/cpdf_interactiveform.h
index e6431c4..4e0e7c4 100644
--- a/core/fpdfdoc/cpdf_interactiveform.h
+++ b/core/fpdfdoc/cpdf_interactiveform.h
@@ -105,6 +105,7 @@
   const std::vector<UnownedPtr<CPDF_FormControl>>& GetControlsForField(
       const CPDF_FormField* field);
 
+  CPDF_Document* document() { return m_pDocument; }
  private:
   void LoadField(RetainPtr<CPDF_Dictionary> field_dict, int nLevel);
   void AddTerminalField(RetainPtr<CPDF_Dictionary> field_dict);
diff --git a/fpdfsdk/cpdfsdk_appstream.cpp b/fpdfsdk/cpdfsdk_appstream.cpp
index b7b06ca..3ef528d 100644
--- a/fpdfsdk/cpdfsdk_appstream.cpp
+++ b/fpdfsdk/cpdfsdk_appstream.cpp
@@ -1190,13 +1190,10 @@
   std::optional<CFX_Color> color = da.GetColor();
   CFX_Color crText = color.value_or(CFX_Color(CFX_Color::Type::kGray, 0));
 
-  float fFontSize;
-  ByteString csNameTag;
-  std::optional<ByteString> font = da.GetFont(&fFontSize);
-  if (font.has_value())
-    csNameTag = font.value();
-  else
-    fFontSize = 12.0f;
+  const float font_size =
+      da.GetFont()
+          .value_or(CPDF_DefaultAppearance::FontNameAndSize{.size = 12.0f})
+          .size;
 
   WideString csWCaption;
   WideString csNormalCaption;
@@ -1237,7 +1234,7 @@
                                    crRightBottom, nBorderStyle, dsBorder) +
         GetPushButtonAppStream(iconFit.GetFittingBounds() ? rcWindow : rcClient,
                                &font_map, pNormalIcon, iconFit, csNormalCaption,
-                               crText, fFontSize, nLayout);
+                               crText, font_size, nLayout);
 
     Write("N", csAP, ByteString());
     if (pNormalIcon)
@@ -1264,7 +1261,7 @@
                                    crRightBottom, nBorderStyle, dsBorder) +
         GetPushButtonAppStream(iconFit.GetFittingBounds() ? rcWindow : rcClient,
                                &font_map, pRolloverIcon, iconFit,
-                               csRolloverCaption, crText, fFontSize, nLayout);
+                               csRolloverCaption, crText, font_size, nLayout);
 
     Write("R", csAP, ByteString());
     if (pRolloverIcon)
@@ -1300,7 +1297,7 @@
                                    crRightBottom, nBorderStyle, dsBorder) +
         GetPushButtonAppStream(iconFit.GetFittingBounds() ? rcWindow : rcClient,
                                &font_map, pDownIcon, iconFit, csDownCaption,
-                               crText, fFontSize, nLayout);
+                               crText, font_size, nLayout);
 
     Write("D", csAP, ByteString());
     if (pDownIcon)
diff --git a/fpdfsdk/cpdfsdk_widget.cpp b/fpdfsdk/cpdfsdk_widget.cpp
index 3cb26d7..b8fa489 100644
--- a/fpdfsdk/cpdfsdk_widget.cpp
+++ b/fpdfsdk/cpdfsdk_widget.cpp
@@ -471,11 +471,7 @@
 }
 
 float CPDFSDK_Widget::GetFontSize() const {
-  CPDF_FormControl* pFormCtrl = GetFormControl();
-  CPDF_DefaultAppearance pDa = pFormCtrl->GetDefaultAppearance();
-  float fFontSize;
-  pDa.GetFont(&fFontSize);
-  return fFontSize;
+  return GetFormControl()->GetDefaultAppearance().GetFontSizeOrZero();
 }
 
 int CPDFSDK_Widget::GetSelectedIndex(int nIndex) const {
diff --git a/fpdfsdk/fpdf_annot.cpp b/fpdfsdk/fpdf_annot.cpp
index e42e6db..adbd1a4 100644
--- a/fpdfsdk/fpdf_annot.cpp
+++ b/fpdfsdk/fpdf_annot.cpp
@@ -11,6 +11,7 @@
 #include <vector>
 
 #include "constants/annotation_common.h"
+#include "core/fpdfapi/edit/cpdf_contentstream_write_utils.h"
 #include "core/fpdfapi/edit/cpdf_pagecontentgenerator.h"
 #include "core/fpdfapi/page/cpdf_annotcontext.h"
 #include "core/fpdfapi/page/cpdf_form.h"
@@ -352,6 +353,27 @@
                     : nullptr;
 }
 
+std::optional<CFX_Color::TypeAndARGB> GetFreetextFontColor(
+    FPDF_FORMHANDLE handle,
+    FPDF_ANNOTATION annot) {
+  const CPDF_Dictionary* annot_dict = GetAnnotDictFromFPDFAnnotation(annot);
+  CHECK(annot_dict);  // Has to be true to determine `annot` is for Freetext.
+
+  CPDFSDK_InteractiveForm* form = FormHandleToInteractiveForm(handle);
+  CPDF_Document* doc = form ? form->GetInteractiveForm()->document() : nullptr;
+  const CPDF_Dictionary* root_dict = doc ? doc->GetRoot() : nullptr;
+  RetainPtr<const CPDF_Dictionary> acroform_dict =
+      root_dict ? root_dict->GetDictFor("AcroForm") : nullptr;
+  CPDF_DefaultAppearance default_appearance(annot_dict, acroform_dict);
+  return default_appearance.GetColorARGB();
+}
+
+std::optional<FX_COLORREF> GetWidgetFontColor(FPDF_FORMHANDLE handle,
+                                              FPDF_ANNOTATION annot) {
+  const CPDFSDK_Widget* widget = GetWidgetOfTypes(handle, annot, {});
+  return widget ? widget->GetTextColor() : std::nullopt;
+}
+
 }  // namespace
 
 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
@@ -1386,6 +1408,46 @@
 }
 
 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFAnnot_SetFontColor(FPDF_FORMHANDLE handle,
+                       FPDF_ANNOTATION annot,
+                       unsigned int R,
+                       unsigned int G,
+                       unsigned int B) {
+  RetainPtr<CPDF_Dictionary> annot_dict =
+      GetMutableAnnotDictFromFPDFAnnotation(annot);
+  if (!annot_dict || R > 255 || G > 255 || B > 255) {
+    return false;
+  }
+
+  const CPDF_Annot::Subtype subtype = CPDF_Annot::StringToAnnotSubtype(
+      annot_dict->GetNameFor(pdfium::annotation::kSubtype));
+  if (subtype != CPDF_Annot::Subtype::FREETEXT) {
+    // TODO(thestig): Consider adding widget support to mirror
+    // FPDFAnnot_GetFontColor().
+    return false;
+  }
+
+  CPDFSDK_InteractiveForm* form = FormHandleToInteractiveForm(handle);
+  if (!form) {
+    return false;
+  }
+
+  bool generated = CPDF_GenerateAP::GenerateDefaultAppearanceWithColor(
+      form->GetInteractiveForm()->document(), annot_dict, CFX_Color(R, G, B));
+  if (!generated) {
+    return false;
+  }
+
+  // Remove the appearance stream. Otherwise PDF viewers will render that and
+  // not use the new color.
+  //
+  // TODO(thestig) When GenerateDefaultAppearanceWithColor() properly updates
+  // the annotation's appearance stream, remove this.
+  annot_dict->RemoveFor(pdfium::annotation::kAP);
+  return true;
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
 FPDFAnnot_GetFontColor(FPDF_FORMHANDLE hHandle,
                        FPDF_ANNOTATION annot,
                        unsigned int* R,
@@ -1395,19 +1457,32 @@
     return false;
   }
 
-  const CPDFSDK_Widget* widget = GetWidgetOfTypes(hHandle, annot, {});
-  if (!widget) {
-    return false;
+  FX_COLORREF font_color;
+  switch (FPDFAnnot_GetSubtype(annot)) {
+    case FPDF_ANNOT_FREETEXT: {
+      auto maybe_font_color = GetFreetextFontColor(hHandle, annot);
+      if (!maybe_font_color.has_value()) {
+        return false;
+      }
+      font_color = ArgbToColorRef(maybe_font_color.value().argb);
+      break;
+    }
+    case FPDF_ANNOT_WIDGET: {
+      auto maybe_font_color = GetWidgetFontColor(hHandle, annot);
+      if (!maybe_font_color.has_value()) {
+        return false;
+      }
+      font_color = maybe_font_color.value();
+      break;
+    }
+    default: {
+      return false;
+    }
   }
 
-  std::optional<FX_COLORREF> text_color = widget->GetTextColor();
-  if (!text_color) {
-    return false;
-  }
-
-  *R = FXSYS_GetRValue(*text_color);
-  *G = FXSYS_GetGValue(*text_color);
-  *B = FXSYS_GetBValue(*text_color);
+  *R = FXSYS_GetRValue(font_color);
+  *G = FXSYS_GetGValue(font_color);
+  *B = FXSYS_GetBValue(font_color);
   return true;
 }
 
diff --git a/fpdfsdk/fpdf_view_c_api_test.c b/fpdfsdk/fpdf_view_c_api_test.c
index 1765faf..3c49c47 100644
--- a/fpdfsdk/fpdf_view_c_api_test.c
+++ b/fpdfsdk/fpdf_view_c_api_test.c
@@ -94,6 +94,7 @@
     CHK(FPDFAnnot_SetColor);
     CHK(FPDFAnnot_SetFlags);
     CHK(FPDFAnnot_SetFocusableSubtypes);
+    CHK(FPDFAnnot_SetFontColor);
     CHK(FPDFAnnot_SetRect);
     CHK(FPDFAnnot_SetStringValue);
     CHK(FPDFAnnot_SetURI);
diff --git a/fxjs/cjs_field.cpp b/fxjs/cjs_field.cpp
index d230b06..49c3030 100644
--- a/fxjs/cjs_field.cpp
+++ b/fxjs/cjs_field.cpp
@@ -1984,10 +1984,10 @@
   if (!pFormControl)
     return CJS_Result::Failure(JSMessage::kBadObjectError);
 
-  float fFontSize;
-  CPDF_DefaultAppearance FieldAppearance = pFormControl->GetDefaultAppearance();
-  FieldAppearance.GetFont(&fFontSize);
-  return CJS_Result::Success(pRuntime->NewNumber(static_cast<int>(fFontSize)));
+  CPDF_DefaultAppearance field_appearance =
+      pFormControl->GetDefaultAppearance();
+  return CJS_Result::Success(pRuntime->NewNumber(
+      static_cast<int>(field_appearance.GetFontSizeOrZero())));
 }
 
 CJS_Result CJS_Field::set_text_size(CJS_Runtime* pRuntime,
diff --git a/public/fpdf_annot.h b/public/fpdf_annot.h
index ef30d9a..cc63679 100644
--- a/public/fpdf_annot.h
+++ b/public/fpdf_annot.h
@@ -846,6 +846,27 @@
                       float* value);
 
 // Experimental API.
+// Set the text color of an annotation.
+//
+//   handle   - handle to the form fill module, returned by
+//              FPDFDOC_InitFormFillEnvironment.
+//   annot    - handle to an annotation.
+//   R        - the red component for the text color.
+//   G        - the green component for the text color.
+//   B        - the blue component for the text color.
+//
+// Returns true if successful.
+//
+// Currently supported subtypes: freetext.
+// The range for the color components is 0 to 255.
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFAnnot_SetFontColor(FPDF_FORMHANDLE handle,
+                       FPDF_ANNOTATION annot,
+                       unsigned int R,
+                       unsigned int G,
+                       unsigned int B);
+
+// Experimental API.
 // Get the RGB value of the font color for an |annot| with variable text.
 //
 //   hHandle  - handle to the form fill module, returned by