1 // Copyright 2016 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 
7 #include "core/fpdfapi/page/cpdf_contentmarks.h"
8 
9 #include <algorithm>
10 #include <utility>
11 
12 #include "core/fpdfapi/parser/cpdf_dictionary.h"
13 #include "third_party/base/ptr_util.h"
14 
CPDF_ContentMarks()15 CPDF_ContentMarks::CPDF_ContentMarks() {}
16 
~CPDF_ContentMarks()17 CPDF_ContentMarks::~CPDF_ContentMarks() {}
18 
Clone()19 std::unique_ptr<CPDF_ContentMarks> CPDF_ContentMarks::Clone() {
20   auto result = pdfium::MakeUnique<CPDF_ContentMarks>();
21   if (m_pMarkData)
22     result->m_pMarkData = pdfium::MakeRetain<MarkData>(*m_pMarkData);
23   return result;
24 }
25 
CountItems() const26 size_t CPDF_ContentMarks::CountItems() const {
27   return m_pMarkData ? m_pMarkData->CountItems() : 0;
28 }
29 
ContainsItem(const CPDF_ContentMarkItem * pItem) const30 bool CPDF_ContentMarks::ContainsItem(const CPDF_ContentMarkItem* pItem) const {
31   return m_pMarkData && m_pMarkData->ContainsItem(pItem);
32 }
33 
GetItem(size_t index)34 CPDF_ContentMarkItem* CPDF_ContentMarks::GetItem(size_t index) {
35   return const_cast<CPDF_ContentMarkItem*>(
36       static_cast<const CPDF_ContentMarks*>(this)->GetItem(index));
37 }
38 
GetItem(size_t index) const39 const CPDF_ContentMarkItem* CPDF_ContentMarks::GetItem(size_t index) const {
40   ASSERT(index < CountItems());
41   return m_pMarkData->GetItem(index);
42 }
43 
GetMarkedContentID() const44 int CPDF_ContentMarks::GetMarkedContentID() const {
45   return m_pMarkData ? m_pMarkData->GetMarkedContentID() : -1;
46 }
47 
AddMark(ByteString name)48 void CPDF_ContentMarks::AddMark(ByteString name) {
49   EnsureMarkDataExists();
50   m_pMarkData->AddMark(std::move(name));
51 }
52 
AddMarkWithDirectDict(ByteString name,CPDF_Dictionary * pDict)53 void CPDF_ContentMarks::AddMarkWithDirectDict(ByteString name,
54                                               CPDF_Dictionary* pDict) {
55   EnsureMarkDataExists();
56   m_pMarkData->AddMarkWithDirectDict(std::move(name), pDict);
57 }
58 
AddMarkWithPropertiesHolder(const ByteString & name,CPDF_Dictionary * pDict,const ByteString & property_name)59 void CPDF_ContentMarks::AddMarkWithPropertiesHolder(
60     const ByteString& name,
61     CPDF_Dictionary* pDict,
62     const ByteString& property_name) {
63   EnsureMarkDataExists();
64   m_pMarkData->AddMarkWithPropertiesHolder(name, pDict, property_name);
65 }
66 
RemoveMark(CPDF_ContentMarkItem * pMarkItem)67 bool CPDF_ContentMarks::RemoveMark(CPDF_ContentMarkItem* pMarkItem) {
68   return m_pMarkData && m_pMarkData->RemoveMark(pMarkItem);
69 }
70 
EnsureMarkDataExists()71 void CPDF_ContentMarks::EnsureMarkDataExists() {
72   if (!m_pMarkData)
73     m_pMarkData = pdfium::MakeRetain<MarkData>();
74 }
75 
DeleteLastMark()76 void CPDF_ContentMarks::DeleteLastMark() {
77   if (!m_pMarkData)
78     return;
79 
80   m_pMarkData->DeleteLastMark();
81   if (CountItems() == 0)
82     m_pMarkData.Reset();
83 }
84 
FindFirstDifference(const CPDF_ContentMarks * other) const85 size_t CPDF_ContentMarks::FindFirstDifference(
86     const CPDF_ContentMarks* other) const {
87   if (m_pMarkData == other->m_pMarkData)
88     return CountItems();
89 
90   size_t min_len = std::min(CountItems(), other->CountItems());
91 
92   for (size_t i = 0; i < min_len; ++i) {
93     if (GetItem(i) != other->GetItem(i))
94       return i;
95   }
96   return min_len;
97 }
98 
MarkData()99 CPDF_ContentMarks::MarkData::MarkData() {}
100 
MarkData(const MarkData & src)101 CPDF_ContentMarks::MarkData::MarkData(const MarkData& src)
102     : m_Marks(src.m_Marks) {}
103 
~MarkData()104 CPDF_ContentMarks::MarkData::~MarkData() {}
105 
CountItems() const106 size_t CPDF_ContentMarks::MarkData::CountItems() const {
107   return m_Marks.size();
108 }
109 
ContainsItem(const CPDF_ContentMarkItem * pItem) const110 bool CPDF_ContentMarks::MarkData::ContainsItem(
111     const CPDF_ContentMarkItem* pItem) const {
112   for (const auto pMark : m_Marks) {
113     if (pMark == pItem)
114       return true;
115   }
116   return false;
117 }
118 
GetItem(size_t index)119 CPDF_ContentMarkItem* CPDF_ContentMarks::MarkData::GetItem(size_t index) {
120   return m_Marks[index].Get();
121 }
122 
GetItem(size_t index) const123 const CPDF_ContentMarkItem* CPDF_ContentMarks::MarkData::GetItem(
124     size_t index) const {
125   return m_Marks[index].Get();
126 }
127 
GetMarkedContentID() const128 int CPDF_ContentMarks::MarkData::GetMarkedContentID() const {
129   for (const auto pMark : m_Marks) {
130     const CPDF_Dictionary* pDict = pMark->GetParam();
131     if (pDict && pDict->KeyExist("MCID"))
132       return pDict->GetIntegerFor("MCID");
133   }
134   return -1;
135 }
136 
AddMark(ByteString name)137 void CPDF_ContentMarks::MarkData::AddMark(ByteString name) {
138   auto pItem = pdfium::MakeRetain<CPDF_ContentMarkItem>(std::move(name));
139   m_Marks.push_back(pItem);
140 }
141 
AddMarkWithDirectDict(ByteString name,CPDF_Dictionary * pDict)142 void CPDF_ContentMarks::MarkData::AddMarkWithDirectDict(
143     ByteString name,
144     CPDF_Dictionary* pDict) {
145   auto pItem = pdfium::MakeRetain<CPDF_ContentMarkItem>(std::move(name));
146   pItem->SetDirectDict(ToDictionary(pDict->Clone()));
147   m_Marks.push_back(pItem);
148 }
149 
AddMarkWithPropertiesHolder(const ByteString & name,CPDF_Dictionary * pDict,const ByteString & property_name)150 void CPDF_ContentMarks::MarkData::AddMarkWithPropertiesHolder(
151     const ByteString& name,
152     CPDF_Dictionary* pDict,
153     const ByteString& property_name) {
154   auto pItem = pdfium::MakeRetain<CPDF_ContentMarkItem>(name);
155   pItem->SetPropertiesHolder(pDict, property_name);
156   m_Marks.push_back(pItem);
157 }
158 
RemoveMark(CPDF_ContentMarkItem * pMarkItem)159 bool CPDF_ContentMarks::MarkData::RemoveMark(CPDF_ContentMarkItem* pMarkItem) {
160   for (auto it = m_Marks.begin(); it != m_Marks.end(); ++it) {
161     if (*it == pMarkItem) {
162       m_Marks.erase(it);
163       return true;
164     }
165   }
166   return false;
167 }
168 
DeleteLastMark()169 void CPDF_ContentMarks::MarkData::DeleteLastMark() {
170   if (!m_Marks.empty())
171     m_Marks.pop_back();
172 }
173