Home | History | Annotate | Download | only in layout
      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 "core/include/fxcrt/fx_arb.h"
     10 #include "xfa/src/fgas/include/fx_lbk.h"
     11 #include "xfa/src/fgas/src/fgas_base.h"
     12 #include "xfa/src/fgas/src/layout/fx_unicode.h"
     13 #include "xfa/src/fgas/src/layout/fx_textbreak.h"
     14 
     15 extern const FX_LINEBREAKTYPE gs_FX_LineBreak_PairTable[64][32];
     16 IFX_TxtBreak* IFX_TxtBreak::Create(FX_DWORD dwPolicies) {
     17   return new CFX_TxtBreak(dwPolicies);
     18 }
     19 CFX_TxtBreak::CFX_TxtBreak(FX_DWORD dwPolicies)
     20     : m_dwPolicies(dwPolicies),
     21       m_pArabicChar(NULL),
     22       m_iLineWidth(2000000),
     23       m_dwLayoutStyles(0),
     24       m_bVertical(FALSE),
     25       m_bArabicContext(FALSE),
     26       m_bArabicShapes(FALSE),
     27       m_bRTL(FALSE),
     28       m_bSingleLine(FALSE),
     29       m_bCombText(FALSE),
     30       m_iArabicContext(1),
     31       m_iCurArabicContext(1),
     32       m_pFont(NULL),
     33       m_iFontSize(240),
     34       m_bEquidistant(TRUE),
     35       m_iTabWidth(720000),
     36       m_wDefChar(0xFEFF),
     37       m_wParagBreakChar(L'\n'),
     38       m_iDefChar(0),
     39       m_iLineRotation(0),
     40       m_iCharRotation(0),
     41       m_iRotation(0),
     42       m_iAlignment(FX_TXTLINEALIGNMENT_Left),
     43       m_dwContextCharStyles(0),
     44       m_iCombWidth(360000),
     45       m_pUserData(NULL),
     46       m_dwCharType(0),
     47       m_bArabicNumber(FALSE),
     48       m_bArabicComma(FALSE),
     49       m_pCurLine(NULL),
     50       m_iReady(0),
     51       m_iTolerance(0),
     52       m_iHorScale(100),
     53       m_iVerScale(100),
     54       m_iCharSpace(0) {
     55   m_bPagination = (m_dwPolicies & FX_TXTBREAKPOLICY_Pagination) != 0;
     56   m_pArabicChar = IFX_ArabicChar::Create();
     57   if (m_bPagination) {
     58     m_pTxtLine1 = new CFX_TxtLine(sizeof(CFX_Char));
     59     m_pTxtLine2 = new CFX_TxtLine(sizeof(CFX_Char));
     60   } else {
     61     m_pTxtLine1 = new CFX_TxtLine(sizeof(CFX_TxtChar));
     62     m_pTxtLine2 = new CFX_TxtLine(sizeof(CFX_TxtChar));
     63   }
     64   m_pCurLine = m_pTxtLine1;
     65   ResetArabicContext();
     66 }
     67 CFX_TxtBreak::~CFX_TxtBreak() {
     68   Reset();
     69   delete m_pTxtLine1;
     70   delete m_pTxtLine2;
     71   m_pArabicChar->Release();
     72 }
     73 void CFX_TxtBreak::SetLineWidth(FX_FLOAT fLineWidth) {
     74   m_iLineWidth = FXSYS_round(fLineWidth * 20000.0f);
     75   FXSYS_assert(m_iLineWidth >= 20000);
     76 }
     77 void CFX_TxtBreak::SetLinePos(FX_FLOAT fLinePos) {
     78   int32_t iLinePos = FXSYS_round(fLinePos * 20000.0f);
     79   if (iLinePos < 0) {
     80     iLinePos = 0;
     81   }
     82   if (iLinePos > m_iLineWidth) {
     83     iLinePos = m_iLineWidth;
     84   }
     85   m_pCurLine->m_iStart = iLinePos;
     86   m_pCurLine->m_iWidth += iLinePos;
     87 }
     88 void CFX_TxtBreak::SetLayoutStyles(FX_DWORD dwLayoutStyles) {
     89   m_dwLayoutStyles = dwLayoutStyles;
     90   m_bVertical = (m_dwLayoutStyles & FX_TXTLAYOUTSTYLE_VerticalChars) != 0;
     91   m_bArabicContext = (m_dwLayoutStyles & FX_TXTLAYOUTSTYLE_ArabicContext) != 0;
     92   m_bArabicShapes = (m_dwLayoutStyles & FX_TXTLAYOUTSTYLE_ArabicShapes) != 0;
     93   m_bRTL = (m_dwLayoutStyles & FX_TXTLAYOUTSTYLE_RTLReadingOrder) != 0;
     94   m_bSingleLine = (m_dwLayoutStyles & FX_TXTLAYOUTSTYLE_SingleLine) != 0;
     95   m_bCombText = (m_dwLayoutStyles & FX_TXTLAYOUTSTYLE_CombText) != 0;
     96   ResetArabicContext();
     97   m_iLineRotation = GetLineRotation(m_dwLayoutStyles);
     98   m_iRotation = m_iLineRotation + m_iCharRotation;
     99   m_iRotation %= 4;
    100 }
    101 void CFX_TxtBreak::SetFont(IFX_Font* pFont) {
    102   if (pFont == NULL) {
    103     return;
    104   }
    105   if (m_pFont == pFont) {
    106     return;
    107   }
    108   SetBreakStatus();
    109   m_pFont = pFont;
    110   m_iDefChar = 0;
    111   if (m_wDefChar != 0xFEFF && m_pFont != NULL) {
    112     m_pFont->GetCharWidth(m_wDefChar, m_iDefChar, FALSE);
    113     m_iDefChar *= m_iFontSize;
    114   }
    115 }
    116 void CFX_TxtBreak::SetFontSize(FX_FLOAT fFontSize) {
    117   int32_t iFontSize = FXSYS_round(fFontSize * 20.0f);
    118   if (m_iFontSize == iFontSize) {
    119     return;
    120   }
    121   SetBreakStatus();
    122   m_iFontSize = iFontSize;
    123   m_iDefChar = 0;
    124   if (m_wDefChar != 0xFEFF && m_pFont != NULL) {
    125     m_pFont->GetCharWidth(m_wDefChar, m_iDefChar, FALSE);
    126     m_iDefChar *= m_iFontSize;
    127   }
    128 }
    129 void CFX_TxtBreak::SetTabWidth(FX_FLOAT fTabWidth, FX_BOOL bEquidistant) {
    130   m_iTabWidth = FXSYS_round(fTabWidth * 20000.0f);
    131   if (m_iTabWidth < FX_TXTBREAK_MinimumTabWidth) {
    132     m_iTabWidth = FX_TXTBREAK_MinimumTabWidth;
    133   }
    134   m_bEquidistant = bEquidistant;
    135 }
    136 void CFX_TxtBreak::SetDefaultChar(FX_WCHAR wch) {
    137   m_wDefChar = wch;
    138   m_iDefChar = 0;
    139   if (m_wDefChar != 0xFEFF && m_pFont != NULL) {
    140     m_pFont->GetCharWidth(m_wDefChar, m_iDefChar, FALSE);
    141     if (m_iDefChar < 0) {
    142       m_iDefChar = 0;
    143     } else {
    144       m_iDefChar *= m_iFontSize;
    145     }
    146   }
    147 }
    148 void CFX_TxtBreak::SetParagraphBreakChar(FX_WCHAR wch) {
    149   if (wch != L'\r' && wch != L'\n') {
    150     return;
    151   }
    152   m_wParagBreakChar = wch;
    153 }
    154 void CFX_TxtBreak::SetLineBreakTolerance(FX_FLOAT fTolerance) {
    155   m_iTolerance = FXSYS_round(fTolerance * 20000.0f);
    156 }
    157 void CFX_TxtBreak::SetCharRotation(int32_t iCharRotation) {
    158   if (iCharRotation < 0) {
    159     iCharRotation += (-iCharRotation / 4 + 1) * 4;
    160   } else if (iCharRotation > 3) {
    161     iCharRotation -= (iCharRotation / 4) * 4;
    162   }
    163   if (m_iCharRotation == iCharRotation) {
    164     return;
    165   }
    166   SetBreakStatus();
    167   m_iCharRotation = iCharRotation;
    168   m_iRotation = m_iLineRotation + m_iCharRotation;
    169   m_iRotation %= 4;
    170 }
    171 void CFX_TxtBreak::SetAlignment(int32_t iAlignment) {
    172   FXSYS_assert(iAlignment >= FX_TXTLINEALIGNMENT_Left &&
    173                iAlignment <= FX_TXTLINEALIGNMENT_Distributed);
    174   m_iAlignment = iAlignment;
    175   ResetArabicContext();
    176 }
    177 void CFX_TxtBreak::ResetContextCharStyles() {
    178   m_dwContextCharStyles = m_bArabicContext ? m_iCurAlignment : m_iAlignment;
    179   if (m_bArabicNumber) {
    180     m_dwContextCharStyles |= FX_TXTCHARSTYLE_ArabicNumber;
    181   }
    182   if (m_bArabicComma) {
    183     m_dwContextCharStyles |= FX_TXTCHARSTYLE_ArabicComma;
    184   }
    185   if ((m_bArabicContext && m_bCurRTL) || (!m_bArabicContext && m_bRTL)) {
    186     m_dwContextCharStyles |= FX_TXTCHARSTYLE_RTLReadingOrder;
    187   }
    188   m_dwContextCharStyles |= (m_iArabicContext << 8);
    189 }
    190 FX_DWORD CFX_TxtBreak::GetContextCharStyles() const {
    191   return m_dwContextCharStyles;
    192 }
    193 void CFX_TxtBreak::SetContextCharStyles(FX_DWORD dwCharStyles) {
    194   m_iCurAlignment = dwCharStyles & 0x0F;
    195   m_bArabicNumber = (dwCharStyles & FX_TXTCHARSTYLE_ArabicNumber) != 0;
    196   m_bArabicComma = (dwCharStyles & FX_TXTCHARSTYLE_ArabicComma) != 0;
    197   m_bCurRTL = (dwCharStyles & FX_TXTCHARSTYLE_RTLReadingOrder) != 0;
    198   m_iCurArabicContext = m_iArabicContext = ((dwCharStyles & 0x0300) >> 8);
    199   ResetContextCharStyles();
    200 }
    201 void CFX_TxtBreak::SetCombWidth(FX_FLOAT fCombWidth) {
    202   m_iCombWidth = FXSYS_round(fCombWidth * 20000.0f);
    203 }
    204 void CFX_TxtBreak::SetUserData(void* pUserData) {
    205   if (m_pUserData == pUserData) {
    206     return;
    207   }
    208   SetBreakStatus();
    209   m_pUserData = pUserData;
    210 }
    211 void CFX_TxtBreak::SetBreakStatus() {
    212   if (m_bPagination) {
    213     return;
    214   }
    215   int32_t iCount = m_pCurLine->CountChars();
    216   if (iCount < 1) {
    217     return;
    218   }
    219   CFX_TxtChar* pTC = (CFX_TxtChar*)m_pCurLine->GetCharPtr(iCount - 1);
    220   if (pTC->m_dwStatus == 0) {
    221     pTC->m_dwStatus = FX_TXTBREAK_PieceBreak;
    222   }
    223 }
    224 void CFX_TxtBreak::SetHorizontalScale(int32_t iScale) {
    225   if (iScale < 0) {
    226     iScale = 0;
    227   }
    228   if (iScale == m_iHorScale) {
    229     return;
    230   }
    231   SetBreakStatus();
    232   m_iHorScale = iScale;
    233 }
    234 void CFX_TxtBreak::SetVerticalScale(int32_t iScale) {
    235   if (iScale < 0) {
    236     iScale = 0;
    237   }
    238   if (iScale == m_iHorScale) {
    239     return;
    240   }
    241   SetBreakStatus();
    242   m_iVerScale = iScale;
    243 }
    244 void CFX_TxtBreak::SetCharSpace(FX_FLOAT fCharSpace) {
    245   m_iCharSpace = FXSYS_round(fCharSpace * 20000.0f);
    246 }
    247 static const int32_t gs_FX_TxtLineRotations[8] = {0, 3, 1, 0, 2, 1, 3, 2};
    248 int32_t CFX_TxtBreak::GetLineRotation(FX_DWORD dwStyles) const {
    249   return gs_FX_TxtLineRotations[(dwStyles & 0x0E) >> 1];
    250 }
    251 CFX_TxtChar* CFX_TxtBreak::GetLastChar(int32_t index, FX_BOOL bOmitChar) const {
    252   CFX_TxtCharArray& ca = *m_pCurLine->m_pLineChars;
    253   int32_t iCount = ca.GetSize();
    254   if (index < 0 || index >= iCount) {
    255     return NULL;
    256   }
    257   CFX_TxtChar* pTC;
    258   int32_t iStart = iCount - 1;
    259   while (iStart > -1) {
    260     pTC = ca.GetDataPtr(iStart--);
    261     if (bOmitChar && pTC->GetCharType() == FX_CHARTYPE_Combination) {
    262       continue;
    263     }
    264     if (--index < 0) {
    265       return pTC;
    266     }
    267   }
    268   return NULL;
    269 }
    270 CFX_TxtLine* CFX_TxtBreak::GetTxtLine(FX_BOOL bReady) const {
    271   if (!bReady) {
    272     return m_pCurLine;
    273   }
    274   if (m_iReady == 1) {
    275     return m_pTxtLine1;
    276   } else if (m_iReady == 2) {
    277     return m_pTxtLine2;
    278   } else {
    279     return NULL;
    280   }
    281 }
    282 CFX_TxtPieceArray* CFX_TxtBreak::GetTxtPieces(FX_BOOL bReady) const {
    283   CFX_TxtLine* pTxtLine = GetTxtLine(bReady);
    284   if (pTxtLine == NULL) {
    285     return NULL;
    286   }
    287   return pTxtLine->m_pLinePieces;
    288 }
    289 inline FX_DWORD CFX_TxtBreak::GetUnifiedCharType(FX_DWORD dwType) const {
    290   return dwType >= FX_CHARTYPE_ArabicAlef ? FX_CHARTYPE_Arabic : dwType;
    291 }
    292 void CFX_TxtBreak::ResetArabicContext() {
    293   if (m_bArabicContext) {
    294     m_bCurRTL = m_iCurArabicContext > 1;
    295     m_iCurAlignment = m_iCurArabicContext > 1 ? FX_TXTLINEALIGNMENT_Right
    296                                               : FX_TXTLINEALIGNMENT_Left;
    297     m_iCurAlignment |= (m_iAlignment & FX_TXTLINEALIGNMENT_HigherMask);
    298     m_bArabicNumber = m_iArabicContext >= 1 && m_bArabicShapes;
    299   } else {
    300     if (m_bPagination) {
    301       m_bCurRTL = FALSE;
    302       m_iCurAlignment = 0;
    303     } else {
    304       m_bCurRTL = m_bRTL;
    305       m_iCurAlignment = m_iAlignment;
    306     }
    307     if (m_bRTL) {
    308       m_bArabicNumber = m_iArabicContext >= 1;
    309     } else {
    310       m_bArabicNumber = m_iArabicContext > 1;
    311     }
    312     m_bArabicNumber = m_bArabicNumber && m_bArabicShapes;
    313   }
    314   m_bArabicComma = m_bArabicNumber;
    315   ResetContextCharStyles();
    316 }
    317 void CFX_TxtBreak::AppendChar_PageLoad(CFX_Char* pCurChar, FX_DWORD dwProps) {
    318   if (!m_bPagination) {
    319     ((CFX_TxtChar*)pCurChar)->m_dwStatus = 0;
    320     ((CFX_TxtChar*)pCurChar)->m_pUserData = m_pUserData;
    321   }
    322   if (m_bArabicContext || m_bArabicShapes) {
    323     int32_t iBidiCls = (dwProps & FX_BIDICLASSBITSMASK) >> FX_BIDICLASSBITS;
    324     int32_t iArabicContext =
    325         (iBidiCls == FX_BIDICLASS_R || iBidiCls == FX_BIDICLASS_AL)
    326             ? 2
    327             : ((iBidiCls == FX_BIDICLASS_L || iBidiCls == FX_BIDICLASS_S) ? 0
    328                                                                           : 1);
    329     if (iArabicContext != m_iArabicContext && iArabicContext != 1) {
    330       m_iArabicContext = iArabicContext;
    331       if (m_iCurArabicContext == 1) {
    332         m_iCurArabicContext = iArabicContext;
    333       }
    334       ResetArabicContext();
    335       if (!m_bPagination) {
    336         CFX_TxtChar* pLastChar = (CFX_TxtChar*)GetLastChar(1, FALSE);
    337         if (pLastChar != NULL && pLastChar->m_dwStatus < 1) {
    338           pLastChar->m_dwStatus = FX_TXTBREAK_PieceBreak;
    339         }
    340       }
    341     }
    342   }
    343   pCurChar->m_dwCharStyles = m_dwContextCharStyles;
    344 }
    345 FX_DWORD CFX_TxtBreak::AppendChar_Combination(CFX_Char* pCurChar,
    346                                               int32_t iRotation) {
    347   FXSYS_assert(pCurChar != NULL);
    348   FX_WCHAR wch = pCurChar->m_wCharCode;
    349   FX_WCHAR wForm;
    350   int32_t iCharWidth = 0;
    351   CFX_Char* pLastChar;
    352   pCurChar->m_iCharWidth = -1;
    353   if (m_bCombText) {
    354     iCharWidth = m_iCombWidth;
    355   } else {
    356     if (m_bVertical != FX_IsOdd(iRotation)) {
    357       iCharWidth = 1000;
    358     } else {
    359       wForm = wch;
    360       if (!m_bPagination) {
    361         pLastChar = GetLastChar(0, FALSE);
    362         if (pLastChar != NULL &&
    363             (((CFX_TxtChar*)pLastChar)->m_dwCharStyles &
    364              FX_TXTCHARSTYLE_ArabicShadda) == 0) {
    365           FX_BOOL bShadda = FALSE;
    366           if (wch == 0x0651) {
    367             FX_WCHAR wLast = pLastChar->m_wCharCode;
    368             if (wLast >= 0x064C && wLast <= 0x0650) {
    369               wForm = FX_GetArabicFromShaddaTable(wLast);
    370               bShadda = TRUE;
    371             }
    372           } else if (wch >= 0x064C && wch <= 0x0650) {
    373             if (pLastChar->m_wCharCode == 0x0651) {
    374               wForm = FX_GetArabicFromShaddaTable(wch);
    375               bShadda = TRUE;
    376             }
    377           }
    378           if (bShadda) {
    379             ((CFX_TxtChar*)pLastChar)->m_dwCharStyles |=
    380                 FX_TXTCHARSTYLE_ArabicShadda;
    381             ((CFX_TxtChar*)pLastChar)->m_iCharWidth = 0;
    382             ((CFX_TxtChar*)pCurChar)->m_dwCharStyles |=
    383                 FX_TXTCHARSTYLE_ArabicShadda;
    384           }
    385         }
    386       }
    387       if (!m_pFont->GetCharWidth(wForm, iCharWidth, FALSE)) {
    388         iCharWidth = 0;
    389       }
    390     }
    391     iCharWidth *= m_iFontSize;
    392     iCharWidth = iCharWidth * m_iHorScale / 100;
    393   }
    394   pCurChar->m_iCharWidth = -iCharWidth;
    395   return FX_TXTBREAK_None;
    396 }
    397 FX_DWORD CFX_TxtBreak::AppendChar_Tab(CFX_Char* pCurChar, int32_t iRotation) {
    398   m_dwCharType = FX_CHARTYPE_Tab;
    399   if ((m_dwLayoutStyles & FX_TXTLAYOUTSTYLE_ExpandTab) == 0) {
    400     return FX_TXTBREAK_None;
    401   }
    402   int32_t& iLineWidth = m_pCurLine->m_iWidth;
    403   int32_t iCharWidth;
    404   if (m_bCombText) {
    405     iCharWidth = m_iCombWidth;
    406   } else {
    407     if (m_bEquidistant) {
    408       iCharWidth = iLineWidth;
    409       iCharWidth = m_iTabWidth * (iCharWidth / m_iTabWidth + 1) - iCharWidth;
    410       if (iCharWidth < FX_TXTBREAK_MinimumTabWidth) {
    411         iCharWidth += m_iTabWidth;
    412       }
    413     } else {
    414       iCharWidth = m_iTabWidth;
    415     }
    416   }
    417   pCurChar->m_iCharWidth = iCharWidth;
    418   iLineWidth += iCharWidth;
    419   if (!m_bSingleLine && iLineWidth >= m_iLineWidth + m_iTolerance) {
    420     return EndBreak(FX_TXTBREAK_LineBreak);
    421   }
    422   return FX_TXTBREAK_None;
    423 }
    424 FX_DWORD CFX_TxtBreak::AppendChar_Control(CFX_Char* pCurChar,
    425                                           int32_t iRotation) {
    426   m_dwCharType = FX_CHARTYPE_Control;
    427   FX_DWORD dwRet = FX_TXTBREAK_None;
    428   if (!m_bSingleLine) {
    429     FX_WCHAR wch = pCurChar->m_wCharCode;
    430     switch (wch) {
    431       case L'\v':
    432       case 0x2028:
    433         dwRet = FX_TXTBREAK_LineBreak;
    434         break;
    435       case L'\f':
    436         dwRet = FX_TXTBREAK_PageBreak;
    437         break;
    438       case 0x2029:
    439         dwRet = FX_TXTBREAK_ParagraphBreak;
    440         break;
    441       default:
    442         if (wch == m_wParagBreakChar) {
    443           dwRet = FX_TXTBREAK_ParagraphBreak;
    444         }
    445         break;
    446     }
    447     if (dwRet != FX_TXTBREAK_None) {
    448       dwRet = EndBreak(dwRet);
    449     }
    450   }
    451   return dwRet;
    452 }
    453 FX_DWORD CFX_TxtBreak::AppendChar_Arabic(CFX_Char* pCurChar,
    454                                          int32_t iRotation) {
    455   FX_DWORD dwType = (pCurChar->m_dwCharProps & FX_CHARTYPEBITSMASK);
    456   int32_t& iLineWidth = m_pCurLine->m_iWidth;
    457   FX_WCHAR wForm;
    458   int32_t iCharWidth = 0;
    459   CFX_Char* pLastChar = NULL;
    460   FX_BOOL bAlef = FALSE;
    461   if (!m_bCombText && m_dwCharType >= FX_CHARTYPE_ArabicAlef &&
    462       m_dwCharType <= FX_CHARTYPE_ArabicDistortion) {
    463     pLastChar = GetLastChar(1);
    464     if (pLastChar != NULL) {
    465       iCharWidth = pLastChar->m_iCharWidth;
    466       if (iCharWidth > 0) {
    467         iLineWidth -= iCharWidth;
    468       }
    469       CFX_Char* pPrevChar = GetLastChar(2);
    470       wForm = m_pArabicChar->GetFormChar(pLastChar, pPrevChar, pCurChar);
    471       bAlef = (wForm == 0xFEFF &&
    472                pLastChar->GetCharType() == FX_CHARTYPE_ArabicAlef);
    473       int32_t iLastRotation = pLastChar->m_nRotation + m_iLineRotation;
    474       if (m_bVertical && (pLastChar->m_dwCharProps & 0x8000) != 0) {
    475         iLastRotation++;
    476       }
    477       if (m_bVertical != FX_IsOdd(iLastRotation)) {
    478         iCharWidth = 1000;
    479       } else {
    480         m_pFont->GetCharWidth(wForm, iCharWidth, FALSE);
    481       }
    482       if (wForm == 0xFEFF) {
    483         iCharWidth = m_iDefChar;
    484       }
    485       iCharWidth *= m_iFontSize;
    486       iCharWidth = iCharWidth * m_iHorScale / 100;
    487       pLastChar->m_iCharWidth = iCharWidth;
    488       iLineWidth += iCharWidth;
    489       iCharWidth = 0;
    490     }
    491   }
    492   m_dwCharType = dwType;
    493   wForm = m_pArabicChar->GetFormChar(pCurChar, bAlef ? NULL : pLastChar, NULL);
    494   if (m_bCombText) {
    495     iCharWidth = m_iCombWidth;
    496   } else {
    497     if (m_bVertical != FX_IsOdd(iRotation)) {
    498       iCharWidth = 1000;
    499     } else {
    500       m_pFont->GetCharWidth(wForm, iCharWidth, FALSE);
    501     }
    502     if (wForm == 0xFEFF) {
    503       iCharWidth = m_iDefChar;
    504     }
    505     iCharWidth *= m_iFontSize;
    506     iCharWidth = iCharWidth * m_iHorScale / 100;
    507   }
    508   pCurChar->m_iCharWidth = iCharWidth;
    509   iLineWidth += iCharWidth;
    510   m_pCurLine->m_iArabicChars++;
    511   if (!m_bSingleLine && iLineWidth > m_iLineWidth + m_iTolerance) {
    512     return EndBreak(FX_TXTBREAK_LineBreak);
    513   }
    514   return FX_TXTBREAK_None;
    515 }
    516 FX_DWORD CFX_TxtBreak::AppendChar_Others(CFX_Char* pCurChar,
    517                                          int32_t iRotation) {
    518   FX_DWORD dwProps = pCurChar->m_dwCharProps;
    519   FX_DWORD dwType = (dwProps & FX_CHARTYPEBITSMASK);
    520   int32_t& iLineWidth = m_pCurLine->m_iWidth;
    521   int32_t iCharWidth = 0;
    522   m_dwCharType = dwType;
    523   FX_WCHAR wch = pCurChar->m_wCharCode;
    524   FX_WCHAR wForm = wch;
    525   if (dwType == FX_CHARTYPE_Numeric) {
    526     if (m_bArabicNumber) {
    527       wForm = wch + 0x0630;
    528       pCurChar->m_dwCharStyles |= FX_TXTCHARSTYLE_ArabicIndic;
    529     }
    530   } else if (wch == L',') {
    531     if (m_bArabicShapes && m_iCurArabicContext > 0) {
    532       wForm = 0x060C;
    533       pCurChar->m_dwCharStyles |= FX_TXTCHARSTYLE_ArabicComma;
    534     }
    535   } else if (m_bCurRTL || m_bVertical) {
    536     wForm = FX_GetMirrorChar(wch, dwProps, m_bCurRTL, m_bVertical);
    537   }
    538   if (m_bCombText) {
    539     iCharWidth = m_iCombWidth;
    540   } else {
    541     if (m_bVertical != FX_IsOdd(iRotation)) {
    542       iCharWidth = 1000;
    543     } else if (!m_pFont->GetCharWidth(wForm, iCharWidth, FALSE)) {
    544       iCharWidth = m_iDefChar;
    545     }
    546     iCharWidth *= m_iFontSize;
    547     iCharWidth = iCharWidth * m_iHorScale / 100;
    548   }
    549   iCharWidth += m_iCharSpace;
    550   pCurChar->m_iCharWidth = iCharWidth;
    551   iLineWidth += iCharWidth;
    552   FX_BOOL bBreak = (dwType != FX_CHARTYPE_Space ||
    553                     (m_dwPolicies & FX_TXTBREAKPOLICY_SpaceBreak) != 0);
    554   if (!m_bSingleLine && bBreak && iLineWidth > m_iLineWidth + m_iTolerance) {
    555     return EndBreak(FX_TXTBREAK_LineBreak);
    556   }
    557   return FX_TXTBREAK_None;
    558 }
    559 typedef FX_DWORD (CFX_TxtBreak::*FX_TxtBreak_LPFAppendChar)(CFX_Char* pCurChar,
    560                                                             int32_t iRotation);
    561 static const FX_TxtBreak_LPFAppendChar g_FX_TxtBreak_lpfAppendChar[16] = {
    562     &CFX_TxtBreak::AppendChar_Others,      &CFX_TxtBreak::AppendChar_Tab,
    563     &CFX_TxtBreak::AppendChar_Others,      &CFX_TxtBreak::AppendChar_Control,
    564     &CFX_TxtBreak::AppendChar_Combination, &CFX_TxtBreak::AppendChar_Others,
    565     &CFX_TxtBreak::AppendChar_Others,      &CFX_TxtBreak::AppendChar_Arabic,
    566     &CFX_TxtBreak::AppendChar_Arabic,      &CFX_TxtBreak::AppendChar_Arabic,
    567     &CFX_TxtBreak::AppendChar_Arabic,      &CFX_TxtBreak::AppendChar_Arabic,
    568     &CFX_TxtBreak::AppendChar_Arabic,      &CFX_TxtBreak::AppendChar_Others,
    569     &CFX_TxtBreak::AppendChar_Others,      &CFX_TxtBreak::AppendChar_Others,
    570 };
    571 FX_DWORD CFX_TxtBreak::AppendChar(FX_WCHAR wch) {
    572   FX_DWORD dwProps = kTextLayoutCodeProperties[(FX_WORD)wch];
    573   FX_DWORD dwType = (dwProps & FX_CHARTYPEBITSMASK);
    574   CFX_TxtChar* pCurChar = m_pCurLine->m_pLineChars->AddSpace();
    575   pCurChar->m_wCharCode = (FX_WORD)wch;
    576   pCurChar->m_nRotation = m_iCharRotation;
    577   pCurChar->m_dwCharProps = dwProps;
    578   pCurChar->m_dwCharStyles = 0;
    579   pCurChar->m_iCharWidth = 0;
    580   pCurChar->m_iHorizontalScale = m_iHorScale;
    581   pCurChar->m_iVertialScale = m_iVerScale;
    582   pCurChar->m_dwStatus = 0;
    583   pCurChar->m_iBidiClass = 0;
    584   pCurChar->m_iBidiLevel = 0;
    585   pCurChar->m_iBidiPos = 0;
    586   pCurChar->m_iBidiOrder = 0;
    587   pCurChar->m_pUserData = NULL;
    588   AppendChar_PageLoad(pCurChar, dwProps);
    589   FX_DWORD dwRet1 = FX_TXTBREAK_None;
    590   if (dwType != FX_CHARTYPE_Combination &&
    591       GetUnifiedCharType(m_dwCharType) != GetUnifiedCharType(dwType)) {
    592     if (m_dwCharType > 0 &&
    593         m_pCurLine->m_iWidth > m_iLineWidth + m_iTolerance && !m_bSingleLine) {
    594       if (m_dwCharType != FX_CHARTYPE_Space || dwType != FX_CHARTYPE_Control) {
    595         dwRet1 = EndBreak(FX_TXTBREAK_LineBreak);
    596         int32_t iCount = m_pCurLine->CountChars();
    597         if (iCount > 0) {
    598           pCurChar = m_pCurLine->m_pLineChars->GetDataPtr(iCount - 1);
    599         }
    600       }
    601     }
    602   }
    603   int32_t iRotation = m_iRotation;
    604   if (m_bVertical && (dwProps & 0x8000) != 0) {
    605     iRotation = (iRotation + 1) % 4;
    606   }
    607   FX_DWORD dwRet2 =
    608       (this->*g_FX_TxtBreak_lpfAppendChar[dwType >> FX_CHARTYPEBITS])(
    609           pCurChar, iRotation);
    610   return std::max(dwRet1, dwRet2);
    611 }
    612 void CFX_TxtBreak::EndBreak_UpdateArabicShapes() {
    613   FXSYS_assert(m_bArabicShapes);
    614   int32_t iCount = m_pCurLine->CountChars();
    615   if (iCount < 2) {
    616     return;
    617   }
    618   int32_t& iLineWidth = m_pCurLine->m_iWidth;
    619   CFX_Char *pCur, *pNext;
    620   pCur = m_pCurLine->GetCharPtr(0);
    621   FX_BOOL bPrevNum = (pCur->m_dwCharStyles & FX_TXTCHARSTYLE_ArabicIndic) != 0;
    622   pCur = m_pCurLine->GetCharPtr(1);
    623   FX_WCHAR wch, wForm;
    624   FX_BOOL bNextNum;
    625   int32_t i = 1, iCharWidth, iRotation;
    626   do {
    627     i++;
    628     if (i < iCount) {
    629       pNext = m_pCurLine->GetCharPtr(i);
    630       bNextNum = (pNext->m_dwCharStyles & FX_TXTCHARSTYLE_ArabicIndic) != 0;
    631     } else {
    632       pNext = NULL;
    633       bNextNum = FALSE;
    634     }
    635     wch = pCur->m_wCharCode;
    636     if (wch == L'.') {
    637       if (bPrevNum && bNextNum) {
    638         iRotation = m_iRotation;
    639         if (m_bVertical && (pCur->m_dwCharProps & 0x8000) != 0) {
    640           iRotation = ((iRotation + 1) & 0x03);
    641         }
    642         wForm = wch == L'.' ? 0x066B : 0x066C;
    643         iLineWidth -= pCur->m_iCharWidth;
    644         if (m_bCombText) {
    645           iCharWidth = m_iCombWidth;
    646         } else {
    647           if (m_bVertical != FX_IsOdd(iRotation)) {
    648             iCharWidth = 1000;
    649           } else if (!m_pFont->GetCharWidth(wForm, iCharWidth, FALSE)) {
    650             iCharWidth = m_iDefChar;
    651           }
    652           iCharWidth *= m_iFontSize;
    653           iCharWidth = iCharWidth * m_iHorScale / 100;
    654         }
    655         pCur->m_iCharWidth = iCharWidth;
    656         iLineWidth += iCharWidth;
    657       }
    658     }
    659     bPrevNum = (pCur->m_dwCharStyles & FX_TXTCHARSTYLE_ArabicIndic) != 0;
    660     pCur = pNext;
    661   } while (i < iCount);
    662 }
    663 FX_BOOL CFX_TxtBreak::EndBreak_SplitLine(CFX_TxtLine* pNextLine,
    664                                          FX_BOOL bAllChars,
    665                                          FX_DWORD dwStatus) {
    666   int32_t iCount = m_pCurLine->CountChars();
    667   FX_BOOL bDone = FALSE;
    668   CFX_Char* pTC;
    669   if (!m_bSingleLine && m_pCurLine->m_iWidth > m_iLineWidth + m_iTolerance) {
    670     pTC = m_pCurLine->GetCharPtr(iCount - 1);
    671     switch (pTC->GetCharType()) {
    672       case FX_CHARTYPE_Tab:
    673       case FX_CHARTYPE_Control:
    674         break;
    675       case FX_CHARTYPE_Space:
    676         if ((m_dwPolicies & FX_TXTBREAKPOLICY_SpaceBreak) != 0) {
    677           SplitTextLine(m_pCurLine, pNextLine, !m_bPagination && bAllChars);
    678           bDone = TRUE;
    679         }
    680         break;
    681       default:
    682         SplitTextLine(m_pCurLine, pNextLine, !m_bPagination && bAllChars);
    683         bDone = TRUE;
    684         break;
    685     }
    686   }
    687   iCount = m_pCurLine->CountChars();
    688   CFX_TxtPieceArray* pCurPieces = m_pCurLine->m_pLinePieces;
    689   CFX_TxtPiece tp;
    690   if (m_bPagination) {
    691     tp.m_dwStatus = dwStatus;
    692     tp.m_iStartPos = m_pCurLine->m_iStart;
    693     tp.m_iWidth = m_pCurLine->m_iWidth;
    694     tp.m_iStartChar = 0;
    695     tp.m_iChars = iCount;
    696     tp.m_pChars = m_pCurLine->m_pLineChars;
    697     tp.m_pUserData = m_pUserData;
    698     pTC = m_pCurLine->GetCharPtr(0);
    699     tp.m_dwCharStyles = pTC->m_dwCharStyles;
    700     tp.m_iHorizontalScale = pTC->m_iHorizontalScale;
    701     tp.m_iVerticalScale = pTC->m_iVertialScale;
    702     pCurPieces->Add(tp);
    703     m_pCurLine = pNextLine;
    704     m_dwCharType = 0;
    705     return TRUE;
    706   }
    707   if (bAllChars && !bDone) {
    708     int32_t iEndPos = m_pCurLine->m_iWidth;
    709     GetBreakPos(*m_pCurLine->m_pLineChars, iEndPos, bAllChars, TRUE);
    710   }
    711   return FALSE;
    712 }
    713 void CFX_TxtBreak::EndBreak_BidiLine(CFX_TPOArray& tpos, FX_DWORD dwStatus) {
    714   CFX_TxtPiece tp;
    715   FX_TPO tpo;
    716   CFX_TxtChar* pTC;
    717   int32_t i, j;
    718   CFX_TxtCharArray& chars = *m_pCurLine->m_pLineChars;
    719   int32_t iCount = m_pCurLine->CountChars();
    720   FX_BOOL bDone = (m_pCurLine->m_iArabicChars > 0 || m_bCurRTL);
    721   if (!m_bPagination && bDone) {
    722     int32_t iBidiNum = 0;
    723     for (i = 0; i < iCount; i++) {
    724       pTC = chars.GetDataPtr(i);
    725       pTC->m_iBidiPos = i;
    726       if (pTC->GetCharType() != FX_CHARTYPE_Control) {
    727         iBidiNum = i;
    728       }
    729       if (i == 0) {
    730         pTC->m_iBidiLevel = 1;
    731       }
    732     }
    733     FX_BidiLine(chars, iBidiNum + 1, m_bCurRTL ? 1 : 0);
    734   }
    735   CFX_TxtPieceArray* pCurPieces = m_pCurLine->m_pLinePieces;
    736   if (!m_bPagination &&
    737       (bDone || (m_dwLayoutStyles & FX_TXTLAYOUTSTYLE_MutipleFormat) != 0)) {
    738     tp.m_dwStatus = FX_TXTBREAK_PieceBreak;
    739     tp.m_iStartPos = m_pCurLine->m_iStart;
    740     tp.m_pChars = m_pCurLine->m_pLineChars;
    741     int32_t iBidiLevel = -1, iCharWidth;
    742     i = 0, j = -1;
    743     while (i < iCount) {
    744       pTC = chars.GetDataPtr(i);
    745       if (iBidiLevel < 0) {
    746         iBidiLevel = pTC->m_iBidiLevel;
    747         tp.m_iWidth = 0;
    748         tp.m_iBidiLevel = iBidiLevel;
    749         tp.m_iBidiPos = pTC->m_iBidiOrder;
    750         tp.m_dwCharStyles = pTC->m_dwCharStyles;
    751         tp.m_pUserData = pTC->m_pUserData;
    752         tp.m_iHorizontalScale = pTC->m_iHorizontalScale;
    753         tp.m_iVerticalScale = pTC->m_iVertialScale;
    754         tp.m_dwStatus = FX_TXTBREAK_PieceBreak;
    755       }
    756       if (iBidiLevel != pTC->m_iBidiLevel || pTC->m_dwStatus != 0) {
    757         if (iBidiLevel == pTC->m_iBidiLevel) {
    758           tp.m_dwStatus = pTC->m_dwStatus;
    759           iCharWidth = pTC->m_iCharWidth;
    760           if (iCharWidth > 0) {
    761             tp.m_iWidth += iCharWidth;
    762           }
    763           i++;
    764         }
    765         tp.m_iChars = i - tp.m_iStartChar;
    766         pCurPieces->Add(tp);
    767         tp.m_iStartPos += tp.m_iWidth;
    768         tp.m_iStartChar = i;
    769         tpo.index = ++j;
    770         tpo.pos = tp.m_iBidiPos;
    771         tpos.Add(tpo);
    772         iBidiLevel = -1;
    773       } else {
    774         iCharWidth = pTC->m_iCharWidth;
    775         if (iCharWidth > 0) {
    776           tp.m_iWidth += iCharWidth;
    777         }
    778         i++;
    779       }
    780     }
    781     if (i > tp.m_iStartChar) {
    782       tp.m_dwStatus = dwStatus;
    783       tp.m_iChars = i - tp.m_iStartChar;
    784       pCurPieces->Add(tp);
    785       tpo.index = ++j;
    786       tpo.pos = tp.m_iBidiPos;
    787       tpos.Add(tpo);
    788     }
    789     if (j > -1) {
    790       if (j > 0) {
    791         FX_TEXTLAYOUT_PieceSort(tpos, 0, j);
    792         int32_t iStartPos = 0;
    793         for (i = 0; i <= j; i++) {
    794           tpo = tpos.GetAt(i);
    795           CFX_TxtPiece& ttp = pCurPieces->GetAt(tpo.index);
    796           ttp.m_iStartPos = iStartPos;
    797           iStartPos += ttp.m_iWidth;
    798         }
    799       }
    800       CFX_TxtPiece& ttp = pCurPieces->GetAt(j);
    801       ttp.m_dwStatus = dwStatus;
    802     }
    803   } else {
    804     tp.m_dwStatus = dwStatus;
    805     tp.m_iStartPos = m_pCurLine->m_iStart;
    806     tp.m_iWidth = m_pCurLine->m_iWidth;
    807     tp.m_iStartChar = 0;
    808     tp.m_iChars = iCount;
    809     tp.m_pChars = m_pCurLine->m_pLineChars;
    810     tp.m_pUserData = m_pUserData;
    811     pTC = chars.GetDataPtr(0);
    812     tp.m_dwCharStyles = pTC->m_dwCharStyles;
    813     tp.m_iHorizontalScale = pTC->m_iHorizontalScale;
    814     tp.m_iVerticalScale = pTC->m_iVertialScale;
    815     pCurPieces->Add(tp);
    816     tpo.index = 0;
    817     tpo.pos = 0;
    818     tpos.Add(tpo);
    819   }
    820 }
    821 void CFX_TxtBreak::EndBreak_Alignment(CFX_TPOArray& tpos,
    822                                       FX_BOOL bAllChars,
    823                                       FX_DWORD dwStatus) {
    824   int32_t iNetWidth = m_pCurLine->m_iWidth, iGapChars = 0, iCharWidth;
    825   CFX_TxtPieceArray* pCurPieces = m_pCurLine->m_pLinePieces;
    826   int32_t i, j, iCount = pCurPieces->GetSize();
    827   FX_BOOL bFind = FALSE;
    828   FX_TPO tpo;
    829   CFX_TxtChar* pTC;
    830   FX_DWORD dwCharType;
    831   for (i = iCount - 1; i > -1; i--) {
    832     tpo = tpos.GetAt(i);
    833     CFX_TxtPiece& ttp = pCurPieces->GetAt(tpo.index);
    834     if (!bFind) {
    835       iNetWidth = ttp.GetEndPos();
    836     }
    837     FX_BOOL bArabic = FX_IsOdd(ttp.m_iBidiLevel);
    838     j = bArabic ? 0 : ttp.m_iChars - 1;
    839     while (j > -1 && j < ttp.m_iChars) {
    840       pTC = ttp.GetCharPtr(j);
    841       if (pTC->m_nBreakType == FX_LBT_DIRECT_BRK) {
    842         iGapChars++;
    843       }
    844       if (!bFind || !bAllChars) {
    845         dwCharType = pTC->GetCharType();
    846         if (dwCharType == FX_CHARTYPE_Space ||
    847             dwCharType == FX_CHARTYPE_Control) {
    848           if (!bFind) {
    849             iCharWidth = pTC->m_iCharWidth;
    850             if (bAllChars && iCharWidth > 0) {
    851               iNetWidth -= iCharWidth;
    852             }
    853           }
    854         } else {
    855           bFind = TRUE;
    856           if (!bAllChars) {
    857             break;
    858           }
    859         }
    860       }
    861       j += bArabic ? 1 : -1;
    862     }
    863     if (!bAllChars && bFind) {
    864       break;
    865     }
    866   }
    867   int32_t iOffset = m_iLineWidth - iNetWidth;
    868   int32_t iLowerAlignment = (m_iCurAlignment & FX_TXTLINEALIGNMENT_LowerMask);
    869   int32_t iHigherAlignment = (m_iCurAlignment & FX_TXTLINEALIGNMENT_HigherMask);
    870   if (iGapChars > 0 && (iHigherAlignment == FX_TXTLINEALIGNMENT_Distributed ||
    871                         (iHigherAlignment == FX_TXTLINEALIGNMENT_Justified &&
    872                          dwStatus != FX_TXTBREAK_ParagraphBreak))) {
    873     int32_t iStart = -1;
    874     for (i = 0; i < iCount; i++) {
    875       tpo = tpos.GetAt(i);
    876       CFX_TxtPiece& ttp = pCurPieces->GetAt(tpo.index);
    877       if (iStart < -1) {
    878         iStart = ttp.m_iStartPos;
    879       } else {
    880         ttp.m_iStartPos = iStart;
    881       }
    882       int32_t k;
    883       for (j = 0; j < ttp.m_iChars; j++) {
    884         pTC = ttp.GetCharPtr(j);
    885         if (pTC->m_nBreakType != FX_LBT_DIRECT_BRK || pTC->m_iCharWidth < 0) {
    886           continue;
    887         }
    888         k = iOffset / iGapChars;
    889         pTC->m_iCharWidth += k;
    890         ttp.m_iWidth += k;
    891         iOffset -= k;
    892         iGapChars--;
    893         if (iGapChars < 1) {
    894           break;
    895         }
    896       }
    897       iStart += ttp.m_iWidth;
    898     }
    899   } else if (iLowerAlignment > FX_TXTLINEALIGNMENT_Left) {
    900     if (iLowerAlignment == FX_TXTLINEALIGNMENT_Center) {
    901       iOffset /= 2;
    902     }
    903     if (iOffset > 0) {
    904       for (i = 0; i < iCount; i++) {
    905         CFX_TxtPiece& ttp = pCurPieces->GetAt(i);
    906         ttp.m_iStartPos += iOffset;
    907       }
    908     }
    909   }
    910 }
    911 FX_DWORD CFX_TxtBreak::EndBreak(FX_DWORD dwStatus) {
    912   FXSYS_assert(dwStatus >= FX_TXTBREAK_PieceBreak &&
    913                dwStatus <= FX_TXTBREAK_PageBreak);
    914   CFX_TxtPieceArray* pCurPieces = m_pCurLine->m_pLinePieces;
    915   int32_t iCount = pCurPieces->GetSize();
    916   if (iCount > 0) {
    917     CFX_TxtPiece* pLastPiece = pCurPieces->GetPtrAt(--iCount);
    918     if (dwStatus > FX_TXTBREAK_PieceBreak) {
    919       pLastPiece->m_dwStatus = dwStatus;
    920     } else {
    921       dwStatus = pLastPiece->m_dwStatus;
    922     }
    923     return dwStatus;
    924   } else {
    925     CFX_TxtLine* pLastLine = GetTxtLine(TRUE);
    926     if (pLastLine != NULL) {
    927       pCurPieces = pLastLine->m_pLinePieces;
    928       iCount = pCurPieces->GetSize();
    929       if (iCount-- > 0) {
    930         CFX_TxtPiece* pLastPiece = pCurPieces->GetPtrAt(iCount);
    931         if (dwStatus > FX_TXTBREAK_PieceBreak) {
    932           pLastPiece->m_dwStatus = dwStatus;
    933         } else {
    934           dwStatus = pLastPiece->m_dwStatus;
    935         }
    936         return dwStatus;
    937       }
    938       return FX_TXTBREAK_None;
    939     }
    940     iCount = m_pCurLine->CountChars();
    941     if (iCount < 1) {
    942       return FX_TXTBREAK_None;
    943     }
    944     if (!m_bPagination) {
    945       CFX_TxtChar* pTC = m_pCurLine->GetCharPtr(iCount - 1);
    946       pTC->m_dwStatus = dwStatus;
    947     }
    948     if (dwStatus <= FX_TXTBREAK_PieceBreak) {
    949       return dwStatus;
    950     }
    951   }
    952   m_iReady = (m_pCurLine == m_pTxtLine1) ? 1 : 2;
    953   CFX_TxtLine* pNextLine =
    954       (m_pCurLine == m_pTxtLine1) ? m_pTxtLine2 : m_pTxtLine1;
    955   FX_BOOL bAllChars = (m_iCurAlignment > FX_TXTLINEALIGNMENT_Right);
    956   CFX_TPOArray tpos;
    957   CFX_Char* pTC;
    958   if (m_bArabicShapes) {
    959     EndBreak_UpdateArabicShapes();
    960   }
    961   if (EndBreak_SplitLine(pNextLine, bAllChars, dwStatus)) {
    962     goto EndBreak_Ret;
    963   }
    964   EndBreak_BidiLine(tpos, dwStatus);
    965   if (!m_bPagination && m_iCurAlignment > FX_TXTLINEALIGNMENT_Left) {
    966     EndBreak_Alignment(tpos, bAllChars, dwStatus);
    967   }
    968 EndBreak_Ret:
    969   m_pCurLine = pNextLine;
    970   pTC = GetLastChar(0, FALSE);
    971   m_dwCharType = pTC == NULL ? 0 : pTC->GetCharType();
    972   if (dwStatus == FX_TXTBREAK_ParagraphBreak) {
    973     m_iArabicContext = m_iCurArabicContext = 1;
    974     ResetArabicContext();
    975   }
    976   return dwStatus;
    977 }
    978 int32_t CFX_TxtBreak::GetBreakPos(CFX_TxtCharArray& ca,
    979                                   int32_t& iEndPos,
    980                                   FX_BOOL bAllChars,
    981                                   FX_BOOL bOnlyBrk) {
    982   int32_t iLength = ca.GetSize() - 1;
    983   if (iLength < 1) {
    984     return iLength;
    985   }
    986   int32_t iBreak = -1, iBreakPos = -1, iIndirect = -1, iIndirectPos = -1,
    987           iLast = -1, iLastPos = -1;
    988   if (m_bSingleLine || iEndPos <= m_iLineWidth) {
    989     if (!bAllChars) {
    990       return iLength;
    991     }
    992     iBreak = iLength;
    993     iBreakPos = iEndPos;
    994   }
    995   FX_BOOL bSpaceBreak = (m_dwPolicies & FX_TXTBREAKPOLICY_SpaceBreak) != 0;
    996   FX_BOOL bNumberBreak = (m_dwPolicies & FX_TXTBREAKPOLICY_NumberBreak) != 0;
    997   FX_LINEBREAKTYPE eType;
    998   FX_DWORD nCodeProp, nCur, nNext;
    999   CFX_Char* pCur = ca.GetDataPtr(iLength--);
   1000   if (bAllChars) {
   1001     pCur->m_nBreakType = FX_LBT_UNKNOWN;
   1002   }
   1003   nCodeProp = pCur->m_dwCharProps;
   1004   nNext = nCodeProp & 0x003F;
   1005   int32_t iCharWidth = pCur->m_iCharWidth;
   1006   if (iCharWidth > 0) {
   1007     iEndPos -= iCharWidth;
   1008   }
   1009   while (iLength >= 0) {
   1010     pCur = ca.GetDataPtr(iLength);
   1011     nCodeProp = pCur->m_dwCharProps;
   1012     nCur = nCodeProp & 0x003F;
   1013     if (nCur == FX_CBP_SP) {
   1014       if (nNext == FX_CBP_SP) {
   1015         eType = bSpaceBreak ? FX_LBT_DIRECT_BRK : FX_LBT_PROHIBITED_BRK;
   1016       } else {
   1017         eType = *((const FX_LINEBREAKTYPE*)gs_FX_LineBreak_PairTable +
   1018                   (nCur << 5) + nNext);
   1019       }
   1020     } else if (bNumberBreak && nCur == FX_CBP_NU && nNext == FX_CBP_NU) {
   1021       eType = FX_LBT_DIRECT_BRK;
   1022     } else {
   1023       if (nNext == FX_CBP_SP) {
   1024         eType = FX_LBT_PROHIBITED_BRK;
   1025       } else {
   1026         eType = *((const FX_LINEBREAKTYPE*)gs_FX_LineBreak_PairTable +
   1027                   (nCur << 5) + nNext);
   1028       }
   1029     }
   1030     if (bAllChars) {
   1031       pCur->m_nBreakType = (uint8_t)eType;
   1032     }
   1033     if (!bOnlyBrk) {
   1034       if (m_bSingleLine || iEndPos <= m_iLineWidth ||
   1035           (nCur == FX_CBP_SP && !bSpaceBreak)) {
   1036         if (eType == FX_LBT_DIRECT_BRK && iBreak < 0) {
   1037           iBreak = iLength;
   1038           iBreakPos = iEndPos;
   1039           if (!bAllChars) {
   1040             return iLength;
   1041           }
   1042         } else if (eType == FX_LBT_INDIRECT_BRK && iIndirect < 0) {
   1043           iIndirect = iLength;
   1044           iIndirectPos = iEndPos;
   1045         }
   1046         if (iLast < 0) {
   1047           iLast = iLength;
   1048           iLastPos = iEndPos;
   1049         }
   1050       }
   1051       iCharWidth = pCur->m_iCharWidth;
   1052       if (iCharWidth > 0) {
   1053         iEndPos -= iCharWidth;
   1054       }
   1055     }
   1056     nNext = nCodeProp & 0x003F;
   1057     iLength--;
   1058   }
   1059   if (bOnlyBrk) {
   1060     return 0;
   1061   }
   1062   if (iBreak > -1) {
   1063     iEndPos = iBreakPos;
   1064     return iBreak;
   1065   }
   1066   if (iIndirect > -1) {
   1067     iEndPos = iIndirectPos;
   1068     return iIndirect;
   1069   }
   1070   if (iLast > -1) {
   1071     iEndPos = iLastPos;
   1072     return iLast;
   1073   }
   1074   return 0;
   1075 }
   1076 void CFX_TxtBreak::SplitTextLine(CFX_TxtLine* pCurLine,
   1077                                  CFX_TxtLine* pNextLine,
   1078                                  FX_BOOL bAllChars) {
   1079   FXSYS_assert(pCurLine != NULL && pNextLine != NULL);
   1080   int32_t iCount = pCurLine->CountChars();
   1081   if (iCount < 2) {
   1082     return;
   1083   }
   1084   int32_t iEndPos = pCurLine->m_iWidth;
   1085   CFX_TxtCharArray& curChars = *pCurLine->m_pLineChars;
   1086   int32_t iCharPos = GetBreakPos(curChars, iEndPos, bAllChars, FALSE);
   1087   if (iCharPos < 0) {
   1088     iCharPos = 0;
   1089   }
   1090   iCharPos++;
   1091   if (iCharPos >= iCount) {
   1092     pNextLine->RemoveAll(TRUE);
   1093     CFX_Char* pTC = curChars.GetDataPtr(iCharPos - 1);
   1094     pTC->m_nBreakType = FX_LBT_UNKNOWN;
   1095     return;
   1096   }
   1097   CFX_TxtCharArray& nextChars = *pNextLine->m_pLineChars;
   1098   int cur_size = curChars.GetSize();
   1099   nextChars.SetSize(cur_size - iCharPos);
   1100   FXSYS_memcpy(nextChars.GetData(), curChars.GetDataPtr(iCharPos),
   1101                (cur_size - iCharPos) * sizeof(CFX_TxtChar));
   1102   iCount -= iCharPos;
   1103   cur_size = curChars.GetSize();
   1104   curChars.RemoveAt(cur_size - iCount, iCount);
   1105   pCurLine->m_iWidth = iEndPos;
   1106   CFX_TxtChar* pTC = curChars.GetDataPtr(iCharPos - 1);
   1107   pTC->m_nBreakType = FX_LBT_UNKNOWN;
   1108   iCount = nextChars.GetSize();
   1109   int32_t iCharWidth, iWidth = 0;
   1110   for (int32_t i = 0; i < iCount; i++) {
   1111     pTC = nextChars.GetDataPtr(i);
   1112     if (pTC->GetCharType() >= FX_CHARTYPE_ArabicAlef) {
   1113       pCurLine->m_iArabicChars--;
   1114       pNextLine->m_iArabicChars++;
   1115     }
   1116     iCharWidth = pTC->m_iCharWidth;
   1117     if (iCharWidth > 0) {
   1118       iWidth += iCharWidth;
   1119     }
   1120     if (m_bPagination) {
   1121       continue;
   1122     }
   1123     pTC->m_dwStatus = 0;
   1124   }
   1125   pNextLine->m_iWidth = iWidth;
   1126 }
   1127 int32_t CFX_TxtBreak::CountBreakChars() const {
   1128   CFX_TxtLine* pTxtLine = GetTxtLine(TRUE);
   1129   return pTxtLine == NULL ? 0 : pTxtLine->CountChars();
   1130 }
   1131 int32_t CFX_TxtBreak::CountBreakPieces() const {
   1132   CFX_TxtPieceArray* pTxtPieces = GetTxtPieces(TRUE);
   1133   if (pTxtPieces == NULL) {
   1134     return 0;
   1135   }
   1136   return pTxtPieces->GetSize();
   1137 }
   1138 const CFX_TxtPiece* CFX_TxtBreak::GetBreakPiece(int32_t index) const {
   1139   CFX_TxtPieceArray* pTxtPieces = GetTxtPieces(TRUE);
   1140   if (pTxtPieces == NULL) {
   1141     return NULL;
   1142   }
   1143   if (index < 0 || index >= pTxtPieces->GetSize()) {
   1144     return NULL;
   1145   }
   1146   return pTxtPieces->GetPtrAt(index);
   1147 }
   1148 void CFX_TxtBreak::ClearBreakPieces() {
   1149   CFX_TxtLine* pTxtLine = GetTxtLine(TRUE);
   1150   if (pTxtLine != NULL) {
   1151     pTxtLine->RemoveAll(TRUE);
   1152   }
   1153   m_iReady = 0;
   1154 }
   1155 void CFX_TxtBreak::Reset() {
   1156   m_dwCharType = 0;
   1157   m_iArabicContext = m_iCurArabicContext = 1;
   1158   ResetArabicContext();
   1159   m_pTxtLine1->RemoveAll(TRUE);
   1160   m_pTxtLine2->RemoveAll(TRUE);
   1161 }
   1162 typedef struct _FX_FORMCHAR {
   1163   FX_WORD wch;
   1164   FX_WORD wForm;
   1165   int32_t iWidth;
   1166 } FX_FORMCHAR, *FX_LPFORMCHAR;
   1167 typedef FX_FORMCHAR const* FX_LPCFORMCHAR;
   1168 int32_t CFX_TxtBreak::GetDisplayPos(FX_LPCTXTRUN pTxtRun,
   1169                                     FXTEXT_CHARPOS* pCharPos,
   1170                                     FX_BOOL bCharCode,
   1171                                     CFX_WideString* pWSForms,
   1172                                     FX_AdjustCharDisplayPos pAdjustPos) const {
   1173   if (pTxtRun == NULL || pTxtRun->iLength < 1) {
   1174     return 0;
   1175   }
   1176   IFX_TxtAccess* pAccess = pTxtRun->pAccess;
   1177   void* pIdentity = pTxtRun->pIdentity;
   1178   const FX_WCHAR* pStr = pTxtRun->pStr;
   1179   int32_t* pWidths = pTxtRun->pWidths;
   1180   int32_t iLength = pTxtRun->iLength - 1;
   1181   IFX_Font* pFont = pTxtRun->pFont;
   1182   FX_DWORD dwStyles = pTxtRun->dwStyles;
   1183   CFX_RectF rtText(*pTxtRun->pRect);
   1184   FX_BOOL bRTLPiece =
   1185       (pTxtRun->dwCharStyles & FX_TXTCHARSTYLE_OddBidiLevel) != 0;
   1186   FX_BOOL bArabicNumber =
   1187       (pTxtRun->dwCharStyles & FX_TXTCHARSTYLE_ArabicNumber) != 0;
   1188   FX_BOOL bArabicComma =
   1189       (pTxtRun->dwCharStyles & FX_TXTCHARSTYLE_ArabicComma) != 0;
   1190   FX_FLOAT fFontSize = pTxtRun->fFontSize;
   1191   int32_t iFontSize = FXSYS_round(fFontSize * 20.0f);
   1192   int32_t iAscent = pFont->GetAscent();
   1193   int32_t iDescent = pFont->GetDescent();
   1194   int32_t iMaxHeight = iAscent - iDescent;
   1195   FX_FLOAT fFontHeight = fFontSize;
   1196   FX_FLOAT fAscent = fFontHeight * (FX_FLOAT)iAscent / (FX_FLOAT)iMaxHeight;
   1197   FX_FLOAT fDescent = fFontHeight * (FX_FLOAT)iDescent / (FX_FLOAT)iMaxHeight;
   1198   FX_BOOL bVerticalDoc = (dwStyles & FX_TXTLAYOUTSTYLE_VerticalLayout) != 0;
   1199   FX_BOOL bVerticalChar = (dwStyles & FX_TXTLAYOUTSTYLE_VerticalChars) != 0;
   1200   int32_t iRotation = GetLineRotation(dwStyles) + pTxtRun->iCharRotation;
   1201   int32_t iCharRotation;
   1202   FX_WCHAR wch, wPrev = 0xFEFF, wNext, wForm, wLast = 0xFEFF;
   1203   int32_t iWidth, iCharWidth, iCharHeight;
   1204   FX_FLOAT fX, fY, fCharWidth, fCharHeight;
   1205   int32_t iHorScale = pTxtRun->iHorizontalScale;
   1206   int32_t iVerScale = pTxtRun->iVerticalScale;
   1207   FX_BOOL bSkipSpace = pTxtRun->bSkipSpace;
   1208   FX_BOOL bEmptyChar, bShadda = FALSE, bLam = FALSE;
   1209   FX_DWORD dwProps, dwCharType;
   1210   FX_FORMCHAR formChars[3];
   1211   FX_FLOAT fYBase;
   1212   fX = rtText.left;
   1213   if (bVerticalDoc) {
   1214     fX += (rtText.width - fFontSize) / 2.0f;
   1215     fYBase = bRTLPiece ? rtText.bottom() : rtText.top;
   1216     fY = fYBase;
   1217   } else {
   1218     if (bRTLPiece) {
   1219       fX = rtText.right();
   1220     }
   1221     fYBase = rtText.top + (rtText.height - fFontSize) / 2.0f;
   1222     fY = fYBase + fAscent;
   1223   }
   1224   int32_t iCount = 0, iNext, iForms;
   1225   for (int32_t i = 0; i <= iLength; i++) {
   1226     if (pAccess != NULL) {
   1227       wch = pAccess->GetChar(pIdentity, i);
   1228       iWidth = pAccess->GetWidth(pIdentity, i);
   1229     } else {
   1230       wch = *pStr++;
   1231       iWidth = *pWidths++;
   1232     }
   1233     dwProps = FX_GetUnicodeProperties(wch);
   1234     dwCharType = (dwProps & FX_CHARTYPEBITSMASK);
   1235     if (dwCharType == FX_CHARTYPE_ArabicAlef && iWidth == 0) {
   1236       wPrev = 0xFEFF;
   1237       wLast = wch;
   1238       continue;
   1239     }
   1240     if (dwCharType >= FX_CHARTYPE_ArabicAlef) {
   1241       if (i < iLength) {
   1242         if (pAccess != NULL) {
   1243           iNext = i + 1;
   1244           while (iNext <= iLength) {
   1245             wNext = pAccess->GetChar(pIdentity, iNext);
   1246             dwProps = FX_GetUnicodeProperties(wNext);
   1247             if ((dwProps & FX_CHARTYPEBITSMASK) != FX_CHARTYPE_Combination) {
   1248               break;
   1249             }
   1250             iNext++;
   1251           }
   1252           if (iNext > iLength) {
   1253             wNext = 0xFEFF;
   1254           }
   1255         } else {
   1256           int32_t j = -1;
   1257           do {
   1258             j++;
   1259             if (i + j >= iLength) {
   1260               break;
   1261             }
   1262             wNext = pStr[j];
   1263             dwProps = FX_GetUnicodeProperties(wNext);
   1264           } while ((dwProps & FX_CHARTYPEBITSMASK) == FX_CHARTYPE_Combination);
   1265           if (i + j >= iLength) {
   1266             wNext = 0xFEFF;
   1267           }
   1268         }
   1269       } else {
   1270         wNext = 0xFEFF;
   1271       }
   1272       wForm = m_pArabicChar->GetFormChar(wch, wPrev, wNext);
   1273       bLam = (wPrev == 0x0644 && wch == 0x0644 && wNext == 0x0647);
   1274     } else if (dwCharType == FX_CHARTYPE_Combination) {
   1275       wForm = wch;
   1276       if (wch >= 0x064C && wch <= 0x0651) {
   1277         if (bShadda) {
   1278           wForm = 0xFEFF;
   1279           bShadda = FALSE;
   1280         } else {
   1281           wNext = 0xFEFF;
   1282           if (pAccess != NULL) {
   1283             iNext = i + 1;
   1284             if (iNext <= iLength) {
   1285               wNext = pAccess->GetChar(pIdentity, iNext);
   1286             }
   1287           } else {
   1288             if (i < iLength) {
   1289               wNext = *pStr;
   1290             }
   1291           }
   1292           if (wch == 0x0651) {
   1293             if (wNext >= 0x064C && wNext <= 0x0650) {
   1294               wForm = FX_GetArabicFromShaddaTable(wNext);
   1295               bShadda = TRUE;
   1296             }
   1297           } else {
   1298             if (wNext == 0x0651) {
   1299               wForm = FX_GetArabicFromShaddaTable(wch);
   1300               bShadda = TRUE;
   1301             }
   1302           }
   1303         }
   1304       } else {
   1305         bShadda = FALSE;
   1306       }
   1307     } else if (dwCharType == FX_CHARTYPE_Numeric) {
   1308       wForm = wch;
   1309       if (bArabicNumber) {
   1310         wForm += 0x0630;
   1311       }
   1312     } else if (wch == L'.') {
   1313       wForm = wch;
   1314       if (bArabicNumber) {
   1315         wNext = 0xFEFF;
   1316         if (pAccess != NULL) {
   1317           iNext = i + 1;
   1318           if (iNext <= iLength) {
   1319             wNext = pAccess->GetChar(pIdentity, iNext);
   1320           }
   1321         } else {
   1322           if (i < iLength) {
   1323             wNext = *pStr;
   1324           }
   1325         }
   1326         if (wNext >= L'0' && wNext <= L'9') {
   1327           wForm = 0x066B;
   1328         }
   1329       }
   1330     } else if (wch == L',') {
   1331       wForm = wch;
   1332       if (bArabicComma) {
   1333         wForm = 0x060C;
   1334       }
   1335     } else if (bRTLPiece || bVerticalChar) {
   1336       wForm = FX_GetMirrorChar(wch, dwProps, bRTLPiece, bVerticalChar);
   1337     } else {
   1338       wForm = wch;
   1339     }
   1340     if (dwCharType != FX_CHARTYPE_Combination) {
   1341       bShadda = FALSE;
   1342     }
   1343     if (dwCharType < FX_CHARTYPE_ArabicAlef) {
   1344       bLam = FALSE;
   1345     }
   1346     dwProps = FX_GetUnicodeProperties(wForm);
   1347     iCharRotation = iRotation;
   1348     if (bVerticalChar && (dwProps & 0x8000) != 0) {
   1349       iCharRotation++;
   1350     }
   1351     iCharRotation %= 4;
   1352     bEmptyChar =
   1353         (dwCharType >= FX_CHARTYPE_Tab && dwCharType <= FX_CHARTYPE_Control);
   1354     if (wForm == 0xFEFF) {
   1355       bEmptyChar = TRUE;
   1356     }
   1357     iForms = bLam ? 3 : 1;
   1358     iCount += (bEmptyChar && bSkipSpace) ? 0 : iForms;
   1359     if (pCharPos == NULL) {
   1360       if (iWidth > 0) {
   1361         wPrev = wch;
   1362       }
   1363       wLast = wch;
   1364       continue;
   1365     }
   1366     iCharWidth = iWidth;
   1367     if (iCharWidth < 0) {
   1368       iCharWidth = -iCharWidth;
   1369     }
   1370     iCharWidth /= iFontSize;
   1371     formChars[0].wch = wch;
   1372     formChars[0].wForm = wForm;
   1373     formChars[0].iWidth = iCharWidth;
   1374     if (bLam) {
   1375       formChars[1].wForm = 0x0651;
   1376       iCharWidth = 0;
   1377       pFont->GetCharWidth(0x0651, iCharWidth, FALSE);
   1378       formChars[1].iWidth = iCharWidth;
   1379       formChars[2].wForm = 0x0670;
   1380       iCharWidth = 0;
   1381       pFont->GetCharWidth(0x0670, iCharWidth, FALSE);
   1382       formChars[2].iWidth = iCharWidth;
   1383     }
   1384     for (int32_t j = 0; j < iForms; j++) {
   1385       wForm = (FX_WCHAR)formChars[j].wForm;
   1386       iCharWidth = formChars[j].iWidth;
   1387       if (j > 0) {
   1388         dwCharType = FX_CHARTYPE_Combination;
   1389         wch = wForm;
   1390         wLast = (FX_WCHAR)formChars[j - 1].wForm;
   1391       }
   1392       if (!bEmptyChar || (bEmptyChar && !bSkipSpace)) {
   1393         pCharPos->m_GlyphIndex =
   1394             bCharCode ? wch : pFont->GetGlyphIndex(wForm, FALSE);
   1395         pCharPos->m_ExtGID = pCharPos->m_GlyphIndex;
   1396         pCharPos->m_FontCharWidth = iCharWidth;
   1397         if (pWSForms) {
   1398           *pWSForms += wForm;
   1399         }
   1400       }
   1401       if (bVerticalDoc) {
   1402         iCharHeight = iCharWidth;
   1403         iCharWidth = 1000;
   1404       } else {
   1405         iCharHeight = 1000;
   1406       }
   1407       fCharWidth = fFontSize * iCharWidth / 1000.0f;
   1408       fCharHeight = fFontSize * iCharHeight / 1000.0f;
   1409       if (bRTLPiece && dwCharType != FX_CHARTYPE_Combination) {
   1410         if (bVerticalDoc) {
   1411           fY -= fCharHeight;
   1412         } else {
   1413           fX -= fCharWidth;
   1414         }
   1415       }
   1416       if (!bEmptyChar || (bEmptyChar && !bSkipSpace)) {
   1417         pCharPos->m_OriginX = fX;
   1418         pCharPos->m_OriginY = fY;
   1419         if ((dwStyles & FX_TXTLAYOUTSTYLE_CombText) != 0) {
   1420           int32_t iFormWidth = iCharWidth;
   1421           pFont->GetCharWidth(wForm, iFormWidth, FALSE);
   1422           FX_FLOAT fOffset = fFontSize * (iCharWidth - iFormWidth) / 2000.0f;
   1423           if (bVerticalDoc) {
   1424             pCharPos->m_OriginY += fOffset;
   1425           } else {
   1426             pCharPos->m_OriginX += fOffset;
   1427           }
   1428         }
   1429         if (dwCharType == FX_CHARTYPE_Combination) {
   1430           CFX_Rect rtBBox;
   1431           rtBBox.Reset();
   1432           if (pFont->GetCharBBox(wForm, rtBBox, FALSE)) {
   1433             pCharPos->m_OriginY =
   1434                 fYBase + fFontSize -
   1435                 fFontSize * (FX_FLOAT)rtBBox.height / (FX_FLOAT)iMaxHeight;
   1436           }
   1437           if (wForm == wch && wLast != 0xFEFF) {
   1438             FX_DWORD dwLastProps = FX_GetUnicodeProperties(wLast);
   1439             if ((dwLastProps & FX_CHARTYPEBITSMASK) ==
   1440                 FX_CHARTYPE_Combination) {
   1441               CFX_Rect rtBBox;
   1442               rtBBox.Reset();
   1443               if (pFont->GetCharBBox(wLast, rtBBox, FALSE)) {
   1444                 pCharPos->m_OriginY -= fFontSize * rtBBox.height / iMaxHeight;
   1445               }
   1446             }
   1447           }
   1448         }
   1449         CFX_PointF ptOffset;
   1450         ptOffset.Reset();
   1451         FX_BOOL bAdjusted = FALSE;
   1452         if (pAdjustPos) {
   1453           bAdjusted = pAdjustPos(wForm, bCharCode, pFont, fFontSize,
   1454                                  bVerticalChar, ptOffset);
   1455         }
   1456         if (!bAdjusted && bVerticalChar && (dwProps & 0x00010000) != 0) {
   1457           CFX_Rect rtBBox;
   1458           rtBBox.Reset();
   1459           if (pFont->GetCharBBox(wForm, rtBBox, FALSE)) {
   1460             ptOffset.x = fFontSize * (850 - rtBBox.right()) / iMaxHeight;
   1461             ptOffset.y = fFontSize * (iAscent - rtBBox.top - 150) / iMaxHeight;
   1462           }
   1463         }
   1464         pCharPos->m_OriginX += ptOffset.x;
   1465         pCharPos->m_OriginY -= ptOffset.y;
   1466       }
   1467       if (!bRTLPiece && dwCharType != FX_CHARTYPE_Combination) {
   1468         if (bVerticalDoc) {
   1469           fY += fCharHeight;
   1470         } else {
   1471           fX += fCharWidth;
   1472         }
   1473       }
   1474       if (!bEmptyChar || (bEmptyChar && !bSkipSpace)) {
   1475         pCharPos->m_bGlyphAdjust = TRUE;
   1476         if (bVerticalDoc) {
   1477           if (iCharRotation == 0) {
   1478             pCharPos->m_AdjustMatrix[0] = -1;
   1479             pCharPos->m_AdjustMatrix[1] = 0;
   1480             pCharPos->m_AdjustMatrix[2] = 0;
   1481             pCharPos->m_AdjustMatrix[3] = 1;
   1482             pCharPos->m_OriginY += fAscent;
   1483           } else if (iCharRotation == 1) {
   1484             pCharPos->m_AdjustMatrix[0] = 0;
   1485             pCharPos->m_AdjustMatrix[1] = -1;
   1486             pCharPos->m_AdjustMatrix[2] = -1;
   1487             pCharPos->m_AdjustMatrix[3] = 0;
   1488             pCharPos->m_OriginX -= fDescent;
   1489           } else if (iCharRotation == 2) {
   1490             pCharPos->m_AdjustMatrix[0] = 1;
   1491             pCharPos->m_AdjustMatrix[1] = 0;
   1492             pCharPos->m_AdjustMatrix[2] = 0;
   1493             pCharPos->m_AdjustMatrix[3] = -1;
   1494             pCharPos->m_OriginX += fCharWidth;
   1495             pCharPos->m_OriginY += fAscent;
   1496           } else {
   1497             pCharPos->m_AdjustMatrix[0] = 0;
   1498             pCharPos->m_AdjustMatrix[1] = 1;
   1499             pCharPos->m_AdjustMatrix[2] = 1;
   1500             pCharPos->m_AdjustMatrix[3] = 0;
   1501             pCharPos->m_OriginX += fAscent;
   1502           }
   1503         } else {
   1504           if (iCharRotation == 0) {
   1505             pCharPos->m_AdjustMatrix[0] = -1;
   1506             pCharPos->m_AdjustMatrix[1] = 0;
   1507             pCharPos->m_AdjustMatrix[2] = 0;
   1508             pCharPos->m_AdjustMatrix[3] = 1;
   1509           } else if (iCharRotation == 1) {
   1510             pCharPos->m_AdjustMatrix[0] = 0;
   1511             pCharPos->m_AdjustMatrix[1] = -1;
   1512             pCharPos->m_AdjustMatrix[2] = -1;
   1513             pCharPos->m_AdjustMatrix[3] = 0;
   1514             pCharPos->m_OriginX -= fDescent;
   1515             pCharPos->m_OriginY -= fAscent + fDescent;
   1516           } else if (iCharRotation == 2) {
   1517             pCharPos->m_AdjustMatrix[0] = 1;
   1518             pCharPos->m_AdjustMatrix[1] = 0;
   1519             pCharPos->m_AdjustMatrix[2] = 0;
   1520             pCharPos->m_AdjustMatrix[3] = -1;
   1521             pCharPos->m_OriginX += fCharWidth;
   1522             pCharPos->m_OriginY -= fAscent;
   1523           } else {
   1524             pCharPos->m_AdjustMatrix[0] = 0;
   1525             pCharPos->m_AdjustMatrix[1] = 1;
   1526             pCharPos->m_AdjustMatrix[2] = 1;
   1527             pCharPos->m_AdjustMatrix[3] = 0;
   1528             pCharPos->m_OriginX += fAscent;
   1529           }
   1530         }
   1531         if (iHorScale != 100 || iVerScale != 100) {
   1532           pCharPos->m_AdjustMatrix[0] =
   1533               pCharPos->m_AdjustMatrix[0] * iHorScale / 100.0f;
   1534           pCharPos->m_AdjustMatrix[1] =
   1535               pCharPos->m_AdjustMatrix[1] * iHorScale / 100.0f;
   1536           pCharPos->m_AdjustMatrix[2] =
   1537               pCharPos->m_AdjustMatrix[2] * iVerScale / 100.0f;
   1538           pCharPos->m_AdjustMatrix[3] =
   1539               pCharPos->m_AdjustMatrix[3] * iVerScale / 100.0f;
   1540         }
   1541         pCharPos++;
   1542       }
   1543     }
   1544     if (iWidth > 0) {
   1545       wPrev = (FX_WCHAR)formChars[0].wch;
   1546     }
   1547     wLast = wch;
   1548   }
   1549   return iCount;
   1550 }
   1551 int32_t CFX_TxtBreak::GetCharRects(FX_LPCTXTRUN pTxtRun,
   1552                                    CFX_RectFArray& rtArray,
   1553                                    FX_BOOL bCharBBox) const {
   1554   if (pTxtRun == NULL || pTxtRun->iLength < 1) {
   1555     return 0;
   1556   }
   1557   IFX_TxtAccess* pAccess = pTxtRun->pAccess;
   1558   void* pIdentity = pTxtRun->pIdentity;
   1559   const FX_WCHAR* pStr = pTxtRun->pStr;
   1560   int32_t* pWidths = pTxtRun->pWidths;
   1561   int32_t iLength = pTxtRun->iLength;
   1562   CFX_RectF rect(*pTxtRun->pRect);
   1563   FX_BOOL bRTLPiece =
   1564       (pTxtRun->dwCharStyles & FX_TXTCHARSTYLE_OddBidiLevel) != 0;
   1565   FX_FLOAT fFontSize = pTxtRun->fFontSize;
   1566   int32_t iFontSize = FXSYS_round(fFontSize * 20.0f);
   1567   FX_FLOAT fScale = fFontSize / 1000.0f;
   1568   IFX_Font* pFont = pTxtRun->pFont;
   1569   if (pFont == NULL) {
   1570     bCharBBox = FALSE;
   1571   }
   1572   CFX_Rect bbox;
   1573   bbox.Set(0, 0, 0, 0);
   1574   if (bCharBBox) {
   1575     bCharBBox = pFont->GetBBox(bbox);
   1576   }
   1577   FX_FLOAT fLeft = std::max(0.0f, bbox.left * fScale);
   1578   FX_FLOAT fHeight = FXSYS_fabs(bbox.height * fScale);
   1579   rtArray.RemoveAll();
   1580   rtArray.SetSize(iLength);
   1581   FX_BOOL bVertical =
   1582       (pTxtRun->dwStyles & FX_TXTLAYOUTSTYLE_VerticalLayout) != 0;
   1583   FX_BOOL bSingleLine = (pTxtRun->dwStyles & FX_TXTLAYOUTSTYLE_SingleLine) != 0;
   1584   FX_BOOL bCombText = (pTxtRun->dwStyles & FX_TXTLAYOUTSTYLE_CombText) != 0;
   1585   FX_WCHAR wch, wLineBreakChar = pTxtRun->wLineBreakChar;
   1586   int32_t iCharSize;
   1587   FX_FLOAT fCharSize, fStart;
   1588   if (bVertical) {
   1589     fStart = bRTLPiece ? rect.bottom() : rect.top;
   1590   } else {
   1591     fStart = bRTLPiece ? rect.right() : rect.left;
   1592   }
   1593   for (int32_t i = 0; i < iLength; i++) {
   1594     if (pAccess != NULL) {
   1595       wch = pAccess->GetChar(pIdentity, i);
   1596       iCharSize = pAccess->GetWidth(pIdentity, i);
   1597     } else {
   1598       wch = *pStr++;
   1599       iCharSize = *pWidths++;
   1600     }
   1601     fCharSize = (FX_FLOAT)iCharSize / 20000.0f;
   1602     FX_BOOL bRet = (!bSingleLine && FX_IsCtrlCode(wch));
   1603     if (!(wch == L'\v' || wch == L'\f' || wch == 0x2028 || wch == 0x2029 ||
   1604           (wLineBreakChar != 0xFEFF && wch == wLineBreakChar))) {
   1605       bRet = FALSE;
   1606     }
   1607     if (bRet) {
   1608       iCharSize = iFontSize * 500;
   1609       fCharSize = fFontSize / 2.0f;
   1610     }
   1611     if (bVertical) {
   1612       rect.top = fStart;
   1613       if (bRTLPiece) {
   1614         rect.top -= fCharSize;
   1615         fStart -= fCharSize;
   1616       } else {
   1617         fStart += fCharSize;
   1618       }
   1619       rect.height = fCharSize;
   1620     } else {
   1621       rect.left = fStart;
   1622       if (bRTLPiece) {
   1623         rect.left -= fCharSize;
   1624         fStart -= fCharSize;
   1625       } else {
   1626         fStart += fCharSize;
   1627       }
   1628       rect.width = fCharSize;
   1629     }
   1630     if (bCharBBox && !bRet) {
   1631       int32_t iCharWidth = 1000;
   1632       pFont->GetCharWidth(wch, iCharWidth);
   1633       FX_FLOAT fRTLeft = 0, fCharWidth = 0;
   1634       if (iCharWidth > 0) {
   1635         fCharWidth = iCharWidth * fScale;
   1636         fRTLeft = fLeft;
   1637         if (bCombText) {
   1638           fRTLeft = (rect.width - fCharWidth) / 2.0f;
   1639         }
   1640       }
   1641       CFX_RectF rtBBoxF;
   1642       if (bVertical) {
   1643         rtBBoxF.top = rect.left + fRTLeft;
   1644         rtBBoxF.left = rect.top + (rect.height - fHeight) / 2.0f;
   1645         rtBBoxF.height = fCharWidth;
   1646         rtBBoxF.width = fHeight;
   1647         rtBBoxF.left = std::max(rtBBoxF.left, 0.0f);
   1648       } else {
   1649         rtBBoxF.left = rect.left + fRTLeft;
   1650         rtBBoxF.top = rect.top + (rect.height - fHeight) / 2.0f;
   1651         rtBBoxF.width = fCharWidth;
   1652         rtBBoxF.height = fHeight;
   1653         rtBBoxF.top = std::max(rtBBoxF.top, 0.0f);
   1654       }
   1655       rtArray.SetAt(i, rtBBoxF);
   1656       continue;
   1657     }
   1658     rtArray.SetAt(i, rect);
   1659   }
   1660   return iLength;
   1661 }
   1662