Remove listbox providers and build into listbox

This CL removes the IFWL_ListBox::DataProvider and builds the data storage
for the list directly into IFWL_ListBox. This removes the need for the provider
in CFWL_ComboBox and CFWL_ListBox.

Change-Id: I74c2286757a0b73083908f1cc630a88e7d730fd9
Reviewed-on: https://pdfium-review.googlesource.com/2050
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
diff --git a/xfa/fwl/core/cfwl_combobox.cpp b/xfa/fwl/core/cfwl_combobox.cpp
index 602e09d..9af4b8d 100644
--- a/xfa/fwl/core/cfwl_combobox.cpp
+++ b/xfa/fwl/core/cfwl_combobox.cpp
@@ -35,32 +35,29 @@
   CFWL_Widget::Initialize();
 }
 
-int32_t CFWL_ComboBox::AddString(const CFX_WideStringC& wsText) {
-  std::unique_ptr<CFWL_ListItem> pItem(new CFWL_ListItem);
-  pItem->m_wsText = wsText;
-  pItem->m_dwStyles = 0;
-  m_ItemArray.push_back(std::move(pItem));
-  return m_ItemArray.size() - 1;
+void CFWL_ComboBox::AddString(const CFX_WideStringC& wsText) {
+  if (GetWidget())
+    ToComboBox(GetWidget())->AddString(wsText);
 }
 
 bool CFWL_ComboBox::RemoveAt(int32_t iIndex) {
-  if (iIndex < 0 || static_cast<size_t>(iIndex) >= m_ItemArray.size())
-    return false;
-
-  m_ItemArray.erase(m_ItemArray.begin() + iIndex);
-  return true;
+  return GetWidget() && ToComboBox(GetWidget())->RemoveAt(iIndex);
 }
 
 void CFWL_ComboBox::RemoveAll() {
-  m_ItemArray.clear();
+  if (GetWidget())
+    ToComboBox(GetWidget())->RemoveAll();
+}
+
+FX_FLOAT CFWL_ComboBox::GetListHeight(IFWL_Widget* pWidget) {
+  return m_fMaxListHeight;
 }
 
 void CFWL_ComboBox::GetTextByIndex(int32_t iIndex,
                                    CFX_WideString& wsText) const {
-  CFWL_ListItem* pItem =
-      static_cast<CFWL_ListItem*>(GetItem(m_pIface.get(), iIndex));
-  if (pItem)
-    wsText = pItem->m_wsText;
+  if (!GetWidget())
+    return;
+  ToComboBox(GetWidget())->GetTextByIndex(iIndex, wsText);
 }
 
 int32_t CFWL_ComboBox::GetCurSel() const {
@@ -155,97 +152,3 @@
         ->EditModifyStylesEx(dwStylesExAdded, dwStylesExRemoved);
   }
 }
-
-int32_t CFWL_ComboBox::CountItems(const IFWL_Widget* pWidget) const {
-  return m_ItemArray.size();
-}
-
-CFWL_ListItem* CFWL_ComboBox::GetItem(const IFWL_Widget* pWidget,
-                                      int32_t nIndex) const {
-  if (nIndex < 0 || static_cast<size_t>(nIndex) >= m_ItemArray.size())
-    return nullptr;
-  return m_ItemArray[nIndex].get();
-}
-
-int32_t CFWL_ComboBox::GetItemIndex(IFWL_Widget* pWidget,
-                                    CFWL_ListItem* pItem) {
-  auto it = std::find_if(
-      m_ItemArray.begin(), m_ItemArray.end(),
-      [pItem](const std::unique_ptr<CFWL_ListItem>& candidate) {
-        return candidate.get() == static_cast<CFWL_ListItem*>(pItem);
-      });
-  return it != m_ItemArray.end() ? it - m_ItemArray.begin() : -1;
-}
-
-uint32_t CFWL_ComboBox::GetItemStyles(IFWL_Widget* pWidget,
-                                      CFWL_ListItem* pItem) {
-  return pItem ? static_cast<CFWL_ListItem*>(pItem)->m_dwStyles : 0;
-}
-
-void CFWL_ComboBox::GetItemText(IFWL_Widget* pWidget,
-                                CFWL_ListItem* pItem,
-                                CFX_WideString& wsText) {
-  if (pItem)
-    wsText = static_cast<CFWL_ListItem*>(pItem)->m_wsText;
-}
-
-void CFWL_ComboBox::GetItemRect(IFWL_Widget* pWidget,
-                                CFWL_ListItem* pItem,
-                                CFX_RectF& rtItem) {
-  if (!pItem)
-    return;
-
-  CFWL_ListItem* pComboItem = static_cast<CFWL_ListItem*>(pItem);
-  rtItem.Set(pComboItem->m_rtItem.left, pComboItem->m_rtItem.top,
-             pComboItem->m_rtItem.width, pComboItem->m_rtItem.height);
-}
-
-void* CFWL_ComboBox::GetItemData(IFWL_Widget* pWidget, CFWL_ListItem* pItem) {
-  return pItem ? static_cast<CFWL_ListItem*>(pItem)->m_pData : nullptr;
-}
-
-void CFWL_ComboBox::SetItemStyles(IFWL_Widget* pWidget,
-                                  CFWL_ListItem* pItem,
-                                  uint32_t dwStyle) {
-  if (pItem)
-    static_cast<CFWL_ListItem*>(pItem)->m_dwStyles = dwStyle;
-}
-
-void CFWL_ComboBox::SetItemRect(IFWL_Widget* pWidget,
-                                CFWL_ListItem* pItem,
-                                const CFX_RectF& rtItem) {
-  if (pItem)
-    static_cast<CFWL_ListItem*>(pItem)->m_rtItem = rtItem;
-}
-
-CFX_DIBitmap* CFWL_ComboBox::GetItemIcon(IFWL_Widget* pWidget,
-                                         CFWL_ListItem* pItem) {
-  return pItem ? static_cast<CFWL_ListItem*>(pItem)->m_pDIB : nullptr;
-}
-
-void CFWL_ComboBox::GetItemCheckRect(IFWL_Widget* pWidget,
-                                     CFWL_ListItem* pItem,
-                                     CFX_RectF& rtCheck) {
-  rtCheck = static_cast<CFWL_ListItem*>(pItem)->m_rtCheckBox;
-}
-
-void CFWL_ComboBox::SetItemCheckRect(IFWL_Widget* pWidget,
-                                     CFWL_ListItem* pItem,
-                                     const CFX_RectF& rtCheck) {
-  static_cast<CFWL_ListItem*>(pItem)->m_rtCheckBox = rtCheck;
-}
-
-uint32_t CFWL_ComboBox::GetItemCheckState(IFWL_Widget* pWidget,
-                                          CFWL_ListItem* pItem) {
-  return static_cast<CFWL_ListItem*>(pItem)->m_dwCheckState;
-}
-
-void CFWL_ComboBox::SetItemCheckState(IFWL_Widget* pWidget,
-                                      CFWL_ListItem* pItem,
-                                      uint32_t dwCheckState) {
-  static_cast<CFWL_ListItem*>(pItem)->m_dwCheckState = dwCheckState;
-}
-
-FX_FLOAT CFWL_ComboBox::GetListHeight(IFWL_Widget* pWidget) {
-  return m_fMaxListHeight;
-}
diff --git a/xfa/fwl/core/cfwl_combobox.h b/xfa/fwl/core/cfwl_combobox.h
index 2036b93..2b63c50 100644
--- a/xfa/fwl/core/cfwl_combobox.h
+++ b/xfa/fwl/core/cfwl_combobox.h
@@ -20,44 +20,10 @@
 
   void Initialize();
 
-  // IFWL_ListBox::DataProvider
-  int32_t CountItems(const IFWL_Widget* pWidget) const override;
-  CFWL_ListItem* GetItem(const IFWL_Widget* pWidget,
-                         int32_t nIndex) const override;
-  int32_t GetItemIndex(IFWL_Widget* pWidget, CFWL_ListItem* pItem) override;
-  uint32_t GetItemStyles(IFWL_Widget* pWidget, CFWL_ListItem* pItem) override;
-  void GetItemText(IFWL_Widget* pWidget,
-                   CFWL_ListItem* pItem,
-                   CFX_WideString& wsText) override;
-  void GetItemRect(IFWL_Widget* pWidget,
-                   CFWL_ListItem* pItem,
-                   CFX_RectF& rtItem) override;
-  void* GetItemData(IFWL_Widget* pWidget, CFWL_ListItem* pItem) override;
-  void SetItemStyles(IFWL_Widget* pWidget,
-                     CFWL_ListItem* pItem,
-                     uint32_t dwStyle) override;
-  void SetItemRect(IFWL_Widget* pWidget,
-                   CFWL_ListItem* pItem,
-                   const CFX_RectF& rtItem) override;
-  CFX_DIBitmap* GetItemIcon(IFWL_Widget* pWidget,
-                            CFWL_ListItem* pItem) override;
-  void GetItemCheckRect(IFWL_Widget* pWidget,
-                        CFWL_ListItem* pItem,
-                        CFX_RectF& rtCheck) override;
-  void SetItemCheckRect(IFWL_Widget* pWidget,
-                        CFWL_ListItem* pItem,
-                        const CFX_RectF& rtCheck) override;
-  uint32_t GetItemCheckState(IFWL_Widget* pWidget,
-                             CFWL_ListItem* pItem) override;
-  void SetItemCheckState(IFWL_Widget* pWidget,
-                         CFWL_ListItem* pItem,
-                         uint32_t dwCheckState) override;
-
   // IFWL_ComboBox::DataProvider
   FX_FLOAT GetListHeight(IFWL_Widget* pWidget) override;
 
-  int32_t AddString(const CFX_WideStringC& wsText);
-
+  void AddString(const CFX_WideStringC& wsText);
   bool RemoveAt(int32_t iIndex);  // Returns false iff |iIndex| out of range.
   void RemoveAll();
 
@@ -90,7 +56,6 @@
   void EditModifyStylesEx(uint32_t dwStylesExAdded, uint32_t dwStylesExRemoved);
 
  private:
-  std::vector<std::unique_ptr<CFWL_ListItem>> m_ItemArray;
   FX_FLOAT m_fMaxListHeight;
 };
 
diff --git a/xfa/fwl/core/cfwl_listbox.cpp b/xfa/fwl/core/cfwl_listbox.cpp
index cefee8c..bf77989 100644
--- a/xfa/fwl/core/cfwl_listbox.cpp
+++ b/xfa/fwl/core/cfwl_listbox.cpp
@@ -34,35 +34,38 @@
   CFWL_Widget::Initialize();
 }
 
+CFWL_ListItem* CFWL_ListBox::GetItem(const IFWL_Widget* pWidget,
+                                     int32_t nIndex) const {
+  return GetWidget() ? ToListBox(GetWidget())->GetItem(pWidget, nIndex)
+                     : nullptr;
+}
+
+void CFWL_ListBox::GetItemText(IFWL_Widget* pWidget,
+                               CFWL_ListItem* pItem,
+                               CFX_WideString& wsText) {
+  if (GetWidget())
+    ToListBox(GetWidget())->GetItemText(pWidget, pItem, wsText);
+}
+
 CFWL_ListItem* CFWL_ListBox::AddString(const CFX_WideStringC& wsAdd,
                                        bool bSelect) {
-  std::unique_ptr<CFWL_ListItem> pItem(new CFWL_ListItem);
-  pItem->m_dwStates = 0;
-  pItem->m_wsText = wsAdd;
-  pItem->m_dwStates = bSelect ? FWL_ITEMSTATE_LTB_Selected : 0;
-  m_ItemArray.push_back(std::move(pItem));
-  return m_ItemArray.back().get();
+  return GetWidget() ? ToListBox(GetWidget())->AddString(wsAdd, bSelect)
+                     : nullptr;
 }
 
 bool CFWL_ListBox::DeleteString(CFWL_ListItem* pItem) {
-  int32_t nIndex = GetItemIndex(GetWidget(), pItem);
-  if (nIndex < 0 || static_cast<size_t>(nIndex) >= m_ItemArray.size())
-    return false;
-
-  int32_t iSel = nIndex + 1;
-  if (iSel >= CountItems(m_pIface.get()))
-    iSel = nIndex - 1;
-  if (iSel >= 0) {
-    CFWL_ListItem* pSel =
-        static_cast<CFWL_ListItem*>(GetItem(m_pIface.get(), iSel));
-    pSel->m_dwStates |= FWL_ITEMSTATE_LTB_Selected;
-  }
-  m_ItemArray.erase(m_ItemArray.begin() + nIndex);
-  return true;
+  return GetWidget() && ToListBox(GetWidget())->DeleteString(pItem);
 }
 
 void CFWL_ListBox::DeleteAll() {
-  m_ItemArray.clear();
+  if (GetWidget())
+    ToListBox(GetWidget())->DeleteAll();
+}
+
+uint32_t CFWL_ListBox::GetItemStates(CFWL_ListItem* pItem) {
+  if (!pItem)
+    return 0;
+  return pItem->m_dwStates | pItem->m_dwCheckState;
 }
 
 int32_t CFWL_ListBox::CountSelItems() {
@@ -81,94 +84,3 @@
   if (GetWidget())
     ToListBox(GetWidget())->SetSelItem(pItem, bSelect);
 }
-
-void CFWL_ListBox::GetItemText(IFWL_Widget* pWidget,
-                               CFWL_ListItem* pItem,
-                               CFX_WideString& wsText) {
-  if (pItem)
-    wsText = static_cast<CFWL_ListItem*>(pItem)->m_wsText;
-}
-
-uint32_t CFWL_ListBox::GetItemStates(CFWL_ListItem* pItem) {
-  if (!pItem)
-    return 0;
-  return pItem->m_dwStates | pItem->m_dwCheckState;
-}
-
-int32_t CFWL_ListBox::CountItems(const IFWL_Widget* pWidget) const {
-  return pdfium::CollectionSize<int32_t>(m_ItemArray);
-}
-
-CFWL_ListItem* CFWL_ListBox::GetItem(const IFWL_Widget* pWidget,
-                                     int32_t nIndex) const {
-  if (nIndex < 0 || nIndex >= CountItems(pWidget))
-    return nullptr;
-  return m_ItemArray[nIndex].get();
-}
-
-int32_t CFWL_ListBox::GetItemIndex(IFWL_Widget* pWidget, CFWL_ListItem* pItem) {
-  auto it = std::find_if(
-      m_ItemArray.begin(), m_ItemArray.end(),
-      [pItem](const std::unique_ptr<CFWL_ListItem>& candidate) {
-        return candidate.get() == static_cast<CFWL_ListItem*>(pItem);
-      });
-  return it != m_ItemArray.end() ? it - m_ItemArray.begin() : -1;
-}
-
-uint32_t CFWL_ListBox::GetItemStyles(IFWL_Widget* pWidget,
-                                     CFWL_ListItem* pItem) {
-  return pItem ? static_cast<CFWL_ListItem*>(pItem)->m_dwStates : 0;
-}
-
-void CFWL_ListBox::GetItemRect(IFWL_Widget* pWidget,
-                               CFWL_ListItem* pItem,
-                               CFX_RectF& rtItem) {
-  if (pItem)
-    rtItem = static_cast<CFWL_ListItem*>(pItem)->m_rtItem;
-}
-
-void* CFWL_ListBox::GetItemData(IFWL_Widget* pWidget, CFWL_ListItem* pItem) {
-  return pItem ? static_cast<CFWL_ListItem*>(pItem)->m_pData : nullptr;
-}
-
-void CFWL_ListBox::SetItemStyles(IFWL_Widget* pWidget,
-                                 CFWL_ListItem* pItem,
-                                 uint32_t dwStyle) {
-  if (pItem)
-    static_cast<CFWL_ListItem*>(pItem)->m_dwStates = dwStyle;
-}
-
-void CFWL_ListBox::SetItemRect(IFWL_Widget* pWidget,
-                               CFWL_ListItem* pItem,
-                               const CFX_RectF& rtItem) {
-  if (pItem)
-    static_cast<CFWL_ListItem*>(pItem)->m_rtItem = rtItem;
-}
-
-CFX_DIBitmap* CFWL_ListBox::GetItemIcon(IFWL_Widget* pWidget,
-                                        CFWL_ListItem* pItem) {
-  return static_cast<CFWL_ListItem*>(pItem)->m_pDIB;
-}
-
-void CFWL_ListBox::GetItemCheckRect(IFWL_Widget* pWidget,
-                                    CFWL_ListItem* pItem,
-                                    CFX_RectF& rtCheck) {
-  rtCheck = static_cast<CFWL_ListItem*>(pItem)->m_rtCheckBox;
-}
-
-void CFWL_ListBox::SetItemCheckRect(IFWL_Widget* pWidget,
-                                    CFWL_ListItem* pItem,
-                                    const CFX_RectF& rtCheck) {
-  static_cast<CFWL_ListItem*>(pItem)->m_rtCheckBox = rtCheck;
-}
-
-uint32_t CFWL_ListBox::GetItemCheckState(IFWL_Widget* pWidget,
-                                         CFWL_ListItem* pItem) {
-  return static_cast<CFWL_ListItem*>(pItem)->m_dwCheckState;
-}
-
-void CFWL_ListBox::SetItemCheckState(IFWL_Widget* pWidget,
-                                     CFWL_ListItem* pItem,
-                                     uint32_t dwCheckState) {
-  static_cast<CFWL_ListItem*>(pItem)->m_dwCheckState = dwCheckState;
-}
diff --git a/xfa/fwl/core/cfwl_listbox.h b/xfa/fwl/core/cfwl_listbox.h
index 504b1d9..941cbfb 100644
--- a/xfa/fwl/core/cfwl_listbox.h
+++ b/xfa/fwl/core/cfwl_listbox.h
@@ -22,52 +22,20 @@
 
   void Initialize();
 
-  // IFWL_ListBox::DataProvider:
-  int32_t CountItems(const IFWL_Widget* pWidget) const override;
-  CFWL_ListItem* GetItem(const IFWL_Widget* pWidget,
-                         int32_t nIndex) const override;
-  int32_t GetItemIndex(IFWL_Widget* pWidget, CFWL_ListItem* pItem) override;
-  uint32_t GetItemStyles(IFWL_Widget* pWidget, CFWL_ListItem* pItem) override;
+  CFWL_ListItem* GetItem(const IFWL_Widget* pWidget, int32_t nIndex) const;
   void GetItemText(IFWL_Widget* pWidget,
                    CFWL_ListItem* pItem,
-                   CFX_WideString& wsText) override;
-  void GetItemRect(IFWL_Widget* pWidget,
-                   CFWL_ListItem* pItem,
-                   CFX_RectF& rtItem) override;
-  void* GetItemData(IFWL_Widget* pWidget, CFWL_ListItem* pItem) override;
-  void SetItemStyles(IFWL_Widget* pWidget,
-                     CFWL_ListItem* pItem,
-                     uint32_t dwStyle) override;
-  void SetItemRect(IFWL_Widget* pWidget,
-                   CFWL_ListItem* pItem,
-                   const CFX_RectF& rtItem) override;
-  CFX_DIBitmap* GetItemIcon(IFWL_Widget* pWidget,
-                            CFWL_ListItem* pItem) override;
-  void GetItemCheckRect(IFWL_Widget* pWidget,
-                        CFWL_ListItem* pItem,
-                        CFX_RectF& rtCheck) override;
-  void SetItemCheckRect(IFWL_Widget* pWidget,
-                        CFWL_ListItem* pItem,
-                        const CFX_RectF& rtCheck) override;
-  uint32_t GetItemCheckState(IFWL_Widget* pWidget,
-                             CFWL_ListItem* pItem) override;
-  void SetItemCheckState(IFWL_Widget* pWidget,
-                         CFWL_ListItem* pItem,
-                         uint32_t dwCheckState) override;
+                   CFX_WideString& wsText);
 
   CFWL_ListItem* AddString(const CFX_WideStringC& wsAdd, bool bSelect = false);
   bool DeleteString(CFWL_ListItem* pItem);
   void DeleteAll();
-
   int32_t CountSelItems();
   void SetSelItem(CFWL_ListItem* pItem, bool bSelect = true);
   CFWL_ListItem* GetSelItem(int32_t nIndexSel);
   int32_t GetSelIndex(int32_t nIndex);
 
   uint32_t GetItemStates(CFWL_ListItem* pItem);
-
- private:
-  std::vector<std::unique_ptr<CFWL_ListItem>> m_ItemArray;
 };
 
 #endif  // XFA_FWL_CORE_CFWL_LISTBOX_H_
diff --git a/xfa/fwl/core/ifwl_combobox.cpp b/xfa/fwl/core/ifwl_combobox.cpp
index f2a85e6..906fe1d 100644
--- a/xfa/fwl/core/ifwl_combobox.cpp
+++ b/xfa/fwl/core/ifwl_combobox.cpp
@@ -100,6 +100,18 @@
   IFWL_Widget::GetWidgetRect(rect, true);
 }
 
+void IFWL_ComboBox::AddString(const CFX_WideStringC& wsText) {
+  m_pListBox->AddString(wsText);
+}
+
+bool IFWL_ComboBox::RemoveAt(int32_t iIndex) {
+  return m_pListBox->RemoveAt(iIndex);
+}
+
+void IFWL_ComboBox::RemoveAll() {
+  m_pListBox->DeleteAll();
+}
+
 void IFWL_ComboBox::ModifyStylesEx(uint32_t dwStylesExAdded,
                                    uint32_t dwStylesExRemoved) {
   if (m_pWidgetMgr->IsFormDisabled()) {
@@ -179,13 +191,11 @@
     param.m_rtPart = rtTextBk;
 
     if (m_iCurSel >= 0) {
-      IFWL_ListBox::DataProvider* pData =
-          static_cast<IFWL_ListBox::DataProvider*>(
-              m_pListBox->GetDataProvider());
-      void* p = pData->GetItemData(m_pListBox.get(),
-                                   pData->GetItem(m_pListBox.get(), m_iCurSel));
-      if (p)
+      if (void* p = m_pListBox->GetItemData(
+              m_pListBox.get(),
+              m_pListBox->GetItem(m_pListBox.get(), m_iCurSel))) {
         param.m_pData = p;
+      }
     }
 
     if (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled) {
@@ -203,10 +213,7 @@
         return;
 
       CFX_WideString wsText;
-      IFWL_ComboBox::DataProvider* pData =
-          static_cast<IFWL_ComboBox::DataProvider*>(
-              m_pProperties->m_pDataProvider);
-      CFWL_ListItem* hItem = pData->GetItem(this, m_iCurSel);
+      CFWL_ListItem* hItem = m_pListBox->GetItem(this, m_iCurSel);
       m_pListBox->GetDataProviderItemText(hItem, wsText);
 
       CFWL_ThemeText theme_text;
@@ -249,18 +256,23 @@
     m_pEdit->SetThemeProvider(pThemeProvider);
 }
 
+void IFWL_ComboBox::GetTextByIndex(int32_t iIndex,
+                                   CFX_WideString& wsText) const {
+  CFWL_ListItem* pItem = static_cast<CFWL_ListItem*>(
+      m_pListBox->GetItem(m_pListBox.get(), iIndex));
+  if (pItem)
+    wsText = pItem->m_wsText;
+}
+
 void IFWL_ComboBox::SetCurSel(int32_t iSel) {
-  int32_t iCount = m_pListBox->CountItems();
+  int32_t iCount = m_pListBox->CountItems(nullptr);
   bool bClearSel = iSel < 0 || iSel >= iCount;
   if (IsDropDownStyle() && m_pEdit) {
     if (bClearSel) {
       m_pEdit->SetText(CFX_WideString());
     } else {
       CFX_WideString wsText;
-      IFWL_ComboBox::DataProvider* pData =
-          static_cast<IFWL_ComboBox::DataProvider*>(
-              m_pProperties->m_pDataProvider);
-      CFWL_ListItem* hItem = pData->GetItem(this, iSel);
+      CFWL_ListItem* hItem = m_pListBox->GetItem(this, iSel);
       m_pListBox->GetDataProviderItemText(hItem, wsText);
       m_pEdit->SetText(wsText);
     }
@@ -295,9 +307,7 @@
   if (!m_pListBox)
     return;
 
-  IFWL_ComboBox::DataProvider* pData =
-      static_cast<IFWL_ComboBox::DataProvider*>(m_pProperties->m_pDataProvider);
-  CFWL_ListItem* hItem = pData->GetItem(this, m_iCurSel);
+  CFWL_ListItem* hItem = m_pListBox->GetItem(this, m_iCurSel);
   m_pListBox->GetDataProviderItemText(hItem, wsText);
 }
 
@@ -432,9 +442,7 @@
 
 void IFWL_ComboBox::SyncEditText(int32_t iListItem) {
   CFX_WideString wsText;
-  IFWL_ComboBox::DataProvider* pData =
-      static_cast<IFWL_ComboBox::DataProvider*>(m_pProperties->m_pDataProvider);
-  CFWL_ListItem* hItem = pData->GetItem(this, iListItem);
+  CFWL_ListItem* hItem = m_pListBox->GetItem(this, iListItem);
   m_pListBox->GetDataProviderItemText(hItem, wsText);
   m_pEdit->SetText(wsText);
   m_pEdit->Update();
@@ -464,10 +472,7 @@
 
   if (m_iCurSel >= 0) {
     CFX_WideString wsText;
-    IFWL_ComboBox::DataProvider* pData =
-        static_cast<IFWL_ComboBox::DataProvider*>(
-            m_pProperties->m_pDataProvider);
-    CFWL_ListItem* hItem = pData->GetItem(this, m_iCurSel);
+    CFWL_ListItem* hItem = m_pListBox->GetItem(this, m_iCurSel);
     m_pListBox->GetDataProviderItemText(hItem, wsText);
     m_pEdit->LockUpdate();
     m_pEdit->SetText(wsText);
@@ -551,22 +556,18 @@
 }
 
 void IFWL_ComboBox::ProcessSelChanged(bool bLButtonUp) {
-  IFWL_ComboBox::DataProvider* pDatas =
-      static_cast<IFWL_ComboBox::DataProvider*>(m_pProperties->m_pDataProvider);
-  m_iCurSel = pDatas->GetItemIndex(this, m_pListBox->GetSelItem(0));
+  m_iCurSel = m_pListBox->GetItemIndex(this, m_pListBox->GetSelItem(0));
   if (!IsDropDownStyle()) {
     Repaint(&m_rtClient);
     return;
   }
 
-  IFWL_ComboBox::DataProvider* pData =
-      static_cast<IFWL_ComboBox::DataProvider*>(m_pProperties->m_pDataProvider);
-  CFWL_ListItem* hItem = pData->GetItem(this, m_iCurSel);
+  CFWL_ListItem* hItem = m_pListBox->GetItem(this, m_iCurSel);
   if (!hItem)
     return;
 
   CFX_WideString wsText;
-  pData->GetItemText(this, hItem, wsText);
+  m_pListBox->GetItemText(this, hItem, wsText);
   if (m_pEdit) {
     m_pEdit->SetText(wsText);
     m_pEdit->Update();
@@ -635,7 +636,7 @@
     DispatchEvent(&preEvent);
 
     IFWL_ComboList* pComboList = m_pListBox.get();
-    int32_t iItems = pComboList->CountItems();
+    int32_t iItems = pComboList->CountItems(nullptr);
     if (iItems < 1)
       return;
 
@@ -800,10 +801,7 @@
 
   if (m_iCurSel >= 0) {
     CFX_WideString wsText;
-    IFWL_ComboBox::DataProvider* pData =
-        static_cast<IFWL_ComboBox::DataProvider*>(
-            m_pProperties->m_pDataProvider);
-    CFWL_ListItem* hItem = pData->GetItem(this, m_iCurSel);
+    CFWL_ListItem* hItem = m_pListBox->GetItem(this, m_iCurSel);
     m_pListBox->GetDataProviderItemText(hItem, wsText);
     m_pEdit->LockUpdate();
     m_pEdit->SetText(wsText);
@@ -973,7 +971,7 @@
   const bool bUp = dwKeyCode == FWL_VKEY_Up;
   const bool bDown = dwKeyCode == FWL_VKEY_Down;
   if (bUp || bDown) {
-    int32_t iCount = m_pListBox->CountItems();
+    int32_t iCount = m_pListBox->CountItems(nullptr);
     if (iCount < 1)
       return;
 
@@ -986,10 +984,7 @@
       iCurSel = m_pListBox->MatchItem(wsText);
       if (iCurSel >= 0) {
         CFX_WideString wsTemp;
-        IFWL_ComboBox::DataProvider* pData =
-            static_cast<IFWL_ComboBox::DataProvider*>(
-                m_pProperties->m_pDataProvider);
-        CFWL_ListItem* hItem = pData->GetItem(this, iCurSel);
+        CFWL_ListItem* hItem = m_pListBox->GetItem(this, iCurSel);
         m_pListBox->GetDataProviderItemText(hItem, wsTemp);
         bMatchEqual = wsText == wsTemp;
       }
@@ -1113,7 +1108,7 @@
   const bool bDown = dwKeyCode == FWL_VKEY_Down;
   if (bUp || bDown) {
     IFWL_ComboList* pComboList = m_pListBox.get();
-    int32_t iCount = pComboList->CountItems();
+    int32_t iCount = pComboList->CountItems(nullptr);
     if (iCount < 1)
       return;
 
diff --git a/xfa/fwl/core/ifwl_combobox.h b/xfa/fwl/core/ifwl_combobox.h
index b2fc23d..7ad7420 100644
--- a/xfa/fwl/core/ifwl_combobox.h
+++ b/xfa/fwl/core/ifwl_combobox.h
@@ -49,7 +49,7 @@
 
 class IFWL_ComboBox : public IFWL_Widget {
  public:
-  class DataProvider : public IFWL_ListBox::DataProvider {
+  class DataProvider : public IFWL_Widget::DataProvider {
    public:
     virtual FX_FLOAT GetListHeight(IFWL_Widget* pWidget) = 0;
   };
@@ -74,9 +74,14 @@
   void OnDrawWidget(CFX_Graphics* pGraphics,
                     const CFX_Matrix* pMatrix) override;
 
+  void GetTextByIndex(int32_t iIndex, CFX_WideString& wsText) const;
   int32_t GetCurSel() const { return m_iCurSel; }
   void SetCurSel(int32_t iSel);
 
+  void AddString(const CFX_WideStringC& wsText);
+  bool RemoveAt(int32_t iIndex);  // Returns false iff |iIndex| out of range.
+  void RemoveAll();
+
   void SetEditText(const CFX_WideString& wsText);
   void GetEditText(CFX_WideString& wsText,
                    int32_t nStart = 0,
diff --git a/xfa/fwl/core/ifwl_combolist.cpp b/xfa/fwl/core/ifwl_combolist.cpp
index 320c7fd..ed7732e 100644
--- a/xfa/fwl/core/ifwl_combolist.cpp
+++ b/xfa/fwl/core/ifwl_combolist.cpp
@@ -28,16 +28,12 @@
 int32_t IFWL_ComboList::MatchItem(const CFX_WideString& wsMatch) {
   if (wsMatch.IsEmpty())
     return -1;
-  if (!m_pProperties->m_pDataProvider)
-    return -1;
 
-  IFWL_ListBox::DataProvider* pData =
-      static_cast<IFWL_ListBox::DataProvider*>(m_pProperties->m_pDataProvider);
-  int32_t iCount = pData->CountItems(this);
+  int32_t iCount = CountItems(this);
   for (int32_t i = 0; i < iCount; i++) {
-    CFWL_ListItem* hItem = pData->GetItem(this, i);
+    CFWL_ListItem* hItem = GetItem(this, i);
     CFX_WideString wsText;
-    pData->GetItemText(this, hItem, wsText);
+    GetItemText(this, hItem, wsText);
     FX_STRSIZE pos = wsText.Find(wsMatch.c_str());
     if (!pos)
       return i;
@@ -46,46 +42,30 @@
 }
 
 void IFWL_ComboList::ChangeSelected(int32_t iSel) {
-  if (!m_pProperties->m_pDataProvider)
-    return;
-
-  IFWL_ListBox::DataProvider* pData =
-      static_cast<IFWL_ListBox::DataProvider*>(m_pProperties->m_pDataProvider);
-  CFWL_ListItem* hItem = pData->GetItem(this, iSel);
+  CFWL_ListItem* hItem = GetItem(this, iSel);
   CFX_RectF rtInvalidate;
   rtInvalidate.Reset();
   CFWL_ListItem* hOld = GetSelItem(0);
-  int32_t iOld = pData->GetItemIndex(this, hOld);
+  int32_t iOld = GetItemIndex(this, hOld);
   if (iOld == iSel)
     return;
   if (iOld > -1) {
-    GetItemRect(iOld, rtInvalidate);
+    CFWL_ListItem* hItem = GetItem(this, iOld);
+    GetItemRect(this, hItem, rtInvalidate);
     SetSelItem(hOld, false);
   }
   if (hItem) {
     CFX_RectF rect;
-    GetItemRect(iSel, rect);
+    CFWL_ListItem* hItem = GetItem(this, iSel);
+    GetItemRect(this, hItem, rect);
     rtInvalidate.Union(rect);
-    CFWL_ListItem* hSel = pData->GetItem(this, iSel);
+    CFWL_ListItem* hSel = GetItem(this, iSel);
     SetSelItem(hSel, true);
   }
   if (!rtInvalidate.IsEmpty())
     Repaint(&rtInvalidate);
 }
 
-int32_t IFWL_ComboList::CountItems() {
-  IFWL_ListBox::DataProvider* pData =
-      static_cast<IFWL_ListBox::DataProvider*>(m_pProperties->m_pDataProvider);
-  return pData ? pData->CountItems(this) : 0;
-}
-
-void IFWL_ComboList::GetItemRect(int32_t nIndex, CFX_RectF& rtItem) {
-  IFWL_ListBox::DataProvider* pData =
-      static_cast<IFWL_ListBox::DataProvider*>(m_pProperties->m_pDataProvider);
-  CFWL_ListItem* hItem = pData->GetItem(this, nIndex);
-  pData->GetItemRect(this, hItem, rtItem);
-}
-
 void IFWL_ComboList::ClientToOuter(FX_FLOAT& fx, FX_FLOAT& fy) {
   fx += m_pProperties->m_rtWidget.left, fy += m_pProperties->m_rtWidget.top;
   IFWL_Widget* pOwner = GetOwner();
@@ -170,13 +150,8 @@
     CFWL_ListItem* hItem = GetItemAtPoint(pMsg->m_fx, pMsg->m_fy);
     if (!hItem)
       return;
-    if (!m_pProperties->m_pDataProvider)
-      return;
 
-    IFWL_ListBox::DataProvider* pData =
-        static_cast<IFWL_ListBox::DataProvider*>(
-            m_pProperties->m_pDataProvider);
-    ChangeSelected(pData->GetItemIndex(this, hItem));
+    ChangeSelected(GetItemIndex(this, hItem));
   } else if (m_bNotifyOwner) {
     ClientToOuter(pMsg->m_fx, pMsg->m_fy);
     IFWL_ComboBox* pOuter = static_cast<IFWL_ComboBox*>(m_pOuter);
@@ -255,11 +230,7 @@
     case FWL_VKEY_Home:
     case FWL_VKEY_End: {
       IFWL_ComboBox* pOuter = static_cast<IFWL_ComboBox*>(m_pOuter);
-      IFWL_ListBox::DataProvider* pData =
-          static_cast<IFWL_ListBox::DataProvider*>(
-              m_pProperties->m_pDataProvider);
-      CFWL_ListItem* hItem =
-          pData->GetItem(this, pOuter->GetCurrentSelection());
+      CFWL_ListItem* hItem = GetItem(this, pOuter->GetCurrentSelection());
       hItem = GetListItem(hItem, dwKeyCode);
       if (!hItem)
         break;
diff --git a/xfa/fwl/core/ifwl_combolist.h b/xfa/fwl/core/ifwl_combolist.h
index 48dfb44..8d01494 100644
--- a/xfa/fwl/core/ifwl_combolist.h
+++ b/xfa/fwl/core/ifwl_combolist.h
@@ -25,12 +25,10 @@
   int32_t MatchItem(const CFX_WideString& wsMatch);
 
   void ChangeSelected(int32_t iSel);
-  int32_t CountItems();
 
   void SetNotifyOwner(bool notify) { m_bNotifyOwner = notify; }
 
  private:
-  void GetItemRect(int32_t nIndex, CFX_RectF& rtItem);
   void ClientToOuter(FX_FLOAT& fx, FX_FLOAT& fy);
   void OnDropListFocusChanged(CFWL_Message* pMsg, bool bSet);
   void OnDropListMouseMove(CFWL_MsgMouse* pMsg);
diff --git a/xfa/fwl/core/ifwl_listbox.cpp b/xfa/fwl/core/ifwl_listbox.cpp
index d45bdd9..2961732 100644
--- a/xfa/fwl/core/ifwl_listbox.cpp
+++ b/xfa/fwl/core/ifwl_listbox.cpp
@@ -11,6 +11,7 @@
 #include <utility>
 
 #include "third_party/base/ptr_util.h"
+#include "third_party/base/stl_util.h"
 #include "xfa/fde/tto/fde_textout.h"
 #include "xfa/fwl/core/cfwl_app.h"
 #include "xfa/fwl/core/cfwl_msgkey.h"
@@ -146,19 +147,14 @@
 }
 
 int32_t IFWL_ListBox::CountSelItems() {
-  if (!m_pProperties->m_pDataProvider)
-    return 0;
-
   int32_t iRet = 0;
-  IFWL_ListBox::DataProvider* pData =
-      static_cast<IFWL_ListBox::DataProvider*>(m_pProperties->m_pDataProvider);
-  int32_t iCount = pData->CountItems(this);
+  int32_t iCount = CountItems(this);
   for (int32_t i = 0; i < iCount; i++) {
-    CFWL_ListItem* pItem = pData->GetItem(this, i);
+    CFWL_ListItem* pItem = GetItem(this, i);
     if (!pItem)
       continue;
 
-    uint32_t dwStyle = pData->GetItemStyles(this, pItem);
+    uint32_t dwStyle = GetItemStyles(this, pItem);
     if (dwStyle & FWL_ITEMSTATE_LTB_Selected)
       iRet++;
   }
@@ -169,25 +165,18 @@
   int32_t idx = GetSelIndex(nIndexSel);
   if (idx < 0)
     return nullptr;
-  IFWL_ListBox::DataProvider* pData =
-      static_cast<IFWL_ListBox::DataProvider*>(m_pProperties->m_pDataProvider);
-  return pData->GetItem(this, idx);
+  return GetItem(this, idx);
 }
 
 int32_t IFWL_ListBox::GetSelIndex(int32_t nIndex) {
-  if (!m_pProperties->m_pDataProvider)
-    return -1;
-
   int32_t index = 0;
-  IFWL_ListBox::DataProvider* pData =
-      static_cast<IFWL_ListBox::DataProvider*>(m_pProperties->m_pDataProvider);
-  int32_t iCount = pData->CountItems(this);
+  int32_t iCount = CountItems(this);
   for (int32_t i = 0; i < iCount; i++) {
-    CFWL_ListItem* pItem = pData->GetItem(this, i);
+    CFWL_ListItem* pItem = GetItem(this, i);
     if (!pItem)
       return -1;
 
-    uint32_t dwStyle = pData->GetItemStyles(this, pItem);
+    uint32_t dwStyle = GetItemStyles(this, pItem);
     if (dwStyle & FWL_ITEMSTATE_LTB_Selected) {
       if (index == nIndex)
         return i;
@@ -198,8 +187,6 @@
 }
 
 void IFWL_ListBox::SetSelItem(CFWL_ListItem* pItem, bool bSelect) {
-  if (!m_pProperties->m_pDataProvider)
-    return;
   if (!pItem) {
     if (bSelect) {
       SelectAll();
@@ -217,15 +204,9 @@
 
 void IFWL_ListBox::GetDataProviderItemText(CFWL_ListItem* pItem,
                                            CFX_WideString& wsText) {
-  if (!m_pProperties->m_pDataProvider)
-    return;
-
-  IFWL_ListBox::DataProvider* pData =
-      static_cast<IFWL_ListBox::DataProvider*>(m_pProperties->m_pDataProvider);
   if (!pItem)
     return;
-
-  pData->GetItemText(this, pItem, wsText);
+  GetItemText(this, pItem, wsText);
 }
 
 CFWL_ListItem* IFWL_ListBox::GetListItem(CFWL_ListItem* pItem,
@@ -239,20 +220,17 @@
       const bool bUp = dwKeyCode == FWL_VKEY_Up;
       const bool bDown = dwKeyCode == FWL_VKEY_Down;
       const bool bHome = dwKeyCode == FWL_VKEY_Home;
-      IFWL_ListBox::DataProvider* pData =
-          static_cast<IFWL_ListBox::DataProvider*>(
-              m_pProperties->m_pDataProvider);
       int32_t iDstItem = -1;
       if (bUp || bDown) {
-        int32_t index = pData->GetItemIndex(this, pItem);
+        int32_t index = GetItemIndex(this, pItem);
         iDstItem = dwKeyCode == FWL_VKEY_Up ? index - 1 : index + 1;
       } else if (bHome) {
         iDstItem = 0;
       } else {
-        int32_t iCount = pData->CountItems(this);
+        int32_t iCount = CountItems(this);
         iDstItem = iCount - 1;
       }
-      hRet = pData->GetItem(this, iDstItem);
+      hRet = GetItem(this, iDstItem);
       break;
     }
     default:
@@ -264,52 +242,44 @@
 void IFWL_ListBox::SetSelection(CFWL_ListItem* hStart,
                                 CFWL_ListItem* hEnd,
                                 bool bSelected) {
-  IFWL_ListBox::DataProvider* pData =
-      static_cast<IFWL_ListBox::DataProvider*>(m_pProperties->m_pDataProvider);
-  int32_t iStart = pData->GetItemIndex(this, hStart);
-  int32_t iEnd = pData->GetItemIndex(this, hEnd);
+  int32_t iStart = GetItemIndex(this, hStart);
+  int32_t iEnd = GetItemIndex(this, hEnd);
   if (iStart > iEnd) {
     int32_t iTemp = iStart;
     iStart = iEnd;
     iEnd = iTemp;
   }
   if (bSelected) {
-    int32_t iCount = pData->CountItems(this);
+    int32_t iCount = CountItems(this);
     for (int32_t i = 0; i < iCount; i++) {
-      CFWL_ListItem* pItem = pData->GetItem(this, i);
+      CFWL_ListItem* pItem = GetItem(this, i);
       SetSelectionDirect(pItem, false);
     }
   }
   for (; iStart <= iEnd; iStart++) {
-    CFWL_ListItem* pItem = pData->GetItem(this, iStart);
+    CFWL_ListItem* pItem = GetItem(this, iStart);
     SetSelectionDirect(pItem, bSelected);
   }
 }
 
 void IFWL_ListBox::SetSelectionDirect(CFWL_ListItem* pItem, bool bSelect) {
-  IFWL_ListBox::DataProvider* pData =
-      static_cast<IFWL_ListBox::DataProvider*>(m_pProperties->m_pDataProvider);
-  uint32_t dwOldStyle = pData->GetItemStyles(this, pItem);
+  uint32_t dwOldStyle = GetItemStyles(this, pItem);
   bSelect ? dwOldStyle |= FWL_ITEMSTATE_LTB_Selected
           : dwOldStyle &= ~FWL_ITEMSTATE_LTB_Selected;
-  pData->SetItemStyles(this, pItem, dwOldStyle);
+  SetItemStyles(this, pItem, dwOldStyle);
 }
 
 bool IFWL_ListBox::IsItemSelected(CFWL_ListItem* pItem) {
-  IFWL_ListBox::DataProvider* pData =
-      static_cast<IFWL_ListBox::DataProvider*>(m_pProperties->m_pDataProvider);
-  uint32_t dwState = pData->GetItemStyles(this, pItem);
+  uint32_t dwState = GetItemStyles(this, pItem);
   return (dwState & FWL_ITEMSTATE_LTB_Selected) != 0;
 }
 
 void IFWL_ListBox::ClearSelection() {
   bool bMulti = m_pProperties->m_dwStyleExes & FWL_STYLEEXT_LTB_MultiSelection;
-  IFWL_ListBox::DataProvider* pData =
-      static_cast<IFWL_ListBox::DataProvider*>(m_pProperties->m_pDataProvider);
-  int32_t iCount = pData->CountItems(this);
+  int32_t iCount = CountItems(this);
   for (int32_t i = 0; i < iCount; i++) {
-    CFWL_ListItem* pItem = pData->GetItem(this, i);
-    uint32_t dwState = pData->GetItemStyles(this, pItem);
+    CFWL_ListItem* pItem = GetItem(this, i);
+    uint32_t dwState = GetItemStyles(this, pItem);
     if (!(dwState & FWL_ITEMSTATE_LTB_Selected))
       continue;
     SetSelectionDirect(pItem, false);
@@ -322,47 +292,41 @@
   if (!m_pProperties->m_dwStyleExes & FWL_STYLEEXT_LTB_MultiSelection)
     return;
 
-  IFWL_ListBox::DataProvider* pData =
-      static_cast<IFWL_ListBox::DataProvider*>(m_pProperties->m_pDataProvider);
-  int32_t iCount = pData->CountItems(this);
+  int32_t iCount = CountItems(this);
   if (iCount <= 0)
     return;
 
-  CFWL_ListItem* pItemStart = pData->GetItem(this, 0);
-  CFWL_ListItem* pItemEnd = pData->GetItem(this, iCount - 1);
+  CFWL_ListItem* pItemStart = GetItem(this, 0);
+  CFWL_ListItem* pItemEnd = GetItem(this, iCount - 1);
   SetSelection(pItemStart, pItemEnd, false);
 }
 
 CFWL_ListItem* IFWL_ListBox::GetFocusedItem() {
-  IFWL_ListBox::DataProvider* pData =
-      static_cast<IFWL_ListBox::DataProvider*>(m_pProperties->m_pDataProvider);
-  int32_t iCount = pData->CountItems(this);
+  int32_t iCount = CountItems(this);
   for (int32_t i = 0; i < iCount; i++) {
-    CFWL_ListItem* pItem = pData->GetItem(this, i);
+    CFWL_ListItem* pItem = GetItem(this, i);
     if (!pItem)
       return nullptr;
-    if (pData->GetItemStyles(this, pItem) & FWL_ITEMSTATE_LTB_Focused)
+    if (GetItemStyles(this, pItem) & FWL_ITEMSTATE_LTB_Focused)
       return pItem;
   }
   return nullptr;
 }
 
 void IFWL_ListBox::SetFocusItem(CFWL_ListItem* pItem) {
-  IFWL_ListBox::DataProvider* pData =
-      static_cast<IFWL_ListBox::DataProvider*>(m_pProperties->m_pDataProvider);
   CFWL_ListItem* hFocus = GetFocusedItem();
   if (pItem == hFocus)
     return;
 
   if (hFocus) {
-    uint32_t dwStyle = pData->GetItemStyles(this, hFocus);
+    uint32_t dwStyle = GetItemStyles(this, hFocus);
     dwStyle &= ~FWL_ITEMSTATE_LTB_Focused;
-    pData->SetItemStyles(this, hFocus, dwStyle);
+    SetItemStyles(this, hFocus, dwStyle);
   }
   if (pItem) {
-    uint32_t dwStyle = pData->GetItemStyles(this, pItem);
+    uint32_t dwStyle = GetItemStyles(this, pItem);
     dwStyle |= FWL_ITEMSTATE_LTB_Focused;
-    pData->SetItemStyles(this, pItem, dwStyle);
+    SetItemStyles(this, pItem, dwStyle);
   }
 }
 
@@ -376,16 +340,14 @@
   if (m_pVertScrollBar)
     fPosY = m_pVertScrollBar->GetPos();
 
-  IFWL_ListBox::DataProvider* pData =
-      static_cast<IFWL_ListBox::DataProvider*>(m_pProperties->m_pDataProvider);
-  int32_t nCount = pData->CountItems(this);
+  int32_t nCount = CountItems(this);
   for (int32_t i = 0; i < nCount; i++) {
-    CFWL_ListItem* pItem = pData->GetItem(this, i);
+    CFWL_ListItem* pItem = GetItem(this, i);
     if (!pItem)
       continue;
 
     CFX_RectF rtItem;
-    pData->GetItemRect(this, pItem, rtItem);
+    GetItemRect(this, pItem, rtItem);
     rtItem.Offset(-fPosX, -fPosY);
     if (rtItem.Contains(fx, fy))
       return pItem;
@@ -395,38 +357,23 @@
 
 bool IFWL_ListBox::GetItemCheckRectInternal(CFWL_ListItem* pItem,
                                             CFX_RectF& rtCheck) {
-  if (!m_pProperties->m_pDataProvider)
-    return false;
   if (!(m_pProperties->m_dwStyleExes & FWL_STYLEEXT_LTB_Check))
     return false;
-
-  IFWL_ListBox::DataProvider* pData =
-      static_cast<IFWL_ListBox::DataProvider*>(m_pProperties->m_pDataProvider);
-  pData->GetItemCheckRect(this, pItem, rtCheck);
+  GetItemCheckRect(this, pItem, rtCheck);
   return true;
 }
 
 bool IFWL_ListBox::GetItemChecked(CFWL_ListItem* pItem) {
-  if (!m_pProperties->m_pDataProvider)
-    return false;
   if (!(m_pProperties->m_dwStyleExes & FWL_STYLEEXT_LTB_Check))
     return false;
-
-  IFWL_ListBox::DataProvider* pData =
-      static_cast<IFWL_ListBox::DataProvider*>(m_pProperties->m_pDataProvider);
-  return !!(pData->GetItemCheckState(this, pItem) & FWL_ITEMSTATE_LTB_Checked);
+  return !!(GetItemCheckState(this, pItem) & FWL_ITEMSTATE_LTB_Checked);
 }
 
 bool IFWL_ListBox::SetItemChecked(CFWL_ListItem* pItem, bool bChecked) {
-  if (!m_pProperties->m_pDataProvider)
-    return false;
   if (!(m_pProperties->m_dwStyleExes & FWL_STYLEEXT_LTB_Check))
     return false;
 
-  IFWL_ListBox::DataProvider* pData =
-      static_cast<IFWL_ListBox::DataProvider*>(m_pProperties->m_pDataProvider);
-  pData->SetItemCheckState(this, pItem,
-                           bChecked ? FWL_ITEMSTATE_LTB_Checked : 0);
+  SetItemCheckState(this, pItem, bChecked ? FWL_ITEMSTATE_LTB_Checked : 0);
   return true;
 }
 
@@ -435,9 +382,7 @@
     return false;
 
   CFX_RectF rtItem;
-  IFWL_ListBox::DataProvider* pData =
-      static_cast<IFWL_ListBox::DataProvider*>(m_pProperties->m_pDataProvider);
-  pData->GetItemRect(this, pItem, rtItem);
+  GetItemRect(this, pItem, rtItem);
 
   bool bScroll = false;
   FX_FLOAT fPosY = m_pVertScrollBar->GetPos();
@@ -500,16 +445,14 @@
 
   bool bMultiCol =
       !!(m_pProperties->m_dwStyleExes & FWL_STYLEEXT_LTB_MultiColumn);
-  IFWL_ListBox::DataProvider* pData =
-      static_cast<IFWL_ListBox::DataProvider*>(m_pProperties->m_pDataProvider);
-  int32_t iCount = pData->CountItems(this);
+  int32_t iCount = CountItems(this);
   for (int32_t i = 0; i < iCount; i++) {
-    CFWL_ListItem* pItem = pData->GetItem(this, i);
+    CFWL_ListItem* pItem = GetItem(this, i);
     if (!pItem)
       continue;
 
     CFX_RectF rtItem;
-    pData->GetItemRect(this, pItem, rtItem);
+    GetItemRect(this, pItem, rtItem);
     rtItem.Offset(m_rtConent.left - fPosX, m_rtConent.top - fPosY);
     if (rtItem.bottom() < m_rtConent.top)
       continue;
@@ -529,9 +472,7 @@
                             int32_t Index,
                             const CFX_RectF& rtItem,
                             const CFX_Matrix* pMatrix) {
-  IFWL_ListBox::DataProvider* pData =
-      static_cast<IFWL_ListBox::DataProvider*>(m_pProperties->m_pDataProvider);
-  uint32_t dwItemStyles = pData->GetItemStyles(this, pItem);
+  uint32_t dwItemStyles = GetItemStyles(this, pItem);
   uint32_t dwPartStates = CFWL_PartState_Normal;
   if (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled)
     dwPartStates = CFWL_PartState_Disabled;
@@ -564,7 +505,7 @@
   bool bHasIcon = !!(GetStylesEx() & FWL_STYLEEXT_LTB_Icon);
   if (bHasIcon) {
     CFX_RectF rtDIB;
-    CFX_DIBitmap* pDib = pData->GetItemIcon(this, pItem);
+    CFX_DIBitmap* pDib = GetItemIcon(this, pItem);
     rtDIB.Set(rtItem.left, rtItem.top, rtItem.height, rtItem.height);
     if (pDib) {
       CFWL_ThemeBackground param;
@@ -584,7 +525,7 @@
     CFX_RectF rtCheck;
     rtCheck.Set(rtItem.left, rtItem.top, rtItem.height, rtItem.height);
     rtCheck.Deflate(2, 2, 2, 2);
-    pData->SetItemCheckRect(this, pItem, rtCheck);
+    SetItemCheckRect(this, pItem, rtCheck);
     CFWL_ThemeBackground param;
     param.m_pWidget = this;
     param.m_iPart = CFWL_Part::Check;
@@ -600,7 +541,7 @@
   }
 
   CFX_WideString wsText;
-  pData->GetItemText(this, pItem, wsText);
+  GetItemText(this, pItem, wsText);
   if (wsText.GetLength() <= 0)
     return;
 
@@ -649,15 +590,13 @@
     fWidth = std::max(fWidth, fActualWidth);
   }
 
-  IFWL_ListBox::DataProvider* pData =
-      static_cast<IFWL_ListBox::DataProvider*>(m_pProperties->m_pDataProvider);
   m_fItemHeight = CalcItemHeight();
   if ((GetStylesEx() & FWL_STYLEEXT_LTB_Icon))
     fWidth += m_fItemHeight;
 
-  int32_t iCount = pData->CountItems(this);
+  int32_t iCount = CountItems(this);
   for (int32_t i = 0; i < iCount; i++) {
-    CFWL_ListItem* htem = pData->GetItem(this, i);
+    CFWL_ListItem* htem = GetItem(this, i);
     GetItemSize(fs, htem, fWidth, m_fItemHeight, bAutoSize);
   }
   if (bAutoSize)
@@ -762,10 +701,7 @@
   if (!bAutoSize) {
     CFX_RectF rtItem;
     rtItem.Set(0, size.y, fWidth, fItemHeight);
-    IFWL_ListBox::DataProvider* pData =
-        static_cast<IFWL_ListBox::DataProvider*>(
-            m_pProperties->m_pDataProvider);
-    pData->SetItemRect(this, pItem, rtItem);
+    SetItemRect(this, pItem, rtItem);
   }
   size.x = fWidth;
   size.y += fItemHeight;
@@ -773,16 +709,14 @@
 
 FX_FLOAT IFWL_ListBox::GetMaxTextWidth() {
   FX_FLOAT fRet = 0.0f;
-  IFWL_ListBox::DataProvider* pData =
-      static_cast<IFWL_ListBox::DataProvider*>(m_pProperties->m_pDataProvider);
-  int32_t iCount = pData->CountItems(this);
+  int32_t iCount = CountItems(this);
   for (int32_t i = 0; i < iCount; i++) {
-    CFWL_ListItem* pItem = pData->GetItem(this, i);
+    CFWL_ListItem* pItem = GetItem(this, i);
     if (!pItem)
       continue;
 
     CFX_WideString wsText;
-    pData->GetItemText(this, pItem, wsText);
+    GetItemText(this, pItem, wsText);
     CFX_SizeF sz = CalcTextSize(wsText, m_pProperties->m_pThemeProvider);
     fRet = std::max(fRet, sz.x);
   }
@@ -1067,3 +1001,126 @@
   }
   return true;
 }
+
+void IFWL_ListBox::GetItemText(IFWL_Widget* pWidget,
+                               CFWL_ListItem* pItem,
+                               CFX_WideString& wsText) {
+  if (pItem)
+    wsText = static_cast<CFWL_ListItem*>(pItem)->m_wsText;
+}
+
+int32_t IFWL_ListBox::CountItems(const IFWL_Widget* pWidget) const {
+  return pdfium::CollectionSize<int32_t>(m_ItemArray);
+}
+
+CFWL_ListItem* IFWL_ListBox::GetItem(const IFWL_Widget* pWidget,
+                                     int32_t nIndex) const {
+  if (nIndex < 0 || nIndex >= CountItems(pWidget))
+    return nullptr;
+  return m_ItemArray[nIndex].get();
+}
+
+int32_t IFWL_ListBox::GetItemIndex(IFWL_Widget* pWidget, CFWL_ListItem* pItem) {
+  auto it = std::find_if(
+      m_ItemArray.begin(), m_ItemArray.end(),
+      [pItem](const std::unique_ptr<CFWL_ListItem>& candidate) {
+        return candidate.get() == static_cast<CFWL_ListItem*>(pItem);
+      });
+  return it != m_ItemArray.end() ? it - m_ItemArray.begin() : -1;
+}
+
+uint32_t IFWL_ListBox::GetItemStyles(IFWL_Widget* pWidget,
+                                     CFWL_ListItem* pItem) {
+  return pItem ? static_cast<CFWL_ListItem*>(pItem)->m_dwStates : 0;
+}
+
+void IFWL_ListBox::GetItemRect(IFWL_Widget* pWidget,
+                               CFWL_ListItem* pItem,
+                               CFX_RectF& rtItem) {
+  if (pItem)
+    rtItem = static_cast<CFWL_ListItem*>(pItem)->m_rtItem;
+}
+
+void* IFWL_ListBox::GetItemData(IFWL_Widget* pWidget, CFWL_ListItem* pItem) {
+  return pItem ? static_cast<CFWL_ListItem*>(pItem)->m_pData : nullptr;
+}
+
+void IFWL_ListBox::SetItemStyles(IFWL_Widget* pWidget,
+                                 CFWL_ListItem* pItem,
+                                 uint32_t dwStyle) {
+  if (pItem)
+    static_cast<CFWL_ListItem*>(pItem)->m_dwStates = dwStyle;
+}
+
+void IFWL_ListBox::SetItemRect(IFWL_Widget* pWidget,
+                               CFWL_ListItem* pItem,
+                               const CFX_RectF& rtItem) {
+  if (pItem)
+    static_cast<CFWL_ListItem*>(pItem)->m_rtItem = rtItem;
+}
+
+CFX_DIBitmap* IFWL_ListBox::GetItemIcon(IFWL_Widget* pWidget,
+                                        CFWL_ListItem* pItem) {
+  return static_cast<CFWL_ListItem*>(pItem)->m_pDIB;
+}
+
+void IFWL_ListBox::GetItemCheckRect(IFWL_Widget* pWidget,
+                                    CFWL_ListItem* pItem,
+                                    CFX_RectF& rtCheck) {
+  rtCheck = static_cast<CFWL_ListItem*>(pItem)->m_rtCheckBox;
+}
+
+void IFWL_ListBox::SetItemCheckRect(IFWL_Widget* pWidget,
+                                    CFWL_ListItem* pItem,
+                                    const CFX_RectF& rtCheck) {
+  static_cast<CFWL_ListItem*>(pItem)->m_rtCheckBox = rtCheck;
+}
+
+uint32_t IFWL_ListBox::GetItemCheckState(IFWL_Widget* pWidget,
+                                         CFWL_ListItem* pItem) {
+  return static_cast<CFWL_ListItem*>(pItem)->m_dwCheckState;
+}
+
+void IFWL_ListBox::SetItemCheckState(IFWL_Widget* pWidget,
+                                     CFWL_ListItem* pItem,
+                                     uint32_t dwCheckState) {
+  static_cast<CFWL_ListItem*>(pItem)->m_dwCheckState = dwCheckState;
+}
+
+CFWL_ListItem* IFWL_ListBox::AddString(const CFX_WideStringC& wsAdd,
+                                       bool bSelect) {
+  auto pItem = pdfium::MakeUnique<CFWL_ListItem>();
+  pItem->m_dwStates = 0;
+  pItem->m_wsText = wsAdd;
+  pItem->m_dwStates = bSelect ? FWL_ITEMSTATE_LTB_Selected : 0;
+  m_ItemArray.push_back(std::move(pItem));
+  return m_ItemArray.back().get();
+}
+
+bool IFWL_ListBox::RemoveAt(int32_t iIndex) {
+  if (iIndex < 0 || static_cast<size_t>(iIndex) >= m_ItemArray.size())
+    return false;
+
+  m_ItemArray.erase(m_ItemArray.begin() + iIndex);
+  return true;
+}
+
+bool IFWL_ListBox::DeleteString(CFWL_ListItem* pItem) {
+  int32_t nIndex = GetItemIndex(this, pItem);
+  if (nIndex < 0 || static_cast<size_t>(nIndex) >= m_ItemArray.size())
+    return false;
+
+  int32_t iSel = nIndex + 1;
+  if (iSel >= CountItems(this))
+    iSel = nIndex - 1;
+  if (iSel >= 0) {
+    CFWL_ListItem* pSel = static_cast<CFWL_ListItem*>(GetItem(this, iSel));
+    pSel->m_dwStates |= FWL_ITEMSTATE_LTB_Selected;
+  }
+  m_ItemArray.erase(m_ItemArray.begin() + nIndex);
+  return true;
+}
+
+void IFWL_ListBox::DeleteAll() {
+  m_ItemArray.clear();
+}
diff --git a/xfa/fwl/core/ifwl_listbox.h b/xfa/fwl/core/ifwl_listbox.h
index ea1c54e..7b23881 100644
--- a/xfa/fwl/core/ifwl_listbox.h
+++ b/xfa/fwl/core/ifwl_listbox.h
@@ -8,6 +8,7 @@
 #define XFA_FWL_CORE_IFWL_LISTBOX_H_
 
 #include <memory>
+#include <vector>
 
 #include "xfa/fwl/core/cfwl_event.h"
 #include "xfa/fwl/core/cfwl_listitem.h"
@@ -39,43 +40,6 @@
 
 class IFWL_ListBox : public IFWL_Widget {
  public:
-  class DataProvider : public IFWL_Widget::DataProvider {
-   public:
-    virtual int32_t CountItems(const IFWL_Widget* pWidget) const = 0;
-    virtual CFWL_ListItem* GetItem(const IFWL_Widget* pWidget,
-                                   int32_t nIndex) const = 0;
-    virtual int32_t GetItemIndex(IFWL_Widget* pWidget,
-                                 CFWL_ListItem* pItem) = 0;
-    virtual uint32_t GetItemStyles(IFWL_Widget* pWidget,
-                                   CFWL_ListItem* pItem) = 0;
-    virtual void GetItemText(IFWL_Widget* pWidget,
-                             CFWL_ListItem* pItem,
-                             CFX_WideString& wsText) = 0;
-    virtual void GetItemRect(IFWL_Widget* pWidget,
-                             CFWL_ListItem* pItem,
-                             CFX_RectF& rtItem) = 0;
-    virtual void* GetItemData(IFWL_Widget* pWidget, CFWL_ListItem* pItem) = 0;
-    virtual void SetItemStyles(IFWL_Widget* pWidget,
-                               CFWL_ListItem* pItem,
-                               uint32_t dwStyle) = 0;
-    virtual void SetItemRect(IFWL_Widget* pWidget,
-                             CFWL_ListItem* pItem,
-                             const CFX_RectF& rtItem) = 0;
-    virtual CFX_DIBitmap* GetItemIcon(IFWL_Widget* pWidget,
-                                      CFWL_ListItem* pItem) = 0;
-    virtual void GetItemCheckRect(IFWL_Widget* pWidget,
-                                  CFWL_ListItem* pItem,
-                                  CFX_RectF& rtCheck) = 0;
-    virtual void SetItemCheckRect(IFWL_Widget* pWidget,
-                                  CFWL_ListItem* pItem,
-                                  const CFX_RectF& rtCheck) = 0;
-    virtual uint32_t GetItemCheckState(IFWL_Widget* pWidget,
-                                       CFWL_ListItem* pItem) = 0;
-    virtual void SetItemCheckState(IFWL_Widget* pWidget,
-                                   CFWL_ListItem* pItem,
-                                   uint32_t dwCheckState) = 0;
-  };
-
   IFWL_ListBox(const CFWL_App* app,
                std::unique_ptr<CFWL_WidgetProperties> properties,
                IFWL_Widget* pOuter);
@@ -94,6 +58,39 @@
   void OnDrawWidget(CFX_Graphics* pGraphics,
                     const CFX_Matrix* pMatrix) override;
 
+  int32_t CountItems(const IFWL_Widget* pWidget) const;
+  CFWL_ListItem* GetItem(const IFWL_Widget* pWidget, int32_t nIndex) const;
+  int32_t GetItemIndex(IFWL_Widget* pWidget, CFWL_ListItem* pItem);
+  uint32_t GetItemStyles(IFWL_Widget* pWidget, CFWL_ListItem* pItem);
+  void GetItemText(IFWL_Widget* pWidget,
+                   CFWL_ListItem* pItem,
+                   CFX_WideString& wsText);
+  void GetItemRect(IFWL_Widget* pWidget,
+                   CFWL_ListItem* pItem,
+                   CFX_RectF& rtItem);
+  void* GetItemData(IFWL_Widget* pWidget, CFWL_ListItem* pItem);
+  void SetItemStyles(IFWL_Widget* pWidget,
+                     CFWL_ListItem* pItem,
+                     uint32_t dwStyle);
+  void SetItemRect(IFWL_Widget* pWidget,
+                   CFWL_ListItem* pItem,
+                   const CFX_RectF& rtItem);
+  CFX_DIBitmap* GetItemIcon(IFWL_Widget* pWidget, CFWL_ListItem* pItem);
+  void GetItemCheckRect(IFWL_Widget* pWidget,
+                        CFWL_ListItem* pItem,
+                        CFX_RectF& rtCheck);
+  void SetItemCheckRect(IFWL_Widget* pWidget,
+                        CFWL_ListItem* pItem,
+                        const CFX_RectF& rtCheck);
+  uint32_t GetItemCheckState(IFWL_Widget* pWidget, CFWL_ListItem* pItem);
+  void SetItemCheckState(IFWL_Widget* pWidget,
+                         CFWL_ListItem* pItem,
+                         uint32_t dwCheckState);
+  CFWL_ListItem* AddString(const CFX_WideStringC& wsAdd, bool bSelect = false);
+  bool RemoveAt(int32_t iIndex);
+  bool DeleteString(CFWL_ListItem* pItem);
+  void DeleteAll();
+
   int32_t CountSelItems();
   CFWL_ListItem* GetSelItem(int32_t nIndexSel);
   int32_t GetSelIndex(int32_t nIndex);
@@ -165,6 +162,7 @@
   FX_FLOAT m_fScorllBarWidth;
   bool m_bLButtonDown;
   IFWL_ThemeProvider* m_pScrollBarTP;
+  std::vector<std::unique_ptr<CFWL_ListItem>> m_ItemArray;
 };
 
 #endif  // XFA_FWL_CORE_IFWL_LISTBOX_H_