// 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 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 = 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 = 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 = new CPDF_AutoReflowElement(LayoutDocument);
    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());
}