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/fpdfdoc/csection.h" 8 9 #include <algorithm> 10 11 #include "core/fpdfdoc/cline.h" 12 #include "core/fpdfdoc/cpdf_variabletext.h" 13 #include "core/fpdfdoc/cpvt_wordinfo.h" 14 #include "third_party/base/ptr_util.h" 15 #include "third_party/base/stl_util.h" 16 17 CSection::CSection(CPDF_VariableText* pVT) : m_pVT(pVT) {} 18 19 CSection::~CSection() {} 20 21 void CSection::ResetAll() { 22 m_WordArray.clear(); 23 m_LineArray.clear(); 24 } 25 26 void CSection::ResetLinePlace() { 27 int32_t i = 0; 28 for (auto& pLine : m_LineArray) { 29 pLine->LinePlace = CPVT_WordPlace(SecPlace.nSecIndex, i, -1); 30 ++i; 31 } 32 } 33 34 CPVT_WordPlace CSection::AddWord(const CPVT_WordPlace& place, 35 const CPVT_WordInfo& wordinfo) { 36 int32_t nWordIndex = pdfium::clamp( 37 place.nWordIndex, 0, pdfium::CollectionSize<int32_t>(m_WordArray)); 38 m_WordArray.insert(m_WordArray.begin() + nWordIndex, 39 pdfium::MakeUnique<CPVT_WordInfo>(wordinfo)); 40 return place; 41 } 42 43 CPVT_WordPlace CSection::AddLine(const CPVT_LineInfo& lineinfo) { 44 m_LineArray.push_back(pdfium::MakeUnique<CLine>(lineinfo)); 45 return CPVT_WordPlace(SecPlace.nSecIndex, m_LineArray.size() - 1, -1); 46 } 47 48 CPVT_FloatRect CSection::Rearrange() { 49 if (m_pVT->GetCharArray() > 0) 50 return CTypeset(this).CharArray(); 51 return CTypeset(this).Typeset(); 52 } 53 54 CFX_SizeF CSection::GetSectionSize(float fFontSize) { 55 return CTypeset(this).GetEditSize(fFontSize); 56 } 57 58 CPVT_WordPlace CSection::GetBeginWordPlace() const { 59 if (m_LineArray.empty()) 60 return SecPlace; 61 return m_LineArray.front()->GetBeginWordPlace(); 62 } 63 64 CPVT_WordPlace CSection::GetEndWordPlace() const { 65 if (m_LineArray.empty()) 66 return SecPlace; 67 return m_LineArray.back()->GetEndWordPlace(); 68 } 69 70 CPVT_WordPlace CSection::GetPrevWordPlace(const CPVT_WordPlace& place) const { 71 if (place.nLineIndex < 0) 72 return GetBeginWordPlace(); 73 74 if (place.nLineIndex >= pdfium::CollectionSize<int32_t>(m_LineArray)) 75 return GetEndWordPlace(); 76 77 CLine* pLine = m_LineArray[place.nLineIndex].get(); 78 if (place.nWordIndex == pLine->m_LineInfo.nBeginWordIndex) 79 return CPVT_WordPlace(place.nSecIndex, place.nLineIndex, -1); 80 81 if (place.nWordIndex >= pLine->m_LineInfo.nBeginWordIndex) 82 return pLine->GetPrevWordPlace(place); 83 84 if (!pdfium::IndexInBounds(m_LineArray, place.nLineIndex - 1)) 85 return place; 86 87 return m_LineArray[place.nLineIndex - 1]->GetEndWordPlace(); 88 } 89 90 CPVT_WordPlace CSection::GetNextWordPlace(const CPVT_WordPlace& place) const { 91 if (place.nLineIndex < 0) 92 return GetBeginWordPlace(); 93 94 if (place.nLineIndex >= pdfium::CollectionSize<int32_t>(m_LineArray)) 95 return GetEndWordPlace(); 96 97 CLine* pLine = m_LineArray[place.nLineIndex].get(); 98 if (place.nWordIndex < pLine->m_LineInfo.nEndWordIndex) 99 return pLine->GetNextWordPlace(place); 100 101 if (!pdfium::IndexInBounds(m_LineArray, place.nLineIndex + 1)) 102 return place; 103 104 return m_LineArray[place.nLineIndex + 1]->GetBeginWordPlace(); 105 } 106 107 void CSection::UpdateWordPlace(CPVT_WordPlace& place) const { 108 int32_t nLeft = 0; 109 int32_t nRight = pdfium::CollectionSize<int32_t>(m_LineArray) - 1; 110 int32_t nMid = (nLeft + nRight) / 2; 111 while (nLeft <= nRight) { 112 CLine* pLine = m_LineArray[nMid].get(); 113 if (place.nWordIndex < pLine->m_LineInfo.nBeginWordIndex) { 114 nRight = nMid - 1; 115 nMid = (nLeft + nRight) / 2; 116 } else if (place.nWordIndex > pLine->m_LineInfo.nEndWordIndex) { 117 nLeft = nMid + 1; 118 nMid = (nLeft + nRight) / 2; 119 } else { 120 place.nLineIndex = nMid; 121 return; 122 } 123 } 124 } 125 126 CPVT_WordPlace CSection::SearchWordPlace(const CFX_PointF& point) const { 127 ASSERT(m_pVT); 128 CPVT_WordPlace place = GetBeginWordPlace(); 129 bool bUp = true; 130 bool bDown = true; 131 int32_t nLeft = 0; 132 int32_t nRight = pdfium::CollectionSize<int32_t>(m_LineArray) - 1; 133 int32_t nMid = pdfium::CollectionSize<int32_t>(m_LineArray) / 2; 134 while (nLeft <= nRight) { 135 CLine* pLine = m_LineArray[nMid].get(); 136 float fTop = pLine->m_LineInfo.fLineY - pLine->m_LineInfo.fLineAscent - 137 m_pVT->GetLineLeading(); 138 float fBottom = pLine->m_LineInfo.fLineY - pLine->m_LineInfo.fLineDescent; 139 if (IsFloatBigger(point.y, fTop)) 140 bUp = false; 141 if (IsFloatSmaller(point.y, fBottom)) 142 bDown = false; 143 if (IsFloatSmaller(point.y, fTop)) { 144 nRight = nMid - 1; 145 nMid = (nLeft + nRight) / 2; 146 continue; 147 } 148 if (IsFloatBigger(point.y, fBottom)) { 149 nLeft = nMid + 1; 150 nMid = (nLeft + nRight) / 2; 151 continue; 152 } 153 place = SearchWordPlace( 154 point.x, 155 CPVT_WordRange(pLine->GetNextWordPlace(pLine->GetBeginWordPlace()), 156 pLine->GetEndWordPlace())); 157 place.nLineIndex = nMid; 158 return place; 159 } 160 if (bUp) 161 place = GetBeginWordPlace(); 162 if (bDown) 163 place = GetEndWordPlace(); 164 return place; 165 } 166 167 CPVT_WordPlace CSection::SearchWordPlace( 168 float fx, 169 const CPVT_WordPlace& lineplace) const { 170 if (!pdfium::IndexInBounds(m_LineArray, lineplace.nLineIndex)) 171 return GetBeginWordPlace(); 172 173 CLine* pLine = m_LineArray[lineplace.nLineIndex].get(); 174 return SearchWordPlace( 175 fx - m_Rect.left, 176 CPVT_WordRange(pLine->GetNextWordPlace(pLine->GetBeginWordPlace()), 177 pLine->GetEndWordPlace())); 178 } 179 180 CPVT_WordPlace CSection::SearchWordPlace(float fx, 181 const CPVT_WordRange& range) const { 182 CPVT_WordPlace wordplace = range.BeginPos; 183 wordplace.nWordIndex = -1; 184 if (!m_pVT) { 185 return wordplace; 186 } 187 int32_t nLeft = range.BeginPos.nWordIndex; 188 int32_t nRight = range.EndPos.nWordIndex + 1; 189 int32_t nMid = (nLeft + nRight) / 2; 190 while (nLeft < nRight) { 191 if (nMid == nLeft) 192 break; 193 if (nMid == nRight) { 194 nMid--; 195 break; 196 } 197 if (!pdfium::IndexInBounds(m_WordArray, nMid)) 198 break; 199 CPVT_WordInfo* pWord = m_WordArray[nMid].get(); 200 if (fx > pWord->fWordX + m_pVT->GetWordWidth(*pWord) * VARIABLETEXT_HALF) { 201 nLeft = nMid; 202 nMid = (nLeft + nRight) / 2; 203 continue; 204 } 205 nRight = nMid; 206 nMid = (nLeft + nRight) / 2; 207 } 208 if (pdfium::IndexInBounds(m_WordArray, nMid)) { 209 CPVT_WordInfo* pWord = m_WordArray[nMid].get(); 210 if (fx > pWord->fWordX + m_pVT->GetWordWidth(*pWord) * VARIABLETEXT_HALF) 211 wordplace.nWordIndex = nMid; 212 } 213 return wordplace; 214 } 215 216 void CSection::ClearLeftWords(int32_t nWordIndex) { 217 for (int32_t i = nWordIndex; i >= 0; i--) { 218 if (pdfium::IndexInBounds(m_WordArray, i)) 219 m_WordArray.erase(m_WordArray.begin() + i); 220 } 221 } 222 223 void CSection::ClearRightWords(int32_t nWordIndex) { 224 int32_t sz = pdfium::CollectionSize<int32_t>(m_WordArray); 225 for (int32_t i = sz - 1; i > nWordIndex; i--) { 226 if (pdfium::IndexInBounds(m_WordArray, i)) 227 m_WordArray.erase(m_WordArray.begin() + i); 228 } 229 } 230 231 void CSection::ClearMidWords(int32_t nBeginIndex, int32_t nEndIndex) { 232 for (int32_t i = nEndIndex; i > nBeginIndex; i--) { 233 if (pdfium::IndexInBounds(m_WordArray, i)) 234 m_WordArray.erase(m_WordArray.begin() + i); 235 } 236 } 237 238 void CSection::ClearWords(const CPVT_WordRange& PlaceRange) { 239 CPVT_WordPlace SecBeginPos = GetBeginWordPlace(); 240 CPVT_WordPlace SecEndPos = GetEndWordPlace(); 241 if (PlaceRange.BeginPos >= SecBeginPos) { 242 if (PlaceRange.EndPos <= SecEndPos) { 243 ClearMidWords(PlaceRange.BeginPos.nWordIndex, 244 PlaceRange.EndPos.nWordIndex); 245 } else { 246 ClearRightWords(PlaceRange.BeginPos.nWordIndex); 247 } 248 } else if (PlaceRange.EndPos <= SecEndPos) { 249 ClearLeftWords(PlaceRange.EndPos.nWordIndex); 250 } else { 251 m_WordArray.clear(); 252 } 253 } 254 255 void CSection::ClearWord(const CPVT_WordPlace& place) { 256 if (pdfium::IndexInBounds(m_WordArray, place.nWordIndex)) 257 m_WordArray.erase(m_WordArray.begin() + place.nWordIndex); 258 } 259