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/foxitlib.h"
8#include "xfa/src/fee/include/ifde_txtedtbuf.h"
9#include "xfa/src/fee/include/ifde_txtedtengine.h"
10#include "xfa/src/fee/include/fx_wordbreak.h"
11#include "fde_txtedtparag.h"
12#include "fde_txtedtengine.h"
13#include "fde_txtedtbuf.h"
14CFDE_TxtEdtParag::CFDE_TxtEdtParag(CFDE_TxtEdtEngine* pEngine)
15    : m_nCharStart(0),
16      m_nCharCount(0),
17      m_nLineCount(0),
18      m_lpData(NULL),
19      m_pEngine(pEngine) {
20  FXSYS_assert(m_pEngine);
21}
22CFDE_TxtEdtParag::~CFDE_TxtEdtParag() {
23  if (m_lpData != NULL) {
24    FX_Free(m_lpData);
25  }
26}
27void CFDE_TxtEdtParag::LoadParag() {
28  if (m_lpData != NULL) {
29    ((int32_t*)m_lpData)[0]++;
30    return;
31  }
32  IFX_TxtBreak* pTxtBreak = m_pEngine->GetTextBreak();
33  IFDE_TxtEdtBuf* pTxtBuf = m_pEngine->GetTextBuf();
34  const FDE_TXTEDTPARAMS* pParam = m_pEngine->GetEditParams();
35  FX_WCHAR wcAlias = 0;
36  if (pParam->dwMode & FDE_TEXTEDITMODE_Password) {
37    wcAlias = m_pEngine->GetAliasChar();
38  }
39  IFX_CharIter* pIter =
40      new CFDE_TxtEdtBufIter((CFDE_TxtEdtBuf*)pTxtBuf, wcAlias);
41  pIter->SetAt(m_nCharStart);
42  int32_t nEndIndex = m_nCharStart + m_nCharCount;
43  CFX_ArrayTemplate<int32_t> LineBaseArr;
44  FX_BOOL bReload = FALSE;
45  FX_DWORD dwBreakStatus = FX_TXTBREAK_None;
46  do {
47    if (bReload) {
48      dwBreakStatus = pTxtBreak->EndBreak(FX_TXTBREAK_ParagraphBreak);
49    } else {
50      FX_WCHAR wAppend = pIter->GetChar();
51      dwBreakStatus = pTxtBreak->AppendChar(wAppend);
52    }
53    if (pIter->GetAt() + 1 == nEndIndex &&
54        dwBreakStatus < FX_TXTBREAK_LineBreak) {
55      dwBreakStatus = pTxtBreak->EndBreak(FX_TXTBREAK_ParagraphBreak);
56    }
57    if (dwBreakStatus > FX_TXTBREAK_PieceBreak) {
58      int32_t nCount = pTxtBreak->CountBreakPieces();
59      int32_t nTotal = 0;
60      for (int32_t j = 0; j < nCount; j++) {
61        const CFX_TxtPiece* Piece = pTxtBreak->GetBreakPiece(j);
62        nTotal += Piece->GetLength();
63      }
64      LineBaseArr.Add(nTotal);
65      pTxtBreak->ClearBreakPieces();
66    }
67    if ((pIter->GetAt() + 1 == nEndIndex) &&
68        (dwBreakStatus == FX_TXTBREAK_LineBreak)) {
69      bReload = TRUE;
70      pIter->Next(TRUE);
71    }
72  } while (pIter->Next(FALSE) && (pIter->GetAt() < nEndIndex));
73  pIter->Release();
74  pTxtBreak->EndBreak(FX_TXTBREAK_ParagraphBreak);
75  pTxtBreak->ClearBreakPieces();
76  int32_t nLineCount = LineBaseArr.GetSize();
77  m_nLineCount = nLineCount;
78  if (m_lpData == NULL) {
79    m_lpData = FX_Alloc(int32_t, nLineCount + 1);
80  } else {
81    m_lpData = FX_Realloc(int32_t, m_lpData, (nLineCount + 1));
82  }
83  int32_t* pIntArr = (int32_t*)m_lpData;
84  pIntArr[0] = 1;
85  m_nLineCount = nLineCount;
86  pIntArr++;
87  for (int32_t j = 0; j < nLineCount; j++, pIntArr++) {
88    *pIntArr = LineBaseArr[j];
89  }
90  LineBaseArr.RemoveAll();
91}
92void CFDE_TxtEdtParag::UnloadParag() {
93  FXSYS_assert(m_lpData != NULL);
94  ((int32_t*)m_lpData)[0]--;
95  FXSYS_assert(((int32_t*)m_lpData)[0] >= 0);
96  if (((int32_t*)m_lpData)[0] == 0) {
97    FX_Free(m_lpData);
98    m_lpData = NULL;
99  }
100}
101void CFDE_TxtEdtParag::CalcLines() {
102  IFX_TxtBreak* pTxtBreak = m_pEngine->GetTextBreak();
103  IFDE_TxtEdtBuf* pTxtBuf = m_pEngine->GetTextBuf();
104  IFX_CharIter* pIter = new CFDE_TxtEdtBufIter((CFDE_TxtEdtBuf*)pTxtBuf);
105  int32_t nCount = 0;
106  FX_DWORD dwBreakStatus = FX_TXTBREAK_None;
107  int32_t nEndIndex = m_nCharStart + m_nCharCount;
108  pIter->SetAt(m_nCharStart);
109  FX_BOOL bReload = FALSE;
110  do {
111    if (bReload) {
112      dwBreakStatus = pTxtBreak->EndBreak(FX_TXTBREAK_ParagraphBreak);
113    } else {
114      FX_WCHAR wAppend = pIter->GetChar();
115      dwBreakStatus = pTxtBreak->AppendChar(wAppend);
116    }
117    if (pIter->GetAt() + 1 == nEndIndex &&
118        dwBreakStatus < FX_TXTBREAK_LineBreak) {
119      dwBreakStatus = pTxtBreak->EndBreak(FX_TXTBREAK_ParagraphBreak);
120    }
121    if (dwBreakStatus > FX_TXTBREAK_PieceBreak) {
122      nCount++;
123      pTxtBreak->ClearBreakPieces();
124    }
125    if ((pIter->GetAt() + 1 == nEndIndex) &&
126        (dwBreakStatus == FX_TXTBREAK_LineBreak)) {
127      bReload = TRUE;
128      pIter->Next(TRUE);
129    }
130  } while (pIter->Next(FALSE) && (pIter->GetAt() < nEndIndex));
131  pIter->Release();
132  pTxtBreak->EndBreak(FX_TXTBREAK_ParagraphBreak);
133  pTxtBreak->ClearBreakPieces();
134  m_nLineCount = nCount;
135}
136void CFDE_TxtEdtParag::GetLineRange(int32_t nLineIndex,
137                                    int32_t& nStart,
138                                    int32_t& nCount) const {
139  int32_t* pLineBaseArr = (int32_t*)m_lpData;
140  FXSYS_assert(nLineIndex < m_nLineCount);
141  nStart = m_nCharStart;
142  pLineBaseArr++;
143  for (int32_t i = 0; i < nLineIndex; i++) {
144    nStart += *pLineBaseArr;
145    pLineBaseArr++;
146  }
147  nCount = *pLineBaseArr;
148}
149