blob: 653fdfffdeb7daa6f3a16036fe048fedcf2a0873 [file] [log] [blame]
// Copyright 2023 The PDFium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "core/fpdfdoc/cpdf_annotlist.h"
#include <stdint.h>
#include <initializer_list>
#include <memory>
#include "constants/annotation_common.h"
#include "core/fpdfapi/page/cpdf_page.h"
#include "core/fpdfapi/page/test_with_page_module.h"
#include "core/fpdfapi/parser/cpdf_array.h"
#include "core/fpdfapi/parser/cpdf_dictionary.h"
#include "core/fpdfapi/parser/cpdf_name.h"
#include "core/fpdfapi/parser/cpdf_string.h"
#include "core/fpdfapi/parser/cpdf_test_document.h"
#include "core/fpdfdoc/cpdf_annot.h"
#include "core/fxcrt/bytestring.h"
#include "core/fxcrt/retain_ptr.h"
#include "core/fxcrt/widestring.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
class CPDFAnnotListTest : public TestWithPageModule {
public:
void SetUp() override {
TestWithPageModule::SetUp();
document_ = std::make_unique<CPDF_TestDocument>();
document_->SetRoot(pdfium::MakeRetain<CPDF_Dictionary>());
page_ = pdfium::MakeRetain<CPDF_Page>(
document_.get(), pdfium::MakeRetain<CPDF_Dictionary>());
}
void TearDown() override {
page_.Reset();
document_.reset();
TestWithPageModule::TearDown();
}
protected:
void AddTextAnnotation(const ByteString& contents) {
RetainPtr<CPDF_Dictionary> annotation =
page_->GetOrCreateAnnotsArray()->AppendNew<CPDF_Dictionary>();
annotation->SetNewFor<CPDF_Name>(pdfium::annotation::kSubtype, "Text");
annotation->SetNewFor<CPDF_String>(pdfium::annotation::kContents, contents,
/*bHex=*/false);
}
std::unique_ptr<CPDF_TestDocument> document_;
RetainPtr<CPDF_Page> page_;
};
ByteString MakeByteString(std::initializer_list<uint8_t> bytes) {
return ByteString(std::data(bytes), std::size(bytes));
}
ByteString GetRawContents(const CPDF_Annot* annotation) {
return annotation->GetAnnotDict()->GetByteStringFor(
pdfium::annotation::kContents);
}
WideString GetDecodedContents(const CPDF_Annot* annotation) {
return annotation->GetAnnotDict()->GetUnicodeTextFor(
pdfium::annotation::kContents);
}
} // namespace
TEST_F(CPDFAnnotListTest, CreatePopupAnnotFromPdfEncoded) {
const ByteString kContents = MakeByteString({'A', 'a', 0xE4, 0xA0});
AddTextAnnotation(kContents);
CPDF_AnnotList list(page_);
ASSERT_EQ(2u, list.Count());
EXPECT_EQ(kContents, GetRawContents(list.GetAt(1)));
EXPECT_EQ(WideString::FromUTF8("Aaä€"), GetDecodedContents(list.GetAt(1)));
}
TEST_F(CPDFAnnotListTest, CreatePopupAnnotFromUnicode) {
const ByteString kContents =
MakeByteString({0xFE, 0xFF, 0x00, 'A', 0x00, 'a', 0x00, 0xE4, 0x20, 0xAC,
0xD8, 0x3C, 0xDF, 0xA8});
AddTextAnnotation(kContents);
CPDF_AnnotList list(page_);
ASSERT_EQ(2u, list.Count());
EXPECT_EQ(kContents, GetRawContents(list.GetAt(1)));
EXPECT_EQ(WideString::FromUTF8("Aaä€🎨"), GetDecodedContents(list.GetAt(1)));
}
TEST_F(CPDFAnnotListTest, CreatePopupAnnotFromEmptyPdfEncoded) {
AddTextAnnotation("");
CPDF_AnnotList list(page_);
EXPECT_EQ(1u, list.Count());
}
TEST_F(CPDFAnnotListTest, CreatePopupAnnotFromEmptyUnicode) {
const ByteString kContents = MakeByteString({0xFE, 0xFF});
AddTextAnnotation(kContents);
CPDF_AnnotList list(page_);
EXPECT_EQ(1u, list.Count());
}
TEST_F(CPDFAnnotListTest, CreatePopupAnnotFromEmptyUnicodedWithEscape) {
const ByteString kContents =
MakeByteString({0xFE, 0xFF, 0x00, 0x1B, 'j', 'a', 0x00, 0x1B});
AddTextAnnotation(kContents);
CPDF_AnnotList list(page_);
EXPECT_EQ(1u, list.Count());
}