Fix crash when typing letters into an XFA datetime field.

The root of the issue is that CXFA_FFDateTimeEdit inherits from
CXFA_FFTextEdit and methods in the former treat its widget as a
CFWL_Edit, while it can be a CFWL_DateTimePicker.

Bug: chromium:857521
Change-Id: I764b6c03095b16f6a9cf72ff36768ca4c57c4070
Reviewed-on: https://pdfium-review.googlesource.com/37910
Reviewed-by: Ryan Harrison <rharrison@chromium.org>
Commit-Queue: Henrique Nakashima <hnakashima@chromium.org>
diff --git a/xfa/fwl/cfwl_datetimepicker.cpp b/xfa/fwl/cfwl_datetimepicker.cpp
index 8c37e1d..0af01fb 100644
--- a/xfa/fwl/cfwl_datetimepicker.cpp
+++ b/xfa/fwl/cfwl_datetimepicker.cpp
@@ -178,6 +178,10 @@
   return m_pEdit ? m_pEdit->GetText() : L"";
 }
 
+int32_t CFWL_DateTimePicker::GetEditTextLength() const {
+  return m_pEdit ? m_pEdit->GetTextLength() : 0;
+}
+
 CFX_RectF CFWL_DateTimePicker::GetBBox() const {
   CFX_RectF rect = m_pProperties->m_rtWidget;
   if (NeedsToShowButton())
@@ -460,3 +464,43 @@
   m_pWidgetMgr->GetAdapterPopupPos(this, fMinHeight, fMaxHeight, rtAnchor,
                                    pPopupRect);
 }
+
+void CFWL_DateTimePicker::ClearText() {
+  m_pEdit->ClearText();
+}
+
+void CFWL_DateTimePicker::SelectAll() {
+  m_pEdit->SelectAll();
+}
+
+void CFWL_DateTimePicker::ClearSelection() {
+  m_pEdit->ClearSelection();
+}
+
+Optional<WideString> CFWL_DateTimePicker::Copy() {
+  return m_pEdit->Copy();
+}
+
+Optional<WideString> CFWL_DateTimePicker::Cut() {
+  return m_pEdit->Cut();
+}
+
+bool CFWL_DateTimePicker::Paste(const WideString& wsPaste) {
+  return m_pEdit->Paste(wsPaste);
+}
+
+bool CFWL_DateTimePicker::Undo() {
+  return m_pEdit->Undo();
+}
+
+bool CFWL_DateTimePicker::Redo() {
+  return m_pEdit->Redo();
+}
+
+bool CFWL_DateTimePicker::CanUndo() {
+  return m_pEdit->CanUndo();
+}
+
+bool CFWL_DateTimePicker::CanRedo() {
+  return m_pEdit->CanRedo();
+}
diff --git a/xfa/fwl/cfwl_datetimepicker.h b/xfa/fwl/cfwl_datetimepicker.h
index 00e7f61..f80f09d 100644
--- a/xfa/fwl/cfwl_datetimepicker.h
+++ b/xfa/fwl/cfwl_datetimepicker.h
@@ -49,13 +49,24 @@
   void SetCurSel(int32_t iYear, int32_t iMonth, int32_t iDay);
 
   void SetEditText(const WideString& wsText);
+  int32_t GetEditTextLength() const;
   WideString GetEditText() const;
+  void ClearText();
 
+  void SelectAll();
+  void ClearSelection();
   bool HasSelection() const { return m_pEdit->HasSelection(); }
   // Returns <start, count> of the selection.
   std::pair<size_t, size_t> GetSelection() const {
     return m_pEdit->GetSelection();
   }
+  Optional<WideString> Copy();
+  Optional<WideString> Cut();
+  bool Paste(const WideString& wsPaste);
+  bool Undo();
+  bool Redo();
+  bool CanUndo();
+  bool CanRedo();
 
   CFX_RectF GetBBox() const;
   void SetEditLimit(int32_t nLimit) { m_pEdit->SetLimit(nLimit); }
diff --git a/xfa/fxfa/cxfa_ffdatetimeedit.cpp b/xfa/fxfa/cxfa_ffdatetimeedit.cpp
index f5531ff..6218e29 100644
--- a/xfa/fxfa/cxfa_ffdatetimeedit.cpp
+++ b/xfa/fxfa/cxfa_ffdatetimeedit.cpp
@@ -24,6 +24,10 @@
 
 CXFA_FFDateTimeEdit::~CXFA_FFDateTimeEdit() {}
 
+CFWL_DateTimePicker* CXFA_FFDateTimeEdit::GetPickerWidget() {
+  return static_cast<CFWL_DateTimePicker*>(m_pNormalWidget.get());
+}
+
 CFX_RectF CXFA_FFDateTimeEdit::GetBBox(uint32_t dwStatus, bool bDrawFocus) {
   if (bDrawFocus)
     return CFX_RectF();
@@ -31,7 +35,7 @@
 }
 
 bool CXFA_FFDateTimeEdit::PtInActiveRect(const CFX_PointF& point) {
-  auto* pPicker = static_cast<CFWL_DateTimePicker*>(m_pNormalWidget.get());
+  CFWL_DateTimePicker* pPicker = GetPickerWidget();
   return pPicker && pPicker->GetBBox().Contains(point);
 }
 
@@ -73,9 +77,8 @@
 }
 
 void CXFA_FFDateTimeEdit::UpdateWidgetProperty() {
-  CFWL_DateTimePicker* pWidget =
-      static_cast<CFWL_DateTimePicker*>(m_pNormalWidget.get());
-  if (!pWidget)
+  CFWL_DateTimePicker* pPicker = GetPickerWidget();
+  if (!pPicker)
     return;
 
   uint32_t dwExtendedStyle = FWL_STYLEEXT_DTP_ShortDateFormat;
@@ -87,14 +90,14 @@
   Optional<int32_t> numCells = m_pNode->GetNumberOfCells();
   if (numCells && *numCells > 0) {
     dwEditStyles |= FWL_STYLEEXT_EDT_CombText;
-    pWidget->SetEditLimit(*numCells);
+    pPicker->SetEditLimit(*numCells);
   }
   if (!m_pNode->IsOpenAccess() || !GetDoc()->GetXFADoc()->IsInteractive())
     dwEditStyles |= FWL_STYLEEXT_EDT_ReadOnly;
   if (!m_pNode->IsHorizontalScrollPolicyOff())
     dwEditStyles |= FWL_STYLEEXT_EDT_AutoHScroll;
 
-  pWidget->ModifyEditStylesEx(dwEditStyles, 0xFFFFFFFF);
+  pPicker->ModifyEditStylesEx(dwEditStyles, 0xFFFFFFFF);
 }
 
 uint32_t CXFA_FFDateTimeEdit::GetAlignment() {
@@ -136,7 +139,7 @@
 }
 
 bool CXFA_FFDateTimeEdit::CommitData() {
-  auto* pPicker = static_cast<CFWL_DateTimePicker*>(m_pNormalWidget.get());
+  CFWL_DateTimePicker* pPicker = GetPickerWidget();
   if (!m_pNode->SetValue(XFA_VALUEPICTURE_Edit, pPicker->GetEditText()))
     return false;
 
@@ -153,14 +156,14 @@
     eType = XFA_VALUEPICTURE_Edit;
 
   WideString wsText = m_pNode->GetValue(eType);
-  auto* normalWidget = static_cast<CFWL_DateTimePicker*>(m_pNormalWidget.get());
-  normalWidget->SetEditText(wsText);
+  CFWL_DateTimePicker* pPicker = GetPickerWidget();
+  pPicker->SetEditText(wsText);
   if (IsFocused() && !wsText.IsEmpty()) {
     CXFA_LocaleValue lcValue = XFA_GetLocaleValue(m_pNode.Get());
     CFX_DateTime date = lcValue.GetDate();
     if (lcValue.IsValid()) {
       if (date.IsSet())
-        normalWidget->SetCurSel(date.GetYear(), date.GetMonth(), date.GetDay());
+        pPicker->SetCurSel(date.GetYear(), date.GetMonth(), date.GetDay());
     }
   }
   m_pNormalWidget->Update();
@@ -171,8 +174,7 @@
   if (m_dwStatus & XFA_WidgetStatus_TextEditValueChanged)
     return true;
 
-  WideString wsText =
-      static_cast<CFWL_DateTimePicker*>(m_pNormalWidget.get())->GetEditText();
+  WideString wsText = GetPickerWidget()->GetEditText();
   return m_pNode->GetValue(XFA_VALUEPICTURE_Edit) != wsText;
 }
 
@@ -189,9 +191,9 @@
   date.FormatPatterns(wsDate, wsPicture, m_pNode->GetLocale(),
                       XFA_VALUEPICTURE_Edit);
 
-  auto* pDateTime = static_cast<CFWL_DateTimePicker*>(m_pNormalWidget.get());
-  pDateTime->SetEditText(wsDate);
-  pDateTime->Update();
+  CFWL_DateTimePicker* pPicker = GetPickerWidget();
+  pPicker->SetEditText(wsDate);
+  pPicker->Update();
   GetDoc()->GetDocEnvironment()->SetFocusWidget(GetDoc(), nullptr);
 
   CXFA_EventParam eParam;
@@ -210,3 +212,65 @@
   }
   CXFA_FFTextEdit::OnProcessEvent(pEvent);
 }
+
+bool CXFA_FFDateTimeEdit::CanUndo() {
+  return GetPickerWidget()->CanUndo();
+}
+
+bool CXFA_FFDateTimeEdit::CanRedo() {
+  return GetPickerWidget()->CanRedo();
+}
+
+bool CXFA_FFDateTimeEdit::Undo() {
+  return GetPickerWidget()->Undo();
+}
+
+bool CXFA_FFDateTimeEdit::Redo() {
+  return GetPickerWidget()->Redo();
+}
+
+bool CXFA_FFDateTimeEdit::CanCopy() {
+  return GetPickerWidget()->HasSelection();
+}
+
+bool CXFA_FFDateTimeEdit::CanCut() {
+  if (GetPickerWidget()->GetStylesEx() & FWL_STYLEEXT_EDT_ReadOnly)
+    return false;
+  return GetPickerWidget()->HasSelection();
+}
+
+bool CXFA_FFDateTimeEdit::CanPaste() {
+  return !(GetPickerWidget()->GetStylesEx() & FWL_STYLEEXT_EDT_ReadOnly);
+}
+
+bool CXFA_FFDateTimeEdit::CanSelectAll() {
+  return GetPickerWidget()->GetEditTextLength() > 0;
+}
+
+Optional<WideString> CXFA_FFDateTimeEdit::Copy() {
+  return GetPickerWidget()->Copy();
+}
+
+Optional<WideString> CXFA_FFDateTimeEdit::Cut() {
+  return GetPickerWidget()->Cut();
+}
+
+bool CXFA_FFDateTimeEdit::Paste(const WideString& wsPaste) {
+  return GetPickerWidget()->Paste(wsPaste);
+}
+
+void CXFA_FFDateTimeEdit::SelectAll() {
+  GetPickerWidget()->SelectAll();
+}
+
+void CXFA_FFDateTimeEdit::Delete() {
+  GetPickerWidget()->ClearText();
+}
+
+void CXFA_FFDateTimeEdit::DeSelect() {
+  GetPickerWidget()->ClearSelection();
+}
+
+WideString CXFA_FFDateTimeEdit::GetText() {
+  return GetPickerWidget()->GetEditText();
+}
diff --git a/xfa/fxfa/cxfa_ffdatetimeedit.h b/xfa/fxfa/cxfa_ffdatetimeedit.h
index a549cbb..8041b31 100644
--- a/xfa/fxfa/cxfa_ffdatetimeedit.h
+++ b/xfa/fxfa/cxfa_ffdatetimeedit.h
@@ -16,6 +16,7 @@
   XFA_DATETIMETYPE_DateAndTime
 };
 
+class CFWL_DateTimePicker;
 class CFWL_Event;
 class CFWL_Widget;
 
@@ -35,12 +36,31 @@
                        int32_t iMonth,
                        int32_t iDay);
 
+  // CXFA_FFWidget
+  bool CanUndo() override;
+  bool CanRedo() override;
+  bool Undo() override;
+  bool Redo() override;
+  bool CanCopy() override;
+  bool CanCut() override;
+  bool CanPaste() override;
+  bool CanSelectAll() override;
+  Optional<WideString> Copy() override;
+  Optional<WideString> Cut() override;
+  bool Paste(const WideString& wsPaste) override;
+  void SelectAll() override;
+  void Delete() override;
+  void DeSelect() override;
+  WideString GetText() override;
+
  private:
   bool PtInActiveRect(const CFX_PointF& point) override;
   bool CommitData() override;
   bool UpdateFWLData() override;
   bool IsDataChanged() override;
 
+  CFWL_DateTimePicker* GetPickerWidget();
+
   uint32_t GetAlignment();
 };