Correctly skip characters in CFDE_TextOut::RetrievePieces().
CFDE_TextOut::RetrievePieces() has a parameter that indicates the
character to start with. Handle this parameter correctly and skip that
many characters before continuing to process more characters.
Bug: chromium:1342078
Change-Id: I20ae6f92e3cd72ef832adad6ce5f8b6ba552967b
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/95150
Reviewed-by: Nigi <nigi@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/xfa/fde/cfde_textout.cpp b/xfa/fde/cfde_textout.cpp
index 1de901c..67c5185 100644
--- a/xfa/fde/cfde_textout.cpp
+++ b/xfa/fde/cfde_textout.cpp
@@ -370,12 +370,19 @@
bool bNeedReload = false;
int32_t iLineWidth = FXSYS_roundf(rect.Width() * 20000.0f);
int32_t iCount = m_pTxtBreak->CountBreakPieces();
+
+ size_t chars_to_skip = *pStartChar;
for (int32_t i = 0; i < iCount; i++) {
const CFGAS_BreakPiece* pPiece = m_pTxtBreak->GetBreakPieceUnstable(i);
size_t iPieceChars = pPiece->GetLength();
+ if (chars_to_skip > iPieceChars) {
+ chars_to_skip -= iPieceChars;
+ continue;
+ }
+
size_t iChar = *pStartChar;
int32_t iWidth = 0;
- size_t j = 0;
+ size_t j = chars_to_skip;
for (; j < iPieceChars; j++) {
const CFGAS_Char* pTC = pPiece->GetChar(j);
int32_t iCurCharWidth = std::max(pTC->m_iCharWidth, 0);
@@ -389,12 +396,12 @@
m_CharWidths[iChar++] = iCurCharWidth;
}
- if (j == 0 && !bReload) {
+ if (j == chars_to_skip && !bReload) {
m_ttoLines[m_iCurLine].set_new_reload(true);
- } else if (j > 0) {
+ } else if (j > chars_to_skip) {
Piece piece;
piece.start_char = *pStartChar;
- piece.char_count = j;
+ piece.char_count = j - chars_to_skip;
piece.char_styles = pPiece->GetCharStyles();
piece.bounds = CFX_RectF(
rect.left + static_cast<float>(pPiece->GetStartPos()) / 20000.0f,
diff --git a/xfa/fde/cfde_textout_unittest.cpp b/xfa/fde/cfde_textout_unittest.cpp
index 46f128d..57e60a5 100644
--- a/xfa/fde/cfde_textout_unittest.cpp
+++ b/xfa/fde/cfde_textout_unittest.cpp
@@ -6,40 +6,42 @@
#include <memory>
+#include "build/build_config.h"
#include "core/fdrm/fx_crypt.h"
#include "core/fxcrt/bytestring.h"
#include "core/fxcrt/fx_codepage.h"
+#include "core/fxcrt/fx_coordinates.h"
#include "core/fxcrt/retain_ptr.h"
#include "core/fxge/cfx_defaultrenderdevice.h"
#include "core/fxge/dib/cfx_dibitmap.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/utils/hash.h"
+#include "xfa/fgas/font/cfgas_fontmgr.h"
#include "xfa/fgas/font/cfgas_gefont.h"
-
-namespace {
-
-const char kEmptyImageChecksum[] = "a042237c5493fdb9656b94a83608d11a";
-
-} // namespace
+#include "xfa/fgas/font/cfgas_gemodule.h"
class CFDETextOutTest : public testing::Test {
public:
+ CFDETextOutTest() = default;
+ ~CFDETextOutTest() override = default;
+
void SetUp() override {
+ CFX_Size bitmap_size = GetBitmapSize();
bitmap_ = pdfium::MakeRetain<CFX_DIBitmap>();
- ASSERT_TRUE(bitmap_->Create(200, 100, FXDIB_Format::kArgb));
+ ASSERT_TRUE(bitmap_->Create(bitmap_size.width, bitmap_size.height,
+ FXDIB_Format::kArgb));
device_ = std::make_unique<CFX_DefaultRenderDevice>();
device_->Attach(bitmap_);
- const wchar_t kFontFamily[] = L"Arimo Bold";
- font_ = CFGAS_GEFont::LoadFont(kFontFamily, 0, FX_CodePage::kDefANSI);
+ font_ = LoadFont();
ASSERT_TRUE(font_);
text_out_ = std::make_unique<CFDE_TextOut>();
text_out_->SetFont(font_);
text_out_->SetFontSize(12.0f);
- EXPECT_STREQ(kEmptyImageChecksum, GetBitmapChecksum().c_str());
+ EXPECT_STREQ(GetEmptyBitmapChecksum(), GetBitmapChecksum().c_str());
}
void TearDown() override {
@@ -49,6 +51,20 @@
bitmap_.Reset();
}
+ virtual RetainPtr<CFGAS_GEFont> LoadFont() {
+ const wchar_t kFontFamily[] = L"Arimo Bold";
+ return CFGAS_GEFont::LoadFont(kFontFamily, /*dwFontStyles=*/0,
+ FX_CodePage::kDefANSI);
+ }
+
+ virtual CFX_Size GetBitmapSize() { return CFX_Size(200, 100); }
+
+ virtual const char* GetEmptyBitmapChecksum() {
+ static const char kEmptyBitmapChecksum[] =
+ "a042237c5493fdb9656b94a83608d11a";
+ return kEmptyBitmapChecksum;
+ }
+
CFX_DefaultRenderDevice* device() { return device_.get(); }
CFDE_TextOut& text_out() { return *text_out_; }
@@ -69,11 +85,63 @@
};
TEST_F(CFDETextOutTest, DrawLogicTextBasic) {
- text_out().DrawLogicText(device(), L"foo", CFX_RectF(0, 0, 200, 100));
+ text_out().DrawLogicText(device(), L"foo", CFX_RectF(0, 0, 2100, 100));
EXPECT_STREQ("b26f1c171fcdbf185823364185adacf0", GetBitmapChecksum().c_str());
}
TEST_F(CFDETextOutTest, DrawLogicTextEmptyRect) {
text_out().DrawLogicText(device(), L"foo", CFX_RectF());
- EXPECT_STREQ(kEmptyImageChecksum, GetBitmapChecksum().c_str());
+ EXPECT_STREQ(GetEmptyBitmapChecksum(), GetBitmapChecksum().c_str());
}
+
+#if !BUILDFLAG(IS_WIN)
+// This test depends on a particular font being present.
+class CFDETextOutLargeBitmapTest : public CFDETextOutTest {
+ public:
+ CFDETextOutLargeBitmapTest() = default;
+ ~CFDETextOutLargeBitmapTest() override = default;
+
+ RetainPtr<CFGAS_GEFont> LoadFont() override {
+ const wchar_t kFontFamily[] = L"DejaVu Sans";
+ auto* font_manager = CFGAS_GEModule::Get()->GetFontMgr();
+ return font_manager->LoadFont(kFontFamily, /*dwFontStyles=*/0,
+ FX_CodePage::kFailure);
+ }
+
+ CFX_Size GetBitmapSize() override { return CFX_Size(2100, 20); }
+
+ const char* GetEmptyBitmapChecksum() override {
+ static const char kEmptyLargeBitmapChecksum[] =
+ "101745f76351fd5d916bf3817b71563c";
+ return kEmptyLargeBitmapChecksum;
+ }
+};
+
+// See crbug.com/1342078
+TEST_F(CFDETextOutLargeBitmapTest, DrawLogicText) {
+ FDE_TextStyle styles;
+ styles.single_line_ = true;
+ text_out().SetStyles(styles);
+ text_out().SetAlignment(FDE_TextAlignment::kCenterLeft);
+ text_out().SetFontSize(10.0f);
+
+ static const wchar_t kText[] =
+ L"SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS"
+ L"SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSssssssssss"
+ L"sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss"
+ L"sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss"
+ L"sssssssssssssssssssssssssssssssssssssssssssssssssnnnnnnnnnnn"
+ "\xfeba"
+ L"Sssssssssssssssssss"
+ "\xfeba"
+ L"iiiiiiiiiisssss";
+ text_out().DrawLogicText(device(), WideString(kText),
+ CFX_RectF(3, 3, 2048, 10));
+#if defined(_SKIA_SUPPORT_)
+ static const char kExpectedChecksum[] = "6181929583fd7651169306852397806f";
+#else
+ static const char kExpectedChecksum[] = "268b71a8660b51e31c6bf30fc7ff1e08";
+#endif
+ EXPECT_STREQ(kExpectedChecksum, GetBitmapChecksum().c_str());
+}
+#endif // !BUILDFLAG(IS_WIN)