OLD | NEW |
| (Empty) |
1 // Copyright 2014 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 "xfa/src/fee/fde_txtedtbuf.h" | |
8 | |
9 #include <algorithm> | |
10 | |
11 #include "xfa/src/fee/ifde_txtedtbuf.h" | |
12 #include "xfa/src/fee/ifde_txtedtengine.h" | |
13 | |
14 #define FDE_DEFCHUNKCOUNT 2 | |
15 #define FDE_TXTEDT_FORMATBLOCK_BGN 0xFFF9 | |
16 #define FDE_TXTEDT_FORMATBLOCK_END 0xFFFB | |
17 #define FDE_TXTEDT_ZEROWIDTHSPACE 0x200B | |
18 | |
19 CFDE_TxtEdtBufIter::CFDE_TxtEdtBufIter(CFDE_TxtEdtBuf* pBuf, FX_WCHAR wcAlias) | |
20 : m_pBuf(pBuf), | |
21 m_nCurChunk(0), | |
22 m_nCurIndex(0), | |
23 m_nIndex(0), | |
24 m_Alias(wcAlias) { | |
25 FXSYS_assert(m_pBuf); | |
26 } | |
27 CFDE_TxtEdtBufIter::~CFDE_TxtEdtBufIter() {} | |
28 void CFDE_TxtEdtBufIter::Release() { | |
29 delete this; | |
30 } | |
31 FX_BOOL CFDE_TxtEdtBufIter::Next(FX_BOOL bPrev) { | |
32 if (bPrev) { | |
33 if (m_nIndex == 0) { | |
34 return FALSE; | |
35 } | |
36 FXSYS_assert(m_nCurChunk < m_pBuf->m_Chunks.GetSize()); | |
37 CFDE_TxtEdtBuf::FDE_LPCHUNKHEADER lpChunk = NULL; | |
38 if (m_nCurIndex > 0) { | |
39 m_nCurIndex--; | |
40 } else { | |
41 while (m_nCurChunk > 0) { | |
42 --m_nCurChunk; | |
43 lpChunk = | |
44 (CFDE_TxtEdtBuf::FDE_LPCHUNKHEADER)m_pBuf->m_Chunks[m_nCurChunk]; | |
45 if (lpChunk->nUsed > 0) { | |
46 m_nCurIndex = lpChunk->nUsed - 1; | |
47 break; | |
48 } | |
49 } | |
50 } | |
51 FXSYS_assert(m_nCurChunk >= 0); | |
52 m_nIndex--; | |
53 return TRUE; | |
54 } else { | |
55 if (m_nIndex >= (m_pBuf->m_nTotal - 1)) { | |
56 return FALSE; | |
57 } | |
58 FXSYS_assert(m_nCurChunk < m_pBuf->m_Chunks.GetSize()); | |
59 CFDE_TxtEdtBuf::FDE_LPCHUNKHEADER lpChunk = | |
60 (CFDE_TxtEdtBuf::FDE_LPCHUNKHEADER)m_pBuf->m_Chunks[m_nCurChunk]; | |
61 if (lpChunk->nUsed != (m_nCurIndex + 1)) { | |
62 m_nCurIndex++; | |
63 } else { | |
64 int32_t nEnd = m_pBuf->m_Chunks.GetSize() - 1; | |
65 while (m_nCurChunk < nEnd) { | |
66 m_nCurChunk++; | |
67 CFDE_TxtEdtBuf::FDE_LPCHUNKHEADER lpChunkTemp = | |
68 (CFDE_TxtEdtBuf::FDE_LPCHUNKHEADER)m_pBuf->m_Chunks[m_nCurChunk]; | |
69 if (lpChunkTemp->nUsed > 0) { | |
70 m_nCurIndex = 0; | |
71 break; | |
72 } | |
73 } | |
74 } | |
75 m_nIndex++; | |
76 return TRUE; | |
77 } | |
78 } | |
79 void CFDE_TxtEdtBufIter::SetAt(int32_t nIndex) { | |
80 FXSYS_assert(nIndex >= 0 && nIndex < m_pBuf->m_nTotal); | |
81 CFDE_TxtEdtBuf::FDE_CHUNKPLACE cp; | |
82 m_pBuf->Index2CP(nIndex, cp); | |
83 m_nIndex = nIndex; | |
84 m_nCurChunk = cp.nChunkIndex; | |
85 m_nCurIndex = cp.nCharIndex; | |
86 } | |
87 int32_t CFDE_TxtEdtBufIter::GetAt() const { | |
88 return m_nIndex; | |
89 } | |
90 FX_WCHAR CFDE_TxtEdtBufIter::GetChar() { | |
91 FXSYS_assert(m_nIndex >= 0 && m_nIndex < m_pBuf->m_nTotal); | |
92 if (m_Alias == 0 || m_nIndex == (m_pBuf->m_nTotal - 1)) { | |
93 return ((CFDE_TxtEdtBuf::FDE_LPCHUNKHEADER)m_pBuf->m_Chunks[m_nCurChunk]) | |
94 ->wChars[m_nCurIndex]; | |
95 } | |
96 return m_Alias; | |
97 } | |
98 FX_BOOL CFDE_TxtEdtBufIter::IsEOF(FX_BOOL bTail) const { | |
99 return bTail ? m_nIndex == (m_pBuf->GetTextLength() - 2) : m_nIndex == 0; | |
100 } | |
101 IFX_CharIter* CFDE_TxtEdtBufIter::Clone() { | |
102 CFDE_TxtEdtBufIter* pIter = new CFDE_TxtEdtBufIter(m_pBuf); | |
103 pIter->m_nCurChunk = m_nCurChunk; | |
104 pIter->m_nCurIndex = m_nCurIndex; | |
105 pIter->m_nIndex = m_nIndex; | |
106 pIter->m_Alias = m_Alias; | |
107 return pIter; | |
108 } | |
109 CFDE_TxtEdtBuf::CFDE_TxtEdtBuf(int32_t nDefChunkSize) | |
110 : m_nChunkSize(nDefChunkSize), | |
111 m_nTotal(0), | |
112 m_bChanged(FALSE), | |
113 m_pAllocator(NULL) { | |
114 FXSYS_assert(m_nChunkSize); | |
115 ResetChunkBuffer(FDE_DEFCHUNKCOUNT, m_nChunkSize); | |
116 } | |
117 void CFDE_TxtEdtBuf::Release() { | |
118 delete this; | |
119 } | |
120 CFDE_TxtEdtBuf::~CFDE_TxtEdtBuf() { | |
121 Clear(TRUE); | |
122 m_pAllocator->Release(); | |
123 m_Chunks.RemoveAll(); | |
124 } | |
125 FX_BOOL CFDE_TxtEdtBuf::SetChunkSize(int32_t nChunkSize) { | |
126 FXSYS_assert(nChunkSize); | |
127 ResetChunkBuffer(FDE_DEFCHUNKCOUNT, nChunkSize); | |
128 return TRUE; | |
129 } | |
130 int32_t CFDE_TxtEdtBuf::GetChunkSize() const { | |
131 return m_nChunkSize; | |
132 } | |
133 int32_t CFDE_TxtEdtBuf::GetTextLength() const { | |
134 return m_nTotal; | |
135 } | |
136 void CFDE_TxtEdtBuf::SetText(const CFX_WideString& wsText) { | |
137 FXSYS_assert(!wsText.IsEmpty()); | |
138 Clear(FALSE); | |
139 int32_t nTextLength = wsText.GetLength(); | |
140 int32_t nNeedCount = | |
141 ((nTextLength - 1) / m_nChunkSize + 1) - m_Chunks.GetSize(); | |
142 int32_t i = 0; | |
143 for (i = 0; i < nNeedCount; i++) { | |
144 FDE_LPCHUNKHEADER lpChunk = (FDE_LPCHUNKHEADER)m_pAllocator->Alloc( | |
145 sizeof(FDE_CHUNKHEADER) + (m_nChunkSize - 1) * sizeof(FX_WCHAR)); | |
146 lpChunk->nUsed = 0; | |
147 m_Chunks.Add(lpChunk); | |
148 } | |
149 int32_t nTotalCount = m_Chunks.GetSize(); | |
150 const FX_WCHAR* lpSrcBuf = wsText.c_str(); | |
151 int32_t nLeave = nTextLength; | |
152 int32_t nCopyedLength = m_nChunkSize; | |
153 for (i = 0; i < nTotalCount && nLeave > 0; i++) { | |
154 if (nLeave < nCopyedLength) { | |
155 nCopyedLength = nLeave; | |
156 } | |
157 FDE_LPCHUNKHEADER lpChunk = (FDE_LPCHUNKHEADER)m_Chunks[i]; | |
158 FXSYS_memcpy(lpChunk->wChars, lpSrcBuf, nCopyedLength * sizeof(FX_WCHAR)); | |
159 nLeave -= nCopyedLength; | |
160 lpSrcBuf += nCopyedLength; | |
161 lpChunk->nUsed = nCopyedLength; | |
162 } | |
163 m_nTotal = nTextLength; | |
164 m_bChanged = TRUE; | |
165 } | |
166 void CFDE_TxtEdtBuf::GetText(CFX_WideString& wsText) const { | |
167 GetRange(wsText, 0, m_nTotal); | |
168 } | |
169 FX_WCHAR CFDE_TxtEdtBuf::GetCharByIndex(int32_t nIndex) const { | |
170 FXSYS_assert(nIndex >= 0 && nIndex < GetTextLength()); | |
171 FDE_LPCHUNKHEADER pChunkHeader = NULL; | |
172 int32_t nTotal = 0; | |
173 int32_t nCount = m_Chunks.GetSize(); | |
174 int32_t i = 0; | |
175 for (i = 0; i < nCount; i++) { | |
176 pChunkHeader = (FDE_LPCHUNKHEADER)m_Chunks[i]; | |
177 nTotal += pChunkHeader->nUsed; | |
178 if (nTotal > nIndex) { | |
179 break; | |
180 } | |
181 } | |
182 FXSYS_assert(pChunkHeader); | |
183 return pChunkHeader->wChars[pChunkHeader->nUsed - (nTotal - nIndex)]; | |
184 } | |
185 void CFDE_TxtEdtBuf::GetRange(CFX_WideString& wsText, | |
186 int32_t nBegin, | |
187 int32_t nLength) const { | |
188 FDE_CHUNKPLACE cp; | |
189 Index2CP(nBegin, cp); | |
190 int32_t nLeave = nLength; | |
191 int32_t nCount = m_Chunks.GetSize(); | |
192 FX_WCHAR* lpDstBuf = wsText.GetBuffer(nLength); | |
193 int32_t nChunkIndex = cp.nChunkIndex; | |
194 FDE_LPCHUNKHEADER lpChunkHeader = (FDE_LPCHUNKHEADER)m_Chunks[nChunkIndex]; | |
195 int32_t nCopyLength = lpChunkHeader->nUsed - cp.nCharIndex; | |
196 FX_WCHAR* lpSrcBuf = lpChunkHeader->wChars + cp.nCharIndex; | |
197 while (nLeave > 0) { | |
198 if (nLeave <= nCopyLength) { | |
199 nCopyLength = nLeave; | |
200 } | |
201 FXSYS_memcpy(lpDstBuf, lpSrcBuf, nCopyLength * sizeof(FX_WCHAR)); | |
202 nChunkIndex++; | |
203 if (nChunkIndex >= nCount) { | |
204 break; | |
205 } | |
206 lpChunkHeader = (FDE_LPCHUNKHEADER)m_Chunks[nChunkIndex]; | |
207 lpSrcBuf = lpChunkHeader->wChars; | |
208 nLeave -= nCopyLength; | |
209 lpDstBuf += nCopyLength; | |
210 nCopyLength = lpChunkHeader->nUsed; | |
211 } | |
212 wsText.ReleaseBuffer(); | |
213 } | |
214 void CFDE_TxtEdtBuf::Insert(int32_t nPos, | |
215 const FX_WCHAR* lpText, | |
216 int32_t nLength) { | |
217 FXSYS_assert(nPos >= 0 && nPos <= m_nTotal); | |
218 FDE_CHUNKPLACE cp; | |
219 Index2CP(nPos, cp); | |
220 int32_t nLengthTemp = nLength; | |
221 if (cp.nCharIndex != 0) { | |
222 FDE_LPCHUNKHEADER lpNewChunk = (FDE_LPCHUNKHEADER)m_pAllocator->Alloc( | |
223 sizeof(FDE_CHUNKHEADER) + (m_nChunkSize - 1) * sizeof(FX_WCHAR)); | |
224 FDE_LPCHUNKHEADER lpChunk = (FDE_LPCHUNKHEADER)m_Chunks[cp.nChunkIndex]; | |
225 int32_t nCopy = lpChunk->nUsed - cp.nCharIndex; | |
226 FXSYS_memcpy(lpNewChunk->wChars, lpChunk->wChars + cp.nCharIndex, | |
227 nCopy * sizeof(FX_WCHAR)); | |
228 lpChunk->nUsed -= nCopy; | |
229 cp.nChunkIndex++; | |
230 m_Chunks.InsertAt(cp.nChunkIndex, lpNewChunk); | |
231 lpNewChunk->nUsed = nCopy; | |
232 cp.nCharIndex = 0; | |
233 } | |
234 if (cp.nChunkIndex != 0) { | |
235 FDE_LPCHUNKHEADER lpChunk = (FDE_LPCHUNKHEADER)m_Chunks[cp.nChunkIndex - 1]; | |
236 if (lpChunk->nUsed != m_nChunkSize) { | |
237 cp.nChunkIndex--; | |
238 int32_t nFree = m_nChunkSize - lpChunk->nUsed; | |
239 int32_t nCopy = std::min(nLengthTemp, nFree); | |
240 FXSYS_memcpy(lpChunk->wChars + lpChunk->nUsed, lpText, | |
241 nCopy * sizeof(FX_WCHAR)); | |
242 lpText += nCopy; | |
243 nLengthTemp -= nCopy; | |
244 lpChunk->nUsed += nCopy; | |
245 cp.nChunkIndex++; | |
246 } | |
247 } | |
248 while (nLengthTemp > 0) { | |
249 FDE_LPCHUNKHEADER lpChunk = (FDE_LPCHUNKHEADER)m_pAllocator->Alloc( | |
250 sizeof(FDE_CHUNKHEADER) + (m_nChunkSize - 1) * sizeof(FX_WCHAR)); | |
251 FXSYS_assert(lpChunk); | |
252 int32_t nCopy = std::min(nLengthTemp, m_nChunkSize); | |
253 FXSYS_memcpy(lpChunk->wChars, lpText, nCopy * sizeof(FX_WCHAR)); | |
254 lpText += nCopy; | |
255 nLengthTemp -= nCopy; | |
256 lpChunk->nUsed = nCopy; | |
257 m_Chunks.InsertAt(cp.nChunkIndex, lpChunk); | |
258 cp.nChunkIndex++; | |
259 } | |
260 m_nTotal += nLength; | |
261 m_bChanged = TRUE; | |
262 } | |
263 void CFDE_TxtEdtBuf::Delete(int32_t nIndex, int32_t nLength) { | |
264 FXSYS_assert(nLength > 0 && nIndex >= 0 && nIndex + nLength <= m_nTotal); | |
265 FDE_CHUNKPLACE cpEnd; | |
266 Index2CP(nIndex + nLength - 1, cpEnd); | |
267 m_nTotal -= nLength; | |
268 FDE_LPCHUNKHEADER lpChunk = (FDE_LPCHUNKHEADER)m_Chunks[cpEnd.nChunkIndex]; | |
269 int32_t nFirstPart = cpEnd.nCharIndex + 1; | |
270 int32_t nMovePart = lpChunk->nUsed - nFirstPart; | |
271 if (nMovePart != 0) { | |
272 int32_t nDelete = std::min(nFirstPart, nLength); | |
273 FXSYS_memmove(lpChunk->wChars + nFirstPart - nDelete, | |
274 lpChunk->wChars + nFirstPart, nMovePart * sizeof(FX_WCHAR)); | |
275 lpChunk->nUsed -= nDelete; | |
276 nLength -= nDelete; | |
277 cpEnd.nChunkIndex--; | |
278 } | |
279 while (nLength > 0) { | |
280 lpChunk = (FDE_LPCHUNKHEADER)m_Chunks[cpEnd.nChunkIndex]; | |
281 int32_t nDeleted = std::min(lpChunk->nUsed, nLength); | |
282 lpChunk->nUsed -= nDeleted; | |
283 if (lpChunk->nUsed == 0) { | |
284 m_pAllocator->Free(lpChunk); | |
285 m_Chunks.RemoveAt(cpEnd.nChunkIndex); | |
286 lpChunk = NULL; | |
287 } | |
288 nLength -= nDeleted; | |
289 cpEnd.nChunkIndex--; | |
290 } | |
291 m_bChanged = TRUE; | |
292 } | |
293 void CFDE_TxtEdtBuf::Clear(FX_BOOL bRelease) { | |
294 int32_t i = 0; | |
295 int32_t nCount = m_Chunks.GetSize(); | |
296 if (bRelease) { | |
297 while (i < nCount) { | |
298 m_pAllocator->Free(m_Chunks[i++]); | |
299 } | |
300 m_Chunks.RemoveAll(); | |
301 } else { | |
302 while (i < nCount) { | |
303 ((FDE_LPCHUNKHEADER)m_Chunks[i++])->nUsed = 0; | |
304 } | |
305 } | |
306 m_nTotal = 0; | |
307 m_bChanged = TRUE; | |
308 } | |
309 FX_BOOL CFDE_TxtEdtBuf::Optimize(IFX_Pause* pPause) { | |
310 if (m_bChanged == FALSE) { | |
311 return TRUE; | |
312 } | |
313 if (m_nTotal == 0) { | |
314 return TRUE; | |
315 } | |
316 int32_t nCount = m_Chunks.GetSize(); | |
317 if (nCount == 0) { | |
318 return TRUE; | |
319 } | |
320 int32_t i = 0; | |
321 for (; i < nCount; i++) { | |
322 FDE_LPCHUNKHEADER lpChunk = (FDE_LPCHUNKHEADER)m_Chunks[i]; | |
323 if (lpChunk->nUsed == 0) { | |
324 m_pAllocator->Free(lpChunk); | |
325 m_Chunks.RemoveAt(i); | |
326 --i; | |
327 --nCount; | |
328 } | |
329 } | |
330 if (pPause != NULL && pPause->NeedToPauseNow()) { | |
331 return FALSE; | |
332 } | |
333 FDE_LPCHUNKHEADER lpPreChunk = (FDE_LPCHUNKHEADER)m_Chunks[0]; | |
334 FDE_LPCHUNKHEADER lpCurChunk = NULL; | |
335 for (i = 1; i < nCount; i++) { | |
336 lpCurChunk = (FDE_LPCHUNKHEADER)m_Chunks[i]; | |
337 if (lpPreChunk->nUsed + lpCurChunk->nUsed <= m_nChunkSize) { | |
338 FXSYS_memcpy(lpPreChunk->wChars + lpPreChunk->nUsed, lpCurChunk->wChars, | |
339 lpCurChunk->nUsed * sizeof(FX_WCHAR)); | |
340 lpPreChunk->nUsed += lpCurChunk->nUsed; | |
341 m_pAllocator->Free(lpCurChunk); | |
342 m_Chunks.RemoveAt(i); | |
343 --i; | |
344 --nCount; | |
345 } else { | |
346 lpPreChunk = lpCurChunk; | |
347 } | |
348 if (pPause != NULL && pPause->NeedToPauseNow()) { | |
349 return FALSE; | |
350 } | |
351 } | |
352 m_bChanged = FALSE; | |
353 return TRUE; | |
354 } | |
355 void CFDE_TxtEdtBuf::ResetChunkBuffer(int32_t nDefChunkCount, | |
356 int32_t nChunkSize) { | |
357 FXSYS_assert(nChunkSize); | |
358 FXSYS_assert(nDefChunkCount); | |
359 if (m_pAllocator) { | |
360 m_pAllocator->Release(); | |
361 m_pAllocator = NULL; | |
362 } | |
363 m_Chunks.RemoveAll(); | |
364 m_nChunkSize = nChunkSize; | |
365 int32_t nChunkLength = | |
366 sizeof(FDE_CHUNKHEADER) + (m_nChunkSize - 1) * sizeof(FX_WCHAR); | |
367 m_pAllocator = | |
368 FX_CreateAllocator(FX_ALLOCTYPE_Fixed, nDefChunkCount, nChunkLength); | |
369 FXSYS_assert(m_pAllocator); | |
370 FDE_LPCHUNKHEADER lpChunkHeader = | |
371 (FDE_LPCHUNKHEADER)m_pAllocator->Alloc(nChunkLength); | |
372 FXSYS_assert(lpChunkHeader); | |
373 lpChunkHeader->nUsed = 0; | |
374 m_Chunks.Add(lpChunkHeader); | |
375 m_nTotal = 0; | |
376 } | |
377 int32_t CFDE_TxtEdtBuf::CP2Index(const FDE_CHUNKPLACE& cp) const { | |
378 int32_t nTotal = cp.nCharIndex; | |
379 int32_t i = 0; | |
380 for (i = 0; i < cp.nChunkIndex; i++) { | |
381 nTotal += ((FDE_LPCHUNKHEADER)m_Chunks[i])->nUsed; | |
382 } | |
383 return nTotal; | |
384 } | |
385 void CFDE_TxtEdtBuf::Index2CP(int32_t nIndex, FDE_CHUNKPLACE& cp) const { | |
386 FXSYS_assert(nIndex <= GetTextLength()); | |
387 if (nIndex == m_nTotal) { | |
388 cp.nChunkIndex = m_Chunks.GetSize() - 1; | |
389 cp.nCharIndex = ((FDE_LPCHUNKHEADER)m_Chunks[cp.nChunkIndex])->nUsed; | |
390 return; | |
391 } | |
392 int32_t i = 0; | |
393 int32_t nTotal = 0; | |
394 int32_t nCount = m_Chunks.GetSize(); | |
395 for (; i < nCount; i++) { | |
396 nTotal += ((FDE_LPCHUNKHEADER)m_Chunks[i])->nUsed; | |
397 if (nTotal > nIndex) { | |
398 break; | |
399 } | |
400 } | |
401 cp.nChunkIndex = i; | |
402 cp.nCharIndex = ((FDE_LPCHUNKHEADER)m_Chunks[i])->nUsed - (nTotal - nIndex); | |
403 } | |
OLD | NEW |