Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
cpdf_pagelabel_unittest.cpp
Go to the documentation of this file.
1// Copyright 2024 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 "core/fpdfdoc/cpdf_pagelabel.h"
6
7#include <memory>
8#include <optional>
9#include <utility>
10
11#include "core/fpdfapi/page/test_with_page_module.h"
12#include "core/fpdfapi/parser/cpdf_array.h"
13#include "core/fpdfapi/parser/cpdf_dictionary.h"
14#include "core/fpdfapi/parser/cpdf_name.h"
15#include "core/fpdfapi/parser/cpdf_number.h"
16#include "core/fpdfapi/parser/cpdf_string.h"
17#include "core/fpdfapi/parser/cpdf_test_document.h"
18#include "core/fxcrt/retain_ptr.h"
19#include "testing/gmock/include/gmock/gmock.h"
20#include "testing/gtest/include/gtest/gtest.h"
21
22using testing::Eq;
23using testing::Optional;
24
25namespace {
26
27struct NumValue {
28 const char* style;
29 const char* prefix;
30 std::optional<int> starting_number;
31};
32
33void AddNumKeyValue(CPDF_Array* nums, int key, const NumValue& value) {
34 nums->AppendNew<CPDF_Number>(key);
35 auto page_label_dict = nums->AppendNew<CPDF_Dictionary>();
36 page_label_dict->SetNewFor<CPDF_Name>("Type", "PageLabel");
37 if (value.style) {
38 page_label_dict->SetNewFor<CPDF_Name>("S", value.style);
39 }
40 if (value.prefix) {
41 page_label_dict->SetNewFor<CPDF_String>("P", value.prefix);
42 }
43 if (value.starting_number.has_value()) {
44 page_label_dict->SetNewFor<CPDF_Number>("St",
45 value.starting_number.value());
46 }
47}
48
49void AddLimitsArray(CPDF_Dictionary* node, int least, int greatest) {
50 auto limits = node->SetNewFor<CPDF_Array>("Limits");
51 limits->AppendNew<CPDF_Number>(least);
52 limits->AppendNew<CPDF_Number>(greatest);
53}
54
55// Set up a number tree with 3 levels and 5 nodes per diagram below. The number
56// tree is intended for use as the /PageLabels entry in a Catalog. The keys in
57// the leaf nodes are page indices, and the values are page label dictionaries.
58// See ISO 32000-1:2008 spec, table 159.
59//
60// The values are in the format: |S,P,St|
61//
62// S: Style (name)
63// P: Prefix (string)
64// St: Starting number (integer) Must be >= 1 if specified.
65//
66// All 3 fields are optional.
67//
68// [page_labels_root]
69// |
70// |
71// |
72// [kid1]
73// |
74// +------------+
75// | |
76// [grand_kid2] [grand_kid3]
77// | {8000: |,"x",|}
78// |
79// +--------------------+
80// | |
81// [great_grand_kid4] [great_grand_kid5]
82// {0: |"R",,|} {3000: |"r",,|}
83// {100: |"A","abc",5|} {5000: |"a",,|}
84// {900: |"D",,999|}
85//
86void FillPageLabelsTreeDict(CPDF_Dictionary* page_labels_root) {
87 constexpr char kKids[] = "Kids";
88 constexpr char kNums[] = "Nums";
89
90 auto page_labels_root_kids = page_labels_root->SetNewFor<CPDF_Array>(kKids);
91 auto kid1 = page_labels_root_kids->AppendNew<CPDF_Dictionary>();
92
93 AddLimitsArray(kid1.Get(), 0, 8000);
94 auto kids1_kids = kid1->SetNewFor<CPDF_Array>(kKids);
95 auto grand_kid2 = kids1_kids->AppendNew<CPDF_Dictionary>();
96 auto grand_kid3 = kids1_kids->AppendNew<CPDF_Dictionary>();
97
98 AddLimitsArray(grand_kid2.Get(), 0, 5000);
99 auto grand_kid2_kids = grand_kid2->SetNewFor<CPDF_Array>(kKids);
100 auto great_grand_kid4 = grand_kid2_kids->AppendNew<CPDF_Dictionary>();
101 auto great_grand_kid5 = grand_kid2_kids->AppendNew<CPDF_Dictionary>();
102
103 AddLimitsArray(grand_kid3.Get(), 8000, 8000);
104 auto nums = grand_kid3->SetNewFor<CPDF_Array>(kNums);
105 AddNumKeyValue(
106 nums.Get(), 8000,
107 {.style = nullptr, .prefix = "x", .starting_number = std::nullopt});
108
109 AddLimitsArray(great_grand_kid4.Get(), 0, 900);
110 nums = great_grand_kid4->SetNewFor<CPDF_Array>(kNums);
111 AddNumKeyValue(
112 nums.Get(), 0,
113 {.style = "R", .prefix = nullptr, .starting_number = std::nullopt});
114 AddNumKeyValue(nums.Get(), 100,
115 {.style = "A", .prefix = "abc", .starting_number = 5});
116 AddNumKeyValue(nums.Get(), 900,
117 {.style = "D", .prefix = nullptr, .starting_number = 999});
118
119 AddLimitsArray(great_grand_kid5.Get(), 3000, 5000);
120 nums = great_grand_kid5->SetNewFor<CPDF_Array>(kNums);
121 AddNumKeyValue(
122 nums.Get(), 3000,
123 {.style = "r", .prefix = nullptr, .starting_number = std::nullopt});
124 AddNumKeyValue(
125 nums.Get(), 5000,
126 {.style = "a", .prefix = nullptr, .starting_number = std::nullopt});
127}
128
129} // namespace
130
132 public:
133 PageLabelTest() = default;
135
138
139 auto root_dict = pdfium::MakeRetain<CPDF_Dictionary>();
140 root_dict->SetNewFor<CPDF_Dictionary>("Pages");
141 auto page_labels_dict = root_dict->SetNewFor<CPDF_Dictionary>("PageLabels");
142 FillPageLabelsTreeDict(page_labels_dict.Get());
143
144 doc_ = std::make_unique<CPDF_TestDocument>();
145 doc_->SetRoot(std::move(root_dict));
146 for (int page_index = 0; page_index < 10001; ++page_index) {
147 ASSERT_TRUE(doc_->CreateNewPage(page_index));
148 }
149
150 page_label_ = std::make_unique<CPDF_PageLabel>(doc_.get());
151 }
152
154 page_label_.reset();
155 doc_.reset();
156
158 }
159
160 const CPDF_PageLabel* page_label() const { return page_label_.get(); }
161
162 private:
163 std::unique_ptr<CPDF_TestDocument> doc_;
164 std::unique_ptr<CPDF_PageLabel> page_label_;
165};
166
168 EXPECT_THAT(page_label()->GetLabel(-1), Eq(std::nullopt));
169 EXPECT_THAT(page_label()->GetLabel(0), Optional(WideString(L"I")));
170 EXPECT_THAT(page_label()->GetLabel(1), Optional(WideString(L"II")));
171 EXPECT_THAT(page_label()->GetLabel(37), Optional(WideString(L"XXXVIII")));
172 EXPECT_THAT(page_label()->GetLabel(99), Optional(WideString(L"C")));
173 EXPECT_THAT(page_label()->GetLabel(100), Optional(WideString(L"abcE")));
174 EXPECT_THAT(page_label()->GetLabel(101), Optional(WideString(L"abcF")));
175 EXPECT_THAT(page_label()->GetLabel(525),
176 Optional(WideString(L"abcNNNNNNNNNNNNNNNNN")));
177 EXPECT_THAT(page_label()->GetLabel(899),
178 Optional(WideString(L"abcXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")));
179 EXPECT_THAT(page_label()->GetLabel(900), Optional(WideString(L"999")));
180 EXPECT_THAT(page_label()->GetLabel(901), Optional(WideString(L"1000")));
181 EXPECT_THAT(page_label()->GetLabel(1234), Optional(WideString(L"1333")));
182 EXPECT_THAT(page_label()->GetLabel(2999), Optional(WideString(L"3098")));
183 EXPECT_THAT(page_label()->GetLabel(3000), Optional(WideString(L"i")));
184 EXPECT_THAT(page_label()->GetLabel(3001), Optional(WideString(L"ii")));
185 EXPECT_THAT(page_label()->GetLabel(3579), Optional(WideString(L"dlxxx")));
186 EXPECT_THAT(page_label()->GetLabel(4999), Optional(WideString(L"mm")));
187 EXPECT_THAT(page_label()->GetLabel(5000), Optional(WideString(L"a")));
188 EXPECT_THAT(page_label()->GetLabel(5001), Optional(WideString(L"b")));
189 EXPECT_THAT(page_label()->GetLabel(7654),
190 Optional(WideString(
191 L"ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
192 L"cccccccccccccccccccccccccccccccccccccccccccc")));
193 EXPECT_THAT(
194 page_label()->GetLabel(7999),
195 Optional(WideString(
196 L"jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj"
197 L"jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj")));
198 EXPECT_THAT(page_label()->GetLabel(8000), Optional(WideString(L"x")));
199 EXPECT_THAT(page_label()->GetLabel(8001), Optional(WideString(L"x")));
200 EXPECT_THAT(page_label()->GetLabel(10000), Optional(WideString(L"x")));
201 EXPECT_THAT(page_label()->GetLabel(10001), Eq(std::nullopt));
202}
203
205 for (int i = 0; i < 10001; ++i) {
206 page_label()->GetLabel(i);
207 }
208}
std::vector< RetainPtr< CPDF_Object > >::const_iterator const_iterator
Definition cpdf_array.h:29
std::map< ByteString, RetainPtr< CPDF_Object >, std::less<> > DictMap
const CPDF_PageLabel * page_label() const
PageLabelTest()=default
~PageLabelTest() override=default
WideString(const wchar_t *ptr)
TEST_F(PageLabelTest, GetLabel)
fxcrt::WideString WideString
Definition widestring.h:207