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