| // Copyright 2014 PDFium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |   | 
 | // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | 
 |  | 
 | #include "autoreflow.h" | 
 | #define approachto(a,b,c) (FXSYS_fabs((float)((a)-(b)))>(c) ? 0 : 1) | 
 | int FPDF_ProcessInterObj(const CPDF_PageObject* pPrevObj, const CPDF_PageObject* pObj) | 
 | { | 
 |     CFX_AffineMatrix matrix; | 
 |     FX_RECT PreRect = pPrevObj->GetBBox(&matrix); | 
 |     FX_RECT rect = pObj->GetBBox(&matrix); | 
 |     int flag = 0; | 
 |     if(PreRect.top > rect.bottom) { | 
 |         flag = 0; | 
 |     } else if(rect.top > PreRect.bottom) { | 
 |         flag = 1; | 
 |     } else if(PreRect.right < rect.left) { | 
 |         flag = 0; | 
 |     } else if(PreRect.left > rect.right) { | 
 |         flag = 1; | 
 |     } else if(pObj->m_Type != PDFPAGE_TEXT) { | 
 |         flag = 1; | 
 |     } else if(pPrevObj->m_Type != PDFPAGE_TEXT) { | 
 |         flag = 0; | 
 |     } else { | 
 |         if((PreRect.top < rect.top && PreRect.bottom > rect.bottom) || | 
 |                 (PreRect.top > rect.top && PreRect.bottom < rect.bottom)) { | 
 |             if(PreRect.left > rect.left) { | 
 |                 flag = 1; | 
 |             } else { | 
 |                 flag = 0; | 
 |             } | 
 |         } else { | 
 |             CPDF_TextObject* pPrevTextObj = (CPDF_TextObject* )pPrevObj; | 
 |             CPDF_TextObject* pTextObj = (CPDF_TextObject* )pObj; | 
 |             CPDF_TextObjectItem item, prevItem; | 
 |             pPrevTextObj->GetItemInfo(0, &prevItem); | 
 |             pTextObj->GetItemInfo(0, &item); | 
 |             CFX_AffineMatrix TextMatrix; | 
 |             pTextObj->GetTextMatrix(&TextMatrix); | 
 |             FX_FLOAT originX, originY, prevOriginX, preOriginY; | 
 |             TextMatrix.Transform(item.m_OriginX, item.m_OriginY, originX, originY); | 
 |             pPrevTextObj->GetTextMatrix(&TextMatrix); | 
 |             TextMatrix.Transform(prevItem.m_OriginX, prevItem.m_OriginY, prevOriginX, preOriginY); | 
 |             if(preOriginY > originY) { | 
 |                 flag = 0; | 
 |             } else { | 
 |                 flag = 1; | 
 |             } | 
 |         } | 
 |     } | 
 |     return flag; | 
 | } | 
 | void CPDF_AutoReflowLayoutProvider::Conver2AppreceOrder(const CPDF_PageObjects* pStreamOrderObjs, CPDF_PageObjects* pAppraceOrderObjs) | 
 | { | 
 |     FX_POSITION pos = pStreamOrderObjs->GetFirstObjectPosition(); | 
 |     CFX_AffineMatrix matrix; | 
 |     while(pos) { | 
 |         CPDF_PageObject* pObj = pStreamOrderObjs->GetNextObject(pos); | 
 |         CFX_AffineMatrix matrix; | 
 |         if(pObj->m_Type != PDFPAGE_TEXT) { | 
 |             continue; | 
 |         } | 
 |         FX_POSITION pos1 = pAppraceOrderObjs->GetLastObjectPosition(); | 
 |         while(pos1) { | 
 |             CPDF_PageObject* pTempObj = pAppraceOrderObjs->GetPrevObject(pos1); | 
 |             if(FPDF_ProcessInterObj(pObj, pTempObj) == 1) { | 
 |                 if(!pos1) { | 
 |                     pos1 = pAppraceOrderObjs->GetFirstObjectPosition(); | 
 |                 } else { | 
 |                     pAppraceOrderObjs->GetNextObject(pos1); | 
 |                 } | 
 |                 break; | 
 |             } | 
 |         } | 
 |         pAppraceOrderObjs->InsertObject(pos1, pObj); | 
 |     } | 
 |     pos = pStreamOrderObjs->GetFirstObjectPosition(); | 
 |     while(pos) { | 
 |         CPDF_PageObject* pObj = pStreamOrderObjs->GetNextObject(pos); | 
 |         if(pObj->m_Type != PDFPAGE_IMAGE) { | 
 |             continue; | 
 |         } | 
 |         FX_POSITION pos1 = pAppraceOrderObjs->GetLastObjectPosition(); | 
 |         while(pos1) { | 
 |             CPDF_PageObject* pTempObj = pAppraceOrderObjs->GetPrevObject(pos1); | 
 |             if(FPDF_ProcessInterObj(pObj, pTempObj) == 1) { | 
 |                 if(!pos1) { | 
 |                     pos1 = pAppraceOrderObjs->GetFirstObjectPosition(); | 
 |                 } else { | 
 |                     pAppraceOrderObjs->GetNextObject(pos1); | 
 |                 } | 
 |                 break; | 
 |             } | 
 |         } | 
 |         pAppraceOrderObjs->InsertObject(pos1, pObj); | 
 |     } | 
 | } | 
 | IPDF_LayoutProvider* IPDF_LayoutProvider::Create_LayoutProvider_AutoReflow(CPDF_PageObjects* pPage, FX_BOOL bReadOrder) | 
 | { | 
 |     return FX_NEW CPDF_AutoReflowLayoutProvider(pPage, bReadOrder); | 
 | } | 
 | CPDF_AutoReflowElement::CPDF_AutoReflowElement(LayoutType layoutType , CPDF_AutoReflowElement* pParent) | 
 | { | 
 |     m_ElmType = layoutType; | 
 |     m_pParentElm = pParent; | 
 |     if(pParent) { | 
 |         pParent->m_ChildArray.Add(this); | 
 |     } | 
 |     m_SpaceBefore = 0; | 
 | } | 
 | CPDF_AutoReflowElement::~CPDF_AutoReflowElement() | 
 | { | 
 |     m_ChildArray.RemoveAll(); | 
 |     m_ObjArray.RemoveAll(); | 
 | } | 
 | int	CPDF_AutoReflowElement::CountAttrValues(LayoutAttr attr_type) | 
 | { | 
 |     return 1; | 
 | } | 
 | LayoutEnum CPDF_AutoReflowElement::GetEnumAttr(LayoutAttr attr_type, int index ) | 
 | { | 
 |     return LayoutInvalid; | 
 | } | 
 | FX_FLOAT	CPDF_AutoReflowElement::GetNumberAttr(LayoutAttr attr_type, int index ) | 
 | { | 
 |     switch (attr_type) { | 
 |         case LayoutSpaceBefore: | 
 |             return m_SpaceBefore; | 
 |         default: | 
 |             return 0; | 
 |     } | 
 | } | 
 | FX_COLORREF	CPDF_AutoReflowElement::GetColorAttr(LayoutAttr attr_type, int index ) | 
 | { | 
 |     return 0; | 
 | } | 
 | #define WritingMode_UNKNOW	0 | 
 | #define WritingMode_LRTB	1 | 
 | #define WritingMode_RLTB	2 | 
 | #define WritingMode_TBRL	3 | 
 | CPDF_AutoReflowLayoutProvider::CPDF_AutoReflowLayoutProvider(CPDF_PageObjects* pPage, FX_BOOL bReadOrder) | 
 | { | 
 |     m_pPDFPage = (CPDF_Page*)pPage; | 
 |     FX_FLOAT width = m_pPDFPage->GetPageWidth(); | 
 |     FX_FLOAT height = m_pPDFPage->GetPageHeight(); | 
 |     m_pPDFPage->GetDisplayMatrix(m_PDFDisplayMatrix, 0, 0, (int)(m_pPDFPage->GetPageWidth()), (int)(m_pPDFPage->GetPageHeight()), 0); | 
 |     m_bReadOrder = bReadOrder; | 
 |     m_Status = LayoutReady; | 
 |     m_pRoot = NULL; | 
 |     m_pCurrElm = NULL; | 
 |     m_pPreObj = NULL; | 
 |     m_Step = 0; | 
 |     m_WritingMode = WritingMode_UNKNOW; | 
 | } | 
 | CPDF_AutoReflowLayoutProvider::~CPDF_AutoReflowLayoutProvider() | 
 | { | 
 |     m_pPDFPage = NULL; | 
 |     ReleaseElm(m_pRoot); | 
 | } | 
 | void CPDF_AutoReflowLayoutProvider::ReleaseElm(CPDF_AutoReflowElement*& pElm, FX_BOOL bReleaseChildren) | 
 | { | 
 |     if(bReleaseChildren) { | 
 |         int count = pElm->CountChildren(); | 
 |         for(int i = 0; i < count; i++) { | 
 |             CPDF_AutoReflowElement* pChild = (CPDF_AutoReflowElement*)pElm->GetChild(i); | 
 |             ReleaseElm(pChild); | 
 |         } | 
 |     } | 
 |     delete pElm; | 
 |     pElm = NULL; | 
 | } | 
 | void CPDF_AutoReflowLayoutProvider::AddObjectArray(CPDF_AutoReflowElement* pElm, CFX_PtrList& ObjList) | 
 | { | 
 |     if(!pElm) { | 
 |         return; | 
 |     } | 
 |     FX_POSITION pos = ObjList.GetHeadPosition(); | 
 |     while (pos) { | 
 |         pElm->m_ObjArray.Add((CPDF_PageObject*)ObjList.GetNext(pos)); | 
 |     } | 
 | } | 
 | void CPDF_AutoReflowLayoutProvider::GenerateStructTree() | 
 | { | 
 |     if (m_Step < AUTOREFLOW_STEP_GENERATELINE) { | 
 |         GenerateLine(m_cellArray); | 
 |         if(m_cellArray.GetSize() == 0) { | 
 |             m_Status = LayoutError; | 
 |             return; | 
 |         } | 
 |         if(m_pPause && m_pPause->NeedToPauseNow()) { | 
 |             m_Step = AUTOREFLOW_STEP_GENERATELINE; | 
 |             m_Status = LayoutToBeContinued; | 
 |             return; | 
 |         } | 
 |     } | 
 |     if (m_Step < AUTOREFLOW_STEP_GENERATEParagraph) { | 
 |         GenerateParagraph(m_cellArray); | 
 |         if(m_pPause && m_pPause->NeedToPauseNow()) { | 
 |             m_Step = AUTOREFLOW_STEP_GENERATEParagraph; | 
 |             m_Status = LayoutToBeContinued; | 
 |             return; | 
 |         } | 
 |     } | 
 |     if (m_Step < AUTOREFLOW_STEP_CREATEELEMENT) { | 
 |         CreateElement(); | 
 |         if(m_pPause && m_pPause->NeedToPauseNow()) { | 
 |             m_Step = AUTOREFLOW_STEP_CREATEELEMENT; | 
 |             m_Status = LayoutToBeContinued; | 
 |             return; | 
 |         } | 
 |     } | 
 |     if (m_Step < AUTOREFLOW_STEP_REMOVEDATA) { | 
 |         int count = m_cellArray.GetSize(); | 
 |         for(int i = 0; i < count; i++) { | 
 |             CRF_CELL* pCell = (CRF_CELL*)m_cellArray.GetAt(i); | 
 |             if(pCell) { | 
 |                 pCell->m_ObjList.RemoveAll(); | 
 |                 delete pCell; | 
 |             } | 
 |         } | 
 |         m_cellArray.RemoveAll(); | 
 |         if(m_pPause && m_pPause->NeedToPauseNow()) { | 
 |             m_Step = AUTOREFLOW_STEP_REMOVEDATA; | 
 |             m_Status = LayoutToBeContinued; | 
 |             return; | 
 |         } | 
 |     } | 
 |     m_Step = AUTOREFLOW_STEP_REMOVEDATA; | 
 |     m_Status = LayoutFinished; | 
 |     return; | 
 | } | 
 | void CPDF_AutoReflowLayoutProvider::CreateElement() | 
 | { | 
 |     int count = m_cellArray.GetSize(); | 
 |     CRF_CELL* plastCell = NULL; | 
 |     CRF_CELL* pCell = NULL; | 
 |     CRF_CELL* pNextCell = NULL; | 
 |     CPDF_AutoReflowElement* pParent = m_pRoot; | 
 |     CPDF_AutoReflowElement* pCurrElm = NULL; | 
 |     int i; | 
 |     for(i = 0; i < count; i++) { | 
 |         pCell = (CRF_CELL*)m_cellArray.GetAt(i); | 
 |         if(!pCell) { | 
 |             continue; | 
 |         } | 
 |         if(i < count - 1) { | 
 |             pNextCell = (CRF_CELL*)m_cellArray.GetAt(i + 1); | 
 |         } else { | 
 |             pNextCell = NULL; | 
 |         } | 
 |         pCurrElm = NULL; | 
 |         pCurrElm = FX_NEW CPDF_AutoReflowElement(LayoutParagraph, pParent); | 
 |         if(pCurrElm->GetType() == LayoutParagraph && plastCell) { | 
 |             int SpaceBefore = 0; | 
 |             if(pCell->m_CellWritingMode != plastCell->m_CellWritingMode ) { | 
 |                 SpaceBefore = 20; | 
 |             } else if(pCell->m_CellWritingMode == WritingMode_LRTB) { | 
 |                 SpaceBefore = plastCell->m_BBox.bottom - pCell->m_BBox.top; | 
 |             } else if(pCell->m_CellWritingMode == WritingMode_TBRL) { | 
 |                 SpaceBefore = plastCell->m_BBox.left - pCell->m_BBox.right; | 
 |             } | 
 |             if(SpaceBefore > 0) { | 
 |                 pCurrElm->m_SpaceBefore = SpaceBefore > 50 ? 50.0f : SpaceBefore; | 
 |             } | 
 |         } | 
 |         AddObjectArray(pCurrElm, pCell->m_ObjList); | 
 |         plastCell = pCell; | 
 |     } | 
 | } | 
 | void CPDF_AutoReflowLayoutProvider::GenerateParagraph(CFX_PtrArray& cellArray) | 
 | { | 
 |     int count = cellArray.GetSize(); | 
 |     if(count <= 1) { | 
 |         return; | 
 |     } | 
 |     CRF_CELL* plastCell = (CRF_CELL*)cellArray.GetAt(0); | 
 |     if(plastCell->m_BBox.Height() > plastCell->m_BBox.Width()) { | 
 |         m_WritingMode = WritingMode_TBRL; | 
 |     } else { | 
 |         m_WritingMode = WritingMode_LRTB; | 
 |     } | 
 |     FX_BOOL bEnforce = FALSE; | 
 |     int i = 0; | 
 |     for(i = 1; i < count; i++) { | 
 |         CRF_CELL* pCell = (CRF_CELL*)cellArray.GetAt(i); | 
 |         if(!pCell) { | 
 |             continue; | 
 |         } | 
 |         int c = pCell->m_ObjList.GetCount(); | 
 |         FX_BOOL bMerge = FALSE; | 
 |         FX_POSITION pos1 = plastCell->m_ObjList.GetTailPosition(); | 
 |         CPDF_PageObject* pLastObj = (CPDF_PageObject*)plastCell->m_ObjList.GetPrev(pos1); | 
 |         pos1 = pCell->m_ObjList.GetHeadPosition(); | 
 |         CPDF_PageObject* pCurObj = (CPDF_PageObject*)pCell->m_ObjList.GetNext(pos1); | 
 |         int WritingMode = GetRectEnd(pCell->m_BBox); | 
 |         if(pCell->m_CellWritingMode == WritingMode_UNKNOW) { | 
 |             if(pCell->m_BBox.Height() > pCell->m_BBox.Width()) { | 
 |                 pCell->m_CellWritingMode = WritingMode_TBRL; | 
 |             } else { | 
 |                 pCell->m_CellWritingMode = WritingMode_LRTB; | 
 |             } | 
 |         } | 
 |         WritingMode = pCell->m_CellWritingMode; | 
 |         if(WritingMode == WritingMode_LRTB && (m_Style.m_Language & LP_Lang_ChinesePRC || m_Style.m_Language & LP_Lang_ChineseTaiwan | 
 |                                                || m_Style.m_Language & LP_Lang_Japanese || m_Style.m_Language & LP_Lang_Korean)) { | 
 |             if(pCurObj->m_Type == PDFPAGE_TEXT) { | 
 |                 CPDF_TextObject* pText; | 
 |                 pText = (CPDF_TextObject*)pCurObj; | 
 |                 if(pText->CountItems()) { | 
 |                     CPDF_TextObjectItem item; | 
 |                     pText->GetItemInfo(0, &item); | 
 |                     CFX_WideString str = pText->GetFont()->UnicodeFromCharCode(item.m_CharCode); | 
 |                     FX_WCHAR unicode = str.GetAt(0); | 
 |                     if(unicode == 32) { | 
 |                         plastCell = pCell; | 
 |                         bMerge = FALSE; | 
 |                         bEnforce = FALSE; | 
 |                         continue; | 
 |                     } | 
 |                 } | 
 |             } | 
 |         } | 
 |         if(m_WritingMode == WritingMode) { | 
 |             if(bEnforce) { | 
 |                 bMerge = FALSE; | 
 |                 bEnforce = FALSE; | 
 |                 if(pCurObj->m_Type == PDFPAGE_TEXT) { | 
 |                     CPDF_TextObject* pText; | 
 |                     pText = (CPDF_TextObject*)pCurObj; | 
 |                     if(pText->CountItems()) { | 
 |                         CPDF_TextObjectItem item; | 
 |                         pText->GetItemInfo(0, &item); | 
 |                         CFX_WideString str = pText->GetFont()->UnicodeFromCharCode(item.m_CharCode); | 
 |                         FX_WCHAR unicode = str.GetAt(0); | 
 |                         if(unicode > 96 && unicode < 123) { | 
 |                             bMerge = TRUE; | 
 |                         } | 
 |                     } | 
 |                 } else { | 
 |                     CPDF_ImageObject* pImage = (CPDF_ImageObject*)pCurObj; | 
 |                     FX_RECT imageBBox = pImage->GetBBox(&m_PDFDisplayMatrix); | 
 |                     if(GetRectEnd(plastCell->m_BBox) - GetRectEnd(pCell->m_BBox) < GetRectWidth(imageBBox)) { | 
 |                         bMerge = TRUE; | 
 |                     } | 
 |                 } | 
 |             } else { | 
 |                 if(!approachto(GetRectStart(pCell->m_BBox), GetRectStart(plastCell->m_BBox), GetRectHeight(pCell->m_BBox) / 4)) { | 
 |                     if(approachto(GetRectStart(plastCell->m_BBox), GetRectStart(pCell->m_BBox), GetRectHeight(pCell->m_BBox) * 2.3) && | 
 |                             GetRectStart(plastCell->m_BBox) - GetRectStart(pCell->m_BBox) > 0) { | 
 |                         if(pCurObj->m_Type == PDFPAGE_TEXT || pLastObj->m_Type == PDFPAGE_TEXT) { | 
 |                             CPDF_TextObject* pText; | 
 |                             if(pCurObj->m_Type == PDFPAGE_TEXT) { | 
 |                                 pText = (CPDF_TextObject*)pCurObj; | 
 |                             } else { | 
 |                                 pText = (CPDF_TextObject*)pLastObj; | 
 |                             } | 
 |                             CPDF_TextObjectItem item; | 
 |                             pText->GetItemInfo(0, &item); | 
 |                             CFX_WideString str = pText->GetFont()->UnicodeFromCharCode(item.m_CharCode); | 
 |                             FX_WCHAR unicode = str.GetAt(0); | 
 |                             if(unicode > 255) { | 
 |                                 bMerge = TRUE; | 
 |                             } | 
 |                         } | 
 |                     } | 
 |                 } else if(!approachto(GetRectEnd(pCell->m_BBox), GetRectEnd(plastCell->m_BBox), GetRectHeight(pCell->m_BBox) * 3)) { | 
 |                     FX_RECT rect = pLastObj->GetBBox(&m_PDFDisplayMatrix); | 
 |                     if(approachto(GetRectStart(pCell->m_BBox), GetRectStart(plastCell->m_BBox), GetRectHeight(pCell->m_BBox) / 4)) { | 
 |                         if(GetRectEnd(rect) - GetRectEnd(pCell->m_BBox) > 0) { | 
 |                             bMerge = TRUE; | 
 |                             bEnforce = TRUE; | 
 |                         } else if(GetRectEnd(rect) - GetRectEnd(pCell->m_BBox) <= 0 && | 
 |                                   GetRectEnd(rect) - GetRectEnd(pCell->m_BBox) > GetRectHeight(pCell->m_BBox) * -3) { | 
 |                             if(pCurObj->m_Type == PDFPAGE_TEXT) { | 
 |                                 CPDF_TextObject* pText = (CPDF_TextObject*)pCurObj; | 
 |                                 CPDF_TextObjectItem item; | 
 |                                 pText->GetItemInfo(0, &item); | 
 |                                 CFX_WideString str = pText->GetFont()->UnicodeFromCharCode(item.m_CharCode); | 
 |                                 FX_WCHAR unicode = str.GetAt(0); | 
 |                                 if(unicode > 96 && unicode < 123) { | 
 |                                     bMerge = TRUE; | 
 |                                 } | 
 |                             } | 
 |                         } | 
 |                     } | 
 |                 } else { | 
 |                     bMerge = TRUE; | 
 |                 } | 
 |             } | 
 |         } else { | 
 |             m_WritingMode = WritingMode; | 
 |             bEnforce = FALSE; | 
 |         } | 
 |         if(bMerge) { | 
 |             if(GetRectEnd(plastCell->m_BBox) - GetRectEnd(pCell->m_BBox) > 30) { | 
 |                 bEnforce = TRUE; | 
 |             } | 
 |             FX_POSITION pos = pCell->m_ObjList.GetHeadPosition(); | 
 |             while(pos) { | 
 |                 plastCell->m_ObjList.AddTail(pCell->m_ObjList.GetNext(pos)); | 
 |             } | 
 |             plastCell->m_BBox.Union(pCell->m_BBox); | 
 |             pCell->m_ObjList.RemoveAll(); | 
 |             delete pCell; | 
 |             cellArray.RemoveAt(i); | 
 |             i--; | 
 |             count--; | 
 |         } else { | 
 |             plastCell = pCell; | 
 |         } | 
 |     } | 
 | } | 
 | void CPDF_AutoReflowLayoutProvider::ProcessObj(CFX_PtrArray& cellArray, CPDF_PageObject* pObj, CFX_AffineMatrix matrix) | 
 | { | 
 | } | 
 | FX_INT32 CPDF_AutoReflowLayoutProvider::LogicPreObj(CPDF_PageObject* pObj) | 
 | { | 
 |     CPDF_PageObject* pPreObj = m_pPreObj; | 
 |     m_pPreObj = pObj; | 
 |     if(!pPreObj) { | 
 |         return 0; | 
 |     } | 
 |     if(pPreObj->m_Type != pObj->m_Type) { | 
 |         return 0; | 
 |     } | 
 |     CFX_FloatRect rcCurObj(pObj->m_Left, pObj->m_Bottom, pObj->m_Right, pObj->m_Top); | 
 |     CFX_FloatRect rcPreObj(pPreObj->m_Left, pPreObj->m_Bottom, pPreObj->m_Right, pPreObj->m_Top); | 
 |     if(pObj->m_Type == PDFPAGE_IMAGE) { | 
 |         if(rcPreObj.Contains(rcCurObj)) { | 
 |             return 2; | 
 |         } | 
 |         if(rcCurObj.Contains(rcPreObj)) { | 
 |             return 2; | 
 |         } | 
 |         return 0; | 
 |     } | 
 |     if(pObj->m_Type == PDFPAGE_TEXT) { | 
 |         if(!((rcPreObj.bottom > rcCurObj.top) || (rcPreObj.top < rcCurObj.bottom))) { | 
 |             FX_FLOAT height = FX_MIN(rcPreObj.Height(), rcCurObj.Height()); | 
 |             if((rcCurObj.left - rcPreObj.right) > height / 3) { | 
 |                 return 3; | 
 |             } | 
 |         } | 
 |         if(FXSYS_fabs(rcPreObj.Width() - rcCurObj.Width()) >= 2 || FXSYS_fabs(rcPreObj.Height() - rcCurObj.Height()) >= 2 ) { | 
 |             return 0; | 
 |         } | 
 |         CPDF_TextObject* pPreTextObj = (CPDF_TextObject*)pPreObj; | 
 |         CPDF_TextObject* pCurTextObj = (CPDF_TextObject*)pObj; | 
 |         int nPreCount = pPreTextObj->CountItems(); | 
 |         int nCurCount = pCurTextObj->CountItems(); | 
 |         if (nPreCount != nCurCount) { | 
 |             return 0; | 
 |         } | 
 |         FX_BOOL bSame = TRUE; | 
 |         for (int i = 0; i < nPreCount; i++) { | 
 |             CPDF_TextObjectItem itemPer, itemCur; | 
 |             pPreTextObj->GetItemInfo(i, &itemPer); | 
 |             pCurTextObj->GetItemInfo(i, &itemCur); | 
 |             if (itemCur.m_CharCode != itemPer.m_CharCode) { | 
 |                 return 0; | 
 |             } | 
 |             if (itemCur.m_OriginX != itemPer.m_OriginX) { | 
 |                 bSame = FALSE; | 
 |             } | 
 |             if (itemCur.m_OriginY != itemPer.m_OriginY) { | 
 |                 bSame = FALSE; | 
 |             } | 
 |         } | 
 |         if(rcPreObj.left == rcCurObj.left && rcPreObj.top == rcCurObj.top) { | 
 |             return 1; | 
 |         } | 
 |         if(FXSYS_fabs(rcPreObj.left - rcCurObj.left) < rcPreObj.Width() / 3 | 
 |                 && FXSYS_fabs(rcPreObj.top - rcCurObj.top) < rcPreObj.Height() / 3) { | 
 |             return 2; | 
 |         } | 
 |     } | 
 |     return 0; | 
 | } | 
 | void CPDF_AutoReflowLayoutProvider::GenerateLine(CFX_PtrArray& cellArray) | 
 | { | 
 |     CRF_CELL* pCell = NULL; | 
 |     CFX_AffineMatrix matrix; | 
 |     FX_POSITION pos = m_pPDFPage->GetFirstObjectPosition(); | 
 |     if(!pos) { | 
 |         return; | 
 |     } | 
 |     FX_FLOAT PDFWidth = m_pPDFPage->GetPageWidth(); | 
 |     FX_FLOAT PDFHeight = m_pPDFPage->GetPageHeight(); | 
 |     m_pPDFPage->GetDisplayMatrix(m_PDFDisplayMatrix, 0, 0, (int)PDFWidth, (int)PDFHeight, 0); | 
 |     CPDF_PageObject* pPerObj = NULL; | 
 |     int a = 0; | 
 |     CFX_FloatRect pageBBox = m_pPDFPage->m_BBox; | 
 |     FX_FLOAT PrevX = 0 , PrevY = 0, PosX, PosY; | 
 |     while(pos) { | 
 |         CPDF_PageObject* pObj = m_pPDFPage->GetNextObject(pos); | 
 |         if(!pObj || pObj->m_Type == PDFPAGE_PATH) { | 
 |             continue; | 
 |         } | 
 |         int logic = LogicPreObj(pObj); | 
 |         if(logic == 2) { | 
 |             if(pCell) { | 
 |                 pCell->m_ObjList.SetAt(pCell->m_ObjList.GetTailPosition(), pObj); | 
 |             } | 
 |             continue; | 
 |         } | 
 |         if (pObj->m_Type == PDFPAGE_TEXT) { | 
 |             CPDF_TextObject* pTextObj = (CPDF_TextObject*)pObj; | 
 |             int textmode = pTextObj->m_TextState.GetObject()->m_TextMode; | 
 |             if(m_Style.m_bIgnoreInvisibleText && pTextObj->m_TextState.GetObject()->m_TextMode == 3) { | 
 |                 continue; | 
 |             } | 
 |             PosX = pTextObj->GetPosX(); | 
 |             PosY = pTextObj->GetPosY(); | 
 |             m_PDFDisplayMatrix.Transform(PosX, PosY); | 
 |         } else { | 
 |             PosX = 0; | 
 |             PosY = 0; | 
 |         } | 
 |         FX_BOOL bNewLine = TRUE; | 
 |         FX_RECT ObjBBox = pObj->GetBBox(&m_PDFDisplayMatrix); | 
 |         if(ObjBBox.left > PDFWidth || ObjBBox.right < 0 || | 
 |                 ObjBBox.bottom < 0 || ObjBBox.top > PDFHeight) { | 
 |             continue; | 
 |         } | 
 |         if(ObjBBox.IsEmpty()) { | 
 |             continue; | 
 |         } | 
 |         a++; | 
 |         if(!pCell) { | 
 |             bNewLine = TRUE; | 
 |             m_WritingMode = GetWritingMode(NULL, pObj); | 
 |         } else { | 
 |             int WritingMode = GetWritingMode(pPerObj, pObj); | 
 |             if(m_WritingMode == WritingMode || m_WritingMode == WritingMode_UNKNOW || WritingMode == WritingMode_UNKNOW) { | 
 |                 if(WritingMode != WritingMode_UNKNOW) { | 
 |                     m_WritingMode = WritingMode; | 
 |                 } | 
 |                 if(m_WritingMode == WritingMode_TBRL) { | 
 |                     if(!(GetRectBottom(ObjBBox) > GetRectTop(pCell->m_BBox) || | 
 |                             GetRectTop(ObjBBox) < GetRectBottom(pCell->m_BBox))) { | 
 |                         bNewLine = FALSE; | 
 |                     } | 
 |                 } else { | 
 |                     if(!(GetRectBottom(ObjBBox) < GetRectTop(pCell->m_BBox) || | 
 |                             GetRectTop(ObjBBox) > GetRectBottom(pCell->m_BBox))) { | 
 |                         bNewLine = FALSE; | 
 |                     } | 
 |                     if (pObj->m_Type == PDFPAGE_TEXT) { | 
 |                         if(FXSYS_fabs(PrevY - PosY) < 1 ) { | 
 |                             bNewLine = FALSE; | 
 |                         } | 
 |                     } | 
 |                 } | 
 |             } else { | 
 |                 m_WritingMode = WritingMode; | 
 |             } | 
 |         } | 
 |         pPerObj = pObj; | 
 |         if(bNewLine) { | 
 |             int c = pCell ? pCell->m_ObjList.GetCount() : 0; | 
 |             pCell = FX_NEW CRF_CELL; | 
 |             pCell->m_CellWritingMode = m_WritingMode; | 
 |             pCell->m_BBox = ObjBBox; | 
 |             if(pObj->m_Type == PDFPAGE_TEXT) { | 
 |                 FX_FLOAT x = ((CPDF_TextObject*)pObj)->GetPosX(), y = ((CPDF_TextObject*)pObj)->GetPosY(); | 
 |                 m_PDFDisplayMatrix.Transform(x, y); | 
 |                 if(x < ObjBBox.left) { | 
 |                     pCell->m_BBox.left = (int)x; | 
 |                 } | 
 |             } | 
 |             pCell->m_ObjList.AddTail(pObj); | 
 |             cellArray.Add(pCell); | 
 |         } else { | 
 |             pCell->m_ObjList.AddTail(pObj); | 
 |             pCell->m_BBox.Union(ObjBBox); | 
 |         } | 
 |         PrevX = PosX; | 
 |         PrevY = PosY; | 
 |     } | 
 | } | 
 | FX_FLOAT CPDF_AutoReflowLayoutProvider::GetLayoutOrderHeight(CPDF_PageObject* pCurObj) | 
 | { | 
 |     CFX_FloatRect rcCurObj(pCurObj->m_Left, pCurObj->m_Bottom, pCurObj->m_Right, pCurObj->m_Top); | 
 |     if (m_WritingMode == WritingMode_TBRL) { | 
 |         return rcCurObj.Width(); | 
 |     } | 
 |     return rcCurObj.Height(); | 
 | } | 
 | FX_FLOAT CPDF_AutoReflowLayoutProvider::GetLayoutOrderWidth(CPDF_PageObject* pCurObj) | 
 | { | 
 |     CFX_FloatRect rcCurObj(pCurObj->m_Left, pCurObj->m_Bottom, pCurObj->m_Right, pCurObj->m_Top); | 
 |     if (m_WritingMode == WritingMode_TBRL) { | 
 |         return rcCurObj.Height(); | 
 |     } | 
 |     return rcCurObj.Width(); | 
 | } | 
 | int CPDF_AutoReflowLayoutProvider:: GetRectWidth(FX_RECT rect) | 
 | { | 
 |     if(m_WritingMode == WritingMode_TBRL) { | 
 |         return rect.Height(); | 
 |     } | 
 |     return rect.Width(); | 
 | } | 
 | int CPDF_AutoReflowLayoutProvider:: GetRectHeight(FX_RECT rect) | 
 | { | 
 |     if(m_WritingMode == WritingMode_TBRL) { | 
 |         return rect.Width(); | 
 |     } | 
 |     return rect.Height(); | 
 | } | 
 | int CPDF_AutoReflowLayoutProvider:: GetRectStart(FX_RECT rect) | 
 | { | 
 |     if(m_WritingMode == WritingMode_TBRL) { | 
 |         return rect.top; | 
 |     } | 
 |     return rect.left; | 
 | } | 
 | int CPDF_AutoReflowLayoutProvider:: GetRectEnd(FX_RECT rect) | 
 | { | 
 |     if(m_WritingMode == WritingMode_TBRL) { | 
 |         return rect.bottom; | 
 |     } | 
 |     return rect.right; | 
 | } | 
 | int CPDF_AutoReflowLayoutProvider:: GetRectTop(FX_RECT rect) | 
 | { | 
 |     if(m_WritingMode == WritingMode_TBRL) { | 
 |         return rect.right; | 
 |     } | 
 |     return rect.top; | 
 | } | 
 | int CPDF_AutoReflowLayoutProvider:: GetRectBottom(FX_RECT rect) | 
 | { | 
 |     if(m_WritingMode == WritingMode_TBRL) { | 
 |         return rect.left; | 
 |     } | 
 |     return rect.bottom; | 
 | } | 
 | int CPDF_AutoReflowLayoutProvider::GetWritingMode(CPDF_PageObject* pPreObj, CPDF_PageObject* pCurObj) | 
 | { | 
 |     CFX_FloatRect rcCurObj(pCurObj->m_Left, pCurObj->m_Bottom, pCurObj->m_Right, pCurObj->m_Top); | 
 |     if(pCurObj->m_Type == PDFPAGE_TEXT) { | 
 |         CPDF_TextObject* ptextObj = (CPDF_TextObject* )pCurObj; | 
 |         int count = ptextObj->CountItems(); | 
 |         if(count > 1) { | 
 |             CPDF_TextObjectItem Item1, Item2; | 
 |             ptextObj->GetItemInfo(0, &Item1); | 
 |             ptextObj->GetItemInfo(count - 1, &Item2); | 
 |             if(Item2.m_CharCode == -1 && count > 2) { | 
 |                 ptextObj->GetItemInfo(2, &Item2); | 
 |             } | 
 |             CFX_AffineMatrix textMatrix; | 
 |             ptextObj->GetTextMatrix(&textMatrix); | 
 |             textMatrix.Transform(Item1.m_OriginX, Item1.m_OriginY); | 
 |             textMatrix.Transform(Item2.m_OriginX, Item2.m_OriginY); | 
 |             FX_FLOAT dx = FXSYS_fabs(Item1.m_OriginX - Item2.m_OriginX); | 
 |             FX_FLOAT dy = FXSYS_fabs(Item1.m_OriginY - Item2.m_OriginY); | 
 |             return dx >= dy ? WritingMode_LRTB : WritingMode_TBRL; | 
 |         } else { | 
 |             if(m_WritingMode != WritingMode_UNKNOW) { | 
 |                 return m_WritingMode; | 
 |             } | 
 |         } | 
 |     } | 
 |     if(pPreObj) { | 
 |         FX_FLOAT threshold = rcCurObj.Width() / 4; | 
 |         if(m_WritingMode == WritingMode_LRTB) { | 
 |             if(FXSYS_fabs(pPreObj->m_Bottom - pCurObj->m_Bottom) < threshold * 2 | 
 |                     && FXSYS_fabs(pPreObj->m_Top - pCurObj->m_Top) < threshold * 2) { | 
 |                 return m_WritingMode; | 
 |             } | 
 |             FX_FLOAT mid = (pCurObj->m_Bottom + pCurObj->m_Top) / 2; | 
 |             if(mid > pPreObj->m_Bottom && mid < pPreObj->m_Top && pCurObj->m_Right > pPreObj->m_Right) { | 
 |                 return m_WritingMode; | 
 |             } | 
 |         } else if(m_WritingMode == WritingMode_TBRL) { | 
 |             if(FXSYS_fabs(pPreObj->m_Left - pCurObj->m_Left) < threshold * 2 | 
 |                     && FXSYS_fabs(pPreObj->m_Right - pCurObj->m_Right) < threshold * 2) { | 
 |                 return m_WritingMode; | 
 |             } | 
 |             FX_FLOAT mid = (pCurObj->m_Right + pCurObj->m_Left) / 2; | 
 |             if(mid > pPreObj->m_Left && mid < pPreObj->m_Right && pCurObj->m_Bottom < pPreObj->m_Bottom) { | 
 |                 return m_WritingMode; | 
 |             } | 
 |         } | 
 |         if(FXSYS_fabs(pPreObj->m_Left - pCurObj->m_Left) < threshold && | 
 |                 FXSYS_fabs(pPreObj->m_Bottom - pCurObj->m_Bottom) > threshold * 2) { | 
 |             return WritingMode_TBRL; | 
 |         } | 
 |         if(FXSYS_fabs(pPreObj->m_Left - pCurObj->m_Left) > threshold && | 
 |                 FXSYS_fabs(pPreObj->m_Bottom - pCurObj->m_Bottom) < threshold * 2) { | 
 |             return WritingMode_LRTB; | 
 |         } | 
 |         int count = 0; | 
 |         if(pPreObj->m_Type == PDFPAGE_TEXT) { | 
 |             CPDF_TextObject* ptextObj = (CPDF_TextObject* )pCurObj; | 
 |             count = ptextObj->CountItems(); | 
 |         } | 
 |         if(pPreObj->m_Type != PDFPAGE_TEXT || count == 1) { | 
 |             if(pCurObj->m_Left > pPreObj->m_Right) { | 
 |                 FX_FLOAT mid = (pCurObj->m_Top + pCurObj->m_Bottom) / 2; | 
 |                 if(mid < pPreObj->m_Top && mid > pPreObj->m_Bottom) { | 
 |                     return WritingMode_LRTB; | 
 |                 } | 
 |             } | 
 |             if(pCurObj->m_Top < pPreObj->m_Bottom) { | 
 |                 FX_FLOAT mid = (pCurObj->m_Left + pCurObj->m_Right) / 2; | 
 |                 if(mid < pPreObj->m_Right && mid > pPreObj->m_Left) { | 
 |                     return WritingMode_TBRL; | 
 |                 } | 
 |             } | 
 |         } | 
 |     } | 
 |     return WritingMode_UNKNOW; | 
 | } | 
 | LayoutStatus CPDF_AutoReflowLayoutProvider::StartLoad(IFX_Pause* pPause) | 
 | { | 
 |     m_pPause = pPause; | 
 |     m_pRoot = FX_NEW CPDF_AutoReflowElement(LayoutDocument); | 
 |     if(!m_pRoot) { | 
 |         return LayoutError; | 
 |     } | 
 |     m_Step = 0; | 
 |     return Continue(); | 
 | } | 
 | LayoutStatus CPDF_AutoReflowLayoutProvider::Continue() | 
 | { | 
 |     GenerateStructTree(); | 
 |     return m_Status; | 
 | } | 
 | int	CPDF_AutoReflowLayoutProvider::GetPosition() | 
 | { | 
 |     if(m_Step == 0) { | 
 |         return 0; | 
 |     } else { | 
 |         return m_Step * 100 / AUTOREFLOW_STEP_REMOVEDATA; | 
 |     } | 
 | } | 
 | FX_FLOAT CPDF_AutoReflowLayoutProvider::GetObjMinCell(CPDF_PageObject* pObj) | 
 | { | 
 |     if(!pObj) { | 
 |         return 0; | 
 |     } | 
 |     if(pObj->m_Type != PDFPAGE_TEXT) { | 
 |         CFX_AffineMatrix matrix; | 
 |         FX_RECT rect = pObj->GetBBox(&matrix); | 
 |         return (FX_FLOAT)(rect.Width()); | 
 |     } | 
 |     CPDF_TextObject* pTextObj = (CPDF_TextObject* )pObj; | 
 |     int count = pTextObj->CountItems(); | 
 |     for(int i = 0; i < count; i++) { | 
 |         CPDF_TextObjectItem Item; | 
 |         pTextObj->GetItemInfo(i, &Item); | 
 |         if(Item.m_CharCode == -1) { | 
 |             continue; | 
 |         } | 
 |         if((Item.m_CharCode > 47 && Item.m_CharCode < 58) || (Item.m_CharCode > 64 && Item.m_CharCode < 91) | 
 |                 || (Item.m_CharCode > 96 && Item.m_CharCode < 123)) { | 
 |             continue; | 
 |         } | 
 |         if(Item.m_CharCode > 127 || (Item.m_CharCode > 32 && Item.m_CharCode < 35) || Item.m_CharCode == 37 || | 
 |                 (Item.m_CharCode > 38 && Item.m_CharCode < 42) || Item.m_CharCode == 44 || Item.m_CharCode == 46 || | 
 |                 Item.m_CharCode == 58 || Item.m_CharCode == 59 || Item.m_CharCode == 63 || Item.m_CharCode == 93) { | 
 |             if(i == count - 1) { | 
 |                 CFX_AffineMatrix matrix; | 
 |                 FX_RECT rect = pObj->GetBBox(&matrix); | 
 |                 return (FX_FLOAT)(rect.Width()); | 
 |             } else { | 
 |                 pTextObj->GetItemInfo(i + 1, &Item); | 
 |                 return Item.m_OriginX; | 
 |             } | 
 |         } | 
 |         return Item.m_OriginX; | 
 |     } | 
 |     CFX_AffineMatrix matrix; | 
 |     FX_RECT rect = pObj->GetBBox(&matrix); | 
 |     return (FX_FLOAT)(rect.Width()); | 
 | } |