// Copyright 2022 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "xfa/fde/cfde_textout.h" #include #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" #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(); ASSERT_TRUE(bitmap_->Create(bitmap_size.width, bitmap_size.height, FXDIB_Format::kArgb)); device_ = std::make_unique(); device_->Attach(bitmap_); font_ = LoadFont(); ASSERT_TRUE(font_); text_out_ = std::make_unique(); text_out_->SetFont(font_); text_out_->SetFontSize(12.0f); EXPECT_STREQ(GetEmptyBitmapChecksum(), GetBitmapChecksum().c_str()); } void TearDown() override { text_out_.reset(); font_.Reset(); device_.reset(); bitmap_.Reset(); } virtual RetainPtr 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_; } ByteString GetBitmapChecksum() { CRYPT_md5_context context = CRYPT_MD5Start(); for (int i = 0; i < bitmap_->GetHeight(); ++i) CRYPT_MD5Update(&context, bitmap_->GetScanline(i)); uint8_t digest[16]; CRYPT_MD5Finish(&context, digest); return ByteString(CryptToBase16(digest).c_str()); } private: RetainPtr bitmap_; std::unique_ptr device_; RetainPtr font_; std::unique_ptr text_out_; }; TEST_F(CFDETextOutTest, DrawLogicTextBasic) { text_out().DrawLogicText(device(), L"foo", CFX_RectF(0, 0, 2100, 100)); const char* checksum = []() { #if BUILDFLAG(IS_WIN) if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) return "76fd535f7d490d963598474494d0701e"; #endif return "b26f1c171fcdbf185823364185adacf0"; }(); EXPECT_STREQ(checksum, GetBitmapChecksum().c_str()); } TEST_F(CFDETextOutTest, DrawLogicTextEmptyRect) { text_out().DrawLogicText(device(), L"foo", CFX_RectF()); 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 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; } const char* GetLargeTextBlobChecksum() { if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) { return "cd357c6afbf17bb2ac48817df5d9eaad"; } return "268b71a8660b51e31c6bf30fc7ff1e08"; } }; TEST_F(CFDETextOutLargeBitmapTest, DrawLogicTextBug953881) { 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"iiiiisssss"; text_out().DrawLogicText(device(), WideString(kText), CFX_RectF(3, 3, 2048, 10)); EXPECT_STREQ(GetLargeTextBlobChecksum(), GetBitmapChecksum().c_str()); } TEST_F(CFDETextOutLargeBitmapTest, DrawLogicTextBug1342078) { 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)); EXPECT_STREQ(GetLargeTextBlobChecksum(), GetBitmapChecksum().c_str()); } #endif // !BUILDFLAG(IS_WIN)