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 "xfa/src/fee/include/ifde_txtedtpage.h"
     13 #include "xfa/src/fee/include/fx_wordbreak.h"
     14 #include "fde_txtedtpage.h"
     15 #include "fde_txtedtengine.h"
     16 #include "fde_txtedtparag.h"
     17 #include "fde_txtedtbuf.h"
     18 #define FDE_TXTEDT_TOLERANCE 0.1f
     19 IFDE_TxtEdtPage* IFDE_TxtEdtPage::Create(IFDE_TxtEdtEngine* pEngine,
     20                                          int32_t nIndex) {
     21   return (IFDE_TxtEdtPage*)new CFDE_TxtEdtPage(pEngine, nIndex);
     22 }
     23 CFDE_TxtEdtTextSet::CFDE_TxtEdtTextSet(CFDE_TxtEdtPage* pPage)
     24     : m_pPage(pPage) {}
     25 CFDE_TxtEdtTextSet::~CFDE_TxtEdtTextSet() {}
     26 FDE_VISUALOBJTYPE CFDE_TxtEdtTextSet::GetType() {
     27   return FDE_VISUALOBJ_Text;
     28 }
     29 FX_BOOL CFDE_TxtEdtTextSet::GetBBox(FDE_HVISUALOBJ hVisualObj,
     30                                     CFX_RectF& bbox) {
     31   return FALSE;
     32 }
     33 FX_BOOL CFDE_TxtEdtTextSet::GetMatrix(FDE_HVISUALOBJ hVisualObj,
     34                                       CFX_Matrix& matrix) {
     35   return FALSE;
     36 }
     37 FX_BOOL CFDE_TxtEdtTextSet::GetRect(FDE_HVISUALOBJ hVisualObj, CFX_RectF& rt) {
     38   rt = ((FDE_LPTEXTEDITPIECE)(hVisualObj))->rtPiece;
     39   return TRUE;
     40 }
     41 FX_BOOL CFDE_TxtEdtTextSet::GetClip(FDE_HVISUALOBJ hVisualObj, CFX_RectF& rt) {
     42   return FALSE;
     43 }
     44 int32_t CFDE_TxtEdtTextSet::GetString(FDE_HVISUALOBJ hText,
     45                                       CFX_WideString& wsText) {
     46   FDE_LPTEXTEDITPIECE pPiece = (FDE_LPTEXTEDITPIECE)hText;
     47   FX_WCHAR* pBuffer = wsText.GetBuffer(pPiece->nCount);
     48   for (int32_t i = 0; i < pPiece->nCount; i++) {
     49     pBuffer[i] = m_pPage->GetChar((void*)hText, i);
     50   }
     51   wsText.ReleaseBuffer(pPiece->nCount);
     52   return pPiece->nCount;
     53 }
     54 IFX_Font* CFDE_TxtEdtTextSet::GetFont(FDE_HVISUALOBJ hText) {
     55   return m_pPage->GetEngine()->GetEditParams()->pFont;
     56 }
     57 FX_FLOAT CFDE_TxtEdtTextSet::GetFontSize(FDE_HVISUALOBJ hText) {
     58   return m_pPage->GetEngine()->GetEditParams()->fFontSize;
     59 }
     60 FX_ARGB CFDE_TxtEdtTextSet::GetFontColor(FDE_HVISUALOBJ hText) {
     61   return m_pPage->GetEngine()->GetEditParams()->dwFontColor;
     62 }
     63 int32_t CFDE_TxtEdtTextSet::GetDisplayPos(FDE_HVISUALOBJ hText,
     64                                           FXTEXT_CHARPOS* pCharPos,
     65                                           FX_BOOL bCharCode,
     66                                           CFX_WideString* pWSForms) {
     67   if (hText == NULL) {
     68     return 0;
     69   }
     70   FDE_LPTEXTEDITPIECE pPiece = (FDE_LPTEXTEDITPIECE)hText;
     71   int32_t nLength = pPiece->nCount;
     72   if (nLength < 1) {
     73     return 0;
     74   }
     75   CFDE_TxtEdtEngine* pEngine = (CFDE_TxtEdtEngine*)(m_pPage->GetEngine());
     76   const FDE_TXTEDTPARAMS* pTextParams = pEngine->GetEditParams();
     77   IFX_TxtBreak* pBreak = pEngine->GetTextBreak();
     78   FX_DWORD dwLayoutStyle = pBreak->GetLayoutStyles();
     79   FX_TXTRUN tr;
     80   tr.pAccess = m_pPage;
     81   tr.pIdentity = (void*)hText;
     82   tr.pStr = NULL;
     83   tr.pWidths = NULL;
     84   tr.iLength = nLength;
     85   tr.pFont = pTextParams->pFont;
     86   tr.fFontSize = pTextParams->fFontSize;
     87   tr.dwStyles = dwLayoutStyle;
     88   tr.iCharRotation = pTextParams->nCharRotation;
     89   tr.dwCharStyles = pPiece->dwCharStyles;
     90   tr.pRect = &(pPiece->rtPiece);
     91   tr.wLineBreakChar = pTextParams->wLineBreakChar;
     92   return pBreak->GetDisplayPos(&tr, pCharPos, bCharCode, pWSForms);
     93 }
     94 int32_t CFDE_TxtEdtTextSet::GetCharRects(FDE_HVISUALOBJ hText,
     95                                          CFX_RectFArray& rtArray) {
     96   return GetCharRects_Impl(hText, rtArray);
     97 }
     98 int32_t CFDE_TxtEdtTextSet::GetCharRects_Impl(FDE_HVISUALOBJ hText,
     99                                               CFX_RectFArray& rtArray,
    100                                               FX_BOOL bBBox) {
    101   if (hText == NULL) {
    102     return 0;
    103   }
    104   FDE_LPTEXTEDITPIECE pPiece = (FDE_LPTEXTEDITPIECE)hText;
    105   CFDE_TxtEdtEngine* pEngine = (CFDE_TxtEdtEngine*)(m_pPage->GetEngine());
    106   int32_t nLength = pPiece->nCount;
    107   if (nLength < 1) {
    108     return 0;
    109   }
    110   const FDE_TXTEDTPARAMS* pTextParams = pEngine->GetEditParams();
    111   FX_DWORD dwLayoutStyle = pEngine->GetTextBreak()->GetLayoutStyles();
    112   FX_TXTRUN tr;
    113   tr.pAccess = m_pPage;
    114   tr.pIdentity = (void*)hText;
    115   tr.pStr = NULL;
    116   tr.pWidths = NULL;
    117   tr.iLength = nLength;
    118   tr.pFont = pTextParams->pFont;
    119   tr.fFontSize = pTextParams->fFontSize;
    120   tr.dwStyles = dwLayoutStyle;
    121   tr.iCharRotation = pTextParams->nCharRotation;
    122   tr.dwCharStyles = pPiece->dwCharStyles;
    123   tr.pRect = &(pPiece->rtPiece);
    124   tr.wLineBreakChar = pTextParams->wLineBreakChar;
    125   return pEngine->GetTextBreak()->GetCharRects(&tr, rtArray, bBBox);
    126 }
    127 CFDE_TxtEdtPage::CFDE_TxtEdtPage(IFDE_TxtEdtEngine* pEngine, int32_t nPageIndex)
    128     : m_pIter(nullptr),
    129       m_pTextSet(nullptr),
    130       m_pBgnParag(nullptr),
    131       m_pEndParag(nullptr),
    132       m_nRefCount(0),
    133       m_nPageStart(-1),
    134       m_nCharCount(0),
    135       m_nPageIndex(nPageIndex),
    136       m_bLoaded(FALSE),
    137       m_pCharWidth(nullptr) {
    138   FXSYS_memset(&m_rtPage, 0, sizeof(CFX_RectF));
    139   FXSYS_memset(&m_rtPageMargin, 0, sizeof(CFX_RectF));
    140   FXSYS_memset(&m_rtPageContents, 0, sizeof(CFX_RectF));
    141   FXSYS_memset(&m_rtPageCanvas, 0, sizeof(CFX_RectF));
    142   m_pEditEngine = (CFDE_TxtEdtEngine*)pEngine;
    143 }
    144 CFDE_TxtEdtPage::~CFDE_TxtEdtPage() {
    145   m_PieceMassArr.RemoveAll(TRUE);
    146   if (m_pTextSet) {
    147     delete m_pTextSet;
    148     m_pTextSet = NULL;
    149   }
    150   if (m_pCharWidth) {
    151     delete[] m_pCharWidth;
    152     m_pCharWidth = NULL;
    153   }
    154   if (m_pIter != NULL) {
    155     m_pIter->Release();
    156     m_pIter = NULL;
    157   }
    158 }
    159 void CFDE_TxtEdtPage::Release() {
    160   delete this;
    161 }
    162 IFDE_TxtEdtEngine* CFDE_TxtEdtPage::GetEngine() const {
    163   return (IFDE_TxtEdtEngine*)m_pEditEngine;
    164 }
    165 FDE_VISUALOBJTYPE CFDE_TxtEdtPage::GetType() {
    166   return FDE_VISUALOBJ_Text;
    167 }
    168 FX_BOOL CFDE_TxtEdtPage::GetBBox(FDE_HVISUALOBJ hVisualObj, CFX_RectF& bbox) {
    169   return FALSE;
    170 }
    171 FX_BOOL CFDE_TxtEdtPage::GetMatrix(FDE_HVISUALOBJ hVisualObj,
    172                                    CFX_Matrix& matrix) {
    173   return FALSE;
    174 }
    175 FX_BOOL CFDE_TxtEdtPage::GetRect(FDE_HVISUALOBJ hVisualObj, CFX_RectF& rt) {
    176   return FALSE;
    177 }
    178 FX_BOOL CFDE_TxtEdtPage::GetClip(FDE_HVISUALOBJ hVisualObj, CFX_RectF& rt) {
    179   return FALSE;
    180 }
    181 int32_t CFDE_TxtEdtPage::GetCharRect(int32_t nIndex,
    182                                      CFX_RectF& rect,
    183                                      FX_BOOL bBBox) const {
    184   FXSYS_assert(m_nRefCount > 0);
    185   FXSYS_assert(nIndex >= 0 && nIndex < m_nCharCount);
    186   if (m_nRefCount < 1) {
    187     return 0;
    188   }
    189   int32_t nCount = m_PieceMassArr.GetSize();
    190   for (int32_t i = 0; i < nCount; i++) {
    191     const FDE_LPTEXTEDITPIECE pPiece = m_PieceMassArr.GetPtrAt(i);
    192     if (nIndex >= pPiece->nStart &&
    193         nIndex < (pPiece->nStart + pPiece->nCount)) {
    194       CFX_RectFArray rectArr;
    195       if (bBBox) {
    196         m_pTextSet->GetCharRects_Impl((FDE_HVISUALOBJ)pPiece, rectArr, bBBox);
    197       } else {
    198         m_pTextSet->GetCharRects((FDE_HVISUALOBJ)pPiece, rectArr);
    199       }
    200       rect = rectArr[nIndex - pPiece->nStart];
    201       return pPiece->nBidiLevel;
    202     }
    203   }
    204   FXSYS_assert(0);
    205   return 0;
    206 }
    207 int32_t CFDE_TxtEdtPage::GetCharIndex(const CFX_PointF& fPoint,
    208                                       FX_BOOL& bBefore) {
    209   FX_BOOL bVertical = m_pEditEngine->GetEditParams()->dwLayoutStyles &
    210                       FDE_TEXTEDITLAYOUT_DocVertical;
    211   CFX_PointF ptF = fPoint;
    212   NormalizePt2Rect(ptF, m_rtPageContents, FDE_TXTEDT_TOLERANCE);
    213   int32_t nCount = m_PieceMassArr.GetSize();
    214   CFX_RectF rtLine;
    215   int32_t nBgn = 0;
    216   int32_t nEnd = 0;
    217   FX_BOOL bInLine = FALSE;
    218   int32_t i = 0;
    219   for (i = 0; i < nCount; i++) {
    220     const FDE_LPTEXTEDITPIECE pPiece = m_PieceMassArr.GetPtrAt(i);
    221     if (!bInLine && (bVertical ? (pPiece->rtPiece.left <= ptF.x &&
    222                                   pPiece->rtPiece.right() > ptF.x)
    223                                : (pPiece->rtPiece.top <= ptF.y &&
    224                                   pPiece->rtPiece.bottom() > ptF.y))) {
    225       nBgn = nEnd = i;
    226       rtLine = pPiece->rtPiece;
    227       bInLine = TRUE;
    228     } else if (bInLine) {
    229       if (bVertical ? (!(pPiece->rtPiece.left <= ptF.x &&
    230                          pPiece->rtPiece.right() > ptF.x))
    231                     : (pPiece->rtPiece.bottom() <= ptF.y ||
    232                        pPiece->rtPiece.top > ptF.y)) {
    233         nEnd = i - 1;
    234         break;
    235       } else {
    236         rtLine.Union(pPiece->rtPiece);
    237       }
    238     }
    239   }
    240   NormalizePt2Rect(ptF, rtLine, FDE_TXTEDT_TOLERANCE);
    241   int32_t nCaret = 0;
    242   FDE_LPTEXTEDITPIECE pPiece = NULL;
    243   for (i = nBgn; i <= nEnd; i++) {
    244     pPiece = m_PieceMassArr.GetPtrAt(i);
    245     nCaret = m_nPageStart + pPiece->nStart;
    246     if (pPiece->rtPiece.Contains(ptF)) {
    247       CFX_RectFArray rectArr;
    248       m_pTextSet->GetCharRects((FDE_HVISUALOBJ)pPiece, rectArr);
    249       int32_t nRtCount = rectArr.GetSize();
    250       for (int32_t j = 0; j < nRtCount; j++) {
    251         if (rectArr[j].Contains(ptF)) {
    252           nCaret = m_nPageStart + pPiece->nStart + j;
    253           if (nCaret >= m_pEditEngine->GetTextBufLength()) {
    254             bBefore = TRUE;
    255             return m_pEditEngine->GetTextBufLength();
    256           }
    257           FX_WCHAR wChar = m_pEditEngine->GetTextBuf()->GetCharByIndex(nCaret);
    258           if (wChar == L'\n' || wChar == L'\r') {
    259             if (wChar == L'\n') {
    260               if (m_pEditEngine->GetTextBuf()->GetCharByIndex(nCaret - 1) ==
    261                   L'\r') {
    262                 nCaret--;
    263               }
    264             }
    265             bBefore = TRUE;
    266             return nCaret;
    267           }
    268           if (bVertical
    269                   ? (ptF.y > ((rectArr[j].top + rectArr[j].bottom()) / 2))
    270                   : (ptF.x > ((rectArr[j].left + rectArr[j].right()) / 2))) {
    271             bBefore = FX_IsOdd(pPiece->nBidiLevel);
    272           } else {
    273             bBefore = !FX_IsOdd(pPiece->nBidiLevel);
    274           }
    275           return nCaret;
    276         }
    277       }
    278     }
    279   }
    280   bBefore = TRUE;
    281   return nCaret;
    282 }
    283 int32_t CFDE_TxtEdtPage::GetCharStart() const {
    284   return m_nPageStart;
    285 }
    286 int32_t CFDE_TxtEdtPage::GetCharCount() const {
    287   return m_nCharCount;
    288 }
    289 int32_t CFDE_TxtEdtPage::GetDisplayPos(const CFX_RectF& rtClip,
    290                                        FXTEXT_CHARPOS*& pCharPos,
    291                                        FX_LPRECTF pBBox) const {
    292   pCharPos = FX_Alloc(FXTEXT_CHARPOS, m_nCharCount);
    293   int32_t nCharPosCount = 0;
    294   FDE_HVISUALOBJ hVisualObj = NULL;
    295   int32_t nVisualObjCount = m_PieceMassArr.GetSize();
    296   FXTEXT_CHARPOS* pos = pCharPos;
    297   CFX_RectF rtObj;
    298   for (int32_t i = 0; i < nVisualObjCount; i++) {
    299     hVisualObj = (FDE_HVISUALOBJ)m_PieceMassArr.GetPtrAt(i);
    300     m_pTextSet->GetRect(hVisualObj, rtObj);
    301     if (!rtClip.IntersectWith(rtObj)) {
    302       continue;
    303     }
    304     int32_t nCount = m_pTextSet->GetDisplayPos(hVisualObj, pos, FALSE);
    305     nCharPosCount += nCount;
    306     pos += nCount;
    307   }
    308   if ((nCharPosCount * 5) < (m_nCharCount << 2)) {
    309     FXTEXT_CHARPOS* pTemp = FX_Alloc(FXTEXT_CHARPOS, nCharPosCount);
    310     FXSYS_memcpy(pTemp, pCharPos, sizeof(FXTEXT_CHARPOS) * nCharPosCount);
    311     FX_Free(pCharPos);
    312     pCharPos = pTemp;
    313   }
    314   return nCharPosCount;
    315 }
    316 void CFDE_TxtEdtPage::CalcRangeRectArray(int32_t nStart,
    317                                          int32_t nCount,
    318                                          CFX_RectFArray& RectFArr) const {
    319   int32_t nPieceCount = m_PieceMassArr.GetSize();
    320   int32_t nEnd = nStart + nCount - 1;
    321   FX_BOOL bInRange = FALSE;
    322   for (int32_t i = 0; i < nPieceCount; i++) {
    323     FDE_LPTEXTEDITPIECE piece = m_PieceMassArr.GetPtrAt(i);
    324     if (!bInRange) {
    325       if (nStart >= piece->nStart && nStart < (piece->nStart + piece->nCount)) {
    326         int32_t nRangeEnd = piece->nCount - 1;
    327         FX_BOOL bEnd = FALSE;
    328         if (nEnd >= piece->nStart && nEnd < (piece->nStart + piece->nCount)) {
    329           nRangeEnd = nEnd - piece->nStart;
    330           bEnd = TRUE;
    331         }
    332         CFX_RectFArray rcArr;
    333         m_pTextSet->GetCharRects((FDE_HVISUALOBJ)piece, rcArr);
    334         CFX_RectF rectPiece = rcArr[nStart - piece->nStart];
    335         rectPiece.Union(rcArr[nRangeEnd]);
    336         RectFArr.Add(rectPiece);
    337         if (bEnd) {
    338           return;
    339         }
    340         bInRange = TRUE;
    341       }
    342     } else {
    343       if (nEnd >= piece->nStart && nEnd < (piece->nStart + piece->nCount)) {
    344         CFX_RectFArray rcArr;
    345         m_pTextSet->GetCharRects((FDE_HVISUALOBJ)piece, rcArr);
    346         CFX_RectF rectPiece = rcArr[0];
    347         rectPiece.Union(rcArr[nEnd - piece->nStart]);
    348         RectFArr.Add(rectPiece);
    349         return;
    350       }
    351       RectFArr.Add(piece->rtPiece);
    352     }
    353   }
    354   return;
    355 }
    356 int32_t CFDE_TxtEdtPage::SelectWord(const CFX_PointF& fPoint, int32_t& nCount) {
    357   if (m_nRefCount < 0) {
    358     return -1;
    359   }
    360   IFDE_TxtEdtBuf* pBuf = m_pEditEngine->GetTextBuf();
    361   FX_BOOL bBefore;
    362   int32_t nIndex = GetCharIndex(fPoint, bBefore);
    363   if (nIndex == m_pEditEngine->GetTextBufLength()) {
    364     nIndex = m_pEditEngine->GetTextBufLength() - 1;
    365   }
    366   if (nIndex < 0) {
    367     return -1;
    368   }
    369   IFX_WordBreak* pIter = FX_WordBreak_Create();
    370   pIter->Attach(new CFDE_TxtEdtBufIter((CFDE_TxtEdtBuf*)pBuf));
    371   pIter->SetAt(nIndex);
    372   nCount = pIter->GetWordLength();
    373   int32_t nRet = pIter->GetWordPos();
    374   pIter->Release();
    375   return nRet;
    376 }
    377 FX_BOOL CFDE_TxtEdtPage::IsLoaded(FX_LPCRECTF pClipBox) {
    378   return m_bLoaded;
    379 }
    380 int32_t CFDE_TxtEdtPage::LoadPage(FX_LPCRECTF pClipBox, IFX_Pause* pPause) {
    381   if (m_nRefCount > 0) {
    382     m_nRefCount++;
    383     return m_nRefCount;
    384   }
    385   IFDE_TxtEdtBuf* pBuf = m_pEditEngine->GetTextBuf();
    386   const FDE_TXTEDTPARAMS* pParams = m_pEditEngine->GetEditParams();
    387   if (m_pIter != NULL) {
    388     m_pIter->Release();
    389   }
    390   FX_WCHAR wcAlias = 0;
    391   if (pParams->dwMode & FDE_TEXTEDITMODE_Password) {
    392     wcAlias = m_pEditEngine->GetAliasChar();
    393   }
    394   m_pIter = new CFDE_TxtEdtBufIter((CFDE_TxtEdtBuf*)pBuf, wcAlias);
    395   IFX_TxtBreak* pBreak = m_pEditEngine->GetTextBreak();
    396   pBreak->EndBreak(FX_TXTBREAK_ParagraphBreak);
    397   pBreak->ClearBreakPieces();
    398   int32_t nPageLineCount = m_pEditEngine->GetPageLineCount();
    399   int32_t nStartLine = nPageLineCount * m_nPageIndex;
    400   int32_t nEndLine = std::min((nStartLine + nPageLineCount - 1),
    401                               (m_pEditEngine->GetLineCount() - 1));
    402   int32_t nPageStart, nPageEnd, nTemp, nBgnParag, nStartLineInParag, nEndParag,
    403       nEndLineInParag;
    404   nBgnParag = m_pEditEngine->Line2Parag(0, 0, nStartLine, nStartLineInParag);
    405   m_pBgnParag = (CFDE_TxtEdtParag*)m_pEditEngine->GetParag(nBgnParag);
    406   m_pBgnParag->LoadParag();
    407   m_pBgnParag->GetLineRange(nStartLine - nStartLineInParag, nPageStart, nTemp);
    408   nEndParag = m_pEditEngine->Line2Parag(nBgnParag, nStartLineInParag, nEndLine,
    409                                         nEndLineInParag);
    410   m_pEndParag = (CFDE_TxtEdtParag*)m_pEditEngine->GetParag(nEndParag);
    411   m_pEndParag->LoadParag();
    412   m_pEndParag->GetLineRange(nEndLine - nEndLineInParag, nPageEnd, nTemp);
    413   nPageEnd += (nTemp - 1);
    414   FX_BOOL bVertial = pParams->dwLayoutStyles & FDE_TEXTEDITLAYOUT_DocVertical;
    415   FX_BOOL bLineReserve =
    416       pParams->dwLayoutStyles & FDE_TEXTEDITLAYOUT_LineReserve;
    417   FX_FLOAT fLineStart =
    418       bVertial
    419           ? (bLineReserve ? (pParams->fPlateWidth - pParams->fLineSpace) : 0.0f)
    420           : 0.0f;
    421   FX_FLOAT fLineStep =
    422       (bVertial && bLineReserve) ? (-pParams->fLineSpace) : pParams->fLineSpace;
    423   FX_FLOAT fLinePos = fLineStart;
    424   if (m_pTextSet == NULL) {
    425     m_pTextSet = new CFDE_TxtEdtTextSet(this);
    426   }
    427   m_PieceMassArr.RemoveAll(TRUE);
    428   FX_DWORD dwBreakStatus = FX_TXTBREAK_None;
    429   int32_t nPieceStart = 0;
    430   if (m_pCharWidth != NULL) {
    431     delete[] m_pCharWidth;
    432   }
    433   m_pCharWidth = new int32_t[nPageEnd - nPageStart + 1];
    434   pBreak->EndBreak(FX_TXTBREAK_ParagraphBreak);
    435   pBreak->ClearBreakPieces();
    436   m_nPageStart = nPageStart;
    437   m_nCharCount = nPageEnd - nPageStart + 1;
    438   FX_BOOL bReload = FALSE;
    439   FX_FLOAT fDefCharWidth = 0;
    440   IFX_CharIter* pIter = m_pIter->Clone();
    441   pIter->SetAt(nPageStart);
    442   m_pIter->SetAt(nPageStart);
    443   FX_BOOL bFirstPiece = TRUE;
    444   do {
    445     if (bReload) {
    446       dwBreakStatus = pBreak->EndBreak(FX_TXTBREAK_ParagraphBreak);
    447     } else {
    448       FX_WCHAR wAppend = pIter->GetChar();
    449       dwBreakStatus = pBreak->AppendChar(wAppend);
    450     }
    451     if (pIter->GetAt() == nPageEnd && dwBreakStatus < FX_TXTBREAK_LineBreak) {
    452       dwBreakStatus = pBreak->EndBreak(FX_TXTBREAK_ParagraphBreak);
    453     }
    454     if (dwBreakStatus > FX_TXTBREAK_PieceBreak) {
    455       int32_t nPieceCount = pBreak->CountBreakPieces();
    456       for (int32_t j = 0; j < nPieceCount; j++) {
    457         const CFX_TxtPiece* pPiece = pBreak->GetBreakPiece(j);
    458         FDE_TEXTEDITPIECE TxtEdtPiece;
    459         FXSYS_memset(&TxtEdtPiece, 0, sizeof(FDE_TEXTEDITPIECE));
    460         TxtEdtPiece.nBidiLevel = pPiece->m_iBidiLevel;
    461         TxtEdtPiece.nCount = pPiece->GetLength();
    462         TxtEdtPiece.nStart = nPieceStart;
    463         TxtEdtPiece.dwCharStyles = pPiece->m_dwCharStyles;
    464         if (FX_IsOdd(pPiece->m_iBidiLevel)) {
    465           TxtEdtPiece.dwCharStyles |= FX_TXTCHARSTYLE_OddBidiLevel;
    466         }
    467         FX_FLOAT fParaBreakWidth = 0.0f;
    468         if (pPiece->m_dwStatus > FX_TXTBREAK_PieceBreak) {
    469           FX_WCHAR wRtChar = pParams->wLineBreakChar;
    470           if (TxtEdtPiece.nCount >= 2) {
    471             FX_WCHAR wChar = pBuf->GetCharByIndex(
    472                 m_nPageStart + TxtEdtPiece.nStart + TxtEdtPiece.nCount - 1);
    473             FX_WCHAR wCharPre = pBuf->GetCharByIndex(
    474                 m_nPageStart + TxtEdtPiece.nStart + TxtEdtPiece.nCount - 2);
    475             if (wChar == wRtChar) {
    476               fParaBreakWidth += fDefCharWidth;
    477             }
    478             if (wCharPre == wRtChar) {
    479               fParaBreakWidth += fDefCharWidth;
    480             }
    481           } else if (TxtEdtPiece.nCount >= 1) {
    482             FX_WCHAR wChar = pBuf->GetCharByIndex(
    483                 m_nPageStart + TxtEdtPiece.nStart + TxtEdtPiece.nCount - 1);
    484             if (wChar == wRtChar) {
    485               fParaBreakWidth += fDefCharWidth;
    486             }
    487           }
    488         }
    489         if (pParams->dwLayoutStyles & FDE_TEXTEDITLAYOUT_DocVertical) {
    490           TxtEdtPiece.rtPiece.left = fLinePos;
    491           TxtEdtPiece.rtPiece.top = (FX_FLOAT)pPiece->m_iStartPos / 20000.0f;
    492           TxtEdtPiece.rtPiece.width = pParams->fLineSpace;
    493           TxtEdtPiece.rtPiece.height =
    494               (FX_FLOAT)pPiece->m_iWidth / 20000.0f + fParaBreakWidth;
    495         } else {
    496           TxtEdtPiece.rtPiece.left = (FX_FLOAT)pPiece->m_iStartPos / 20000.0f;
    497           TxtEdtPiece.rtPiece.top = fLinePos;
    498           TxtEdtPiece.rtPiece.width =
    499               (FX_FLOAT)pPiece->m_iWidth / 20000.0f + fParaBreakWidth;
    500           TxtEdtPiece.rtPiece.height = pParams->fLineSpace;
    501         }
    502         if (bFirstPiece) {
    503           m_rtPageContents = TxtEdtPiece.rtPiece;
    504           bFirstPiece = FALSE;
    505         } else {
    506           m_rtPageContents.Union(TxtEdtPiece.rtPiece);
    507         }
    508         nPieceStart += TxtEdtPiece.nCount;
    509         m_PieceMassArr.Add(TxtEdtPiece);
    510         for (int32_t k = 0; k < TxtEdtPiece.nCount; k++) {
    511           CFX_Char* ptc = pPiece->GetCharPtr(k);
    512           m_pCharWidth[TxtEdtPiece.nStart + k] = ptc->m_iCharWidth;
    513         }
    514       }
    515       fLinePos += fLineStep;
    516       pBreak->ClearBreakPieces();
    517     }
    518     if (pIter->GetAt() == nPageEnd && dwBreakStatus == FX_TXTBREAK_LineBreak) {
    519       bReload = TRUE;
    520       pIter->Next(TRUE);
    521     }
    522   } while (pIter->Next(FALSE) && (pIter->GetAt() <= nPageEnd));
    523   if (m_rtPageContents.left != 0) {
    524     FX_FLOAT fDelta = 0.0f;
    525     if (m_rtPageContents.width < pParams->fPlateWidth) {
    526       if (pParams->dwAlignment & FDE_TEXTEDITALIGN_Right) {
    527         fDelta = pParams->fPlateWidth - m_rtPageContents.width;
    528       } else if (pParams->dwAlignment & FDE_TEXTEDITALIGN_Center) {
    529         if ((pParams->dwLayoutStyles & FDE_TEXTEDITLAYOUT_CombText) &&
    530             m_nCharCount > 1) {
    531           int32_t nCount = m_nCharCount - 1;
    532           int32_t n = (m_pEditEngine->m_nLimit - nCount) / 2;
    533           fDelta = (m_rtPageContents.width / nCount) * n;
    534         } else {
    535           fDelta = (pParams->fPlateWidth - m_rtPageContents.width) / 2;
    536         }
    537       }
    538     }
    539     FX_FLOAT fOffset = m_rtPageContents.left - fDelta;
    540     int32_t nCount = m_PieceMassArr.GetSize();
    541     for (int32_t i = 0; i < nCount; i++) {
    542       FDE_LPTEXTEDITPIECE pPiece = m_PieceMassArr.GetPtrAt(i);
    543       pPiece->rtPiece.Offset(-fOffset, 0.0f);
    544     }
    545     m_rtPageContents.Offset(-fOffset, 0.0f);
    546   }
    547   if (m_pEditEngine->GetEditParams()->dwLayoutStyles &
    548       FDE_TEXTEDITLAYOUT_LastLineHeight) {
    549     m_rtPageContents.height -= pParams->fLineSpace - pParams->fFontSize;
    550     int32_t nCount = m_PieceMassArr.GetSize();
    551     FDE_LPTEXTEDITPIECE pPiece = m_PieceMassArr.GetPtrAt(nCount - 1);
    552     pPiece->rtPiece.height = pParams->fFontSize;
    553   }
    554   pIter->Release();
    555   m_nRefCount = 1;
    556   m_bLoaded = TRUE;
    557   return 0;
    558 }
    559 void CFDE_TxtEdtPage::UnloadPage(FX_LPCRECTF pClipBox) {
    560   FXSYS_assert(m_nRefCount > 0);
    561   m_nRefCount--;
    562   if (m_nRefCount == 0) {
    563     m_PieceMassArr.RemoveAll();
    564     if (m_pTextSet) {
    565       delete m_pTextSet;
    566       m_pTextSet = NULL;
    567     }
    568     if (m_pCharWidth) {
    569       delete[] m_pCharWidth;
    570       m_pCharWidth = NULL;
    571     }
    572     if (m_pBgnParag) {
    573       m_pBgnParag->UnloadParag();
    574     }
    575     if (m_pEndParag) {
    576       m_pEndParag->UnloadParag();
    577     }
    578     if (m_pIter) {
    579       m_pIter->Release();
    580       m_pIter = NULL;
    581     }
    582     m_pBgnParag = NULL;
    583     m_pEndParag = NULL;
    584   }
    585   return;
    586 }
    587 const CFX_RectF& CFDE_TxtEdtPage::GetContentsBox() {
    588   return m_rtPageContents;
    589 }
    590 FX_POSITION CFDE_TxtEdtPage::GetFirstPosition(FDE_HVISUALOBJ hCanvas) {
    591   if (m_PieceMassArr.GetSize() < 1) {
    592     return NULL;
    593   }
    594   return (FX_POSITION)1;
    595 }
    596 FDE_HVISUALOBJ CFDE_TxtEdtPage::GetNext(FDE_HVISUALOBJ hCanvas,
    597                                         FX_POSITION& pos,
    598                                         IFDE_VisualSet*& pVisualSet) {
    599   if (m_pTextSet == NULL) {
    600     pos = NULL;
    601     return NULL;
    602   }
    603   int32_t nPos = (int32_t)(uintptr_t)pos;
    604   pVisualSet = m_pTextSet;
    605   if (nPos + 1 > m_PieceMassArr.GetSize()) {
    606     pos = NULL;
    607   } else {
    608     pos = (FX_POSITION)(uintptr_t)(nPos + 1);
    609   }
    610   return (FDE_HVISUALOBJ)(m_PieceMassArr.GetPtrAt(nPos - 1));
    611 }
    612 FDE_HVISUALOBJ CFDE_TxtEdtPage::GetParentCanvas(FDE_HVISUALOBJ hCanvas,
    613                                                 IFDE_VisualSet*& pVisualSet) {
    614   return NULL;
    615 }
    616 FX_WCHAR CFDE_TxtEdtPage::GetChar(void* pIdentity, int32_t index) const {
    617   int32_t nIndex =
    618       m_nPageStart + ((FDE_LPTEXTEDITPIECE)pIdentity)->nStart + index;
    619   if (nIndex != m_pIter->GetAt()) {
    620     m_pIter->SetAt(nIndex);
    621   }
    622   FX_WCHAR wChar = m_pIter->GetChar();
    623   m_pIter->Next();
    624   return wChar;
    625 }
    626 int32_t CFDE_TxtEdtPage::GetWidth(void* pIdentity, int32_t index) const {
    627   int32_t nWidth =
    628       m_pCharWidth[((FDE_LPTEXTEDITPIECE)pIdentity)->nStart + index];
    629   return nWidth;
    630 }
    631 void CFDE_TxtEdtPage::NormalizePt2Rect(CFX_PointF& ptF,
    632                                        const CFX_RectF& rtF,
    633                                        FX_FLOAT fTolerance) const {
    634   if (rtF.Contains(ptF.x, ptF.y)) {
    635     return;
    636   }
    637   if (ptF.x < rtF.left) {
    638     ptF.x = rtF.left;
    639   } else if (ptF.x >= rtF.right()) {
    640     ptF.x = rtF.right() - fTolerance;
    641   }
    642   if (ptF.y < rtF.top) {
    643     ptF.y = rtF.top;
    644   } else if (ptF.y >= rtF.bottom()) {
    645     ptF.y = rtF.bottom() - fTolerance;
    646   }
    647 }
    648