1 // Copyright 2022 The PDFium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "xfa/fde/cfde_textout.h"
6
7 #include <memory>
8
9 #include "build/build_config.h"
10 #include "core/fdrm/fx_crypt.h"
11 #include "core/fxcrt/bytestring.h"
12 #include "core/fxcrt/fx_codepage.h"
13 #include "core/fxcrt/fx_coordinates.h"
14 #include "core/fxcrt/retain_ptr.h"
15 #include "core/fxge/cfx_defaultrenderdevice.h"
16 #include "core/fxge/dib/cfx_dibitmap.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 #include "testing/utils/hash.h"
19 #include "xfa/fgas/font/cfgas_fontmgr.h"
20 #include "xfa/fgas/font/cfgas_gefont.h"
21 #include "xfa/fgas/font/cfgas_gemodule.h"
22
23 class CFDETextOutTest : public testing::Test {
24 public:
25 CFDETextOutTest() = default;
26 ~CFDETextOutTest() override = default;
27
SetUp()28 void SetUp() override {
29 CFX_Size bitmap_size = GetBitmapSize();
30 bitmap_ = pdfium::MakeRetain<CFX_DIBitmap>();
31 ASSERT_TRUE(bitmap_->Create(bitmap_size.width, bitmap_size.height,
32 FXDIB_Format::kArgb));
33
34 device_ = std::make_unique<CFX_DefaultRenderDevice>();
35 device_->Attach(bitmap_);
36
37 font_ = LoadFont();
38 ASSERT_TRUE(font_);
39
40 text_out_ = std::make_unique<CFDE_TextOut>();
41 text_out_->SetFont(font_);
42 text_out_->SetFontSize(12.0f);
43
44 EXPECT_STREQ(GetEmptyBitmapChecksum(), GetBitmapChecksum().c_str());
45 }
46
TearDown()47 void TearDown() override {
48 text_out_.reset();
49 font_.Reset();
50 device_.reset();
51 bitmap_.Reset();
52 }
53
LoadFont()54 virtual RetainPtr<CFGAS_GEFont> LoadFont() {
55 const wchar_t kFontFamily[] = L"Arimo Bold";
56 return CFGAS_GEFont::LoadFont(kFontFamily, /*dwFontStyles=*/0,
57 FX_CodePage::kDefANSI);
58 }
59
GetBitmapSize()60 virtual CFX_Size GetBitmapSize() { return CFX_Size(200, 100); }
61
GetEmptyBitmapChecksum()62 virtual const char* GetEmptyBitmapChecksum() {
63 static const char kEmptyBitmapChecksum[] =
64 "a042237c5493fdb9656b94a83608d11a";
65 return kEmptyBitmapChecksum;
66 }
67
device()68 CFX_DefaultRenderDevice* device() { return device_.get(); }
text_out()69 CFDE_TextOut& text_out() { return *text_out_; }
70
GetBitmapChecksum()71 ByteString GetBitmapChecksum() {
72 CRYPT_md5_context context = CRYPT_MD5Start();
73 for (int i = 0; i < bitmap_->GetHeight(); ++i)
74 CRYPT_MD5Update(&context, bitmap_->GetScanline(i));
75 uint8_t digest[16];
76 CRYPT_MD5Finish(&context, digest);
77 return ByteString(CryptToBase16(digest).c_str());
78 }
79
80 private:
81 RetainPtr<CFX_DIBitmap> bitmap_;
82 std::unique_ptr<CFX_DefaultRenderDevice> device_;
83 RetainPtr<CFGAS_GEFont> font_;
84 std::unique_ptr<CFDE_TextOut> text_out_;
85 };
86
TEST_F(CFDETextOutTest,DrawLogicTextBasic)87 TEST_F(CFDETextOutTest, DrawLogicTextBasic) {
88 text_out().DrawLogicText(device(), L"foo", CFX_RectF(0, 0, 2100, 100));
89 const char* checksum = []() {
90 #if BUILDFLAG(IS_WIN)
91 if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
92 return "76fd535f7d490d963598474494d0701e";
93 #endif
94 return "b26f1c171fcdbf185823364185adacf0";
95 }();
96 EXPECT_STREQ(checksum, GetBitmapChecksum().c_str());
97 }
98
TEST_F(CFDETextOutTest,DrawLogicTextEmptyRect)99 TEST_F(CFDETextOutTest, DrawLogicTextEmptyRect) {
100 text_out().DrawLogicText(device(), L"foo", CFX_RectF());
101 EXPECT_STREQ(GetEmptyBitmapChecksum(), GetBitmapChecksum().c_str());
102 }
103
104 #if !BUILDFLAG(IS_WIN)
105 // This test depends on a particular font being present.
106 class CFDETextOutLargeBitmapTest : public CFDETextOutTest {
107 public:
108 CFDETextOutLargeBitmapTest() = default;
109 ~CFDETextOutLargeBitmapTest() override = default;
110
LoadFont()111 RetainPtr<CFGAS_GEFont> LoadFont() override {
112 const wchar_t kFontFamily[] = L"DejaVu Sans";
113 auto* font_manager = CFGAS_GEModule::Get()->GetFontMgr();
114 return font_manager->LoadFont(kFontFamily, /*dwFontStyles=*/0,
115 FX_CodePage::kFailure);
116 }
117
GetBitmapSize()118 CFX_Size GetBitmapSize() override { return CFX_Size(2100, 20); }
119
GetEmptyBitmapChecksum()120 const char* GetEmptyBitmapChecksum() override {
121 static const char kEmptyLargeBitmapChecksum[] =
122 "101745f76351fd5d916bf3817b71563c";
123 return kEmptyLargeBitmapChecksum;
124 }
125
GetLargeTextBlobChecksum()126 const char* GetLargeTextBlobChecksum() {
127 if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
128 return "cd357c6afbf17bb2ac48817df5d9eaad";
129 }
130 return "268b71a8660b51e31c6bf30fc7ff1e08";
131 }
132 };
133
TEST_F(CFDETextOutLargeBitmapTest,DrawLogicTextBug953881)134 TEST_F(CFDETextOutLargeBitmapTest, DrawLogicTextBug953881) {
135 FDE_TextStyle styles;
136 styles.single_line_ = true;
137 text_out().SetStyles(styles);
138 text_out().SetAlignment(FDE_TextAlignment::kCenterLeft);
139 text_out().SetFontSize(10.0f);
140
141 static const wchar_t kText[] =
142 L"SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS"
143 L"SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSssssssssss"
144 L"sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss"
145 L"sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss"
146 L"sssssssssssssssssssssssssssssssssssssssssssssssssnnnnnnnnnnn"
147 "\xfeba"
148 L"Sssssssssssssssssss"
149 "\xfeba"
150 L"iiiiisssss";
151 text_out().DrawLogicText(device(), WideString(kText),
152 CFX_RectF(3, 3, 2048, 10));
153 EXPECT_STREQ(GetLargeTextBlobChecksum(), GetBitmapChecksum().c_str());
154 }
155
TEST_F(CFDETextOutLargeBitmapTest,DrawLogicTextBug1342078)156 TEST_F(CFDETextOutLargeBitmapTest, DrawLogicTextBug1342078) {
157 FDE_TextStyle styles;
158 styles.single_line_ = true;
159 text_out().SetStyles(styles);
160 text_out().SetAlignment(FDE_TextAlignment::kCenterLeft);
161 text_out().SetFontSize(10.0f);
162
163 static const wchar_t kText[] =
164 L"SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS"
165 L"SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSssssssssss"
166 L"sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss"
167 L"sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss"
168 L"sssssssssssssssssssssssssssssssssssssssssssssssssnnnnnnnnnnn"
169 "\xfeba"
170 L"Sssssssssssssssssss"
171 "\xfeba"
172 L"iiiiiiiiiisssss";
173 text_out().DrawLogicText(device(), WideString(kText),
174 CFX_RectF(3, 3, 2048, 10));
175 EXPECT_STREQ(GetLargeTextBlobChecksum(), GetBitmapChecksum().c_str());
176 }
177 #endif // !BUILDFLAG(IS_WIN)
178