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