Restructure EAN barcode classes to merge common code.

Add an additional layer of class hierarchy to merge some common code
between 3 very similar barcode implementations.

Change-Id: I435613006a59b1af8c7d05e7c8ba50f64a2c43b5
Reviewed-on: https://pdfium-review.googlesource.com/c/46150
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/fxbarcode/BUILD.gn b/fxbarcode/BUILD.gn
index 19ced51..344a310 100644
--- a/fxbarcode/BUILD.gn
+++ b/fxbarcode/BUILD.gn
@@ -30,6 +30,8 @@
     "cbc_ean13.h",
     "cbc_ean8.cpp",
     "cbc_ean8.h",
+    "cbc_eancode.cpp",
+    "cbc_eancode.h",
     "cbc_onecode.cpp",
     "cbc_onecode.h",
     "cbc_pdf417i.cpp",
@@ -90,6 +92,8 @@
     "oned/BC_OnedEAN8Writer.h",
     "oned/BC_OnedEANChecksum.cpp",
     "oned/BC_OnedEANChecksum.h",
+    "oned/BC_OnedEANWriter.cpp",
+    "oned/BC_OnedEANWriter.h",
     "oned/BC_OnedUPCAWriter.cpp",
     "oned/BC_OnedUPCAWriter.h",
     "pdf417/BC_PDF417.cpp",
diff --git a/fxbarcode/cbc_ean13.cpp b/fxbarcode/cbc_ean13.cpp
index b038f81..934e61c 100644
--- a/fxbarcode/cbc_ean13.cpp
+++ b/fxbarcode/cbc_ean13.cpp
@@ -27,55 +27,18 @@
 #include "third_party/base/ptr_util.h"
 
 CBC_EAN13::CBC_EAN13()
-    : CBC_OneCode(pdfium::MakeUnique<CBC_OnedEAN13Writer>()) {}
+    : CBC_EANCode(pdfium::MakeUnique<CBC_OnedEAN13Writer>()) {}
 
-CBC_EAN13::~CBC_EAN13() {}
-
-WideString CBC_EAN13::Preprocess(const WideStringView& contents) {
-  auto* pWriter = GetOnedEAN13Writer();
-  WideString encodeContents = pWriter->FilterContents(contents);
-  size_t length = encodeContents.GetLength();
-  if (length <= 12) {
-    for (size_t i = 0; i < 12 - length; i++)
-      encodeContents.InsertAtFront(L'0');
-
-    ByteString byteString = encodeContents.ToUTF8();
-    int32_t checksum = pWriter->CalcChecksum(byteString);
-    byteString += checksum + '0';
-    encodeContents = WideString::FromUTF8(byteString.AsStringView());
-  } else {
-    encodeContents = encodeContents.Left(13);
-  }
-
-  return encodeContents;
-}
-
-bool CBC_EAN13::Encode(const WideStringView& contents) {
-  if (contents.IsEmpty())
-    return false;
-
-  BCFORMAT format = BCFORMAT_EAN_13;
-  int32_t outWidth = 0;
-  int32_t outHeight = 0;
-  m_renderContents = Preprocess(contents);
-  ByteString byteString = m_renderContents.ToUTF8();
-  auto* pWriter = GetOnedEAN13Writer();
-  std::unique_ptr<uint8_t, FxFreeDeleter> data(
-      pWriter->Encode(byteString, format, outWidth, outHeight));
-  return data && pWriter->RenderResult(m_renderContents.AsStringView(),
-                                       data.get(), outWidth);
-}
-
-bool CBC_EAN13::RenderDevice(CFX_RenderDevice* device,
-                             const CFX_Matrix* matrix) {
-  return GetOnedEAN13Writer()->RenderDeviceResult(
-      device, matrix, m_renderContents.AsStringView());
-}
+CBC_EAN13::~CBC_EAN13() = default;
 
 BC_TYPE CBC_EAN13::GetType() {
   return BC_EAN13;
 }
 
-CBC_OnedEAN13Writer* CBC_EAN13::GetOnedEAN13Writer() {
-  return static_cast<CBC_OnedEAN13Writer*>(m_pBCWriter.get());
+BCFORMAT CBC_EAN13::GetFormat() const {
+  return BCFORMAT_EAN_13;
+}
+
+size_t CBC_EAN13::GetMaxLength() const {
+  return 12;
 }
diff --git a/fxbarcode/cbc_ean13.h b/fxbarcode/cbc_ean13.h
index f5887c7..a82a03f 100644
--- a/fxbarcode/cbc_ean13.h
+++ b/fxbarcode/cbc_ean13.h
@@ -7,29 +7,21 @@
 #ifndef FXBARCODE_CBC_EAN13_H_
 #define FXBARCODE_CBC_EAN13_H_
 
-#include "core/fxcrt/fx_coordinates.h"
 #include "core/fxcrt/fx_string.h"
 #include "core/fxcrt/fx_system.h"
-#include "fxbarcode/cbc_onecode.h"
+#include "fxbarcode/cbc_eancode.h"
 
 class CBC_OnedEAN13Writer;
 
-class CBC_EAN13 final : public CBC_OneCode {
+class CBC_EAN13 final : public CBC_EANCode {
  public:
   CBC_EAN13();
   ~CBC_EAN13() override;
 
-  // CBC_OneCode:
-  bool Encode(const WideStringView& contents) override;
-  bool RenderDevice(CFX_RenderDevice* device,
-                    const CFX_Matrix* matrix) override;
+  // CBC_EANCode:
   BC_TYPE GetType() override;
-
- private:
-  CBC_OnedEAN13Writer* GetOnedEAN13Writer();
-  WideString Preprocess(const WideStringView& contents);
-
-  WideString m_renderContents;
+  BCFORMAT GetFormat() const override;
+  size_t GetMaxLength() const override;
 };
 
 #endif  // FXBARCODE_CBC_EAN13_H_
diff --git a/fxbarcode/cbc_ean8.cpp b/fxbarcode/cbc_ean8.cpp
index d74a712..84ed672 100644
--- a/fxbarcode/cbc_ean8.cpp
+++ b/fxbarcode/cbc_ean8.cpp
@@ -26,54 +26,18 @@
 #include "fxbarcode/oned/BC_OnedEAN8Writer.h"
 #include "third_party/base/ptr_util.h"
 
-CBC_EAN8::CBC_EAN8() : CBC_OneCode(pdfium::MakeUnique<CBC_OnedEAN8Writer>()) {}
+CBC_EAN8::CBC_EAN8() : CBC_EANCode(pdfium::MakeUnique<CBC_OnedEAN8Writer>()) {}
 
-CBC_EAN8::~CBC_EAN8() {}
-
-WideString CBC_EAN8::Preprocess(const WideStringView& contents) {
-  auto* pWriter = GetOnedEAN8Writer();
-  WideString encodeContents = pWriter->FilterContents(contents);
-  size_t length = encodeContents.GetLength();
-  if (length <= 7) {
-    for (size_t i = 0; i < 7 - length; i++)
-      encodeContents = L'0' + encodeContents;
-
-    ByteString byteString = encodeContents.ToUTF8();
-    int32_t checksum = pWriter->CalcChecksum(byteString);
-    encodeContents += L'0' + checksum;
-  } else {
-    encodeContents = encodeContents.Left(8);
-  }
-
-  return encodeContents;
-}
-
-bool CBC_EAN8::Encode(const WideStringView& contents) {
-  if (contents.IsEmpty())
-    return false;
-
-  BCFORMAT format = BCFORMAT_EAN_8;
-  int32_t outWidth = 0;
-  int32_t outHeight = 0;
-  m_renderContents = Preprocess(contents);
-  ByteString byteString = m_renderContents.ToUTF8();
-  auto* pWriter = GetOnedEAN8Writer();
-  std::unique_ptr<uint8_t, FxFreeDeleter> data(
-      pWriter->Encode(byteString, format, outWidth, outHeight));
-  return data && pWriter->RenderResult(m_renderContents.AsStringView(),
-                                       data.get(), outWidth);
-}
-
-bool CBC_EAN8::RenderDevice(CFX_RenderDevice* device,
-                            const CFX_Matrix* matrix) {
-  return GetOnedEAN8Writer()->RenderDeviceResult(
-      device, matrix, m_renderContents.AsStringView());
-}
+CBC_EAN8::~CBC_EAN8() = default;
 
 BC_TYPE CBC_EAN8::GetType() {
   return BC_EAN8;
 }
 
-CBC_OnedEAN8Writer* CBC_EAN8::GetOnedEAN8Writer() {
-  return static_cast<CBC_OnedEAN8Writer*>(m_pBCWriter.get());
+BCFORMAT CBC_EAN8::GetFormat() const {
+  return BCFORMAT_EAN_8;
+}
+
+size_t CBC_EAN8::GetMaxLength() const {
+  return 7;
 }
diff --git a/fxbarcode/cbc_ean8.h b/fxbarcode/cbc_ean8.h
index d0c7b21..57c06fa 100644
--- a/fxbarcode/cbc_ean8.h
+++ b/fxbarcode/cbc_ean8.h
@@ -9,25 +9,19 @@
 
 #include "core/fxcrt/fx_string.h"
 #include "core/fxcrt/fx_system.h"
-#include "fxbarcode/cbc_onecode.h"
+#include "fxbarcode/cbc_eancode.h"
 
 class CBC_OnedEAN8Writer;
 
-class CBC_EAN8 final : public CBC_OneCode {
+class CBC_EAN8 final : public CBC_EANCode {
  public:
   CBC_EAN8();
   ~CBC_EAN8() override;
 
-  // CBC_OneCode:
-  bool Encode(const WideStringView& contents) override;
-  bool RenderDevice(CFX_RenderDevice* device,
-                    const CFX_Matrix* matrix) override;
+  // CBC_EANCode:
   BC_TYPE GetType() override;
-
- private:
-  CBC_OnedEAN8Writer* GetOnedEAN8Writer();
-  WideString Preprocess(const WideStringView& contents);
-  WideString m_renderContents;
+  BCFORMAT GetFormat() const override;
+  size_t GetMaxLength() const override;
 };
 
 #endif  // FXBARCODE_CBC_EAN8_H_
diff --git a/fxbarcode/cbc_eancode.cpp b/fxbarcode/cbc_eancode.cpp
new file mode 100644
index 0000000..6325b85
--- /dev/null
+++ b/fxbarcode/cbc_eancode.cpp
@@ -0,0 +1,63 @@
+// Copyright 2018 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#include "fxbarcode/cbc_eancode.h"
+
+#include <utility>
+
+#include "fxbarcode/oned/BC_OnedEANWriter.h"
+
+CBC_EANCode::CBC_EANCode(std::unique_ptr<CBC_OneDimEANWriter> pWriter)
+    : CBC_OneCode(std::move(pWriter)) {}
+
+CBC_EANCode::~CBC_EANCode() = default;
+
+CBC_OneDimEANWriter* CBC_EANCode::GetOneDimEANWriter() {
+  return static_cast<CBC_OneDimEANWriter*>(m_pBCWriter.get());
+}
+
+bool CBC_EANCode::Encode(const WideStringView& contents) {
+  if (contents.IsEmpty())
+    return false;
+
+  BCFORMAT format = GetFormat();
+  int32_t out_width = 0;
+  int32_t out_height = 0;
+  m_renderContents = Preprocess(contents);
+  ByteString str = m_renderContents.ToUTF8();
+  auto* pWriter = GetOneDimEANWriter();
+  pWriter->InitEANWriter();
+  std::unique_ptr<uint8_t, FxFreeDeleter> data(
+      pWriter->Encode(str, format, out_width, out_height));
+  return data && pWriter->RenderResult(m_renderContents.AsStringView(),
+                                       data.get(), out_width);
+}
+
+bool CBC_EANCode::RenderDevice(CFX_RenderDevice* device,
+                               const CFX_Matrix* matrix) {
+  return GetOneDimEANWriter()->RenderDeviceResult(
+      device, matrix, m_renderContents.AsStringView());
+}
+
+WideString CBC_EANCode::Preprocess(const WideStringView& contents) {
+  auto* pWriter = GetOneDimEANWriter();
+  WideString encoded_contents = pWriter->FilterContents(contents);
+  size_t length = encoded_contents.GetLength();
+  size_t max_length = GetMaxLength();
+  if (length <= max_length) {
+    for (size_t i = 0; i < max_length - length; i++)
+      encoded_contents.InsertAtFront(L'0');
+
+    ByteString str = encoded_contents.ToUTF8();
+    int32_t checksum = pWriter->CalcChecksum(str);
+    str += '0' + checksum;
+    encoded_contents = WideString::FromUTF8(str.AsStringView());
+  } else {
+    encoded_contents = encoded_contents.Left(max_length + 1);
+  }
+
+  return encoded_contents;
+}
diff --git a/fxbarcode/cbc_eancode.h b/fxbarcode/cbc_eancode.h
new file mode 100644
index 0000000..5c2e737
--- /dev/null
+++ b/fxbarcode/cbc_eancode.h
@@ -0,0 +1,38 @@
+// Copyright 2018 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#ifndef FXBARCODE_CBC_EANCODE_H_
+#define FXBARCODE_CBC_EANCODE_H_
+
+#include <memory>
+
+#include "core/fxcrt/fx_string.h"
+#include "fxbarcode/cbc_onecode.h"
+#include "fxbarcode/utils.h"
+
+class CBC_OneDimEANWriter;
+
+class CBC_EANCode : public CBC_OneCode {
+ public:
+  explicit CBC_EANCode(std::unique_ptr<CBC_OneDimEANWriter> pWriter);
+  ~CBC_EANCode() override;
+
+  virtual BCFORMAT GetFormat() const = 0;
+  virtual size_t GetMaxLength() const = 0;
+
+  // CBC_EANCode:
+  bool Encode(const WideStringView& contents) override;
+  bool RenderDevice(CFX_RenderDevice* device,
+                    const CFX_Matrix* matrix) override;
+
+ protected:
+  CBC_OneDimEANWriter* GetOneDimEANWriter();
+  WideString Preprocess(const WideStringView& contents);
+
+  WideString m_renderContents;
+};
+
+#endif  // FXBARCODE_CBC_EANCODE_H_
diff --git a/fxbarcode/cbc_onecode.h b/fxbarcode/cbc_onecode.h
index eae618e..946911c 100644
--- a/fxbarcode/cbc_onecode.h
+++ b/fxbarcode/cbc_onecode.h
@@ -24,13 +24,13 @@
   virtual bool CheckContentValidity(const WideStringView& contents);
   virtual WideString FilterContents(const WideStringView& contents);
 
-  virtual void SetPrintChecksum(bool checksum);
-  virtual void SetDataLength(int32_t length);
-  virtual void SetCalChecksum(bool calc);
-  virtual bool SetFont(CFX_Font* cFont);
-  virtual void SetFontSize(float size);
-  virtual void SetFontStyle(int32_t style);
-  virtual void SetFontColor(FX_ARGB color);
+  void SetPrintChecksum(bool checksum);
+  void SetDataLength(int32_t length);
+  void SetCalChecksum(bool calc);
+  bool SetFont(CFX_Font* cFont);
+  void SetFontSize(float size);
+  void SetFontStyle(int32_t style);
+  void SetFontColor(FX_ARGB color);
 
  private:
   CBC_OneDimWriter* GetOneDimWriter();
diff --git a/fxbarcode/cbc_upca.cpp b/fxbarcode/cbc_upca.cpp
index 77c4c49..3a3e87f 100644
--- a/fxbarcode/cbc_upca.cpp
+++ b/fxbarcode/cbc_upca.cpp
@@ -26,56 +26,18 @@
 #include "fxbarcode/oned/BC_OnedUPCAWriter.h"
 #include "third_party/base/ptr_util.h"
 
-CBC_UPCA::CBC_UPCA() : CBC_OneCode(pdfium::MakeUnique<CBC_OnedUPCAWriter>()) {}
+CBC_UPCA::CBC_UPCA() : CBC_EANCode(pdfium::MakeUnique<CBC_OnedUPCAWriter>()) {}
 
-CBC_UPCA::~CBC_UPCA() {}
-
-WideString CBC_UPCA::Preprocess(const WideStringView& contents) {
-  CBC_OnedUPCAWriter* pWriter = GetOnedUPCAWriter();
-  WideString encodeContents = pWriter->FilterContents(contents);
-  size_t length = encodeContents.GetLength();
-  if (length <= 11) {
-    for (size_t i = 0; i < 11 - length; i++)
-      encodeContents = L'0' + encodeContents;
-
-    ByteString byteString = encodeContents.ToUTF8();
-    int32_t checksum = pWriter->CalcChecksum(byteString);
-    byteString += '0' + checksum;
-    encodeContents = WideString::FromUTF8(byteString.AsStringView());
-  } else {
-    encodeContents = encodeContents.Left(12);
-  }
-
-  return encodeContents;
-}
-
-bool CBC_UPCA::Encode(const WideStringView& contents) {
-  if (contents.IsEmpty())
-    return false;
-
-  BCFORMAT format = BCFORMAT_UPC_A;
-  int32_t outWidth = 0;
-  int32_t outHeight = 0;
-  m_renderContents = Preprocess(contents);
-  ByteString byteString = m_renderContents.ToUTF8();
-  CBC_OnedUPCAWriter* pWriter = GetOnedUPCAWriter();
-  pWriter->Init();
-  std::unique_ptr<uint8_t, FxFreeDeleter> data(
-      pWriter->Encode(byteString, format, outWidth, outHeight));
-  return data && pWriter->RenderResult(m_renderContents.AsStringView(),
-                                       data.get(), outWidth);
-}
-
-bool CBC_UPCA::RenderDevice(CFX_RenderDevice* device,
-                            const CFX_Matrix* matrix) {
-  return GetOnedUPCAWriter()->RenderDeviceResult(
-      device, matrix, m_renderContents.AsStringView());
-}
+CBC_UPCA::~CBC_UPCA() = default;
 
 BC_TYPE CBC_UPCA::GetType() {
   return BC_UPCA;
 }
 
-CBC_OnedUPCAWriter* CBC_UPCA::GetOnedUPCAWriter() {
-  return static_cast<CBC_OnedUPCAWriter*>(m_pBCWriter.get());
+BCFORMAT CBC_UPCA::GetFormat() const {
+  return BCFORMAT_UPC_A;
+}
+
+size_t CBC_UPCA::GetMaxLength() const {
+  return 11;
 }
diff --git a/fxbarcode/cbc_upca.h b/fxbarcode/cbc_upca.h
index 89bfc52..bf71fc9 100644
--- a/fxbarcode/cbc_upca.h
+++ b/fxbarcode/cbc_upca.h
@@ -9,25 +9,19 @@
 
 #include "core/fxcrt/fx_string.h"
 #include "core/fxcrt/fx_system.h"
-#include "fxbarcode/cbc_onecode.h"
+#include "fxbarcode/cbc_eancode.h"
 
 class CBC_OnedUPCAWriter;
 
-class CBC_UPCA final : public CBC_OneCode {
+class CBC_UPCA final : public CBC_EANCode {
  public:
   CBC_UPCA();
   ~CBC_UPCA() override;
 
-  // CBC_CodeBase:
-  bool Encode(const WideStringView& contents) override;
-  bool RenderDevice(CFX_RenderDevice* device,
-                    const CFX_Matrix* matrix) override;
+  // CBC_EANCode:
   BC_TYPE GetType() override;
-
- private:
-  CBC_OnedUPCAWriter* GetOnedUPCAWriter();
-  WideString Preprocess(const WideStringView& contents);
-  WideString m_renderContents;
+  BCFORMAT GetFormat() const override;
+  size_t GetMaxLength() const override;
 };
 
 #endif  // FXBARCODE_CBC_UPCA_H_
diff --git a/fxbarcode/oned/BC_OnedEAN13Writer.h b/fxbarcode/oned/BC_OnedEAN13Writer.h
index c800918..8436a4f 100644
--- a/fxbarcode/oned/BC_OnedEAN13Writer.h
+++ b/fxbarcode/oned/BC_OnedEAN13Writer.h
@@ -9,17 +9,17 @@
 
 #include "core/fxcrt/fx_string.h"
 #include "core/fxcrt/fx_system.h"
-#include "fxbarcode/oned/BC_OneDimWriter.h"
+#include "fxbarcode/oned/BC_OnedEANWriter.h"
 
 class CFX_DIBitmap;
 class CFX_RenderDevice;
 
-class CBC_OnedEAN13Writer final : public CBC_OneDimWriter {
+class CBC_OnedEAN13Writer final : public CBC_OneDimEANWriter {
  public:
   CBC_OnedEAN13Writer();
   ~CBC_OnedEAN13Writer() override;
 
-  // CBC_OneDimWriter
+  // CBC_OneDimEANWriter:
   uint8_t* EncodeWithHint(const ByteString& contents,
                           BCFORMAT format,
                           int32_t& outWidth,
@@ -28,8 +28,7 @@
   uint8_t* EncodeImpl(const ByteString& contents, int32_t& outLength) override;
   bool CheckContentValidity(const WideStringView& contents) override;
   WideString FilterContents(const WideStringView& contents) override;
-
-  int32_t CalcChecksum(const ByteString& contents);
+  int32_t CalcChecksum(const ByteString& contents) override;
 
  private:
   bool ShowChars(const WideStringView& contents,
diff --git a/fxbarcode/oned/BC_OnedEAN13Writer_unittest.cpp b/fxbarcode/oned/BC_OnedEAN13Writer_unittest.cpp
index 932e1f4..0f85496 100644
--- a/fxbarcode/oned/BC_OnedEAN13Writer_unittest.cpp
+++ b/fxbarcode/oned/BC_OnedEAN13Writer_unittest.cpp
@@ -9,6 +9,7 @@
 
 TEST(OnedEAN13WriterTest, Encode) {
   CBC_OnedEAN13Writer writer;
+  writer.InitEANWriter();
   int32_t width;
   int32_t height;
   uint8_t* encoded;
@@ -89,6 +90,7 @@
 
 TEST(OnedEAN13WriterTest, Checksum) {
   CBC_OnedEAN13Writer writer;
+  writer.InitEANWriter();
   EXPECT_EQ(0, writer.CalcChecksum(""));
   EXPECT_EQ(6, writer.CalcChecksum("123"));
   EXPECT_EQ(8, writer.CalcChecksum("123456789012"));
diff --git a/fxbarcode/oned/BC_OnedEAN8Writer.h b/fxbarcode/oned/BC_OnedEAN8Writer.h
index 6295c4e..9d107b9 100644
--- a/fxbarcode/oned/BC_OnedEAN8Writer.h
+++ b/fxbarcode/oned/BC_OnedEAN8Writer.h
@@ -10,17 +10,17 @@
 #include "core/fxcrt/fx_string.h"
 #include "core/fxcrt/fx_system.h"
 #include "fxbarcode/BC_Library.h"
-#include "fxbarcode/oned/BC_OneDimWriter.h"
+#include "fxbarcode/oned/BC_OnedEANWriter.h"
 
 class CFX_DIBitmap;
 class CFX_RenderDevice;
 
-class CBC_OnedEAN8Writer final : public CBC_OneDimWriter {
+class CBC_OnedEAN8Writer final : public CBC_OneDimEANWriter {
  public:
   CBC_OnedEAN8Writer();
   ~CBC_OnedEAN8Writer() override;
 
-  // CBC_OneDimWriter
+  // CBC_OneDimEANWriter:
   uint8_t* EncodeWithHint(const ByteString& contents,
                           BCFORMAT format,
                           int32_t& outWidth,
@@ -31,8 +31,7 @@
   WideString FilterContents(const WideStringView& contents) override;
   void SetDataLength(int32_t length) override;
   bool SetTextLocation(BC_TEXT_LOC location) override;
-
-  int32_t CalcChecksum(const ByteString& contents);
+  int32_t CalcChecksum(const ByteString& contents) override;
 
  private:
   bool ShowChars(const WideStringView& contents,
diff --git a/fxbarcode/oned/BC_OnedEAN8Writer_unittest.cpp b/fxbarcode/oned/BC_OnedEAN8Writer_unittest.cpp
index 16a1df6..55a0a33 100644
--- a/fxbarcode/oned/BC_OnedEAN8Writer_unittest.cpp
+++ b/fxbarcode/oned/BC_OnedEAN8Writer_unittest.cpp
@@ -9,6 +9,7 @@
 
 TEST(OnedEAN8WriterTest, Encode) {
   CBC_OnedEAN8Writer writer;
+  writer.InitEANWriter();
   int32_t width;
   int32_t height;
   uint8_t* encoded;
@@ -79,6 +80,7 @@
 
 TEST(OnedEAN8WriterTest, Checksum) {
   CBC_OnedEAN8Writer writer;
+  writer.InitEANWriter();
   EXPECT_EQ(0, writer.CalcChecksum(""));
   EXPECT_EQ(6, writer.CalcChecksum("123"));
   EXPECT_EQ(0, writer.CalcChecksum("1234567"));
diff --git a/fxbarcode/oned/BC_OnedEANWriter.cpp b/fxbarcode/oned/BC_OnedEANWriter.cpp
new file mode 100644
index 0000000..f43b9ad
--- /dev/null
+++ b/fxbarcode/oned/BC_OnedEANWriter.cpp
@@ -0,0 +1,11 @@
+// Copyright 2018 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "fxbarcode/oned/BC_OnedEANWriter.h"
+
+CBC_OneDimEANWriter::CBC_OneDimEANWriter() = default;
+
+CBC_OneDimEANWriter::~CBC_OneDimEANWriter() = default;
+
+void CBC_OneDimEANWriter::InitEANWriter() {}
diff --git a/fxbarcode/oned/BC_OnedEANWriter.h b/fxbarcode/oned/BC_OnedEANWriter.h
new file mode 100644
index 0000000..5d80167
--- /dev/null
+++ b/fxbarcode/oned/BC_OnedEANWriter.h
@@ -0,0 +1,19 @@
+// Copyright 2018 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef FXBARCODE_ONED_BC_ONEDEANWRITER_H_
+#define FXBARCODE_ONED_BC_ONEDEANWRITER_H_
+
+#include "fxbarcode/oned/BC_OneDimWriter.h"
+
+class CBC_OneDimEANWriter : public CBC_OneDimWriter {
+ public:
+  CBC_OneDimEANWriter();
+  ~CBC_OneDimEANWriter() override;
+
+  virtual void InitEANWriter();
+  virtual int32_t CalcChecksum(const ByteString& contents) = 0;
+};
+
+#endif  // FXBARCODE_ONED_BC_ONEDEANWRITER_H_
diff --git a/fxbarcode/oned/BC_OnedUPCAWriter.cpp b/fxbarcode/oned/BC_OnedUPCAWriter.cpp
index 9e7400a..d3b9226 100644
--- a/fxbarcode/oned/BC_OnedUPCAWriter.cpp
+++ b/fxbarcode/oned/BC_OnedUPCAWriter.cpp
@@ -36,10 +36,6 @@
   m_bRightPadding = true;
 }
 
-void CBC_OnedUPCAWriter::Init() {
-  m_subWriter = pdfium::MakeUnique<CBC_OnedEAN13Writer>();
-}
-
 CBC_OnedUPCAWriter::~CBC_OnedUPCAWriter() {}
 
 bool CBC_OnedUPCAWriter::CheckContentValidity(const WideStringView& contents) {
@@ -66,6 +62,10 @@
   return filtercontents;
 }
 
+void CBC_OnedUPCAWriter::InitEANWriter() {
+  m_subWriter = pdfium::MakeUnique<CBC_OnedEAN13Writer>();
+}
+
 int32_t CBC_OnedUPCAWriter::CalcChecksum(const ByteString& contents) {
   int32_t odd = 0;
   int32_t even = 0;
diff --git a/fxbarcode/oned/BC_OnedUPCAWriter.h b/fxbarcode/oned/BC_OnedUPCAWriter.h
index 6101b4d..8e2f770 100644
--- a/fxbarcode/oned/BC_OnedUPCAWriter.h
+++ b/fxbarcode/oned/BC_OnedUPCAWriter.h
@@ -11,19 +11,19 @@
 
 #include "core/fxcrt/fx_string.h"
 #include "core/fxcrt/fx_system.h"
-#include "fxbarcode/oned/BC_OneDimWriter.h"
+#include "fxbarcode/oned/BC_OnedEANWriter.h"
 
 class CBC_OnedEAN13Writer;
 class CFX_DIBitmap;
 class CFX_Matrix;
 class CFX_RenderDevice;
 
-class CBC_OnedUPCAWriter final : public CBC_OneDimWriter {
+class CBC_OnedUPCAWriter final : public CBC_OneDimEANWriter {
  public:
   CBC_OnedUPCAWriter();
   ~CBC_OnedUPCAWriter() override;
 
-  // CBC_OneDimWriter
+  // CBC_OneDimEANWriter:
   uint8_t* EncodeWithHint(const ByteString& contents,
                           BCFORMAT format,
                           int32_t& outWidth,
@@ -32,9 +32,8 @@
   uint8_t* EncodeImpl(const ByteString& contents, int32_t& outLength) override;
   bool CheckContentValidity(const WideStringView& contents) override;
   WideString FilterContents(const WideStringView& contents) override;
-
-  void Init();
-  int32_t CalcChecksum(const ByteString& contents);
+  void InitEANWriter() override;
+  int32_t CalcChecksum(const ByteString& contents) override;
 
  private:
   bool ShowChars(const WideStringView& contents,
diff --git a/fxbarcode/oned/BC_OnedUPCAWriter_unittest.cpp b/fxbarcode/oned/BC_OnedUPCAWriter_unittest.cpp
index 3d9f6c5..cd9ff47 100644
--- a/fxbarcode/oned/BC_OnedUPCAWriter_unittest.cpp
+++ b/fxbarcode/oned/BC_OnedUPCAWriter_unittest.cpp
@@ -9,13 +9,10 @@
 
 TEST(OnedUPCAWriterTest, Encode) {
   CBC_OnedUPCAWriter writer;
+  writer.InitEANWriter();
   int32_t width;
   int32_t height;
 
-  // TODO(hnakashima): CBC_OnedUPCAWriter is unique in that it needs to be
-  // Init()'d. Get rid of this call.
-  writer.Init();
-
   // UPCA barcodes encode 12-digit numbers into 95 modules in a unidimensional
   // disposition.
   uint8_t* encoded = writer.Encode("", BCFORMAT_UPC_A, width, height);
@@ -87,6 +84,7 @@
 
 TEST(OnedUPCAWriterTest, Checksum) {
   CBC_OnedUPCAWriter writer;
+  writer.InitEANWriter();
   EXPECT_EQ(0, writer.CalcChecksum(""));
   EXPECT_EQ(6, writer.CalcChecksum("123"));
   EXPECT_EQ(2, writer.CalcChecksum("12345678901"));