Font subsetting for form fields
diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index f40643a..faf523d 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -3302,7 +3302,7 @@
     return fontDict;
 }
 
-std::vector<std::shared_ptr<const GfxFont>> AnnotFreeText::subsetFonts(const FontSubsetter *fontSubsetter)
+AnnotFreeText::SubsetFontsResult AnnotFreeText::subsetFonts(const FontSubsetter *fontSubsetter)
 {
 #if ENABLE_HARFBUZZ
     if (appearance.isNull()) {
@@ -3388,7 +3388,7 @@
     Dict *apDict = appearance.fetch(doc->getXRef()).getStream()->getDict();
     apDict->set("Resources", std::move(resourcesCopy));
 
-    return result.fontsToRemove;
+    return { .success = true, .fontsToRemove = result.fontsToRemove };
 #else
     (void)fontSubsetter;
     return {};
@@ -4733,11 +4733,9 @@
     const bool forceZapfDingbats = flags & ForceZapfDingbatsDrawTextFlag;
 
     std::vector<std::string> daToks;
-    const GfxFont *font;
     double fontSize;
     int tfPos, tmPos;
     std::unique_ptr<std::string> textToFree;
-    std::unique_ptr<const GfxFont> fontToFree = nullptr;
 
     //~ if there is no MK entry, this should use the existing content stream,
     //~ and only replace the marked content portion of it
@@ -4761,39 +4759,11 @@
     }
 
     // get the font and font size
-    font = nullptr;
-    fontSize = 0;
-    if (tfPos >= 0) {
-        std::string &tok = daToks[tfPos];
-        if (forceZapfDingbats) {
-            if (tok != "/ZaDb") {
-                tok = "/ZaDb";
-            }
-        }
-        if (!tok.empty() && tok[0] == '/') {
-            const auto fontName = std::string_view(tok).substr(1);
-            if (!resources || !(font = resources->lookupFont(fontName).get())) {
-                const char *fallback = determineFallbackFont(tok, forceZapfDingbats ? "ZapfDingbats" : "Helvetica");
-                // The font variable sometimes points to an object that needs to be deleted
-                // and sometimes not, depending on whether the call to lookupFont above fails.
-                // When the code path right here is taken, the destructor of fontToFree
-                // (which is a std::unique_ptr) will delete the font object at the end of this method.
-                fontToFree = createAnnotDrawFont(&xref, &resourcesDict, fontName, fallback);
-                font = fontToFree.get();
-                if (font && forceZapfDingbats) {
-                    addedDingbatsResource = true;
-                }
-            }
-        } else {
-            error(errSyntaxError, -1, "Invalid font name in 'Tf' operator in field's DA string");
-        }
-        fontSize = gatof(daToks[tfPos + 1].c_str());
-    } else {
-        error(errSyntaxError, -1, "Missing 'Tf' operator in field's DA string");
-    }
+    std::shared_ptr<const GfxFont> font = calculateFont(daToks, resources, resourcesDict, xref, tfPos, flags);
     if (!font) {
         return false;
     }
+    fontSize = gatof(daToks[tfPos + 1].c_str());
 
     if (tmPos < 0) {
         // Add fake Tm to the DA tokens
@@ -4938,7 +4908,7 @@
                     int uLen, n;
                     double char_dx, char_dy, ox, oy;
 
-                    const GfxFont *currentFont = font;
+                    const GfxFont *currentFont = font.get();
                     if (!d.fontName.empty()) {
                         appearBuf.append(" q\n");
                         GooString::appendf(appearBuf, "/{0:s} {1:.2f} Tf\n", d.fontName.c_str(), fontSize);
@@ -5583,6 +5553,196 @@
     recursiveMergeDicts(primary, secondary, &alreadySeenDicts);
 }
 
+AnnotWidget::SubsetFontsResult AnnotWidget::subsetFonts(const FontSubsetter *fontSubsetter, const std::string &content)
+{
+#if ENABLE_HARFBUZZ
+    const auto *textField = dynamic_cast<FormFieldText *>(field);
+    if (!textField) {
+        error(errInternal, -1, "AnnotWidget::subsetFonts, subsetFonts() called on a non-text form field. This should never happen. Abort subsetting.");
+        return {};
+    }
+
+    // TODO: Implement subsetting when appearance is null
+    if (appearance.isNull() || form->getNeedAppearances()) {
+        return {};
+    }
+
+    Object resourcesDictObj;
+    const GfxResources *resources = nullptr;
+    std::unique_ptr<GfxResources> resourcesToFree = nullptr;
+    if (field->getObj() && field->getObj()->isDict()) {
+        // Let's use a field's resource dictionary.
+        resourcesDictObj = field->getObj()->dictLookup("DR");
+        if (resourcesDictObj.isDict()) {
+            if (form && form->getDefaultResourcesObj()->isDict()) {
+                resourcesDictObj = resourcesDictObj.deepCopy();
+                recursiveMergeDicts(resourcesDictObj.getDict(), form->getDefaultResourcesObj()->getDict());
+            }
+            resourcesToFree = std::make_unique<GfxResources>(doc->getXRef(), resourcesDictObj.getDict(), nullptr);
+            resources = resourcesToFree.get();
+        }
+    }
+    if (!resourcesDictObj.isDict()) {
+        // No luck with a field's resource dictionary. Let's use an AcroForm's resource dictionary.
+        if (form && form->getDefaultResourcesObj()->isDict()) {
+            resourcesDictObj = form->getDefaultResourcesObj()->deepCopy();
+            resources = form->getDefaultResources();
+        }
+    }
+    if (!resourcesDictObj.isDict()) {
+        resourcesDictObj = Object(std::make_unique<Dict>(doc->getXRef()));
+    }
+
+    const std::string &fieldDA = field->getDefaultAppearance();
+    const std::string &daToUse = fieldDA.empty() && form ? form->getDefaultAppearance() : fieldDA;
+
+    std::vector<std::string> daToks;
+    int tfPos = -1;
+
+    // parse the default appearance string
+    FormFieldText::tokenizeDA(daToUse, &daToks, nullptr /*searchTok*/);
+    for (size_t i = 2; i < daToks.size(); ++i) {
+        if (daToks[i] == "Tf") {
+            tfPos = i - 2;
+        }
+    }
+
+    AnnotAppearanceBuilder appearBuilderA;
+    std::shared_ptr<const GfxFont> primaryFont = appearBuilderA.calculateFont(daToks, resources, *resourcesDictObj.getDict(), *doc->getXRef(), tfPos, 0 /* No flags required when our purpose is to get the primary font for a form field*/);
+
+    if (!primaryFont) {
+        error(errInternal, -1, "AnnotWidget::subsetFonts, Could not determine primary font");
+        return {};
+    }
+
+    HorizontalTextLayouter textLayouter(content, form, *primaryFont, std::nullopt, false);
+
+    FontSubsetter::FontStringMap fontStringMap;
+    bool isPassword = textField->isPassword();
+
+    for (const auto &d : textLayouter.data) {
+        const std::string &text = d.text;
+
+        std::shared_ptr<const GfxFont> font = nullptr;
+
+        if (d.fontName.empty()) {
+            font = primaryFont;
+        } else {
+            font = form->getDefaultResources()->lookupFont(d.fontName);
+            if (!font) {
+                error(errInternal, -1, "AnnotWidget::subsetFonts, Could not find font in default resources");
+                return {};
+            }
+        }
+
+        // If it's a password field, subset only '*' in all the fonts
+        if (isPassword) {
+            Unicode uChar = pdfDocEncoding['*' & 0xff];
+            fontStringMap[font] = { uChar };
+            continue;
+        }
+
+        bool isUnicode;
+        if (d.charCount == text.size()) {
+            isUnicode = false;
+        } else if (d.charCount * 2 == text.size()) {
+            isUnicode = true;
+        } else {
+            error(errInternal, -1, "AnnotWidget::subsetFonts, Invalid result from HorizontalTextLayouter");
+            return {};
+        }
+
+        if (text.empty()) {
+            if (!fontStringMap.contains(font)) {
+                fontStringMap[font] = {};
+            }
+        }
+
+        size_t i = 0;
+        while (i < text.size()) {
+            if (isUnicode) {
+                Unicode uChar = ((text[i] & 0xff) << 8) | (text[i + 1] & 0xff);
+                fontStringMap[font].emplace_back(uChar);
+            } else {
+                Unicode uChar = pdfDocEncoding[text[i] & 0xff];
+                fontStringMap[font].emplace_back(uChar);
+            }
+            i += (isUnicode ? 2 : 1);
+        }
+    }
+
+    FontSubsetter::GetSubsetFontsResult result = fontSubsetter->getSubsetFonts(fontStringMap);
+
+    /*
+        - Deep copy the Resources present in appearance dictionary
+        - Get a pointer to the font dictionary inside the resources copy
+        - Modify the font dictionary
+        - Set "Resources" in the appearance dictionary to our resources copy
+    */
+
+    Object resourcesCopy = getAppearanceResDict().deepCopy();
+    Dict *fontDict = getFontDictFromResourcesDict(resourcesCopy, doc->getXRef(), false);
+
+    if (!fontDict) {
+        error(errInternal, -1, "AnnotWidget::subsetFonts, Unable to find font dictionary inside appearance resource dictionary");
+        return {};
+    }
+
+    for (const auto &[tag, newFontRef] : result.tagRefMappings) {
+        if (fontDict->hasKey(tag)) {
+            fontDict->set(tag, Object(newFontRef));
+        } else {
+            // This should never happen. We are just being extra safe here.
+            error(errInternal, -1, "AnnotWidget::subsetFonts, a tag was not found in font dictionary. Aborting subsetting.");
+            return {};
+        }
+    }
+
+    Dict *apDict = appearance.fetch(doc->getXRef()).getStream()->getDict();
+    apDict->set("Resources", std::move(resourcesCopy));
+
+    return { .success = true, .fontsToRemove = result.fontsToRemove };
+#else
+    (void)fontSubsetter;
+    (void)content;
+    return {};
+#endif
+}
+
+std::shared_ptr<const GfxFont> AnnotAppearanceBuilder::calculateFont(std::vector<std::string> &daToks, const GfxResources *resources, Dict &resourcesDict, XRef &xref, int tfPos, const int flags)
+{
+    const bool forceZapfDingbats = flags & ForceZapfDingbatsDrawTextFlag;
+
+    std::shared_ptr<const GfxFont> font;
+
+    // get the font
+    font = nullptr;
+    if (tfPos >= 0) {
+        std::string &tok = daToks[tfPos];
+        if (forceZapfDingbats) {
+            if (tok != "/ZaDb") {
+                tok = "/ZaDb";
+            }
+        }
+        if (!tok.empty() && tok[0] == '/') {
+            const auto fontName = std::string_view(tok).substr(1);
+            if (!resources || !(font = resources->lookupFont(fontName))) {
+                const char *fallback = determineFallbackFont(tok, forceZapfDingbats ? "ZapfDingbats" : "Helvetica");
+                font = createAnnotDrawFont(&xref, &resourcesDict, fontName, fallback);
+                if (font && forceZapfDingbats) {
+                    addedDingbatsResource = true;
+                }
+            }
+        } else {
+            error(errSyntaxError, -1, "Invalid font name in 'Tf' operator in field's DA string");
+        }
+    } else {
+        error(errSyntaxError, -1, "Missing 'Tf' operator in field's DA string");
+    }
+
+    return font;
+}
+
 void AnnotWidget::generateFieldAppearance(bool *addedDingbatsResource)
 {
     AnnotAppearanceBuilder appearBuilder;
diff --git a/poppler/Annot.h b/poppler/Annot.h
index 8eea9f1..4764d42 100644
--- a/poppler/Annot.h
+++ b/poppler/Annot.h
@@ -609,6 +609,8 @@
     const std::string &buffer() const;
     bool getAddedDingbatsResource() const { return addedDingbatsResource; }
 
+    std::shared_ptr<const GfxFont> calculateFont(std::vector<std::string> &daToks, const GfxResources *resources, Dict &resourcesDict, XRef &xref, int tfPos, int flags);
+
 private:
     enum DrawTextFlags
     {
@@ -1090,7 +1092,12 @@
     AnnotLineEndingStyle getEndStyle() const { return endStyle; }
 
     // Performs the subsetting and returns the original fonts to delete
-    std::vector<std::shared_ptr<const GfxFont>> subsetFonts(const FontSubsetter *fontSubsetter);
+    struct SubsetFontsResult
+    {
+        bool success = false;
+        std::vector<std::shared_ptr<const GfxFont>> fontsToRemove;
+    };
+    SubsetFontsResult subsetFonts(const FontSubsetter *fontSubsetter);
 
 protected:
     void initialize(Dict *dict);
@@ -1486,6 +1493,14 @@
 
     void setField(FormField *f) { field = f; };
 
+    // Performs the subsetting and returns the original fonts to delete
+    struct SubsetFontsResult
+    {
+        bool success = false;
+        std::vector<std::shared_ptr<const GfxFont>> fontsToRemove;
+    };
+    SubsetFontsResult subsetFonts(const FontSubsetter *fontSubsetter, const std::string &content);
+
 private:
     void initialize(Dict *dict);
 
diff --git a/poppler/FontSubsetter.cc b/poppler/FontSubsetter.cc
index e2c6b3f..0db2687 100644
--- a/poppler/FontSubsetter.cc
+++ b/poppler/FontSubsetter.cc
@@ -96,6 +96,38 @@
     xref->removeIndirectObject(fontStreamRef);
 }
 
+void FontSubsetter::subsetFormFieldText(const std::unique_ptr<FormPageWidgets> &form, std::vector<std::shared_ptr<const GfxFont>> &fontsToRemove, std::unordered_set<Ref> &refSet, XRef *xref, bool &subsettingSuccessful) const
+{
+    int numWidgets = form->getNumWidgets();
+    for (int i = 0; i < numWidgets; ++i) {
+        FormWidget *widget = form->getWidget(i);
+        if (widget->getType() != FormFieldType::formText) {
+            continue;
+        }
+
+        auto *widgetText = static_cast<FormWidgetText *>(widget);
+
+        if (auto wdgAnnot = widgetText->getWidgetAnnotation(); wdgAnnot != nullptr) {
+            unsigned int id = wdgAnnot->getId();
+            if (!xref->getEntry(id)->getFlag(XRefEntry::Updated) || !widgetText->getContent()) {
+                continue;
+            }
+
+            auto result = wdgAnnot->subsetFonts(this, widgetText->getContent()->toStr());
+            if (!result.success) {
+                subsettingSuccessful = false;
+            }
+
+            for (const auto &font : result.fontsToRemove) {
+                if (!refSet.contains(*font->getID())) {
+                    fontsToRemove.emplace_back(font);
+                    refSet.insert(*font->getID());
+                }
+            }
+        }
+    }
+}
+
 static void removeFontsFromFontDict(Dict *fontDict, std::unordered_set<Ref> &refSet)
 {
     std::vector<std::string> keysToRemove;
@@ -119,40 +151,29 @@
     }
 }
 
-static bool formFieldModified(const FormField *field, XRef *xref)
+static void removeFontsFromFieldRes(const std::unique_ptr<FormPageWidgets> &form, std::unordered_set<Ref> &refSet, XRef *xref)
 {
-    int numChildren = field->getNumChildren();
-    if (numChildren == 0) {
-        int numWidgets = field->getNumWidgets();
+    int numWidgets = form->getNumWidgets();
+    for (int i = 0; i < numWidgets; ++i) {
+        FormWidget *widget = form->getWidget(i);
+        if (widget->getType() != FormFieldType::formText || !widget->getField()) {
+            continue;
+        }
 
-        for (int i = 0; i < numWidgets; ++i) {
-            if (FormWidget *wdg = field->getWidget(i); wdg != nullptr) {
-                if (std::shared_ptr<AnnotWidget> wdgAnnot = wdg->getWidgetAnnotation(); wdgAnnot != nullptr) {
-                    unsigned int id = wdgAnnot->getId();
-                    if (xref->getEntry(id)->getFlag(XRefEntry::Updated)) {
-                        return true;
-                    }
+        FormField *field = widget->getField();
+        if (Object *fieldObj = field->getObj(); fieldObj && fieldObj->isDict()) {
+            if (Object dr = fieldObj->dictLookup("DR"); dr.isDict()) {
+                if (Dict *fontDict = getFontDictFromResourcesDict(dr, xref, false); fontDict != nullptr) {
+                    removeFontsFromFontDict(fontDict, refSet);
                 }
             }
         }
-        return false;
     }
-
-    for (int i = 0; i < numChildren; ++i) {
-        if (const FormField *childField = field->getChildren(i); childField != nullptr) {
-            if (formFieldModified(childField, xref)) {
-                return true;
-            }
-        }
-    }
-
-    return false;
 }
 
 void FontSubsetter::subsetAll() const
 {
     XRef *xref = doc->getXRef();
-    Form *form = doc->getCatalog()->getCreateForm();
     int numPages = doc->getNumPages();
     Object *acroForm = doc->getCatalog()->getAcroForm();
 
@@ -162,25 +183,13 @@
     std::unordered_set<Ref> refSet;
     std::vector<std::shared_ptr<const GfxFont>> fontsToRemove;
 
-    /*
-     * Do not perform font subsetting if a form field is also modified
-     * This is because we might remove a font that is already getting used in a form field
-     * TODO: Remove this code when we have font subsetting ready for form fields
-     */
-    bool anyFormFieldModified = false;
-    for (int i = 0; i < form->getNumFields(); i++) {
-        if (FormField *field = form->getRootField(i); field != nullptr) {
-            if (formFieldModified(field, xref)) {
-                anyFormFieldModified = true;
-                break;
-            }
-        }
-    }
-    if (anyFormFieldModified) {
-        return;
+    bool subsettingSuccessful = true;
+
+    for (int i = 1; i <= numPages; i++) {
+        Page *page = doc->getPage(i);
+        subsetFormFieldText(page->getFormWidgets(), fontsToRemove, refSet, xref, subsettingSuccessful);
     }
 
-    bool subsettingSuccessful = true;
     for (int i = 1; i <= numPages; i++) {
         Page *page = doc->getPage(i);
 
@@ -200,12 +209,12 @@
             if (annot->getType() == Annot::typeFreeText) {
                 auto *ftAnnot = static_cast<AnnotFreeText *>(annot.get());
 
-                auto fontsToRemoveLocal = ftAnnot->subsetFonts(this);
-                if (fontsToRemoveLocal.empty()) {
+                auto result = ftAnnot->subsetFonts(this);
+                if (!result.success) {
                     subsettingSuccessful = false;
                 }
 
-                for (const auto &font : fontsToRemoveLocal) {
+                for (const auto &font : result.fontsToRemove) {
                     if (!refSet.contains(*font->getID())) {
                         fontsToRemove.emplace_back(font);
                         refSet.insert(*font->getID());
@@ -219,6 +228,7 @@
      * If subsetting fails for even one entity (annotation or form), it may not be safe to remove the original fonts since the entity might be using the old fonts
      */
     if (!subsettingSuccessful) {
+        error(errInternal, -1, "FontSubsetter::subsetAll, subsetting was not fully successful so skipping removal of original fonts");
         return;
     }
 
@@ -232,7 +242,7 @@
         }
     }
 
-    // Scan local resources of all modified annotations and remove the old font refs
+    // Scan local resources of all modified freetext annotations and widget annotations (forms) and remove the old font refs
     for (int i = 1; i <= numPages; i++) {
         Page *page = doc->getPage(i);
 
@@ -249,15 +259,18 @@
                 continue;
             }
 
-            if (annot->getType() == Annot::typeFreeText) {
-                auto *ftAnnot = static_cast<AnnotFreeText *>(annot.get());
-
-                Object resourcesCopy = ftAnnot->getAppearanceResDict().deepCopy();
+            if (annot->getType() == Annot::typeFreeText || annot->getType() == Annot::typeWidget) {
+                Object resourcesCopy = annot->getAppearanceResDict().deepCopy();
                 if (!resourcesCopy.isDict()) {
                     continue;
                 }
 
-                Dict *fontDict = getFontDictFromResourcesDict(resourcesCopy, xref, (ftAnnot->getOpacity() != 1));
+                bool transparency = false;
+                if (annot->getType() == Annot::typeFreeText) {
+                    auto *ftAnnot = static_cast<AnnotFreeText *>(annot.get());
+                    transparency = (ftAnnot->getOpacity() != 1);
+                }
+                Dict *fontDict = getFontDictFromResourcesDict(resourcesCopy, xref, transparency);
                 if (!fontDict) {
                     continue;
                 }
@@ -275,6 +288,12 @@
         }
     }
 
+    // Remove old font refs from modified field resources
+    for (int i = 1; i <= numPages; i++) {
+        Page *page = doc->getPage(i);
+        removeFontsFromFieldRes(page->getFormWidgets(), refSet, xref);
+    }
+
     // Remove the actual font and it's associated objects
     for (const auto &font : fontsToRemove) {
         removeOldFont(font, xref);
diff --git a/poppler/FontSubsetter.h b/poppler/FontSubsetter.h
index 47f4ef8..addeabe 100644
--- a/poppler/FontSubsetter.h
+++ b/poppler/FontSubsetter.h
@@ -14,10 +14,12 @@
 #include "GfxFont.h"
 #include "Object.h"
 #include <vector>
+#include <unordered_set>
 
 struct hb_blob_t;
 
 class PDFDoc;
+class FormPageWidgets;
 
 class FontSubsetter
 {
@@ -49,6 +51,8 @@
 
     Object createNewSubsetFont(const GfxFont *oldFont, SubsetFontResult &&subsettingResult, const std::vector<Unicode> &unicodeValues, Ref &newFontRef) const;
 
+    void subsetFormFieldText(const std::unique_ptr<FormPageWidgets> &form, std::vector<std::shared_ptr<const GfxFont>> &fontsToRemove, std::unordered_set<Ref> &refSet, XRef *xref, bool &subsettingSuccessful) const;
+
     // Harfbuzz related APIs
     static SubsetFontResult hbSubsetFont(std::string &fontStream, const std::vector<Unicode> &unicodeValues);
 };
diff --git a/poppler/Form.h b/poppler/Form.h
index 0fd8677..98a3c84 100644
--- a/poppler/Form.h
+++ b/poppler/Form.h
@@ -491,7 +491,7 @@
 // FormFieldText
 //------------------------------------------------------------------------
 
-class FormFieldText : public FormField
+class POPPLER_PRIVATE_EXPORT FormFieldText : public FormField
 {
 public:
     FormFieldText(PDFDoc *docA, Object &&dictObj, Ref ref, FormField *parent, std::set<int> *usedParents);
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 933edba..60779d1 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -302,11 +302,11 @@
 endif()
 
 if (ENABLE_HARFBUZZ)
-  set(fontsubsetting_basic_test_SRCS font-subsetting/fontsubsetting-basic-test.cc)
-  add_executable(fontsubsetting-basic-test ${fontsubsetting_basic_test_SRCS})
-  target_link_libraries(fontsubsetting-basic-test Freetype::Freetype poppler)
-  add_test(
-    NAME fontsubsetting-basic-test
-    COMMAND fontsubsetting-basic-test ${TESTDATADIR}/unittestcases/UseNone.pdf
-  )
-endif()
\ No newline at end of file
+    set(fontsubsetting_basic_test_SRCS font-subsetting/fontsubsetting-basic-test.cc)
+    add_executable(fontsubsetting-basic-test ${fontsubsetting_basic_test_SRCS})
+    target_link_libraries(fontsubsetting-basic-test Freetype::Freetype poppler)
+    add_test(
+      NAME fontsubsetting-basic-test
+      COMMAND fontsubsetting-basic-test ${TESTDATADIR}/unittestcases/UseNone.pdf ${TESTDATADIR}/unittestcases/pdf_with_text_form_field.pdf
+    )
+endif()
diff --git a/test/font-subsetting/fontsubsetting-basic-test.cc b/test/font-subsetting/fontsubsetting-basic-test.cc
index f263825..73f2f53 100644
--- a/test/font-subsetting/fontsubsetting-basic-test.cc
+++ b/test/font-subsetting/fontsubsetting-basic-test.cc
@@ -167,7 +167,7 @@
  * Goes over all the fonts used by the annotation and collects all the glyphs
  * Checks if the glyphs are only what we need
  */
-static bool subsettingWorksInAnnot(Annot *annot, XRef *xref, bool transparency)
+static bool subsettingWorksInAnnot(Annot *annot, const std::string &text, XRef *xref, bool transparency)
 {
     Object resources = annot->getAppearanceResDict();
     const Dict *fontDict = getFontDictFromResourcesDict(resources, xref, transparency);
@@ -180,7 +180,6 @@
     std::vector<unsigned long> allChars;
     for (auto &font : allFonts) {
         std::string data = getFontDataFromFont(font, xref);
-
         if (data.empty()) {
             continue;
         }
@@ -195,8 +194,7 @@
         }
     }
 
-    std::vector<unsigned long> neededChars = convertUnicodetoNormalStr(annot->getContents().toStr());
-
+    std::vector<unsigned long> neededChars = convertUnicodetoNormalStr(text);
     return match(allChars, neededChars);
 }
 
@@ -264,7 +262,7 @@
         return false;
     }
 
-    return subsettingWorksInAnnot(annot.get(), doc->getXRef(), false);
+    return subsettingWorksInAnnot(annot.get(), annot->getContents().toStr(), doc->getXRef(), false);
 }
 
 /*
@@ -279,7 +277,6 @@
     }
 
     auto doc = PDFDocFactory().createPDFDoc(*filename);
-
     if (!doc->isOk() || doc->getNumPages() < 1) {
         return false;
     }
@@ -299,7 +296,6 @@
 
     // Re-open the file and check if the fonts only contain the needed glyphs
     doc = PDFDocFactory().createPDFDoc(*tempFilePath);
-
     if (!doc->isOk() || doc->getNumPages() < 1) {
         return false;
     }
@@ -321,24 +317,100 @@
         return false;
     }
 
-    return subsettingWorksInAnnot(annot.get(), doc->getXRef(), true);
+    return subsettingWorksInAnnot(annot.get(), annot->getContents().toStr(), doc->getXRef(), true);
+}
+
+static bool testFormFieldSubsetting(std::shared_ptr<GooString> &filename)
+{
+    std::string UNICODE_TEXT;
+    int unicodeVals[] = { -2, -1, 101, -27, 103, 44, -118, -98 }; // "日本語"
+    for (int val : unicodeVals) {
+        UNICODE_TEXT += static_cast<char>(val);
+    }
+
+    auto doc = PDFDocFactory().createPDFDoc(*filename);
+    if (!doc->isOk() || doc->getNumPages() < 1) {
+        return false;
+    }
+
+    Form *form = doc->getCatalog()->getCreateForm();
+
+    int numFields = form->getNumFields();
+
+    if (numFields != 1) {
+        return false;
+    }
+
+    FormField *field = form->getRootField(0);
+    if (field->getNumChildren() != 0 || field->getType() != FormFieldType::formText) {
+        return false;
+    }
+
+    auto *textField = dynamic_cast<FormFieldText *>(field);
+
+    textField->setContent(std::make_unique<GooString>(UNICODE_TEXT));
+
+    auto tempFilePath = std::make_unique<GooString>(std::filesystem::current_path() / "temp.pdf");
+
+    doc->saveAs(tempFilePath->toStr());
+
+    doc = PDFDocFactory().createPDFDoc(*tempFilePath);
+    if (!doc->isOk() || doc->getNumPages() < 1) {
+        return false;
+    }
+
+    form = doc->getCatalog()->getCreateForm();
+
+    numFields = form->getNumFields();
+    if (numFields != 1) {
+        return false;
+    }
+
+    field = form->getRootField(0);
+    if (field->getNumChildren() != 0 || field->getType() != FormFieldType::formText) {
+        return false;
+    }
+
+    textField = dynamic_cast<FormFieldText *>(field);
+    std::string newText = textField->getContent()->toStr();
+
+    if (newText != UNICODE_TEXT) {
+        return false;
+    }
+
+    int numWidgets = textField->getNumWidgets();
+    if (numWidgets != 1) {
+        return false;
+    }
+
+    FormWidget *widget = textField->getWidget(0);
+
+    std::shared_ptr<AnnotWidget> wdgAnnot = widget->getWidgetAnnotation();
+
+    return subsettingWorksInAnnot(wdgAnnot.get(), newText, doc->getXRef(), false);
 }
 
 int main(int argc, char *argv[])
 {
-    if (argc != 2) {
+    if (argc != 3) {
         return 1;
     }
 
     globalParams = std::make_unique<GlobalParams>();
 
-    // For test1 and test2
-    auto filename = std::make_shared<GooString>(argv[1]);
+    auto filename1 = std::make_shared<GooString>(argv[1]);
+    auto filename2 = std::make_shared<GooString>(argv[2]);
 
-    auto test1 = testSingleAnnotationSubsetting(filename);
-    auto test2 = testSingleAnnotationSubsettingWithOpacity(filename);
+    auto test1 = testSingleAnnotationSubsetting(filename1);
+    auto test2 = testSingleAnnotationSubsettingWithOpacity(filename1);
+    auto test3 = testFormFieldSubsetting(filename2);
 
-    if (!(test1 && test2)) {
+    // Check and remove the temporary pdf file we save for the tests
+    if (std::filesystem::exists(std::filesystem::current_path() / "temp.pdf")) {
+        std::filesystem::remove(std::filesystem::current_path() / "temp.pdf");
+    }
+
+    if (!(test1 && test2 && test3)) {
         return 1;
     }