diff options
author | John Abd-El-Malek <jabdelmalek@google.com> | 2014-05-17 22:33:34 -0700 |
---|---|---|
committer | John Abd-El-Malek <jabdelmalek@google.com> | 2014-05-17 22:33:34 -0700 |
commit | 5110c4743751145c4ae1934cd1d83bc6c55bb43f (patch) | |
tree | b141608096b73163182764c25b895d3df4b2c182 /core/src/reflow | |
parent | 76b563d2feed92ed328afb1f15e3466a9536b11b (diff) | |
download | pdfium-5110c4743751145c4ae1934cd1d83bc6c55bb43f.tar.xz |
Initial commit.
Diffstat (limited to 'core/src/reflow')
-rw-r--r-- | core/src/reflow/autoreflow.cpp | 781 | ||||
-rw-r--r-- | core/src/reflow/autoreflow.h | 122 | ||||
-rw-r--r-- | core/src/reflow/layoutprocessor_reflow.cpp | 1560 | ||||
-rw-r--r-- | core/src/reflow/layoutprovider_taggedpdf.cpp | 780 | ||||
-rw-r--r-- | core/src/reflow/layoutprovider_taggedpdf.h | 82 | ||||
-rw-r--r-- | core/src/reflow/reflowedpage.cpp | 622 | ||||
-rw-r--r-- | core/src/reflow/reflowedpage.h | 372 | ||||
-rw-r--r-- | core/src/reflow/reflowedtextpage.cpp | 402 | ||||
-rw-r--r-- | core/src/reflow/reflowedtextpage.h | 71 | ||||
-rw-r--r-- | core/src/reflow/reflowengine.cpp | 38 |
10 files changed, 4830 insertions, 0 deletions
diff --git a/core/src/reflow/autoreflow.cpp b/core/src/reflow/autoreflow.cpp new file mode 100644 index 0000000000..8c37960932 --- /dev/null +++ b/core/src/reflow/autoreflow.cpp @@ -0,0 +1,781 @@ +// 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()); +} diff --git a/core/src/reflow/autoreflow.h b/core/src/reflow/autoreflow.h new file mode 100644 index 0000000000..d98f33bf4e --- /dev/null +++ b/core/src/reflow/autoreflow.h @@ -0,0 +1,122 @@ +// 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 + +#ifndef _AUTOREFLOW_H +#define _AUTOREFLOW_H +#include "../../include/reflow/reflowengine.h" +#include "reflowedpage.h" +class CPDF_AutoReflowElement; +class CPDF_AutoReflowLayoutProvider; +typedef CFX_ArrayTemplate<CPDF_AutoReflowElement*> CAR_ElmPtrArray; +typedef CFX_ArrayTemplate<CPDF_PageObject*> CAR_ObjPtrArray; +class CRF_CELL : public CFX_Object +{ +public: + CRF_CELL() { }; + ~CRF_CELL() { }; + CFX_PtrList m_ObjList; + int m_CellWritingMode; + FX_RECT m_BBox; +}; +class CPDF_AutoReflowElement : public IPDF_LayoutElement, public CFX_Object +{ +public: + CPDF_AutoReflowElement(LayoutType layoutType = LayoutUnknown , CPDF_AutoReflowElement* pParent = NULL) ; + ~CPDF_AutoReflowElement(); + LayoutType GetType() + { + return m_ElmType; + } + void GetRect(CFX_FloatRect& rcRect) {}; + + int CountAttrValues(LayoutAttr attr_type); + LayoutEnum GetEnumAttr(LayoutAttr attr_type, int index); + FX_FLOAT GetNumberAttr(LayoutAttr attr_type, int index); + FX_COLORREF GetColorAttr(LayoutAttr attr_type, int index); + + int CountChildren() + { + return m_ChildArray.GetSize(); + } + IPDF_LayoutElement* GetChild(int index) + { + return m_ChildArray.GetAt(index); + } + + IPDF_LayoutElement* GetParent() + { + return m_pParentElm; + } + int CountObjects() + { + return m_ObjArray.GetSize(); + } + CPDF_PageObject* GetObject(int index) + { + return m_ObjArray.GetAt(index); + } + CPDF_AutoReflowElement* m_pParentElm; + LayoutType m_ElmType; + CAR_ElmPtrArray m_ChildArray; + CAR_ObjPtrArray m_ObjArray; + FX_FLOAT m_SpaceBefore; +}; +#define AUTOREFLOW_STEP_GENERATELINE 1 +#define AUTOREFLOW_STEP_GENERATEParagraph 2 +#define AUTOREFLOW_STEP_CREATEELEMENT 3 +#define AUTOREFLOW_STEP_REMOVEDATA 4 +class CPDF_AutoReflowLayoutProvider : public IPDF_LayoutProvider, public CFX_Object +{ +public: + CPDF_AutoReflowLayoutProvider(CPDF_PageObjects* pPage, FX_BOOL bReadOrder); + ~CPDF_AutoReflowLayoutProvider(); + void SetLayoutProviderStyle(LAYOUTPROVIDER_STYLE Style) + { + m_Style = Style; + } + LayoutStatus StartLoad(IFX_Pause* pPause = NULL); + LayoutStatus Continue(); + int GetPosition(); + IPDF_LayoutElement* GetRoot() + { + return m_pRoot; + } + FX_FLOAT GetObjMinCell(CPDF_PageObject* pObj); + void Conver2AppreceOrder(const CPDF_PageObjects* pStreamOrderObjs, CPDF_PageObjects* pAppraceOrderObjs); + void ReleaseElm(CPDF_AutoReflowElement*& pElm, FX_BOOL bReleaseChildren = TRUE); + void GenerateCell(); + void GenerateStructTree(); + void GenerateLine(CFX_PtrArray& cellArray); + void GenerateParagraph(CFX_PtrArray& cellArray); + void CreateElement(); + void AddObjectArray(CPDF_AutoReflowElement* pElm, CFX_PtrList& ObjList); + FX_FLOAT GetLayoutOrderHeight(CPDF_PageObject* pCurObj); + FX_FLOAT GetLayoutOrderWidth(CPDF_PageObject* pCurObj); + int GetWritingMode(CPDF_PageObject* pPreObj, CPDF_PageObject* pCurObj); + int GetRectStart(FX_RECT rect); + int GetRectEnd(FX_RECT rect); + int GetRectTop(FX_RECT rect); + int GetRectBottom(FX_RECT rect); + int GetRectHeight(FX_RECT rect); + int GetRectWidth(FX_RECT rect); + void ProcessObj(CFX_PtrArray& cellArray, CPDF_PageObject* pObj, CFX_AffineMatrix matrix); + FX_INT32 LogicPreObj(CPDF_PageObject* pObj); + + CPDF_AutoReflowElement* m_pRoot; + CPDF_AutoReflowElement* m_pCurrElm; + CPDF_Page* m_pPDFPage; + IFX_Pause* m_pPause; + CFX_AffineMatrix m_PDFDisplayMatrix; + CPDF_PageObject* m_pPreObj; + LayoutStatus m_Status; + int m_WritingMode; + CFX_PtrArray m_CellArray; + FX_BOOL m_bReadOrder; + LAYOUTPROVIDER_STYLE m_Style; + CFX_PtrArray m_cellArray; + int m_Step; +}; +#endif diff --git a/core/src/reflow/layoutprocessor_reflow.cpp b/core/src/reflow/layoutprocessor_reflow.cpp new file mode 100644 index 0000000000..d2fa7e9371 --- /dev/null +++ b/core/src/reflow/layoutprocessor_reflow.cpp @@ -0,0 +1,1560 @@ +// 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 "../../include/reflow/reflowengine.h" +#include "reflowedpage.h" +#include "layoutprovider_taggedpdf.h" +IPDF_LayoutProcessor* IPDF_LayoutProcessor::Create_LayoutProcessor_Reflow(FX_FLOAT TopIndent, FX_FLOAT fWidth, FX_FLOAT fHeight, void* pReflowedPage, int flags, FX_FLOAT lineSpace ) +{ + if(pReflowedPage == NULL || fWidth <= 20) { + return NULL; + } + CPDF_LayoutProcessor_Reflow* pReflowEngine = FX_NEW CPDF_LayoutProcessor_Reflow(); + if (NULL == pReflowEngine) { + return NULL; + } + pReflowEngine->Init(TopIndent, fWidth, fHeight, (CPDF_ReflowedPage*)pReflowedPage, flags, lineSpace); + return pReflowEngine; +} +CPDF_LayoutProcessor_Reflow::CPDF_LayoutProcessor_Reflow() +{ + m_pPause = NULL; + m_pLayoutElement = NULL; + m_fRefWidth = 0; + m_fRefWidth = 0; + m_fCurrLineWidth = 0; + m_fCurrLineHeight = 0; + m_bIllustration = FALSE; + m_pPreObj = NULL; + m_pCurrLine = FX_NEW CRF_DataPtrArray(50); + m_pTempLine = FX_NEW CRF_DataPtrArray(50); + m_StartIndent = 0; + m_PausePosition = 0; +} +CPDF_LayoutProcessor_Reflow::~CPDF_LayoutProcessor_Reflow() +{ + if (m_pCurrLine) { + m_pCurrLine->RemoveAll(); + delete m_pCurrLine; + } + m_pCurrLine = NULL; + if (m_pTempLine) { + m_pTempLine->RemoveAll(); + delete m_pTempLine; + } + m_pTempLine = NULL; +} +void CPDF_LayoutProcessor_Reflow::Init(FX_FLOAT TopIndent, FX_FLOAT fWidth, FX_FLOAT fHeight, CPDF_ReflowedPage* pReflowedPage, int flags, FX_FLOAT lineSpace) +{ + m_pLayoutElement = NULL; + m_TopIndent = TopIndent; + m_Status = LayoutReady; + m_flags = flags; + m_pReflowedPage = pReflowedPage; + m_fScreenHeight = fHeight; + m_fRefWidth = fWidth; + m_fCurrLineHeight = 0; + m_fCurrLineWidth = 0; + m_fLineSpace = lineSpace; + pReflowedPage->m_PageWidth = fWidth; + pReflowedPage->m_PageHeight = TopIndent; +} +void CPDF_LayoutProcessor_Reflow::FitPageMode() +{ + if(m_flags & RF_PARSER_PAGEMODE && m_fScreenHeight > 20) { + float fitPageHeight = m_fScreenHeight; + CPDF_ReflowedPage* pRFPage = m_pReflowedPage; + int count = pRFPage->m_pReflowed->GetSize(); + CFX_WordArray dy; + dy.Add(0); + int pos = 0; + int screenCount = 1; + FX_FLOAT h = pRFPage->GetPageHeight(); + while (h > screenCount * fitPageHeight) { + FX_FLOAT tempPageHeight = screenCount * fitPageHeight; + int j = 0; + FX_FLOAT tempDy = 0; + for(int i = 0; i < count; i++) { + CRF_Data* pData = (*pRFPage->m_pReflowed)[i]; + FX_FLOAT posY; + posY = pData->m_PosY; + if(FXSYS_fabs(posY) > tempPageHeight && + FXSYS_fabs(posY + pData->m_Height) < tempPageHeight) { + if(j == 0) { + j = i; + } + if(pData->m_Height > fitPageHeight) { + FX_FLOAT zoom; + FX_FLOAT spaceh = screenCount * fitPageHeight + posY + pData->m_Height; + if(spaceh < fitPageHeight / 3 * 2) { + spaceh = fitPageHeight; + } + zoom = spaceh / pData->m_Height; + tempDy = spaceh - pData->m_Height; + pData->m_Height = spaceh; + pData->m_Width *= zoom; + break; + } + FX_FLOAT dy = pData->m_PosY + pData->m_Height + tempPageHeight; + if(dy > tempDy) { + tempDy = dy; + } + } else if(FXSYS_fabs(posY + pData->m_Height) > tempPageHeight) { + break; + } + } + for(; j < count; j++) { + CRF_Data* pData = (*pRFPage->m_pReflowed)[j]; + FX_FLOAT posY; + posY = pData->m_PosY; + if(FXSYS_fabs(posY) > tempPageHeight ) { + pData->m_PosY -= tempDy; + } + if(pData->m_Height >= fitPageHeight) { + pData->m_Height = fitPageHeight - 1; + if(pData->GetType() == CRF_Data::Text) { + CRF_CharData* pCharData = (CRF_CharData*)pData; + pCharData->m_pCharState->m_fFontSize = pData->m_Height; + } + } + } + pRFPage->m_PageHeight += tempDy; + h += tempDy; + screenCount++; + } + } +} +LayoutStatus CPDF_LayoutProcessor_Reflow::StartProcess(IPDF_LayoutElement* pElement, IFX_Pause* pPause, const CFX_AffineMatrix* pPDFMatrix) +{ + if(!pElement) { + return LayoutError; + } + m_pPause = pPause; + m_PDFMatrix = *pPDFMatrix; + m_pRootElement = pElement; + ProcessElement(m_pRootElement, m_fRefWidth); + if(m_Status == LayoutToBeContinued) { + return LayoutToBeContinued; + } + m_Status = LayoutFinished; + FitPageMode(); + return LayoutFinished; +} +LayoutStatus CPDF_LayoutProcessor_Reflow::Continue() +{ + int size = m_pReflowedPage->m_pReflowed->GetSize(); + ProcessElement(m_pRootElement, m_CurrRefWidth); + size = m_pReflowedPage->m_pReflowed->GetSize(); + if(m_Status == LayoutReady) { + m_Status = LayoutFinished; + FitPageMode(); + } + return m_Status; +} +int CPDF_LayoutProcessor_Reflow::GetPosition() +{ + return m_PausePosition; +} +FX_BOOL CPDF_LayoutProcessor_Reflow::IsCanBreakAfter(FX_DWORD unicode) +{ + if(unicode == -1) { + return FALSE; + } + switch(unicode) { + case 40: + case 91: + case 123: + return FALSE; + } + if(unicode >= 256) { + return TRUE; + } else if(unicode >= 48 && unicode <= 57) { + return FALSE; + } else if(unicode >= 64 && unicode <= 90) { + return FALSE; + } else if(unicode >= 97 && unicode <= 122) { + return FALSE; + } + return TRUE; +} +FX_BOOL CPDF_LayoutProcessor_Reflow::IsCanBreakBefore(FX_DWORD unicode) +{ + if(unicode == -1) { + return FALSE; + } + switch(unicode) { + case 33: + case 41: + case 44: + case 46: + case 59: + case 63: + case 93: + case 125: + return FALSE; + } + if(unicode >= 256) { + return TRUE; + } else if(unicode >= 48 && unicode <= 57) { + return FALSE; + } else if(unicode >= 64 && unicode <= 90) { + return FALSE; + } else if(unicode >= 97 && unicode <= 122) { + return FALSE; + } + return TRUE; +} +void CPDF_LayoutProcessor_Reflow::ProcessTable(FX_FLOAT dx) +{ + if(m_pReflowedPage->m_pReflowed->GetSize() == 0) { + return; + } + CRF_Table* pTable = m_TableArray.GetAt(m_TableArray.GetSize() - 1); + int rowCount = pTable->m_nCell.GetSize(); + int n = 0; + FX_FLOAT* dyRow = FX_Alloc(FX_FLOAT, rowCount + 1); + FXSYS_memset32(dyRow, 0, sizeof(FX_FLOAT) * (rowCount + 1)); + dyRow[0] = 0 ; + dyRow[0] = - pTable->m_ReflowPageHeight; + int tableColCount = 0; + int i; + for(i = 0; i < rowCount; i++) { + int colCount = pTable->m_nCell.GetAt(i); + if(colCount > tableColCount) { + tableColCount = colCount; + } + } + int cellCount = tableColCount * rowCount; + RF_TableCell** pVirtualTable = FX_Alloc(RF_TableCell*, cellCount); + FXSYS_memset32(pVirtualTable, 0, sizeof(RF_TableCell*) * cellCount); + for(i = 0; i < rowCount; i++) { + int colCount = pTable->m_nCell.GetAt(i); + FX_FLOAT rowWidth = 0; + int j = 0; + int s = pTable->m_pCellArray.GetSize(); + for(j = 0; j < colCount; j++) { + RF_TableCell* pCell = (RF_TableCell*)pTable->m_pCellArray.GetAt(n++); + if(pCell->m_EndPos < pCell->m_BeginPos) { + continue; + } + int pos = i * tableColCount; + while(pos < cellCount && pVirtualTable[pos] != NULL) { + pos++; + } + if(pos >= (i + 1) * tableColCount) { + pos = i * tableColCount + j; + } + int RowSpan = pCell->m_RowSpan; + int ColSpan = pCell->m_ColSpan; + if(RowSpan + i > rowCount) { + RowSpan = rowCount - i; + } + if(ColSpan + j > colCount) { + ColSpan = colCount - j; + } + for(int m = 0; m < RowSpan; m++) { + for(int nn = 0; nn < ColSpan; nn++) { + if(pos + nn >= cellCount) { + break; + } + pVirtualTable[pos + nn] = pCell; + } + pos += tableColCount; + } + FX_FLOAT dxCell = dx; + for(pos = i * tableColCount; pVirtualTable[pos] != pCell && pos < cellCount; pos++) { + dxCell += (pVirtualTable[pos])->m_MaxWidth; + } + CRF_Data* pData = (*m_pReflowedPage->m_pReflowed)[pCell->m_BeginPos]; + FX_FLOAT dy = dyRow[i] - pData->m_Height - pData->m_PosY; + CFX_AffineMatrix matrix(1, 0, 0, 1, dxCell, dy); + Transform(&matrix, m_pReflowedPage->m_pReflowed, pCell->m_BeginPos, pCell->m_EndPos - pCell->m_BeginPos + 1); + if(pCell->m_RowSpan + i <= rowCount) { + if(FXSYS_fabs(dyRow[pCell->m_RowSpan + i]) < FXSYS_fabs(dyRow[i] - pCell->m_CellHeight)) { + dyRow[pCell->m_RowSpan + i] = dyRow[i] - pCell->m_CellHeight; + } + } + } + } + n = 0; + for(i = 0; i < rowCount; i++) { + int colCount = pTable->m_nCell.GetAt(i); + for(int j = 0; j < colCount; j++) { + RF_TableCell* pCell = (RF_TableCell*)pTable->m_pCellArray.GetAt(n++); + switch(pCell->m_BlockAlign) { + case LayoutAfter: { + FX_FLOAT dy = dyRow[i + pCell->m_RowSpan] - pCell->m_CellHeight - dyRow[i]; + CFX_AffineMatrix matrix(1, 0, 0, 1, 0, dy); + Transform(&matrix, m_pReflowedPage->m_pReflowed, pCell->m_BeginPos, pCell->m_EndPos - pCell->m_BeginPos + 1); + } + break; + case LayoutMiddle: + case LayoutJustify: { + FX_FLOAT dy = (dyRow[i + pCell->m_RowSpan] + pCell->m_CellHeight - dyRow[i]) / 2; + CFX_AffineMatrix matrix(1, 0, 0, 1, 0, dy); + Transform(&matrix, m_pReflowedPage->m_pReflowed, pCell->m_BeginPos, pCell->m_EndPos - pCell->m_BeginPos + 1); + break; + } + default: + break; + } + } + } + CRF_Data* pData = (*m_pReflowedPage->m_pReflowed)[m_pReflowedPage->m_pReflowed->GetSize() - 1]; + m_pReflowedPage->m_PageHeight = - dyRow[rowCount] + pData->m_Height; + FX_Free(pVirtualTable); + FX_Free(dyRow); + int size = pTable->m_pCellArray.GetSize(); + for(i = 0; i < size; i++) { + RF_TableCell* pCell = pTable->m_pCellArray.GetAt(i); + FX_Free(pCell); + } + pTable->m_pCellArray.RemoveAll(); + pTable->m_nCell.RemoveAll(); + int s = sizeof(CRF_Table); + delete pTable; + m_TableArray.RemoveAt(m_TableArray.GetSize() - 1); +} +CFX_FloatRect CPDF_LayoutProcessor_Reflow::GetElmBBox(IPDF_LayoutElement* pElement) +{ + CFX_FloatRect rect; + int objCount = pElement->CountObjects(); + int count = pElement->CountChildren(); + if(objCount == 0 && count == 0) { + return rect; + } + CFX_AffineMatrix matrix; + int i; + for(i = 0; i < objCount; i++) { + CPDF_PageObject* pObj = pElement->GetObject(0); + if(!pObj) { + continue; + } + if( rect.Height() == 0 ) { + rect = pObj->GetBBox(&matrix); + } else { + rect.Union(pObj->GetBBox(&matrix)); + } + } + for(i = 0; i < count; i++) { + IPDF_LayoutElement* pChildElement = pElement->GetChild(i); + if( rect.Height() == 0 ) { + rect = GetElmBBox(pChildElement); + } else { + rect.Union(GetElmBBox(pChildElement)); + } + } + return rect; +} +FX_FLOAT CPDF_LayoutProcessor_Reflow::GetElmWidth(IPDF_LayoutElement* pElement) +{ + if(!pElement) { + return 0; + } + LayoutType layoutType = pElement->GetType(); + FX_FLOAT width = 0; + if(layoutType == LayoutTable || layoutType == LayoutTableDataCell || layoutType == LayoutTableHeaderCell) { + width = pElement->GetNumberAttr(LayoutWidth); + if(width > 0) { + return width; + } + } else if( layoutType == LayoutTableRow) { + int count = pElement->CountChildren(); + for(int i = 0; i < count; i++) { + IPDF_LayoutElement* pElm = pElement->GetChild(i); + width += pElm->GetNumberAttr(LayoutWidth); + } + if(width > 0) { + return width; + } + } + CFX_FloatRect rect = GetElmBBox(pElement); + return rect.Width(); +} +FX_BOOL GetIntersection(FX_FLOAT low1, FX_FLOAT high1, FX_FLOAT low2, FX_FLOAT high2, + FX_FLOAT& interlow, FX_FLOAT& interhigh); +FX_BOOL IsSameLine(FX_BOOL bHorizontal, CFX_FloatRect Rect1, CFX_FloatRect Rect2) +{ + if(bHorizontal) { + FX_FLOAT inter_top, inter_bottom; + if (!GetIntersection(Rect1.bottom, Rect1.top, Rect2.bottom, Rect2.top, + inter_bottom, inter_top)) { + return FALSE; + } + FX_FLOAT lineHeight = Rect1.top - Rect1.bottom; + if(lineHeight > 20 && lineHeight > Rect2.Height() * 2) { + return FALSE; + } + if(lineHeight > 5 && Rect2.Height() / 2 > lineHeight) { + return FALSE; + } + FX_FLOAT inter_h = inter_top - inter_bottom; + if (inter_h < (lineHeight) / 2 && inter_h < Rect2.Height() / 2) { + return FALSE; + } + } else { + FX_FLOAT inter_left, inter_right; + if(!GetIntersection(Rect1.left, Rect1.right, Rect2.left, Rect2.right, inter_left, inter_right)) { + return FALSE; + } + FX_FLOAT inter_w = inter_right - inter_left; + if (inter_w < (Rect1.right - Rect1.left) / 2 && inter_w < (Rect2.right - Rect2.left) / 2) { + return FALSE; + } + } + return TRUE; +} +FX_INT32 IsCanMergeParagraph(IPDF_LayoutElement* pPrevElement, IPDF_LayoutElement* pNextElement) +{ + FX_INT32 analogial = 100; + FX_INT32 nPrevObj = pPrevElement->CountObjects(), i; + CPDF_PageObject* pPrevObj = NULL; + CFX_FloatRect prevRect, rect; + CFX_PtrArray prevLine, line; + FX_BOOL bParagraphStart = FALSE; + for(i = 0; i < nPrevObj; i++) { + CPDF_PageObject* pObj = pPrevElement->GetObject(i); + if(!pPrevObj) { + pPrevObj = pObj; + rect = CFX_FloatRect(pObj->m_Left, pObj->m_Bottom, pObj->m_Right, pObj->m_Top); + line.Add(pObj); + continue; + } + CFX_FloatRect objRect = CFX_FloatRect(pObj->m_Left, pObj->m_Bottom, pObj->m_Right, pObj->m_Top); + if(IsSameLine(TRUE, rect, objRect)) { + line.Add(pObj); + rect.Union(objRect); + } else { + prevLine.RemoveAll(); + prevLine.Append(line); + prevRect = rect; + line.RemoveAll(); + line.Add(pObj); + rect = objRect; + if(!bParagraphStart) { + if (prevRect.left > rect.left + rect.Height() * 1.5) { + bParagraphStart = TRUE; + } + } + } + } + if(prevLine.GetSize()) { + if(FXSYS_fabs(rect.right - prevRect.right) > rect.Height()) { + analogial -= 50; + } + } + CPDF_PageObject* pObj = pPrevElement->GetObject(nPrevObj - 1); + if(pObj->m_Type == PDFPAGE_TEXT) { + CPDF_TextObject* pText = (CPDF_TextObject*)pObj; + FX_INT32 nItem = pText->CountItems(); + CPDF_TextObjectItem item; + pText->GetItemInfo(nItem - 1, &item); + CFX_WideString wStr = pText->GetFont()->UnicodeFromCharCode(item.m_CharCode); + if(wStr.IsEmpty()) { + wStr = (FX_WCHAR)item.m_CharCode; + } + FX_WCHAR wch = wStr.GetAt(wStr.GetLength() - 1); + switch(wch) { + case '.': + case 12290: + case 65311: + case 63: + case 33: + case 65281: + analogial -= 50; + break; + } + } + prevLine.RemoveAll(); + prevLine.Append(line); + line.RemoveAll(); + FX_INT32 nNextObj = pNextElement->CountObjects(); + pPrevObj = NULL; + FX_BOOL bFirst = TRUE; + for(i = 0; i < nNextObj; i++) { + CPDF_PageObject* pObj = pNextElement->GetObject(i); + if(!pPrevObj) { + pPrevObj = pObj; + rect = CFX_FloatRect(pObj->m_Left, pObj->m_Bottom, pObj->m_Right, pObj->m_Top); + line.Add(pObj); + continue; + } + CFX_FloatRect objRect = CFX_FloatRect(pObj->m_Left, pObj->m_Bottom, pObj->m_Right, pObj->m_Top); + if(IsSameLine(TRUE, rect, objRect)) { + line.Add(pObj); + rect.Union(objRect); + } else { + if(FXSYS_fabs(rect.right - prevRect.right) < rect.Height() && FXSYS_fabs(rect.left - prevRect.left) < rect.Height()) { + analogial += 50; + } + prevLine.RemoveAll(); + prevLine.Append(line); + prevRect = rect; + line.RemoveAll(); + line.Add(pObj); + rect = objRect; + if(!bFirst) { + break; + } + bFirst = FALSE; + } + } + if(prevLine.GetSize()) { + if(bParagraphStart) { + if(prevRect.left - rect.left > rect.Height() && prevRect.left - rect.left < rect.Height() * 3) { + analogial -= 50; + } + } else { + if(FXSYS_fabs(prevRect.left - rect.left) < rect.Height()) { + analogial -= 50; + } + } + } + return analogial; +} +void CPDF_LayoutProcessor_Reflow::ProcessElement(IPDF_LayoutElement* pElement, FX_FLOAT reflowWidth) +{ + if(pElement == NULL) { + return; + } + if(m_Status == LayoutReady) { + LayoutType layoutType = pElement->GetType(); + FX_INT32 ElementType = GetElementTypes(layoutType); + switch(ElementType) { + case SST_IE: + m_bIllustration = TRUE; + break; + case SST_BLSE: + FinishedCurrLine(); + FX_FLOAT StartIndent = 0; + if(IPDF_LayoutElement* pParent = pElement->GetParent()) { + StartIndent = pParent->GetNumberAttr(LayoutStartIndent); + } + FX_FLOAT currStartIndent = pElement->GetNumberAttr(LayoutStartIndent); + m_StartIndent = ConverWidth(currStartIndent); + FX_FLOAT width = reflowWidth; + if(StartIndent != currStartIndent) { + reflowWidth -= m_StartIndent; + } + FX_FLOAT spaceBefore = pElement->GetNumberAttr(LayoutSpaceBefore); + m_pReflowedPage->m_PageHeight += spaceBefore; + m_TextAlign = pElement->GetEnumAttr(LayoutTextAlign); + if(IPDF_LayoutElement* pParent = pElement->GetParent()) { + StartIndent = pParent->GetNumberAttr(LayoutEndIndent); + FX_FLOAT currEndIndent = pElement->GetNumberAttr(LayoutEndIndent); + if(StartIndent != currStartIndent) { + reflowWidth -= ConverWidth(currEndIndent); + } + } + if(reflowWidth * 2 < width) { + reflowWidth = width; + m_StartIndent = 0; + } + break; + } + switch(layoutType) { + case LayoutTable: { + CRF_Table* pTable = FX_NEW CRF_Table; + if (NULL == pTable) { + break; + } + m_TableArray.Add(pTable); + pTable->m_ReflowPageHeight = m_pReflowedPage->m_PageHeight; + pTable->m_TableWidth = GetElmWidth(pElement); + break; + } + case LayoutTableRow: { + if(!m_TableArray.GetSize()) { + break; + } + int count = pElement->CountChildren(); + CRF_Table* pTable = m_TableArray.GetAt(m_TableArray.GetSize() - 1); + int f = 0; + for(int i = 0; i < count; i++) { + IPDF_LayoutElement* pChildElement = pElement->GetChild(i); + LayoutType type = pChildElement->GetType(); + if(type == LayoutTableDataCell || type == LayoutTableHeaderCell) { + f++; + } + } + pTable->m_nCell.Add(f); + break; + } + case LayoutTableDataCell: + case LayoutTableHeaderCell: { + if(!m_TableArray.GetSize()) { + break; + } + RF_TableCell* pCell = FX_Alloc(RF_TableCell, 1); + FXSYS_memset32(pCell, 0 , sizeof(RF_TableCell)); + CRF_Table* pTable = m_TableArray.GetAt(m_TableArray.GetSize() - 1); + int pos = pTable->m_nCell.GetSize() - 1; + pCell->m_BeginPos = m_pReflowedPage->m_pReflowed->GetSize(); + FX_FLOAT cellWidth = pElement->GetNumberAttr(LayoutWidth); + if(cellWidth == 0 || pCell->m_MaxWidth > pTable->m_TableWidth) { + CRF_Table* pTable = m_TableArray.GetAt(m_TableArray.GetSize() - 1); + pCell->m_MaxWidth = reflowWidth / pTable->m_nCell.GetAt(pTable->m_nCell.GetSize() - 1); + } else { + pCell->m_MaxWidth = pElement->GetNumberAttr(LayoutWidth) * reflowWidth / pTable->m_TableWidth; + } + pCell->m_ColSpan = (int)(pElement->GetNumberAttr(LayoutColSpan)); + pCell->m_RowSpan = (int)(pElement->GetNumberAttr(LayoutRowSpan)); + if(!pCell->m_ColSpan) { + pCell->m_ColSpan = 1; + } + if(!pCell->m_RowSpan ) { + pCell->m_RowSpan = 1; + } + pCell->m_BlockAlign = pElement->GetEnumAttr(LayoutBlockAlign); + m_TextAlign = pElement->GetEnumAttr(LayoutInlineAlign); + pCell->m_PosX = 0; + pCell->m_PosY = 0; + reflowWidth = pCell->m_MaxWidth; + pTable->m_pCellArray.Add(pCell); + break; + } + default: + break; + } + m_fLineHeight = pElement->GetNumberAttr(LayoutLineHeight); + int ReflowedSize = m_pReflowedPage->m_pReflowed->GetSize(); + if(pElement->CountObjects()) { + ProcessObjs(pElement, reflowWidth); + } + } + int count = pElement->CountChildren(); + for(int i = 0; i < count; i++) { + IPDF_LayoutElement* pChildElement = pElement->GetChild(i); + ProcessElement(pChildElement, reflowWidth); + if(m_pPause && m_pRootElement == pElement && m_Status != LayoutToBeContinued ) { + if(m_pPause->NeedToPauseNow()) { + m_pLayoutElement = pChildElement; + m_Status = LayoutToBeContinued; + m_CurrRefWidth = reflowWidth; + m_PausePosition = (i + 1) * 100 / (count + 1); + return ; + } + } + if(m_Status == LayoutToBeContinued && m_pLayoutElement == pChildElement) { + m_Status = LayoutReady; + } + } + if(m_Status == LayoutReady) { + FX_FLOAT dx = 0; + LayoutType layoutType = pElement->GetType(); + FX_INT32 ElementType = GetElementTypes(layoutType); + switch(ElementType) { + case SST_IE: + m_bIllustration = FALSE; + FinishedCurrLine(); + break; + case SST_BLSE: + FinishedCurrLine(); + FX_FLOAT StartIndent = 0; + if(IPDF_LayoutElement* pParent = pElement->GetParent()) { + StartIndent = pParent->GetNumberAttr(LayoutStartIndent); + } + FX_FLOAT currStartIndent = pElement->GetNumberAttr(LayoutStartIndent); + if(StartIndent != currStartIndent) { + reflowWidth += ConverWidth(currStartIndent); + dx += ConverWidth(currStartIndent); + } + FX_FLOAT spaceAfter = pElement->GetNumberAttr(LayoutSpaceAfter); + m_pReflowedPage->m_PageHeight += spaceAfter; + break; + } + switch(layoutType) { + case LayoutTableDataCell: + case LayoutTableHeaderCell: { + if(!m_TableArray.GetSize()) { + break; + } + CRF_Table* pTable = m_TableArray.GetAt(m_TableArray.GetSize() - 1); + RF_TableCell* pCell = pTable->m_pCellArray.GetAt(pTable->m_pCellArray.GetSize() - 1); + pCell->m_EndPos = m_pReflowedPage->m_pReflowed->GetSize() - 1; + if(pCell->m_EndPos < pCell->m_BeginPos) { + pCell->m_CellHeight = 0; + } else { + CRF_Data* pBeginData = (*m_pReflowedPage->m_pReflowed)[pCell->m_BeginPos]; + CRF_Data* pEndData = (*m_pReflowedPage->m_pReflowed)[pCell->m_EndPos]; + pCell->m_CellHeight = pBeginData->m_Height > pEndData->m_Height ? pBeginData->m_Height : pEndData->m_Height; + pCell->m_CellHeight -= pEndData->m_PosY - pBeginData->m_PosY; + } + break; + } + case LayoutTableRow: { + if(!m_TableArray.GetSize()) { + break; + } + CRF_Table* pTable = m_TableArray.GetAt(m_TableArray.GetSize() - 1); + if(pTable->m_nCol == 0) { + pTable->m_nCol = pTable->m_pCellArray.GetSize(); + } + break; + } + case LayoutTable: { + ProcessTable(dx); + break; + } + default: + if(dx) { + CFX_AffineMatrix matrix(1, 0, 0, 1, dx, 0); + int ReflowedSize = m_pReflowedPage->m_pReflowed->GetSize(); + Transform(&matrix, m_pReflowedPage->m_pReflowed, ReflowedSize, m_pReflowedPage->m_pReflowed->GetSize() - ReflowedSize); + } + } + } + if(m_pRootElement == pElement) { + m_PausePosition = 100; + } +} +FX_INT32 CPDF_LayoutProcessor_Reflow::GetElementTypes(LayoutType layoutType) +{ + switch(layoutType) { + case LayoutParagraph: + case LayoutHeading: + case LayoutHeading1: + case LayoutHeading2: + case LayoutHeading3: + case LayoutHeading4: + case LayoutHeading5: + case LayoutHeading6: + case LayoutList: + case LayoutListItem: + case LayoutListLabel: + case LayoutListBody: + case LayoutTable: + case LayoutTableHeaderCell: + case LayoutTableDataCell: + case LayoutTableRow: + case LayoutTableHeaderGroup: + case LayoutTableBodyGroup: + case LayoutTableFootGroup: + case LayoutTOCI: + case LayoutCaption: + return SST_BLSE; + case LayoutFigure: + case LayoutFormula: + case LayoutForm: + return SST_IE; + case LayoutSpan: + case LayoutQuote: + case LayoutNote: + case LayoutReference: + case LayoutBibEntry: + case LayoutCode: + case LayoutLink: + case LayoutAnnot: + case LayoutRuby: + case LayoutWarichu: + return SST_ILSE; + default: + return SST_GE; + } + return FALSE; +} +FX_FLOAT CPDF_LayoutProcessor_Reflow::ConverWidth(FX_FLOAT width) +{ + return width; +} +void CPDF_LayoutProcessor_Reflow::ProcessObject(CPDF_PageObject* pObj, FX_FLOAT reflowWidth, CFX_AffineMatrix objMatrix) +{ + if(!pObj) { + return; + } + if(pObj->m_Type == PDFPAGE_TEXT) { + ProcessTextObject( (CPDF_TextObject *)pObj, reflowWidth, objMatrix); + } else if(pObj->m_Type == PDFPAGE_IMAGE) { + if(!(m_flags & RF_PARSER_IMAGE)) { + return; + } + CPDF_PageObjects* pObjs = FX_NEW CPDF_PageObjects(FALSE); + if (NULL == pObjs) { + return; + } + FX_POSITION pos = pObjs->GetLastObjectPosition(); + pos = pObjs->InsertObject(pos, pObj); + CFX_AffineMatrix matrix; + FX_RECT rect = pObj->GetBBox(&matrix); + CPDF_ImageObject* ImageObj = (CPDF_ImageObject*)pObj; + ProcessUnitaryObjs(pObjs, reflowWidth, objMatrix); + delete pObjs; + } else if(pObj->m_Type == PDFPAGE_PATH) { + } else if(pObj->m_Type == PDFPAGE_FORM) { + CPDF_FormObject* pForm = (CPDF_FormObject*)pObj; + FX_POSITION pos = pForm->m_pForm->GetFirstObjectPosition(); + objMatrix.Concat(pForm->m_FormMatrix); + while (pos) { + CPDF_PageObject* pObj1 = pForm->m_pForm->GetNextObject(pos); + ProcessObject(pObj1, reflowWidth, objMatrix); + } + } +} +void CPDF_LayoutProcessor_Reflow::ProcessObjs(IPDF_LayoutElement* pElement, FX_FLOAT reflowWidth) +{ + m_fCurrMaxWidth = reflowWidth; + int ObjCount = pElement->CountObjects(); + for(int i = 0; i < ObjCount; i++) { + CPDF_PageObject* pObj = pElement->GetObject(i); + ProcessObject(pObj, reflowWidth, m_PDFMatrix); + continue; + } +} +void CPDF_LayoutProcessor_Reflow::AddTemp2CurrLine(int begin, int count) +{ + if(begin < 0 || count <= 0 || !m_pReflowedPage || !m_pReflowedPage->m_pReflowed || !m_pTempLine) { + return; + } else { + count += begin; + } + int size = m_pReflowedPage->m_pReflowed->GetSize(); + int temps = m_pTempLine->GetSize(); + for(int i = begin; i < count; i++) { + CRF_Data* pData = (*m_pTempLine)[i]; + AddData2CurrLine(pData); + } +} +void CPDF_LayoutProcessor_Reflow::AddData2CurrLine(CRF_Data* pData) +{ + if(pData == NULL || m_pCurrLine == NULL) { + return; + } + m_pCurrLine->Add(pData); + m_fCurrLineWidth = pData->m_PosX + pData->m_Width; + if(pData->m_Height > m_fCurrLineHeight) { + m_fCurrLineHeight = pData->m_Height; + } +} +void CPDF_LayoutProcessor_Reflow::UpdateCurrLine() +{ +} +void CPDF_LayoutProcessor_Reflow::Transform(const CFX_AffineMatrix* pMatrix, CRF_DataPtrArray* pDataArray, int beginPos, int count) +{ + if (!pDataArray) { + return; + } + if(count == 0) { + count = pDataArray->GetSize(); + } else { + count += beginPos; + } + for(int i = beginPos; i < count; i++) { + CRF_Data* pData = (*pDataArray)[i]; + Transform(pMatrix, pData); + } +} +void CPDF_LayoutProcessor_Reflow::Transform(const CFX_AffineMatrix* pMatrix, CRF_Data* pData) +{ + if(pData->GetType() == CRF_Data::Path) { + CRF_PathData* pPathData = (CRF_PathData*)pData; + pPathData->m_pPath2Device.Concat(*pMatrix); + } + pMatrix->Transform(pData->m_PosX, pData->m_PosY, pData->m_PosX, pData->m_PosY); +} +FX_BOOL CPDF_LayoutProcessor_Reflow::FinishedCurrLine() +{ + if (NULL == m_pCurrLine) { + return FALSE; + } + int count = m_pCurrLine->GetSize(); + if(count == 0) { + return FALSE; + } + if(m_fLineHeight > m_fCurrLineHeight) { + m_fCurrLineHeight = m_fLineHeight; + } else { + m_fCurrLineHeight += 2; + } + if(m_pReflowedPage->m_pReflowed->GetSize() > 0) { + m_fCurrLineHeight += m_fLineSpace; + } + FX_FLOAT height = m_pReflowedPage->m_PageHeight + m_fCurrLineHeight; + FX_FLOAT lineHeight = m_fLineHeight; + if(lineHeight == 0) { + lineHeight = m_fCurrLineHeight; + } + FX_FLOAT dx = 0; + switch(m_TextAlign) { + case LayoutCenter: + dx = (m_fCurrMaxWidth - m_fCurrLineWidth) / 2; + break; + case LayoutEnd: + dx = m_fCurrMaxWidth - m_fCurrLineWidth; + break; + case LayoutJustify: + break; + default: + break; + } + FX_FLOAT dy = - height; + int refedSize = m_pReflowedPage->m_pReflowed->GetSize(); + if(count == 13) { + int a = 0; + } + for(int i = 0; i < count; i++) { + CRF_Data* pData = (*m_pCurrLine)[i]; + m_pReflowedPage->m_pReflowed->Add(pData); + FX_FLOAT x = m_StartIndent + dx * (m_TextAlign == LayoutJustify ? i + 1 : 1); + CFX_AffineMatrix matrix(1, 0, 0, 1, x, dy); + Transform(&matrix, pData); + } + m_pCurrLine->RemoveAll(); + m_fCurrLineWidth = 0; + m_pReflowedPage->m_PageHeight += m_fCurrLineHeight; + m_fCurrLineHeight = 0; + return TRUE; +} +CRF_CharState* CPDF_LayoutProcessor_Reflow::GetCharState(CPDF_TextObject* pObj, CPDF_Font* pFont, FX_FLOAT fHeight, FX_ARGB color) +{ + if (NULL == m_pReflowedPage->m_pCharState) { + return NULL; + } + int count = m_pReflowedPage->m_pCharState->GetSize(); + for(int i = count - 1; i >= 0; i--) { + CRF_CharState* pState = (CRF_CharState*)m_pReflowedPage->m_pCharState->GetAt(i); + if(pState->m_Color == color && pState->m_fFontSize == fHeight && pState->m_pFont == pFont && pState->m_pTextObj == pObj) { + return pState; + } + } + CRF_CharState pState; + pState.m_pTextObj = pObj; + pState.m_Color = color; + pState.m_pFont = pFont; + pState.m_fFontSize = fHeight; + int ascent = pFont->GetTypeAscent(); + int descent = pFont->GetTypeDescent(); + pState.m_fAscent = ascent * fHeight / (ascent - descent); + if(descent == 0) { + pState.m_fDescent = 0; + } else { + pState.m_fDescent = descent * fHeight / (ascent - descent); + } + pState.m_bVert = FALSE; + CPDF_CIDFont *pCIDFont = pFont->GetCIDFont(); + if(pCIDFont) { + pState.m_bVert = pCIDFont->IsVertWriting(); + } + m_pReflowedPage->m_pCharState->Add(pState); + return (CRF_CharState*)m_pReflowedPage->m_pCharState->GetAt(count); +} +int CPDF_LayoutProcessor_Reflow::GetCharWidth(FX_DWORD charCode, CPDF_Font* pFont) const +{ + if(charCode == -1) { + return 0; + } + int w = pFont->GetCharWidthF(charCode); + if(w == 0) { + CFX_ByteString str; + pFont->AppendChar(str, charCode); + w = pFont->GetStringWidth(str, 1); + if(w == 0) { + FX_RECT BBox; + pFont->GetCharBBox(charCode, BBox); + w = BBox.right - BBox.left; + } + } + return w; +} +void CPDF_LayoutProcessor_Reflow::CreateRFData(CPDF_PageObject* pObj, CFX_AffineMatrix* pObjMatrix) +{ + if (NULL == m_pReflowedPage->m_pMemoryPool) { + return; + } + if(pObj->m_Type == PDFPAGE_TEXT) { + CPDF_TextObject* pTextObj = (CPDF_TextObject* )pObj; + int count = pTextObj->CountItems(); + if(!count) { + return; + } + if(count == 1) { + CPDF_TextObjectItem Item; + pTextObj->GetItemInfo(0, &Item); + if(Item.m_CharCode == 49) { + int a = 0; + } + } + CPDF_Font * pFont = pTextObj->GetFont(); + FX_FLOAT fs = pTextObj->GetFontSize(); + FX_FLOAT* pmatrix = pTextObj->m_TextState.GetMatrix(); + FX_FLOAT matrix1 = pmatrix[1]; + if(pmatrix[2] == 0) { + matrix1 = 0; + } + CFX_AffineMatrix textMatrix(pmatrix[0], matrix1, pmatrix[2], pmatrix[3], 0, 0); + FX_FLOAT height = FXSYS_fabs(textMatrix.TransformDistance(fs)); + if(pObjMatrix) { + height = FXSYS_fabs(pObjMatrix->TransformDistance(height)); + } + int r = 0, g = 0, b = 0; + pTextObj->m_ColorState.GetFillColor()->GetRGB(r, g, b); + FX_ARGB col = r * 0x10000; + col += g * 0x100; + col += b; + CRF_CharState* pState = GetCharState(pTextObj, pFont, height, col); + FX_FLOAT dx = 0, dy = 0; + FX_RECT ObjBBox; + if(pObjMatrix) { + ObjBBox = pTextObj->GetBBox(pObjMatrix); + dx = (float)ObjBBox.left; + dy = (float)ObjBBox.bottom; + } else { + CFX_AffineMatrix matrix; + ObjBBox = pTextObj->GetBBox(&matrix); + } + FX_FLOAT objWidth = 0; + CFX_ByteString str; + FX_BOOL bOrder = TRUE; + CFX_PtrArray tempArray; + int i = 0; + CPDF_TextObjectItem Item; + pTextObj->GetItemInfo(i, &Item); + dx = Item.m_OriginX; + dy = Item.m_OriginY; + textMatrix.Transform(Item.m_OriginX, Item.m_OriginY, dx, dy); + CRF_CharData* pLastData = NULL; + FX_FLOAT horzScale = pTextObj->m_TextState.GetFontSizeV() / pTextObj->m_TextState.GetFontSizeH(); + while(i < count) { + pTextObj->GetItemInfo(i, &Item); + if(Item.m_CharCode == -1) { + i++; + continue; + } + FX_FLOAT OriginX, OriginY; + textMatrix.Transform(Item.m_OriginX, Item.m_OriginY, OriginX, OriginY); + CRF_CharData* pData = (CRF_CharData*)m_pReflowedPage->m_pMemoryPool->Alloc(sizeof(CRF_CharData)); + if (NULL == pData) { + continue; + } + pData->m_Type = CRF_Data::Text; + if(FXSYS_fabs(OriginY - dy) > FXSYS_fabs(OriginX - dx)) { + pData->m_PosY = dy; + pData->m_PosX = pLastData->m_PosX + pLastData->m_Width + textMatrix.TransformDistance(pTextObj->m_TextState.GetObject()->m_CharSpace); + } else { + pData->m_PosY = OriginY; + pData->m_PosX = OriginX; + } + int size = tempArray.GetSize(); + if(size && pData->m_PosX < pLastData->m_PosX ) { + for (int j = 0; j < size; j++) { + CRF_CharData* pData1 = (CRF_CharData*)tempArray.GetAt(j); + if(pData1->m_PosX > pData->m_PosX) { + tempArray.InsertAt(j, pData); + break; + } + } + } else { + tempArray.Add(pData); + } + pLastData = pData; + pData->m_CharCode = Item.m_CharCode; + pData->m_Height = FXSYS_fabs(height); + int w = GetCharWidth(Item.m_CharCode, pFont); + pData->m_Width = FXSYS_fabs(fs * textMatrix.TransformDistance((FX_FLOAT)w) / 1000); + if(horzScale) { + pData->m_Width /= horzScale; + } + pData->m_pCharState = pState; + i++; + } + count = tempArray.GetSize(); + for (int j = 0; j < count; j++) { + CRF_CharData* pData = (CRF_CharData*)tempArray.GetAt(j); + if (m_pTempLine) { + m_pTempLine->Add(pData); + } + } + tempArray.RemoveAll(); + } else if(pObj->m_Type == PDFPAGE_IMAGE) { + CPDF_ImageObject* pImageObj = (CPDF_ImageObject* )pObj; + CRF_ImageData* pRFImage = (CRF_ImageData*)m_pReflowedPage->m_pMemoryPool->Alloc(sizeof(CRF_ImageData)); + if (NULL == pRFImage) { + return; + } + pRFImage->m_pBitmap = NULL; + pRFImage->m_Type = CRF_Data::Image; + if (m_pTempLine) { + m_pTempLine->Add(pRFImage); + } + CPDF_Image *pImage = pImageObj->m_pImage; + if (!pImage->m_pDIBSource || !pImage->m_pMask) { + if(pImage->StartLoadDIBSource(m_pReflowedPage->GetFormResDict(pImageObj), m_pReflowedPage->m_pPDFPage->m_pResources, 0, 0, TRUE)) { + pImage->Continue(NULL); + } + } + CFX_DIBSource* pDibSource = pImage->DetachBitmap(); + if (pDibSource) { + pRFImage->m_pBitmap = pDibSource->Clone(); + delete pDibSource; + } + CFX_DIBSource* pMask = pImage->DetachMask(); + if (pMask) { + if (!pMask->IsAlphaMask()) { + CFX_DIBitmap* pMaskBmp = pMask->Clone(); + pMaskBmp->ConvertFormat(FXDIB_8bppMask); + pRFImage->m_pBitmap->MultiplyAlpha(pMaskBmp); + delete pMaskBmp; + } else { + pRFImage->m_pBitmap->MultiplyAlpha(pMask); + } + delete pMask; + } + CFX_FloatRect ObjBBox; + if(pObjMatrix) { + ObjBBox = pImageObj->GetBBox(pObjMatrix); + } else { + CFX_AffineMatrix matrix; + ObjBBox = pImageObj->GetBBox(&matrix); + } + pRFImage->m_Width = ObjBBox.Width(); + pRFImage->m_Height = ObjBBox.Height(); + pRFImage->m_PosX = 0; + pRFImage->m_PosY = 0; + CFX_AffineMatrix matrix(1, 0, 0, -1, 0, 0); + matrix.Concat(pImageObj->m_Matrix); + matrix.Concat(*pObjMatrix); + pRFImage->m_Matrix.Set(matrix.a == 0 ? 0 : matrix.a / FXSYS_fabs(matrix.a), + matrix.b == 0 ? 0 : matrix.b / FXSYS_fabs(matrix.b), + matrix.c == 0 ? 0 : matrix.c / FXSYS_fabs(matrix.c), + matrix.d == 0 ? 0 : matrix.d / FXSYS_fabs(matrix.d), 0, 0); + } else if(pObj->m_Type == PDFPAGE_PATH) { + } +} +FX_FLOAT CPDF_LayoutProcessor_Reflow:: GetDatasWidth(int beginPos, int endpos) +{ + if(endpos < beginPos || !m_pTempLine) { + return 0; + } + if(endpos > m_pTempLine->GetSize() - 1) { + endpos = m_pTempLine->GetSize() - 1; + } + CRF_Data* pBeginData = (*m_pTempLine)[beginPos]; + CRF_Data* pEndData = (*m_pTempLine)[endpos]; + return pEndData->m_PosX - pBeginData->m_PosX + pEndData->m_Width; +} +FX_WCHAR CPDF_LayoutProcessor_Reflow::GetPreChar() +{ + if (NULL == m_pCurrLine) { + return -1; + } + int index = m_pCurrLine->GetSize() - 1; + CRF_CharData* pCharData = NULL; + while (index >= 0 && !pCharData) { + CRF_Data* pData = (*m_pCurrLine)[index]; + if(pData->GetType() == CRF_Data::Text) { + pCharData = (CRF_CharData*)pData; + } else { + return -1; + } + index --; + } + if(m_pReflowedPage) { + index = m_pReflowedPage->m_pReflowed->GetSize() - 1; + } + while(!pCharData && index >= 0) { + CRF_Data* pData = (*m_pReflowedPage->m_pReflowed)[index]; + if(pData->GetType() == CRF_Data::Text) { + pCharData = (CRF_CharData*)pData; + } else { + return -1; + } + index --; + } + if(pCharData) { + CFX_WideString str = pCharData->m_pCharState->m_pFont->UnicodeFromCharCode(pCharData->m_CharCode); + return str.GetAt(0); + } + return -1; +} +int CPDF_LayoutProcessor_Reflow::ProcessInsertObject(CPDF_TextObject* pObj, CFX_AffineMatrix formMatrix) +{ + if(!pObj || !m_pPreObj || !m_pCurrLine) { + return 0; + } + if(m_pCurrLine->GetSize() == 0) { + return 0; + } + CPDF_TextObjectItem item; + int nItem = m_pPreObj->CountItems(); + m_pPreObj->GetItemInfo(nItem - 1, &item); + FX_FLOAT last_pos = item.m_OriginX; + FX_FLOAT last_width = GetCharWidth(item.m_CharCode, m_pPreObj->GetFont()) * m_pPreObj->GetFontSize() / 1000; + last_width = FXSYS_fabs(last_width); + pObj->GetItemInfo(0, &item); + FX_FLOAT this_width = GetCharWidth(item.m_CharCode, pObj->GetFont()) * pObj->GetFontSize() / 1000; + this_width = FXSYS_fabs(this_width); + FX_FLOAT threshold = last_width > this_width ? last_width / 4 : this_width / 4; + CFX_AffineMatrix prev_matrix, prev_reverse; + m_pPreObj->GetTextMatrix(&prev_matrix); + prev_matrix.Concat(m_perMatrix); + prev_reverse.SetReverse(prev_matrix); + FX_FLOAT x = pObj->GetPosX(), y = pObj->GetPosY(); + formMatrix.Transform(x, y); + prev_reverse.Transform(x, y); + FX_WCHAR preChar = GetPreChar(); + CFX_WideString wstrItem = pObj->GetFont()->UnicodeFromCharCode(item.m_CharCode); + FX_WCHAR curChar = wstrItem.GetAt(0); + if (FXSYS_fabs(y) > threshold * 2) { + if (preChar == L'-') { + return 3; + } + if (preChar != L' ') { + return 1; + } + return 2; + } + if ((x - last_pos - last_width) > threshold && curChar != L' ' && preChar != L' ') { + return 1; + } + return 0; +} +FX_INT32 CPDF_LayoutProcessor_Reflow::LogicPreObj(CPDF_TextObject* pObj) +{ + CPDF_TextObject* pPreObj = m_pPreObj; + m_pPreObj = pObj; + if(!pObj || !pPreObj) { + return 0; + } + CPDF_TextObjectItem item; + pPreObj->GetItemInfo(pPreObj->CountItems() - 1, &item); + FX_FLOAT last_pos = item.m_OriginX; + FX_FLOAT last_width = pPreObj->GetFont()->GetCharWidthF(item.m_CharCode) * pPreObj->GetFontSize() / 1000; + last_width = FXSYS_fabs(last_width); + pObj->GetItemInfo(0, &item); + FX_FLOAT this_width = pObj->GetFont()->GetCharWidthF(item.m_CharCode) * pObj->GetFontSize() / 1000; + this_width = FXSYS_fabs(this_width); + FX_FLOAT threshold = last_width > this_width ? last_width / 4 : this_width / 4; + CFX_AffineMatrix prev_matrix, prev_reverse; + pPreObj->GetTextMatrix(&prev_matrix); + prev_reverse.SetReverse(prev_matrix); + FX_FLOAT x = pObj->GetPosX(), y = pObj->GetPosY(); + prev_reverse.Transform(x, y); + CFX_WideString wstrItem = pObj->GetFont()->UnicodeFromCharCode(item.m_CharCode); + FX_WCHAR curChar = wstrItem.GetAt(0); + if (FXSYS_fabs(y) > threshold * 2) { + return 2; + } + FX_WCHAR preChar = 0; + if (FXSYS_fabs(last_pos + last_width - x) > threshold && curChar != L' ') { + return 1; + } + return 0; + 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; +} +FX_BOOL CPDF_LayoutProcessor_Reflow::IsSameTextObject(CPDF_TextObject* pTextObj1, CPDF_TextObject* pTextObj2) +{ + if (!pTextObj1 || !pTextObj2) { + return FALSE; + } + CFX_FloatRect rcPreObj(pTextObj2->m_Left, pTextObj2->m_Bottom, pTextObj2->m_Right, pTextObj2->m_Top); + CFX_FloatRect rcCurObj(pTextObj1->m_Left, pTextObj1->m_Bottom, pTextObj1->m_Right, pTextObj1->m_Top); + if (rcPreObj.IsEmpty() && rcCurObj.IsEmpty()) { + return FALSE; + } + if (!rcPreObj.IsEmpty() || !rcCurObj.IsEmpty()) { + rcPreObj.Intersect(rcCurObj); + if (rcPreObj.IsEmpty()) { + return FALSE; + } + if (FXSYS_fabs(rcPreObj.Width() - rcCurObj.Width()) > rcCurObj.Width() / 2) { + return FALSE; + } + if (pTextObj2->GetFontSize() != pTextObj1->GetFontSize()) { + return FALSE; + } + } + int nPreCount = pTextObj2->CountItems(); + int nCurCount = pTextObj1->CountItems(); + if (nPreCount != nCurCount) { + return FALSE; + } + for (int i = 0; i < nPreCount; i++) { + CPDF_TextObjectItem itemPer, itemCur; + pTextObj2->GetItemInfo(i, &itemPer); + pTextObj1->GetItemInfo(i, &itemCur); + if (itemCur.m_CharCode != itemPer.m_CharCode) { + return FALSE; + } + } + return TRUE; +} +void CPDF_LayoutProcessor_Reflow::ProcessTextObject(CPDF_TextObject *pTextObj, FX_FLOAT reflowWidth, CFX_AffineMatrix objMatrix) +{ + if(reflowWidth < 0 || !m_pCurrLine || !m_pTempLine) { + return; + } + if(IsSameTextObject(pTextObj, m_pPreObj)) { + return; + } + CPDF_PageObject* pPreObj = m_pPreObj; + FX_INT32 logic = ProcessInsertObject(pTextObj, objMatrix); + m_pPreObj = pTextObj; + m_perMatrix.Copy(objMatrix); + int size = m_pTempLine->GetSize(); + int curs = m_pCurrLine->GetSize(); + CreateRFData(pTextObj); + size = m_pTempLine->GetSize(); + int reds = m_pReflowedPage->m_pReflowed->GetSize(); + if(size == 0) { + return; + } + if(logic == 1) { + m_fCurrLineWidth += pTextObj->GetBBox(&objMatrix).Height() / 3; + } else if(logic == 3 && curs) { + m_fCurrLineWidth -= (*m_pCurrLine)[curs - 1]->m_Width; + m_pCurrLine->Delete(curs - 1); + } + int beginPos = 0, endPos = m_pTempLine->GetSize() - 1; + while(beginPos <= endPos) { + int tempBeginPos = beginPos; + int tempEndPos = endPos; + FX_FLOAT all_width = GetDatasWidth( beginPos, endPos); + if(all_width < reflowWidth - m_fCurrLineWidth) { + CRF_CharData* pBeginData = (CRF_CharData*)(*m_pTempLine)[beginPos]; + CFX_AffineMatrix matrix(1, 0, 0, 1, -pBeginData->m_PosX + m_fCurrLineWidth, -pBeginData->m_PosY); + Transform(&matrix, m_pTempLine, beginPos, endPos - beginPos + 1); + AddTemp2CurrLine(beginPos, endPos - beginPos + 1); + m_pTempLine->RemoveAll(); + return; + } + int midPos ; + if(tempBeginPos >= tempEndPos && tempEndPos != 0) { + midPos = tempEndPos; + } else { + while (tempBeginPos < tempEndPos ) { + midPos = (tempEndPos - tempBeginPos) / 2 + tempBeginPos; + if(midPos == tempBeginPos || midPos == tempEndPos) { + break; + } + FX_FLOAT w = GetDatasWidth( beginPos, midPos); + if(w < reflowWidth - m_fCurrLineWidth) { + tempBeginPos = midPos; + } else { + tempEndPos = midPos; + } + } + midPos = tempBeginPos; + if(midPos == 0) { + FX_FLOAT w = GetDatasWidth( beginPos, 1); + if(w > reflowWidth - m_fCurrLineWidth) { + midPos = -1; + } + } + } + if(midPos == -1) { + int count = m_pCurrLine->GetSize(); + if(count == 0) { + midPos = 0; + } + } + int f = -1; + int i = 0; + for(i = midPos; i >= beginPos; i--) { + CRF_CharData* pData = (CRF_CharData*)(*m_pTempLine)[i]; + CFX_WideString Wstr = pData->m_pCharState->m_pFont->UnicodeFromCharCode(pData->m_CharCode); + FX_WCHAR cha = Wstr.GetAt(0); + if(i < m_pTempLine->GetSize() - 1) { + CRF_CharData* pNextData = (CRF_CharData*)(*m_pTempLine)[i + 1]; + if(pNextData->m_PosX - (pData->m_PosX + pData->m_Width) >= pData->m_Height / 4) { + f = i; + i++; + } + } + if(f == -1) { + if(IsCanBreakAfter((FX_DWORD)cha)) { + f = i; + i++; + } else if(IsCanBreakBefore((FX_DWORD)cha)) { + f = i - 1; + if(f < beginPos) { + f = -1; + } + } + } + if(f != -1) { + CRF_CharData* pBeginData = (CRF_CharData*)(*m_pTempLine)[beginPos]; + CFX_AffineMatrix matrix(1, 0, 0, 1, -pBeginData->m_PosX + m_fCurrLineWidth, -pBeginData->m_PosY); + Transform(&matrix, m_pTempLine, beginPos, f - beginPos + 1); + CRF_Data* pData = (*m_pTempLine)[0]; + AddTemp2CurrLine(beginPos, f - beginPos + 1); + beginPos = i; + FinishedCurrLine(); + f = 1; + break; + } + } + if(f == -1 && i < beginPos) { + if( m_pCurrLine->GetSize()) { + int count = m_pCurrLine->GetSize(); + f = -1; + for(int i = count - 1; i >= 0; i--) { + CRF_Data* pData = (*m_pCurrLine)[i]; + if(pData->GetType() != CRF_Data::Text) { + f = i + 1; + } else { + CRF_CharData* pCharData = (CRF_CharData*)pData; + CFX_WideString Wstr = pCharData->m_pCharState->m_pFont->UnicodeFromCharCode(pCharData->m_CharCode); + FX_WCHAR cha = Wstr.GetAt(0); + if(IsCanBreakAfter(cha)) { + f = i + 1; + i++; + } else if(IsCanBreakBefore(cha)) { + f = i; + } + if(f == 0) { + f = -1; + } + } + if(f != -1) { + FinishedCurrLine(); + if(f < count) { + int reflowdCount = m_pReflowedPage->m_pReflowed->GetSize(); + int pos = reflowdCount + f - count; + CRF_CharData* pData = (CRF_CharData*)(*m_pReflowedPage->m_pReflowed)[pos]; + CFX_AffineMatrix matrix(1, 0, 0, 1, -pData->m_PosX + m_fCurrLineWidth, -pData->m_PosY); + Transform(&matrix, m_pReflowedPage->m_pReflowed, pos, reflowdCount - pos); + for(int j = pos; j < reflowdCount; j++) { + AddData2CurrLine((*m_pReflowedPage->m_pReflowed)[j]); + } + m_pReflowedPage->m_pReflowed->Delete(pos, count - f); + if(logic == 3) { + m_fCurrLineWidth += pTextObj->GetBBox(&objMatrix).Height() / 3; + } + } + break; + } + } + } + if(f == -1) { + CRF_CharData* pData = (CRF_CharData*)(*m_pTempLine)[beginPos]; + CFX_AffineMatrix matrix(1, 0, 0, 1, -pData->m_PosX + m_fCurrLineWidth, -pData->m_PosY); + if(beginPos == midPos) { + Transform(&matrix, pData); + FX_RECT rect; + pData->m_pCharState->m_pFont->GetFontBBox(rect); + FX_FLOAT* pmatrix = pTextObj->m_TextState.GetMatrix(); + CFX_AffineMatrix textMatrix(pmatrix[0], pmatrix[1], pmatrix[2], pmatrix[3], 0, 0); + FX_FLOAT width = pData->m_Height * (rect.right - rect.left) / 1000; + FX_FLOAT f = (reflowWidth - m_fCurrLineWidth) / width; + pData->m_PosY *= f; + pData->m_Width *= f; + pData->m_Height *= f; + pData->m_pCharState = GetCharState(pData->m_pCharState->m_pTextObj, pData->m_pCharState->m_pFont, pData->m_Height, pData->m_pCharState->m_Color); + AddData2CurrLine(pData); + } else { + for(int m = beginPos; m <= midPos; m++) { + CRF_CharData* pData = (CRF_CharData*)(*m_pTempLine)[m]; + Transform(&matrix, pData); + AddData2CurrLine(pData); + } + } + FinishedCurrLine(); + beginPos = midPos + 1; + } + } + } + m_pTempLine->RemoveAll(); + return; +} +void CPDF_LayoutProcessor_Reflow::ProcessUnitaryObjs(CPDF_PageObjects *pObjs, FX_FLOAT reflowWidth, CFX_AffineMatrix objMatrix) +{ + if(!pObjs) { + return; + } + CFX_FloatRect ObjBBox = pObjs->CalcBoundingBox(); + objMatrix.TransformRect(ObjBBox); + FX_FLOAT ObjWidth = ObjBBox.Width(); + FX_FLOAT ObjHeight = ObjBBox.Height(); + CFX_AffineMatrix matrix; + if(ObjWidth <= reflowWidth - m_fCurrLineWidth) { + matrix.Set(1, 0, 0, 1, m_fCurrLineWidth , 0); + } else if(ObjWidth <= reflowWidth) { + FinishedCurrLine(); + matrix.Set(1, 0, 0, 1, 0, 0); + } else { + FinishedCurrLine(); + FX_FLOAT f = reflowWidth / ObjWidth ; + matrix.Set(f, 0, 0, f, 0, 0); + } + CFX_AffineMatrix tempMatrix = matrix; + matrix.Concat(objMatrix); + FX_POSITION pos = pObjs->GetFirstObjectPosition(); + while(pos) { + CPDF_PageObject* pObj = pObjs->GetNextObject(pos); + if(pObj->m_Type == PDFPAGE_TEXT) { + FX_INT32 ret = LogicPreObj((CPDF_TextObject*)pObj); + if(ret == 1 || ret == 2) { + continue; + } + } + CreateRFData(pObj, &matrix); + } + if (m_pTempLine) { + Transform(&tempMatrix, m_pTempLine, 0, m_pTempLine->GetSize()); + AddTemp2CurrLine(0, m_pTempLine->GetSize()); + m_pTempLine->RemoveAll(); + } +} +void CPDF_LayoutProcessor_Reflow::ProcessPathObject(CPDF_PathObject *pObj, FX_FLOAT reflowWidth) +{ +} diff --git a/core/src/reflow/layoutprovider_taggedpdf.cpp b/core/src/reflow/layoutprovider_taggedpdf.cpp new file mode 100644 index 0000000000..c40c1cdb64 --- /dev/null +++ b/core/src/reflow/layoutprovider_taggedpdf.cpp @@ -0,0 +1,780 @@ +// 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 "layoutprovider_taggedpdf.h" +CPDF_LayoutElement::CPDF_LayoutElement() +{ + m_pTaggedElement = NULL; + m_pParentElement = NULL; +} +CPDF_LayoutElement::~CPDF_LayoutElement() +{ + m_ObjArray.RemoveAll(); + int size = m_ChildArray.GetSize(); + for(int i = 0; i < size; i++) { + CPDF_LayoutElement* pChild = (CPDF_LayoutElement*)m_ChildArray.GetAt(i); + delete pChild; + pChild = NULL; + } + m_ChildArray.RemoveAll(); +} +LayoutType CPDF_LayoutElement::ConvertLayoutType(FX_BSTR name) +{ + if(name == (const char*)("Document")) { + return LayoutDocument; + } else if(name == (const char*)("Part")) { + return LayoutPart; + } else if(name == (const char*)("Art")) { + return LayoutArt; + } else if(name == (const char*)("Sect")) { + return LayoutSect; + } else if(name == (const char*)("Div")) { + return LayoutDiv; + } else if(name == (const char*)("BlockQuote")) { + return LayoutBlockQuote; + } else if(name == (const char*)("Caption")) { + return LayoutCaption; + } else if(name == (const char*)("TOC")) { + return LayoutTOC; + } else if(name == (const char*)("TOCI")) { + return LayoutTOCI; + } else if(name == (const char*)("Index")) { + return LayoutIndex; + } else if(name == (const char*)("NonStruct")) { + return LayoutNonStruct; + } else if(name == (const char*)("Private")) { + return LayoutPrivate; + } else if(name == (const char*)("P")) { + return LayoutParagraph; + } else if(name == (const char*)("H")) { + return LayoutHeading; + } else if(name == (const char*)("H1")) { + return LayoutHeading1; + } else if(name == (const char*)("H2")) { + return LayoutHeading2; + } else if(name == (const char*)("H3")) { + return LayoutHeading3; + } else if(name == (const char*)("H4")) { + return LayoutHeading4; + } else if(name == (const char*)("H5")) { + return LayoutHeading5; + } else if(name == (const char*)("H6")) { + return LayoutHeading6; + } else if(name == (const char*)("L")) { + return LayoutList; + } else if(name == (const char*)("LI")) { + return LayoutListItem; + } else if(name == (const char*)("Lbl")) { + return LayoutListLabel; + } else if(name == (const char*)("LBody")) { + return LayoutListBody; + } else if(name == (const char*)("Table")) { + return LayoutTable; + } else if(name == (const char*)("TR")) { + return LayoutTableRow; + } else if(name == (const char*)("TH")) { + return LayoutTableHeaderCell; + } else if(name == (const char*)("TD")) { + return LayoutTableDataCell; + } else if(name == (const char*)("THead")) { + return LayoutTableHeaderGroup; + } else if(name == (const char*)("TBody")) { + return LayoutTableBodyGroup; + } else if(name == (const char*)("TFoot")) { + return LayoutTableFootGroup; + } else if(name == (const char*)("Span")) { + return LayoutSpan; + } else if(name == (const char*)("Quote")) { + return LayoutQuote; + } else if(name == (const char*)("Note")) { + return LayoutNote; + } else if(name == (const char*)("Reference")) { + return LayoutReference; + } else if(name == (const char*)("BibEntry")) { + return LayoutBibEntry; + } else if(name == (const char*)("Code")) { + return LayoutCode; + } else if(name == (const char*)("Link")) { + return LayoutLink; + } else if(name == (const char*)("Annot")) { + return LayoutAnnot; + } else if(name == (const char*)("Ruby")) { + return LayoutRuby; + } else if(name == (const char*)("RB")) { + return LayoutRubyBase; + } else if(name == (const char*)("RT")) { + return LayoutRubyAnnot; + } else if(name == (const char*)("RP")) { + return LayoutRubyPunc; + } else if(name == (const char*)("Warichu")) { + return LayoutWarichu; + } else if(name == (const char*)("WT")) { + return LayoutWarichuText; + } else if(name == (const char*)("WP")) { + return LayoutWarichuPunc; + } else if(name == (const char*)("Figure")) { + return LayoutFigure; + } else if(name == (const char*)("Formula")) { + return LayoutFormula; + } else if(name == (const char*)("Form")) { + return LayoutForm; + } else { + return LayoutUnknown; + } +} +CFX_ByteStringC CPDF_LayoutElement::ConvertLayoutType(LayoutType type) +{ + FX_BSTR name = ""; + if(type == LayoutArifact) { + return "Arifact"; + } else if( type == LayoutDocument) { + return "Document"; + } else if( type == LayoutPart) { + return "Part"; + } else if( type == LayoutArt) { + return "Art"; + } else if( type == LayoutSect) { + return "Sect"; + } else if( type == LayoutDiv) { + return "Div"; + } else if( type == LayoutBlockQuote) { + return "BlockQuote"; + } else if( type == LayoutCaption) { + return "Caption"; + } else if( type == LayoutTOC) { + return "TOC"; + } else if( type == LayoutTOCI) { + return "TOCI"; + } else if( type == LayoutIndex) { + return "Index"; + } else if( type == LayoutNonStruct) { + return "NonStruct"; + } else if( type == LayoutPrivate) { + return "Private"; + } else if( type == LayoutParagraph) { + return "P"; + } else if( type == LayoutHeading) { + return "H"; + } else if( type == LayoutHeading1) { + return "H1"; + } else if( type == LayoutHeading2) { + return "H2"; + } else if( type == LayoutHeading3) { + return "H3"; + } else if( type == LayoutHeading4) { + return "H4"; + } else if( type == LayoutHeading5) { + return "H5"; + } else if( type == LayoutHeading6) { + return "H6"; + } else if( type == LayoutList) { + return "L"; + } else if( type == LayoutListItem) { + return "LI"; + } else if( type == LayoutListLabel) { + return "Lbl"; + } else if( type == LayoutListBody) { + return "LBody"; + } else if( type == LayoutTable) { + return "Table"; + } else if( type == LayoutTableRow) { + return "TR"; + } else if( type == LayoutTableHeaderCell) { + return "TH"; + } else if( type == LayoutTableDataCell) { + return "TD"; + } else if( type == LayoutTableHeaderGroup) { + return "THead"; + } else if( type == LayoutTableBodyGroup) { + return "TBody"; + } else if( type == LayoutTableFootGroup) { + return "TFoot"; + } else if( type == LayoutSpan) { + return "Span"; + } else if( type == LayoutQuote) { + return "Quote"; + } else if( type == LayoutNote) { + return "Note"; + } else if( type == LayoutReference) { + return "Reference"; + } else if( type == LayoutBibEntry) { + return "BibEntry"; + } else if( type == LayoutCode) { + return "Code"; + } else if( type == LayoutLink) { + return "Link"; + } else if( type == LayoutAnnot) { + return "Annot"; + } else if( type == LayoutRuby) { + return "Ruby"; + } else if( type == LayoutRubyBase) { + return "RB"; + } else if( type == LayoutRubyAnnot) { + return "RT"; + } else if( type == LayoutRubyPunc) { + return "RP"; + } else if( type == LayoutWarichu) { + return "Warichu"; + } else if( type == LayoutWarichuText) { + return "WT"; + } else if( type == LayoutWarichuPunc) { + return "WP"; + } else if( type == LayoutFigure) { + return "Figure"; + } else if( type == LayoutFormula) { + return "Formula"; + } else if( type == LayoutForm) { + return "Form"; + } + return name; +} +CFX_ByteStringC CPDF_LayoutElement::ConvertLayoutAttr(LayoutAttr attr) +{ + switch(attr) { + case LayoutArtifactType: + return "Type"; + case LayoutArtifactAttached: + return "Attached"; + case LayoutArtifactSubType: + return "Subtype"; + case LayoutPlacement: + return "Placement"; + case LayoutWritingMode: + return "WritingMode"; + case LayoutBackgroundColor: + return "BackgroundColor"; + case LayoutBorderColor: + return "BorderColor"; + case LayoutBorderStyle: + return "BorderStyle"; + case LayoutBorderThickness: + return "BorderThickness"; + case LayoutPadding: + return "Padding"; + case LayoutColor: + return "Color"; + case LayoutSpaceBefore: + return "SpaceBefore"; + case LayoutSpaceAfter: + return "SpaceAfter"; + case LayoutStartIndent: + return "StartIndent"; + case LayoutEndIndent: + return "EndIndent"; + case LayoutTextIndent: + return "TextIndent"; + case LayoutTextAlign: + return "TextAlign"; + case LayoutBBox: + return "BBox"; + case LayoutWidth: + return "Width"; + case LayoutHeight: + return "Height"; + case LayoutBlockAlign: + return "BlockAlign"; + case LayoutInlineAlign: + return "InlineAlign"; + case LayoutTBorderStyle: + return "TBorderStyle"; + case LayoutTPadding: + return "TPadding"; + case LayoutBaselineShift: + return "BaselineShift"; + case LayoutLineHeight: + return "LineHeight"; + case LayoutTextDecorationColor: + return "TextDecorationColor"; + case LayoutTextDecorationThickness: + return "TextDecorationThickness"; + case LayoutTextDecorationType: + return "TextDecorationType"; + case LayoutRubyAlign: + return "RubyAlign"; + case LayoutRubyPosition: + return "RubyPosition"; + case LayoutGlyphOrientationVertical: + return "GlyphOrientationVertical"; + case LayoutColumnCount: + return "ColumnCount"; + case LayoutColumnGap: + return "ColumnGap"; + case LayoutColumnWidths: + return "ColumnWidths"; + case LayoutListNumbering: + return "ListNumbering"; + case LayoutFieldRole: + return "Role"; + case LayoutFieldChecked: + return "checked"; + case LayoutFieldDesc: + return "Desc"; + case LayoutRowSpan: + return "RowSpan"; + case LayoutColSpan: + return "ColSpan"; + case LayoutTableHeaders: + return "Headers"; + case LayoutTableHeaderScope: + return "Scope"; + case LayoutTableSummary: + return "Summary"; + default: + return ""; + } +} +LayoutEnum CPDF_LayoutElement::ConvertLayoutEnum(CFX_ByteStringC Enum) +{ + if(Enum == "Block") { + return LayoutBlock; + } else if (Enum == "Inline") { + return LayoutInline; + } else if (Enum == "Before") { + return LayoutBefore; + } else if (Enum == "Start") { + return LayoutStart; + } else if (Enum == "End") { + return LayoutEnd; + } else if (Enum == "LrTb") { + return LayoutLrTb; + } else if (Enum == "RlTb") { + return LayoutRlTb; + } else if (Enum == "TbRl") { + return LayoutTbRl; + } else if (Enum == "None") { + return LayoutNone; + } else if (Enum == "Hidden") { + return LayoutHidden; + } else if (Enum == "Dotted") { + return LayoutDotted; + } else if (Enum == "Dashed") { + return LayoutDashed; + } else if (Enum == "Solid") { + return LayoutSolid; + } else if (Enum == "Double") { + return LayoutDouble; + } else if (Enum == "Groove") { + return LayoutGroove; + } else if (Enum == "Ridge") { + return LayoutRidge; + } else if (Enum == "Inset") { + return LayoutInset; + } else if (Enum == "Outset") { + return LayoutOutset; + } else if (Enum == "Normal") { + return LayoutNormal; + } else if (Enum == "Auto") { + return LayoutAuto; + } else if (Enum == "Center") { + return LayoutCenter; + } else if (Enum == "Justify") { + return LayoutJustify; + } else if (Enum == "Middle") { + return LayoutMiddle; + } else if (Enum == "Underline") { + return LayoutUnderline; + } else if (Enum == "Overline") { + return LayoutOverline; + } else if (Enum == "LineThrough") { + return LayoutLineThrough; + } else if (Enum == "Distribute") { + return LayoutDistribute; + } else if (Enum == "Disc") { + return LayoutDisc; + } else if (Enum == "Circle") { + return LayoutCircle; + } else if (Enum == "Square") { + return LayoutSquare; + } else if (Enum == "Decimal") { + return LayoutDecimal; + } else if (Enum == "UpperRoman") { + return LayoutUpperRoman; + } else if (Enum == "LowerRoman") { + return LayoutLowerRoman; + } else if (Enum == "UpperAlpha") { + return LayoutUpperAlpha; + } else if (Enum == "LowerAlpha") { + return LayoutLowerAlpha; + } else if (Enum == "rb") { + return LayoutRB; + } else if (Enum == "cb") { + return LayoutCB; + } else if (Enum == "pb") { + return LayoutPB; + } else if (Enum == "tv") { + return LayoutTV; + } else if (Enum == "on") { + return LayoutOn; + } else if (Enum == "off") { + return LayoutOff; + } else if (Enum == "neutral") { + return LayoutNeutral; + } else if (Enum == "Row") { + return LayoutRow; + } else if (Enum == "Column") { + return LayoutColumn; + } else if (Enum == "Both") { + return LayoutBoth; + } else if (Enum == "Left") { + return LayoutLeft; + } else if (Enum == "Top") { + return LayoutTop; + } else if (Enum == "Bottom") { + return LayoutBottom; + } else if (Enum == "Right") { + return LayoutRight; + } else if (Enum == "Pagination") { + return LayoutPagination; + } else if (Enum == "Layout") { + return LayoutLayout; + } else if (Enum == "Page") { + return LayoutPage; + } else if (Enum == "Background") { + return LayoutBackground; + } else if (Enum == "Header") { + return LayoutHeader; + } else if (Enum == "Footer") { + return LayoutFooter; + } else if (Enum == "Watermark") { + return LayoutWatermark; + } else { + return LayoutInvalid; + } +} +LayoutType CPDF_LayoutElement::GetType() +{ + if(!m_pTaggedElement) { + return LayoutUnknown; + } + CFX_ByteString name = m_pTaggedElement->GetType(); + return this->ConvertLayoutType(name); +} +int CPDF_LayoutElement::CountAttrValues(LayoutAttr attr_type) +{ + if(!m_pTaggedElement) { + return 0; + } + CPDF_Object* pObj = m_pTaggedElement->GetAttr(GetAttrOwner(attr_type), ConvertLayoutAttr(attr_type), IsInheritable(attr_type)); + if(pObj) { + return 1; + } else { + return 0; + } +} +LayoutEnum CPDF_LayoutElement::GetEnumAttr(LayoutAttr attr_type, int index) +{ + if(!m_pTaggedElement) { + return LayoutInvalid; + } + CFX_ByteStringC owner = GetAttrOwner(attr_type); + CFX_ByteStringC default_value = GetDefaultNameValue(attr_type); + CFX_ByteStringC AttrName = ConvertLayoutAttr(attr_type); + CFX_ByteString AttrValue = m_pTaggedElement->GetName(owner, AttrName, default_value, IsInheritable(attr_type), index); + return ConvertLayoutEnum(AttrValue); +} +CFX_ByteStringC CPDF_LayoutElement::GetAttrOwner(LayoutAttr attr_type) +{ + switch(attr_type) { + case LayoutListNumbering: + return "List"; + case LayoutFieldRole: + case LayoutFieldChecked : + case LayoutFieldDesc: + return "PrintField"; + case LayoutRowSpan: + case LayoutColSpan: + case LayoutTableHeaders: + case LayoutTableHeaderScope: + case LayoutTableSummary: + return "Table"; + default: + return "Layout"; + } +} +FX_FLOAT CPDF_LayoutElement::GetNumberAttr(LayoutAttr attr_type, int index) +{ + if(!m_pTaggedElement) { + return 0; + } + CFX_ByteStringC owner = GetAttrOwner(attr_type); + FX_FLOAT default_value = GetDefaultFloatValue(attr_type); + CFX_ByteStringC AttrName = ConvertLayoutAttr(attr_type); + FX_FLOAT f = m_pTaggedElement->GetNumber(owner, AttrName, default_value, IsInheritable(attr_type), index); + if(attr_type == LayoutWidth && !f) { + f = m_pTaggedElement->GetNumber("Table", AttrName, default_value, IsInheritable(attr_type), index); + } + return f; +} +FX_COLORREF CPDF_LayoutElement::GetColorAttr(LayoutAttr attr_type, int index) +{ + if(!m_pTaggedElement) { + return 0; + } + CFX_ByteStringC owner = GetAttrOwner(attr_type); + FX_COLORREF default_value = GetDefaultColorValue(attr_type); + CFX_ByteStringC AttrName = ConvertLayoutAttr(attr_type); + FX_ARGB f = m_pTaggedElement->GetColor(owner, AttrName, default_value, IsInheritable(attr_type), index); + return f; +} +FX_FLOAT CPDF_LayoutElement::GetDefaultFloatValue(LayoutAttr attr_type) +{ + switch(attr_type) { + case LayoutColumnCount: + return 1; + case LayoutRowSpan: + return 1; + case LayoutColSpan: + return 1; + default: + return 0; + } +} +FX_COLORREF CPDF_LayoutElement::GetDefaultColorValue(LayoutAttr attr_type) +{ + return -1; +} +CFX_ByteStringC CPDF_LayoutElement::GetDefaultNameValue(LayoutAttr attr_type) +{ + switch(attr_type) { + case LayoutPlacement: + return "Inline"; + case LayoutWritingMode: + return "LrTb"; + case LayoutBorderStyle: + return "None"; + case LayoutTextAlign: + return "Start"; + case LayoutBlockAlign: + return "Before"; + case LayoutInlineAlign: + return "Start"; + case LayoutTBorderStyle: + return "None"; + case LayoutTextDecorationType: + return "None"; + case LayoutRubyAlign: + return "Distribute"; + case LayoutRubyPosition: + return "Before"; + case LayoutGlyphOrientationVertical: + return "Auto"; + case LayoutListNumbering: + return "None"; + case LayoutFieldRole: + return "None"; + default: + return ""; + } +} +FX_BOOL CPDF_LayoutElement::IsInheritable(LayoutAttr type) +{ + switch(type) { + case LayoutWritingMode: + case LayoutTextAlign: + case LayoutBlockAlign: + case LayoutInlineAlign: + case LayoutLineHeight: + case LayoutGlyphOrientationVertical: + case LayoutRubyAlign: + case LayoutRubyPosition: + case LayoutBorderThickness: + case LayoutStartIndent: + case LayoutEndIndent: + case LayoutTextIndent: + case LayoutTPadding: + case LayoutTextDecorationThickness: + case LayoutBorderColor: + case LayoutColor: + case LayoutTextDecorationColor: + return TRUE; + default: + return FALSE; + } +} +int CPDF_LayoutElement::CountChildren() +{ + return m_ChildArray.GetSize(); +} +IPDF_LayoutElement* CPDF_LayoutElement::GetChild(int index) +{ + return (IPDF_LayoutElement*)m_ChildArray.GetAt(index); +} +IPDF_LayoutElement* CPDF_LayoutElement::GetParent() +{ + return m_pParentElement; +} +int CPDF_LayoutElement::CountObjects() +{ + if(m_pTaggedElement == NULL) { + return 0; + } + CFX_PtrArray* pObj = &m_ObjArray; + int size = pObj->GetSize(); + return size; +} +CPDF_PageObject* CPDF_LayoutElement::GetObject(int index) +{ + if(m_pTaggedElement == NULL) { + return NULL; + } + CFX_PtrArray *pObj = &m_ObjArray; + int size = pObj->GetSize(); + if(index < size) { + return (CPDF_PageObject*)pObj->GetAt(index); + } + return NULL; +} +FX_BOOL CPDF_LayoutElement::AddObject(CPDF_PageObject* pObj) +{ + return m_ObjArray.Add(pObj); +} +IPDF_LayoutProvider* IPDF_LayoutProvider::Create_LayoutProvider_TaggedPDF(CPDF_PageObjects* pPage) +{ + if(pPage == NULL) { + return NULL; + } + CPDF_LayoutProvider_TaggedPDF* pProvider = FX_NEW CPDF_LayoutProvider_TaggedPDF; + if (!pProvider) { + return NULL; + } + pProvider->Init(pPage); + return pProvider; +} +CPDF_LayoutProvider_TaggedPDF::CPDF_LayoutProvider_TaggedPDF() +{ + m_pPause = NULL; + m_pRoot = NULL; + m_pPageTree = NULL; + m_pCurTaggedElement = NULL; +} +CPDF_LayoutProvider_TaggedPDF::~CPDF_LayoutProvider_TaggedPDF() +{ + m_pCurTaggedElement = NULL; + m_pPause = NULL; + if(m_pRoot) { + delete m_pRoot; + } + m_pRoot = NULL; + if(m_pPageTree) { + delete m_pPageTree; + } + m_pPageTree = NULL; +} +void CPDF_LayoutProvider_TaggedPDF::ProcessElement(CPDF_LayoutElement*pParent, CPDF_StructElement* pTaggedElement) +{ + if(!pTaggedElement) { + return; + } + if(!pParent) { + m_Status = LayoutError; + return; + } + CPDF_LayoutElement* pElement = FX_NEW CPDF_LayoutElement; + if (!pElement) { + m_Status = LayoutError; + return; + } + pElement->m_pParentElement = pParent; + pElement->m_pTaggedElement = pTaggedElement; + pParent->m_ChildArray.Add(pElement); + int count = pTaggedElement->CountKids(); + for(int i = 0; i < count; i++) { + CPDF_StructKid Kid = pTaggedElement->GetKid(i); + switch(Kid.m_Type) { + case CPDF_StructKid::Element: { + ProcessElement(pElement, Kid.m_Element.m_pElement); + if(m_Status != LayoutReady) { + return ; + } + } + break; + case CPDF_StructKid::PageContent: { + int count = m_pPage->CountObjects(); + FX_POSITION pos = m_pPage->GetFirstObjectPosition(); + if(!pos) { + m_Status = LayoutError; + return ; + } + while (pos) { + CPDF_PageObject* pObj = m_pPage->GetNextObject(pos); + int pbjMCID = pObj->m_ContentMark.GetMCID(); + if((FX_DWORD)(pObj->m_ContentMark.GetMCID()) == Kid.m_PageContent.m_ContentId) { + pElement->AddObject(pObj); + } + } + } + break; + case CPDF_StructKid::StreamContent: + case CPDF_StructKid::Object: + default: + break; + } + } +} +LayoutStatus CPDF_LayoutProvider_TaggedPDF::StartLoad(IFX_Pause* pPause) +{ + m_pPause = pPause; + if(m_pPage->m_pDocument && m_pPage->m_pFormDict) { + m_pPageTree = CPDF_StructTree::LoadPage(m_pPage->m_pDocument, m_pPage->m_pFormDict); + } + if(!m_pPageTree) { + m_Status = LayoutError; + return LayoutError; + } + int count = m_pPageTree->CountTopElements(); + if(count == 0) { + m_Status = LayoutError; + return LayoutError; + } + m_pRoot = FX_NEW CPDF_LayoutElement; + if (!m_pRoot) { + m_Status = LayoutError; + return LayoutError; + } + for(int i = 0; i < count; i++) { + CPDF_StructElement* pElement = m_pPageTree->GetTopElement(i); + if(pElement) { + ProcessElement(m_pRoot, pElement); + if(m_Status != LayoutReady) { + return m_Status; + } + } + } + m_pCurTaggedElement = NULL; + m_Status = LayoutFinished; + return LayoutFinished; +} +LayoutStatus CPDF_LayoutProvider_TaggedPDF::Continue() +{ + if(!m_pCurTaggedElement) { + return LayoutError; + } + if(m_Status != LayoutToBeContinued) { + return LayoutError; + } + m_Status = LayoutReady; + int count = m_pPageTree->CountTopElements(); + for(int i = 0; i < count; i++) { + CPDF_StructElement* pElement = m_pPageTree->GetTopElement(i); + if(pElement) { + ProcessElement(m_pRoot, pElement); + if(m_Status != LayoutReady) { + return m_Status; + } + } + } + m_pCurTaggedElement = NULL; + m_Status = LayoutFinished; + return LayoutFinished; +} +int CPDF_LayoutProvider_TaggedPDF::GetPosition() +{ + if(m_TopElementIndex == 0) { + return 0; + } + int count = m_pPageTree->CountTopElements(); + return m_TopElementIndex / count * 100; +} diff --git a/core/src/reflow/layoutprovider_taggedpdf.h b/core/src/reflow/layoutprovider_taggedpdf.h new file mode 100644 index 0000000000..b2c8947a82 --- /dev/null +++ b/core/src/reflow/layoutprovider_taggedpdf.h @@ -0,0 +1,82 @@ +// 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 + +#ifndef LayoutProvider_TaggedPDF_H +#define LayoutProvider_TaggedPDF_H +#include "../../include/reflow/reflowengine.h" +class CPDF_LayoutElement : public IPDF_LayoutElement, public CFX_Object +{ +public: + CPDF_LayoutElement(); + ~CPDF_LayoutElement(); + + LayoutType GetType(); + void GetRect(CFX_FloatRect& rcRect) {}; + + int CountAttrValues(LayoutAttr attr_type); + + LayoutEnum GetEnumAttr(LayoutAttr attr_type, int index); + FX_FLOAT GetNumberAttr(LayoutAttr attr_type, int index); + FX_COLORREF GetColorAttr(LayoutAttr attr_type, int index); + + int CountChildren(); + + IPDF_LayoutElement* GetChild(int index); + + IPDF_LayoutElement* GetParent(); + + int CountObjects(); + CPDF_PageObject* GetObject(int index); + FX_BOOL AddObject(CPDF_PageObject* pObj); + CPDF_StructElement* m_pTaggedElement; + CPDF_LayoutElement* m_pParentElement; + CFX_PtrArray m_ChildArray; + LayoutType ConvertLayoutType(FX_BSTR name); + CFX_ByteStringC ConvertLayoutType(LayoutType type); + CFX_ByteStringC ConvertLayoutAttr(LayoutAttr attr); + LayoutEnum ConvertLayoutEnum(CFX_ByteStringC Enum); + +protected: + FX_BOOL IsInheritable(LayoutAttr attr_type); + CFX_ByteStringC GetAttrOwner(LayoutAttr attr_type); + CFX_ByteStringC GetDefaultNameValue(LayoutAttr attr_type); + FX_FLOAT GetDefaultFloatValue(LayoutAttr attr_type); + FX_COLORREF GetDefaultColorValue(LayoutAttr attr_type); + CFX_PtrArray m_ObjArray; +}; +class CPDF_LayoutProvider_TaggedPDF : public IPDF_LayoutProvider, public CFX_Object +{ +public: + CPDF_LayoutProvider_TaggedPDF(); + ~CPDF_LayoutProvider_TaggedPDF(); + void SetLayoutProviderStyle(LAYOUTPROVIDER_STYLE style) {}; + + void Init(CPDF_PageObjects* pPage) + { + m_pPage = pPage; + m_Status = LayoutReady; + }; + + LayoutStatus StartLoad(IFX_Pause* pPause = NULL); + LayoutStatus Continue(); + int GetPosition(); + + IPDF_LayoutElement* GetRoot() + { + return m_pRoot; + }; + +protected: + void ProcessElement(CPDF_LayoutElement*pParent, CPDF_StructElement* pTaggedElement); + LayoutStatus m_Status; + CPDF_StructElement* m_pCurTaggedElement; + CPDF_LayoutElement* m_pRoot; + IFX_Pause* m_pPause; + CPDF_PageObjects* m_pPage; + CPDF_StructTree* m_pPageTree; + int m_TopElementIndex; +}; +#endif diff --git a/core/src/reflow/reflowedpage.cpp b/core/src/reflow/reflowedpage.cpp new file mode 100644 index 0000000000..11baef8718 --- /dev/null +++ b/core/src/reflow/reflowedpage.cpp @@ -0,0 +1,622 @@ +// 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 "../../include/reflow/reflowengine.h" +#include "reflowedpage.h" +CPDF_ProgressiveReflowPageParser::CPDF_ProgressiveReflowPageParser() +{ + m_nObjProcessed = 0; + m_pReflowEngine = NULL; + m_pProvider = NULL; +} +CPDF_ProgressiveReflowPageParser::~CPDF_ProgressiveReflowPageParser() +{ + if(m_pProvider) { + delete m_pProvider; + } + m_pProvider = NULL; + if(m_pReflowEngine) { + delete m_pReflowEngine; + } + m_pReflowEngine = NULL; +} +void CPDF_ProgressiveReflowPageParser::Init() +{ + m_Status = Ready; +} +CPDF_ReflowedPage::CPDF_ReflowedPage(CFX_GrowOnlyPool* pMemoryPool) +{ + m_PageWidth = 0; + m_PageHeight = 0; + m_bWaiting = TRUE; + if(pMemoryPool) { + m_pMemoryPool = pMemoryPool; + m_bCreateMemoryPool = FALSE; + } else { + m_pMemoryPool = FX_NEW CFX_GrowOnlyPool; + m_bCreateMemoryPool = TRUE; + } + m_pCharState = FX_NEW CRF_CharStateArray(10); + m_pReflowed = FX_NEW CRF_DataPtrArray(500); + m_pPageInfos = NULL; +} +CPDF_ReflowedPage::~CPDF_ReflowedPage() +{ + if (m_pReflowed) { + for(int i = 0; i < m_pReflowed->GetSize(); i++) { + CRF_Data* pData = (*m_pReflowed)[i]; + if(pData->m_Type == CRF_Data::Image) { + delete ((CRF_ImageData*)pData)->m_pBitmap; + } + } + m_pReflowed->RemoveAll(); + delete m_pReflowed; + } + m_pReflowed = NULL; + if (m_pCharState) { + m_pCharState->RemoveAll(); + delete m_pCharState; + } + m_pCharState = NULL; + if(m_bCreateMemoryPool && m_pMemoryPool) { + m_pMemoryPool->FreeAll(); + } + if (m_pMemoryPool) { + delete m_pMemoryPool; + } + m_pMemoryPool = NULL; + m_pPDFPage = NULL; + if (m_pPageInfos) { + ReleasePageObjsMemberShip(); + } +} +FX_BOOL CPDF_ReflowedPage::RetainPageObjsMemberShip() +{ + if (NULL == m_pPDFPage) { + return FALSE; + } + if (NULL == m_pPageInfos) { + m_pPageInfos = FX_NEW CFX_MapPtrToPtr(); + } else { + return TRUE; + } + FX_POSITION pos = m_pPDFPage->GetFirstObjectPosition(); + if (!pos) { + return FALSE; + } + CPDF_PageObject* pPageObj = NULL; + while (pos) { + pPageObj = m_pPDFPage->GetNextObject(pos); + MarkPageObjMemberShip(pPageObj, NULL); + pPageObj = NULL; + } + return TRUE; +} +void CPDF_ReflowedPage::MarkPageObjMemberShip(CPDF_PageObject* pObj, CRF_PageInfo* pParent) +{ + if (NULL == m_pPageInfos) { + return; + } + CRF_PageInfo* pPageInfo = FX_NEW CRF_PageInfo(pObj, pParent); + if (NULL == pPageInfo) { + return; + } + m_pPageInfos->SetAt(pObj, pPageInfo); + if (PDFPAGE_FORM != pObj->m_Type) { + return; + } + CPDF_FormObject* pFormObj = (CPDF_FormObject*)pObj; + FX_POSITION pos; + pos = pFormObj->m_pForm->GetFirstObjectPosition(); + if (!pos) { + return; + } + CPDF_PageObject* pPageObj = NULL; + while (pos) { + pPageObj = pFormObj->m_pForm->GetNextObject(pos); + MarkPageObjMemberShip(pPageObj, pPageInfo); + pPageObj = NULL; + } +} +void CPDF_ReflowedPage::ReleasePageObjsMemberShip() +{ + if (NULL == m_pPageInfos) { + return; + } + CPDF_PageObject* pPageObj = NULL; + CRF_PageInfo* pPageInfo = NULL; + FX_POSITION pos = m_pPageInfos->GetStartPosition(); + while (pos) { + m_pPageInfos->GetNextAssoc(pos, (void*&)pPageObj, (void*&)pPageInfo); + delete pPageInfo; + } + m_pPageInfos->RemoveAll(); + delete m_pPageInfos; + m_pPageInfos = NULL; +} +CPDF_Dictionary* CPDF_ReflowedPage::GetFormResDict(CPDF_PageObject* pObj) +{ + if (NULL == m_pPageInfos) { + return NULL; + } + if (FALSE == RetainPageObjsMemberShip()) { + return NULL; + } + CRF_PageInfo* pPageInfo = (CRF_PageInfo*)m_pPageInfos->GetValueAt(pObj); + if (NULL == pPageInfo) { + return NULL; + } + return pPageInfo->GetFormDict(); +} +void CPDF_ReflowedPage::GetDisplayMatrix(CFX_AffineMatrix& matrix, FX_INT32 xPos, FX_INT32 yPos, FX_INT32 xSize, FX_INT32 ySize, FX_INT32 iRotate, const CFX_AffineMatrix* pPageMatrix) +{ + CFX_AffineMatrix display_matrix; + if(m_PageHeight == 0) { + matrix.Set(1, 0, 0, -1, 0, 0); + return; + } + FX_INT32 x0, y0, x1, y1, x2, y2; + iRotate %= 4; + switch (iRotate) { + case 0: + x0 = xPos; + y0 = yPos; + x1 = xPos; + y1 = yPos + ySize; + x2 = xPos + xSize; + y2 = yPos; + break; + case 3: + x0 = xPos; + y0 = ySize + yPos; + x1 = xPos + xSize; + y1 = yPos + ySize; + x2 = xPos; + y2 = yPos; + break; + case 2: + x0 = xSize + xPos; + y0 = ySize + yPos; + x1 = xSize + xPos ; + y1 = yPos; + x2 = xPos; + y2 = ySize + yPos; + break; + case 1: + x0 = xPos + xSize; + y0 = yPos; + x1 = xPos; + y1 = yPos; + x2 = xPos + xSize; + y2 = yPos + ySize; + break; + } + display_matrix.Set(FXSYS_Div((FX_FLOAT)(x2 - x0), m_PageWidth), + FXSYS_Div((FX_FLOAT)(y2 - y0), m_PageWidth), + FXSYS_Div((FX_FLOAT)(x1 - x0), m_PageHeight), + FXSYS_Div((FX_FLOAT)(y1 - y0), m_PageHeight), + (FX_FLOAT)(x0), (FX_FLOAT)(y0)); + matrix.Set(1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f); + matrix.Concat(display_matrix); + return; +} +FX_FLOAT CPDF_ReflowedPage::GetPageHeight() +{ + return m_PageHeight; +} +void CPDF_ReflowedPage::FocusGetData(const CFX_AffineMatrix matrix, FX_INT32 x, FX_INT32 y, CFX_ByteString& str) +{ + if (NULL == m_pReflowed) { + return; + } + CFX_AffineMatrix revMatrix; + revMatrix.SetReverse(matrix); + FX_FLOAT x1, y1; + revMatrix.Transform((float)x, (float)y, x1, y1); + int count = m_pReflowed->GetSize(); + FX_FLOAT dx = 1000, dy = 1000; + FX_INT32 pos = 0; + FX_INT32 i; + for(i = 0; i < count; i++) { + CRF_Data* pData = (*m_pReflowed)[i]; + FX_FLOAT tempdy = FXSYS_fabs(pData->m_PosY - y1); + if(FXSYS_fabs(tempdy - dy) < 1) { + continue; + } + CFX_FloatRect rect (0, pData->m_PosY + pData->m_Height, this->m_PageWidth, pData->m_PosY); + if(rect.Contains(x1, y1)) { + pos = i; + dx = 0; + dy = 0; + break; + } else if(tempdy < dy) { + dy = tempdy; + dx = FXSYS_fabs(pData->m_PosX - x1); + pos = i; + } else if (tempdy == dy) { + FX_FLOAT tempdx = FXSYS_fabs(pData->m_PosX - x1); + if(tempdx < dx) { + dx = tempdx; + pos = i; + } + } else if (tempdy > dy) { + break; + } + } + if(dx != 0 || dy != 0) { + count = count < (pos + 10) ? count : (pos + 10); + for(i = 0 > (pos - 10) ? 0 : (pos - 10); i < count; i++) { + CRF_Data* pData = (*m_pReflowed)[i]; + FX_FLOAT tempdy = FXSYS_fabs(pData->m_PosY - y1); + if(tempdy < dy) { + dy = tempdy; + dx = FXSYS_fabs(pData->m_PosX - x1); + pos = i; + } else if (tempdy == dy) { + FX_FLOAT tempdx = FXSYS_fabs(pData->m_PosX - x1); + if(tempdx < dx) { + dx = tempdx; + pos = i; + } + } + } + } + str.Format("%d", pos); +} +FX_BOOL CPDF_ReflowedPage::FocusGetPosition(const CFX_AffineMatrix matrix, CFX_ByteString str, FX_INT32& x, FX_INT32& y) +{ + if (NULL == m_pReflowed) { + return FALSE; + } + FX_INT32 pos = FXSYS_atoi(str); + if(pos < 0 || pos >= m_pReflowed->GetSize()) { + return FALSE; + } + CRF_Data* pData = (*m_pReflowed)[pos]; + FX_FLOAT x1, y1; + matrix.Transform(pData->m_PosX, pData->m_PosY + pData->m_Height, x1, y1); + x = (int)x1; + y = (int)y1; + return TRUE; +} +int CPDF_ProgressiveReflowPageParser::GetPosition() +{ + if(!m_pProvider) { + return 0; + } + if(!m_pReflowEngine) { + return m_pProvider->GetPosition() / 2; + } + return m_pProvider->GetPosition() / 2 + m_pReflowEngine->GetPosition() / 2; +} +void CPDF_ProgressiveReflowPageParser::Continue(IFX_Pause* pPause) +{ + if (NULL == m_pReflowPage) { + return; + } + if(m_Status != ToBeContinued) { + return; + } + m_pPause = pPause; + if(m_pReflowEngine) { + if(m_pReflowEngine->Continue() != LayoutToBeContinued) { + m_Status = Done; + } + } else { + if(m_pProvider->Continue() == LayoutFinished) { + m_pReflowEngine = IPDF_LayoutProcessor::Create_LayoutProcessor_Reflow(m_TopIndent, m_ReflowedWidth, m_fScreenHeight, m_pReflowPage, m_flags, m_ParseStyle.m_LineSpace); + CFX_AffineMatrix matrix; + m_pPDFPage->GetDisplayMatrix(matrix, 0, 0, (int)(m_pPDFPage->GetPageWidth()), (int)(m_pPDFPage->GetPageHeight()), 0); + if(m_pReflowEngine->StartProcess(m_pProvider->GetRoot(), m_pPause, &matrix) != LayoutToBeContinued) { + m_Status = Done; + } + } + } + if(m_TopIndent && m_Status == Done) { + m_pReflowPage->m_PageHeight -= m_TopIndent; + } +} +void CPDF_ProgressiveReflowPageParser::Clear() +{ + this->Init(); + return; +} +FX_BOOL IPDF_ProgressiveReflowPageParser::IsTaggedPage(CPDF_PageObjects*pPage) +{ + if(!pPage) { + return FALSE; + } + CPDF_StructTree* pPageTree = CPDF_StructTree::LoadPage(pPage->m_pDocument, pPage->m_pFormDict); + if(pPageTree) { + int count = pPageTree->CountTopElements(); + if(count) { + for(int i = 0; i < count; i++) { + CPDF_StructElement* pElm = pPageTree->GetTopElement(i); + if(pElm) { + delete pPageTree; + pPageTree = NULL; + return TRUE; + } + } + } + delete pPageTree; + pPageTree = NULL; + return FALSE; + } + return FALSE; +} +void CPDF_ProgressiveReflowPageParser::Start(IPDF_ReflowedPage* pReflowPage, CPDF_Page* pPage, FX_FLOAT topIndent, FX_FLOAT fWidth, FX_FLOAT fHeight, IFX_Pause* pPause, int flags) +{ + if (NULL == pReflowPage) { + m_Status = Failed; + return; + } + m_flags = flags; + m_pReflowPage = (CPDF_ReflowedPage*)pReflowPage; + m_pReflowPage->m_pPDFPage = pPage; + m_pReflowPage->ReleasePageObjsMemberShip(); + m_pPDFPage = pPage; + m_TopIndent = topIndent; + m_pPause = pPause; + m_fScreenHeight = fHeight; + m_ReflowedWidth = fWidth; + m_pProvider = IPDF_LayoutProvider::Create_LayoutProvider_TaggedPDF(m_pPDFPage); + LayoutStatus status = m_pProvider->StartLoad(pPause); + if(status == LayoutError) { + delete m_pProvider; + m_pProvider = IPDF_LayoutProvider::Create_LayoutProvider_AutoReflow(m_pPDFPage, m_flags & RF_PARSER_READERORDER); + if (NULL == m_pProvider) { + m_Status = Failed; + return; + } + status = m_pProvider->StartLoad(pPause); + } + if(status == LayoutError) { + delete m_pProvider; + m_pProvider = NULL; + m_Status = Failed; + return; + } + if(status == LayoutToBeContinued) { + m_Status = ToBeContinued; + } else if (status == LayoutFinished) { + m_pReflowEngine = IPDF_LayoutProcessor::Create_LayoutProcessor_Reflow(topIndent, fWidth, fHeight, pReflowPage, m_flags, m_ParseStyle.m_LineSpace); + if(NULL == m_pReflowEngine) { + delete m_pProvider; + m_pProvider = NULL; + m_Status = Failed; + return; + } + CFX_AffineMatrix matrix; + pPage->GetDisplayMatrix(matrix, 0, 0, (int)(pPage->GetPageWidth()), (int)(pPage->GetPageHeight()), 0); + CFX_AffineMatrix matrix1 = pPage->GetPageMatrix(); + if((status = m_pReflowEngine->StartProcess(m_pProvider->GetRoot(), pPause, &matrix)) != LayoutToBeContinued) { + delete m_pReflowEngine; + m_pReflowEngine = NULL; + m_Status = Done; + } else { + m_Status = ToBeContinued; + } + } + if(status != LayoutToBeContinued) { + delete m_pProvider; + m_pProvider = NULL; + } + if(m_TopIndent && m_Status == Done) { + m_pReflowPage->m_PageHeight -= m_TopIndent; + } + return; +} +CPDF_ProgressiveReflowPageRender::~CPDF_ProgressiveReflowPageRender() +{ + if(m_pDisplayMatrix) { + delete m_pDisplayMatrix; + } + m_pDisplayMatrix = NULL; +} +CPDF_ProgressiveReflowPageRender::CPDF_ProgressiveReflowPageRender() +{ + m_Status = Ready; + m_pReflowPage = NULL; + m_pDisplayMatrix = NULL; + m_CurrNum = 0; + m_pFontEncoding = NULL; + m_DisplayColor = -1; +} +static FX_FLOAT _CIDTransformToFloat(FX_BYTE ch) +{ + if (ch < 128) { + return ch * 1.0f / 127; + } + return (-255 + ch) * 1.0f / 127; +} +int CPDF_ProgressiveReflowPageRender::GetPosition() +{ + if(m_CurrNum == 0 || NULL == m_pReflowPage) { + return 0; + } + int size = m_pReflowPage->m_pReflowed->GetSize(); + if(size == 0 || m_CurrNum >= size) { + return 100; + } + return (int)(m_CurrNum * 100 / size); +} +void CPDF_ProgressiveReflowPageRender::Display(IFX_Pause* pPause) +{ + if (NULL == m_pReflowPage) { + m_Status = Done; + return; + } + FX_RECT clipBox = m_pFXDevice->GetClipBox(); + int size = m_pReflowPage->m_pReflowed->GetSize(); + if (size < 1 || NULL == m_pDisplayMatrix) { + m_Status = Done; + return; + } + for(int i = m_CurrNum; i < size; i++) { + CRF_Data* pData = (*m_pReflowPage->m_pReflowed)[i]; + if(!pData) { + continue; + } + CFX_FloatRect rect (pData->m_PosX, pData->m_PosY + pData->m_Height, pData->m_PosX + pData->m_Width, pData->m_PosY); + m_pDisplayMatrix->TransformRect(rect); + if(rect.left > clipBox.right || rect.right < clipBox.left || rect.bottom > clipBox.bottom || rect.top < clipBox.top) { + continue; + } + if(pData->GetType() == CRF_Data::Text) { + CRF_CharData* pCharData = (CRF_CharData*)pData; + CPDF_Font* pPDFFont = pCharData->m_pCharState->m_pFont; + if(pPDFFont->GetFontType() == PDFFONT_TYPE3) { + continue; + } + FX_FLOAT x = pData->m_PosX, y = pData->m_PosY - pCharData->m_pCharState->m_fDescent; + FXTEXT_CHARPOS charpos ; + charpos.m_GlyphIndex = pPDFFont->GlyphFromCharCode(pCharData->m_CharCode); + charpos.m_FontCharWidth = pPDFFont->m_Font.GetGlyphWidth(charpos.m_GlyphIndex); + charpos.m_OriginX = x; + charpos.m_OriginY = y; + FX_FLOAT charW = pData->m_Width * 1000 / pData->m_Height; + if(charW != charpos.m_FontCharWidth) { + charpos.m_bGlyphAdjust = TRUE; + charpos.m_AdjustMatrix[0] = charW / charpos.m_FontCharWidth; + charpos.m_AdjustMatrix[1] = 0; + charpos.m_AdjustMatrix[2] = 0; + charpos.m_AdjustMatrix[3] = 1; + } else { + charpos.m_bGlyphAdjust = FALSE; + } + FX_BOOL bRet = FALSE; + if(m_DisplayColor == -1) + bRet = m_pFXDevice->DrawNormalText(1, &charpos, &(pPDFFont->m_Font), + NULL, pCharData->m_pCharState->m_fFontSize, + m_pDisplayMatrix, pCharData->m_pCharState->m_Color + 0xff000000, FXTEXT_CLEARTYPE); + else + bRet = m_pFXDevice->DrawNormalText(1, &charpos, &(pPDFFont->m_Font), + NULL, pCharData->m_pCharState->m_fFontSize, m_pDisplayMatrix, m_DisplayColor, FXTEXT_CLEARTYPE); + } else if(pData->GetType() == CRF_Data::Image) { + CRF_ImageData* pImageData = (CRF_ImageData*)pData; + if(!pImageData->m_pBitmap) { + continue; + } + int left = 0, top = 0; + CFX_DIBitmap* pDiBmp = NULL; + CFX_DIBSource* pDispSource = pImageData->m_pBitmap; + if(pImageData->m_Matrix.d < 0) { + CFX_AffineMatrix matrix(pImageData->m_Matrix.a, 0, 0, -pImageData->m_Matrix.d, 0, 0); + int left, top; + pDiBmp = pImageData->m_pBitmap->TransformTo(&matrix, left, top); + pDispSource = pDiBmp; + } + if (NULL == pDispSource) { + continue; + } + if (pDispSource->GetFormat() == FXDIB_1bppMask || pDispSource->GetFormat() == FXDIB_8bppMask) { + m_pFXDevice->StretchBitMask(pDispSource, (int)(rect.left + 0.5), (int)(rect.bottom + 0.5), (int)(rect.Width() + 0.5), (int)(rect.Height() + 0.5), 0xff000000); + } else { + m_pFXDevice->StretchDIBits(pDispSource, (int)(rect.left + 0.5), (int)(rect.bottom + 0.5), (int)(rect.Width() + 0.5), (int)(rect.Height() + 0.5)); + } + if(m_pFXDevice->GetBitmap() && m_pFXDevice->GetBitmap()->GetFormat() == FXDIB_8bppRgb && + m_pFXDevice->GetBitmap()->GetPalette() == NULL) { + int nPalette = 0; + switch(m_DitherBits) { + case 0: + nPalette = 0; + break; + case 1: + nPalette = 2; + break; + case 2: + nPalette = 4; + break; + case 3: + nPalette = 8; + break; + case 4: + nPalette = 16; + break; + case 5: + nPalette = 32; + break; + case 6: + nPalette = 64; + break; + case 7: + nPalette = 128; + break; + default: + nPalette = 256; + break; + } + if(nPalette >= 2) { + FX_ARGB * palette = FX_Alloc(FX_ARGB, nPalette); + nPalette --; + palette[0] = 0; + palette[nPalette] = 255; + FX_FLOAT Dither = (FX_FLOAT)255 / (nPalette); + for(int i = 1; i < nPalette; i++) { + palette[i] = (FX_ARGB)(Dither * i + 0.5); + } + FX_RECT tmpRect = rect.GetOutterRect(); + m_pFXDevice->GetBitmap()->DitherFS(palette, nPalette + 1, &tmpRect); + FX_Free (palette); + } + } + if(pDiBmp) { + delete pDiBmp; + } + } else if(pData->GetType() == CRF_Data::Path) { + } + if(!(i % 10)) { + if(pPause && pPause->NeedToPauseNow()) { + i++; + m_CurrNum = i; + m_Status = ToBeContinued; + return; + } + } + } + m_CurrNum = size; + m_Status = Done; +} +void CPDF_ProgressiveReflowPageRender::Start(IPDF_ReflowedPage* pReflowPage, CFX_RenderDevice* pDevice, const CFX_AffineMatrix* pMatrix, IFX_Pause* pPause, int DitherBits) +{ + if(!pReflowPage || !pDevice || !pMatrix) { + m_Status = Failed; + return; + } + m_DitherBits = DitherBits; + m_Status = Ready; + m_CurrNum = 0; + m_pReflowPage = (CPDF_ReflowedPage*)pReflowPage; + m_pFXDevice = pDevice; + if(NULL == m_pDisplayMatrix) { + m_pDisplayMatrix = FX_NEW CFX_AffineMatrix; + } + if (m_pDisplayMatrix) { + m_pDisplayMatrix->Copy(*pMatrix); + } + m_Status = ToBeContinued; + Display(pPause); +} +void CPDF_ProgressiveReflowPageRender::Continue(IFX_Pause* pPause) +{ + Display(pPause); +} +void CPDF_ProgressiveReflowPageRender::SetDisplayColor(FX_COLORREF color) +{ + m_DisplayColor = color; +} +void CPDF_ProgressiveReflowPageRender::Clear() +{ + if (m_pDisplayMatrix) { + delete m_pDisplayMatrix; + } + m_pDisplayMatrix = NULL; + m_pReflowPage = NULL; + m_pFXDevice = NULL; + m_CurrNum = 0; + m_Status = Ready; +} diff --git a/core/src/reflow/reflowedpage.h b/core/src/reflow/reflowedpage.h new file mode 100644 index 0000000000..b76834132e --- /dev/null +++ b/core/src/reflow/reflowedpage.h @@ -0,0 +1,372 @@ +// 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 + +#ifndef _REFLOWED_PAGE_H +#define _REFLOWED_PAGE_H +#include "../../include/reflow/reflowengine.h" +#define GET_SIGNED(a) ( (a)>0 ? a/a : (a==0 ? 0 : -a/a) ) +class CRF_Data; +class CRF_LineData; +class CRF_CharData; +class CRF_PathData; +class CRF_ImageData; +class CRF_Table; +class CRF_AttrOperation; +class CRF_OperationDate; +class CPDF_ReflowedPage; +class CPDF_Rect; +class CFX_Object; +typedef CFX_SegmentedArray<CRF_Data*> CRF_DataPtrArray; +class CRF_CharState; +typedef CFX_SegmentedArray<CRF_CharState> CRF_CharStateArray; +#define SST_GE 1 +#define SST_BLSE 2 +#define SST_ILSE 3 +#define SST_IE 4 +class CPDF_LayoutProcessor_Reflow : public IPDF_LayoutProcessor, public CFX_Object +{ +public: + CPDF_LayoutProcessor_Reflow(); + ~CPDF_LayoutProcessor_Reflow(); + void Init(FX_FLOAT TopIndent, FX_FLOAT fWidth, FX_FLOAT fHeight, CPDF_ReflowedPage* pReflowedPage, int flags, FX_FLOAT lineSpace); + + LayoutStatus StartProcess(IPDF_LayoutElement* pElement, IFX_Pause* pPause, const CFX_AffineMatrix* pPDFMatrix = NULL); + LayoutStatus Continue(); + int GetPosition(); +protected: + void FitPageMode(); + void ProcessElement(IPDF_LayoutElement* pElement, FX_FLOAT reflowWidth); + FX_FLOAT GetElmWidth(IPDF_LayoutElement* pElement); + CFX_FloatRect GetElmBBox(IPDF_LayoutElement* pElement); + void ProcessTable(FX_FLOAT dx); + void ProcessObjs(IPDF_LayoutElement* pElement, FX_FLOAT reflowWidth); + void ProcessObject(CPDF_PageObject* pObj, FX_FLOAT reflowWidth, CFX_AffineMatrix objMatrix); + void ProcessTextObject(CPDF_TextObject *pObj, FX_FLOAT reflowWidth, CFX_AffineMatrix objMatrix); + void ProcessPathObject(CPDF_PathObject *pObj, FX_FLOAT reflowWidth); + void ProcessUnitaryObjs(CPDF_PageObjects *pObjs, FX_FLOAT reflowWidth, CFX_AffineMatrix objMatrix); + FX_INT32 LogicPreObj(CPDF_TextObject* pObj); + int ProcessInsertObject(CPDF_TextObject* pObj, CFX_AffineMatrix formMatrix); + FX_WCHAR GetPreChar(); + FX_BOOL IsSameTextObject(CPDF_TextObject* pTextObj1, CPDF_TextObject* pTextObj2); + int GetCharWidth(FX_DWORD charCode, CPDF_Font* pFont) const; + FX_BOOL IsCanBreakAfter(FX_DWORD unicode); + FX_BOOL IsCanBreakBefore(FX_DWORD unicode); + FX_INT32 GetElementTypes(LayoutType layoutType); + void CreateRFData(CPDF_PageObject* pObj, CFX_AffineMatrix* pMatrix = NULL); + CRF_CharState* GetCharState(CPDF_TextObject* pObj, CPDF_Font* pFont, FX_FLOAT fHeight, FX_ARGB color); + FX_FLOAT ConverWidth(FX_FLOAT width); + void AddData2CurrLine(CRF_Data* pData); + void AddTemp2CurrLine(int begin, int count ); + void Transform(const CFX_AffineMatrix* pMatrix, CRF_Data* pData); + void Transform(const CFX_AffineMatrix* pMatrix, CRF_DataPtrArray* pDataArray, int beginPos, int count = 0); + FX_FLOAT GetDatasWidth( int beginPos, int endpos); + void UpdateCurrLine(); + FX_BOOL FinishedCurrLine(); + int m_flags; + CFX_AffineMatrix m_PDFMatrix; + LayoutStatus m_Status; + CPDF_TextObject* m_pPreObj; + CFX_AffineMatrix m_perMatrix; + IPDF_LayoutElement* m_pLayoutElement; + IPDF_LayoutElement* m_pRootElement; + FX_FLOAT m_CurrRefWidth; + IFX_Pause* m_pPause; + LayoutEnum m_CurrWritingMode; + CPDF_ReflowedPage* m_pReflowedPage; + FX_FLOAT m_fRefWidth; + FX_FLOAT m_TopIndent; + FX_FLOAT m_fLineSpace; + FX_FLOAT m_fScreenHeight; + FX_FLOAT m_fCurrMaxWidth; + FX_FLOAT m_fCurrLineWidth; + FX_FLOAT m_fCurrLineHeight; + CRF_DataPtrArray* m_pCurrLine; + CRF_DataPtrArray* m_pTempLine; + FX_BOOL m_bIllustration; + FX_FLOAT m_fLineHeight; + LayoutEnum m_TextAlign; + FX_FLOAT m_StartIndent; + CFX_ArrayTemplate<CRF_Table*> m_TableArray; + int m_PausePosition; +}; +struct RF_TableCell { + int m_BeginPos; + int m_EndPos; + FX_FLOAT m_MaxWidth; + FX_FLOAT m_PosX; + FX_FLOAT m_PosY; + FX_FLOAT m_CellWidth; + FX_FLOAT m_CellHeight; + int m_RowSpan; + int m_ColSpan; + LayoutEnum m_BlockAlign; + LayoutEnum m_InlineAlign; +}; +typedef CFX_ArrayTemplate<RF_TableCell*> CRF_TableCellArray; +class CRF_Table : public CFX_Object +{ +public: + CRF_Table() + { + m_TableWidth = 0; + m_nCol = 0; + } + CRF_TableCellArray m_pCellArray; + CFX_WordArray m_nCell; + int m_nCol; + FX_FLOAT m_TableWidth; + FX_FLOAT m_ReflowPageHeight; +}; +class CRF_CharState : public CFX_Object +{ +public: + CPDF_Font* m_pFont; + FX_ARGB m_Color; + FX_BOOL m_bVert; + FX_FLOAT m_fFontSize; + FX_FLOAT m_fAscent; + FX_FLOAT m_fDescent; + + CPDF_TextObject* m_pTextObj; +}; +class CRF_PageInfo : public CFX_Object +{ +public: + CRF_PageInfo(CPDF_PageObject* pPageObj, CRF_PageInfo* pParent = NULL) + : m_pPageObj(pPageObj) , m_pParent(pParent) + { + } + CPDF_PageObject* GetPageObj() + { + return m_pPageObj; + } + CPDF_Dictionary* GetFormDict() + { + if (NULL == m_pParent) { + return NULL; + } + CPDF_PageObject* pParentObj = m_pParent->GetPageObj(); + if (NULL == pParentObj || PDFPAGE_FORM != pParentObj->m_Type) { + return NULL; + } + return ((CPDF_FormObject*)pParentObj)->m_pForm->m_pResources; + } +protected: + CPDF_PageObject* m_pPageObj; + CRF_PageInfo* m_pParent; +}; +class CPDF_ReflowedPage : public IPDF_ReflowedPage, public CFX_PrivateData, public CFX_Object +{ +public: + + CPDF_ReflowedPage(CFX_GrowOnlyPool* pMemoryPool); + ~CPDF_ReflowedPage(); + CFX_PrivateData* GetPrivateDataCtrl() + { + return this; + }; + void GetDisplayMatrix(CFX_AffineMatrix& matrix, FX_INT32 xPos, FX_INT32 yPos, FX_INT32 xSize, FX_INT32 ySize, FX_INT32 iRotate, const CFX_AffineMatrix* pPageMatrix); + + FX_FLOAT GetPageHeight() ; + FX_FLOAT GetPageWidth() + { + return m_PageWidth; + }; + void FocusGetData(const CFX_AffineMatrix matrix, FX_INT32 x, FX_INT32 y, CFX_ByteString& str); + FX_BOOL FocusGetPosition(const CFX_AffineMatrix matrix, CFX_ByteString str, FX_INT32& x, FX_INT32& y); + CRF_DataPtrArray* m_pReflowed; + FX_FLOAT m_PageWidth; + FX_FLOAT m_PageHeight; + FX_BOOL m_bWaiting; + CRF_CharStateArray* m_pCharState; + CFX_GrowOnlyPool* m_pMemoryPool; + FX_BOOL m_bCreateMemoryPool; + CPDF_Page* m_pPDFPage; + FX_BOOL RetainPageObjsMemberShip(); + void MarkPageObjMemberShip(CPDF_PageObject* pObj, CRF_PageInfo* pParent); + void ReleasePageObjsMemberShip(); + CPDF_Dictionary* GetFormResDict(CPDF_PageObject* pObj); + + CFX_MapPtrToPtr* m_pPageInfos; +}; +class CPDF_ProgressiveReflowPageParser : public IPDF_ProgressiveReflowPageParser, public CFX_Object +{ +public: + CPDF_ProgressiveReflowPageParser(); + ~CPDF_ProgressiveReflowPageParser() ; + void Init(); + + ParseStatus GetStatus() + { + return m_Status; + }; + + void SetParserStyle(RF_ParseStyle style) + { + m_ParseStyle = style; + }; + void Start(IPDF_ReflowedPage* pReflowPage, CPDF_Page* pPage, FX_FLOAT TopIndent, FX_FLOAT fWidth, FX_FLOAT fHeight, IFX_Pause* pPause, int flags); + void Continue(IFX_Pause* pPause); + int GetPosition() ; + + void Clear(); + ParseStatus m_Status; +protected: + RF_ParseStyle m_ParseStyle; + CPDF_Page* m_pPDFPage; + IFX_Pause* m_pPause; + CPDF_ReflowedPage* m_pReflowPage; + FX_FLOAT m_TopIndent; + FX_FLOAT m_ReflowedWidth; + FX_FLOAT m_fScreenHeight; + IPDF_LayoutProvider* m_pProvider; + IPDF_LayoutProcessor* m_pReflowEngine; + int m_nObjProcessed; + int m_flags; +}; +class CPDF_ProgressiveReflowPageRender : public IPDF_ProgressiveReflowPageRender, public CFX_Object +{ +public: + CPDF_ProgressiveReflowPageRender(); + ~CPDF_ProgressiveReflowPageRender() ; + + RenderStatus GetStatus() + { + return m_Status; + }; + + + void SetDisplayColor(FX_COLORREF color); + void Start(IPDF_ReflowedPage* pReflowPage, CFX_RenderDevice* pDevice, const CFX_AffineMatrix* pMatrix, IFX_Pause* pPause, int DitherBits); + void Continue(IFX_Pause* pPause); + int GetPosition(); + + + void Clear(); +protected: + void Display(IFX_Pause* pPause); + RenderStatus m_Status; + CPDF_ReflowedPage* m_pReflowPage; + CFX_AffineMatrix* m_pDisplayMatrix; + int m_CurrNum; + IFX_FontEncoding* m_pFontEncoding; + CFX_RenderDevice* m_pFXDevice; + int m_DitherBits; + FX_COLORREF m_DisplayColor; + typedef struct CRF_TextDataAtt { + CRF_TextDataAtt() + { + pFont = NULL; + fFontSize = 0.0f; + Color = 0; + } + CRF_TextDataAtt(CPDF_Font* font, FX_FLOAT fontSize, FX_ARGB color) + { + pFont = font; + fFontSize = fontSize; + Color = color; + } + CPDF_Font* pFont; + FX_FLOAT fFontSize; + FX_ARGB Color; + } CRF_TEXTDATAATT; + inline bool isTextDataAttSame(CRF_TEXTDATAATT data1, CRF_TEXTDATAATT data2) + { + if (data1.pFont != data2.pFont) { + return false; + } + if (data1.Color != data2.Color) { + return false; + } + if (fabs(data1.fFontSize - data2.fFontSize) > 0.0f) { + return false; + } + return true; + }; +}; +#define TYPE_UNKNOW 0 +#define TYPE_TEXT 1 +#define TYPE_PATH 2 +#define TYPE_IMAGE 3 +#define TYPE_LINE 4 +class CRF_Data : public CFX_Object +{ +public: + typedef enum {Unknow, Text, Image, Path, Line, paragraph} RF_DataType; + CRF_Data() + { + m_Type = Unknow; + m_Width = 0; + m_PosY = 0; + m_PosX = 0; + m_Height = 0; + } + RF_DataType GetType() + { + return m_Type; + } + virtual ~CRF_Data() {} + RF_DataType m_Type; + FX_FLOAT m_PosX; + FX_FLOAT m_PosY; + FX_FLOAT m_Width; + FX_FLOAT m_Height; +}; +class CRF_LineData : public CRF_Data +{ +public: + CRF_LineData() + { + m_Type = Line; + } +}; +class CRF_CharData : public CRF_Data +{ +public: + CRF_CharData() + { + m_Type = Text; + m_CharCode = -1; + } + CRF_CharState* m_pCharState; + FX_DWORD m_CharCode; +}; +class CRF_ImageData : public CRF_Data +{ +public: + CRF_ImageData() + { + m_Type = Image; + m_pBitmap = NULL; + } + ~CRF_ImageData() + { + if(m_pBitmap) { + delete m_pBitmap; + } + m_pBitmap = NULL; + } + CFX_AffineMatrix m_Matrix; + CFX_DIBitmap* m_pBitmap; +}; +class CRF_PathData : public CRF_Data +{ +public: + CRF_PathData() + { + m_Type = Path; + m_bDecoration = FALSE; + } + ~CRF_PathData() {}; + FX_BOOL m_bDecoration; + CPDF_Path m_pPathData; + CFX_AffineMatrix m_pPath2Device; + CPDF_GraphState m_pGraphState; + FX_ARGB m_fill_argb; + FX_ARGB m_stroke_argb; + int m_fill_mode; +}; +#endif diff --git a/core/src/reflow/reflowedtextpage.cpp b/core/src/reflow/reflowedtextpage.cpp new file mode 100644 index 0000000000..a5ad0be948 --- /dev/null +++ b/core/src/reflow/reflowedtextpage.cpp @@ -0,0 +1,402 @@ +// 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 "reflowedtextpage.h" +IPDF_TextPage* IPDF_TextPage::CreateReflowTextPage(IPDF_ReflowedPage* pRefPage) +{ + return FX_NEW CRF_TextPage(pRefPage); +} +CRF_TextPage::CRF_TextPage(IPDF_ReflowedPage* pRefPage) +{ + m_pRefPage = (CPDF_ReflowedPage*)(pRefPage); + m_pDataList = NULL; + m_CountBSArray = NULL; +} +CRF_TextPage::~CRF_TextPage() +{ + if(m_pDataList) { + delete m_pDataList; + m_pDataList = NULL; + } + if(m_CountBSArray) { + delete m_CountBSArray; + m_CountBSArray = NULL; + } +} +FX_BOOL CRF_TextPage::ParseTextPage() +{ + if(!m_pRefPage) { + return FALSE; + } + int count = m_pRefPage->m_pReflowed->GetSize(); + if(count < 500) { + m_pDataList = FX_NEW CRF_CharDataPtrArray(count); + } else { + m_pDataList = FX_NEW CRF_CharDataPtrArray(500); + } + if (NULL == m_pDataList) { + return FALSE; + } + for(int i = 0; i < count; i++) { + CRF_Data* pData = (*(m_pRefPage->m_pReflowed))[i]; + if(pData->GetType() == CRF_Data::Text) { + m_pDataList->Add((CRF_CharData*)pData); + } + } + m_CountBSArray = FX_NEW CFX_CountBSINT32Array(20); + if(NULL == m_CountBSArray) { + return FALSE; + } + return TRUE; +} +FX_BOOL CRF_TextPage::IsParsered() const +{ + if(m_pDataList) { + return TRUE; + } + return FALSE; +} +int CRF_TextPage::CharIndexFromTextIndex(int TextIndex) const +{ + return TextIndex; +} +int CRF_TextPage::TextIndexFromCharIndex(int CharIndex) const +{ + return CharIndex; +} + +int CRF_TextPage::CountChars() const +{ + if (NULL == m_pDataList) { + return -1; + } + return m_pDataList->GetSize(); +} +void CRF_TextPage::GetCharInfo(int index, FPDF_CHAR_INFO & info) const +{ + if(index >= CountChars() || index < 0 || !m_pDataList) { + return; + } + CRF_CharData* pData = (*m_pDataList)[index]; + FX_FLOAT ReltiveCorddDs = pData->m_pCharState->m_fDescent; + FX_FLOAT ReltiveCorddAs = pData->m_pCharState->m_fAscent; + info.m_Flag = CHAR_NORMAL; + info.m_pTextObj = pData->m_pCharState->m_pTextObj; + info.m_OriginX = pData->m_PosX; + info.m_OriginY = pData->m_PosY - ReltiveCorddDs; + info.m_FontSize = pData->m_pCharState->m_fFontSize; + CFX_FloatRect FloatRectTmp(pData->m_PosX, pData->m_PosY, pData->m_PosX + pData->m_Width, pData->m_PosY + ReltiveCorddAs - ReltiveCorddDs); + info.m_CharBox = FloatRectTmp; + CFX_WideString str = pData->m_pCharState->m_pFont->UnicodeFromCharCode(pData->m_CharCode); + if(!str.IsEmpty()) { + info.m_Unicode = str.GetAt(0); + } else { + info.m_Unicode = -1; + } + info.m_Charcode = (FX_WCHAR)pData->m_CharCode; + info.m_Matrix = CFX_Matrix(1, 0, 0, 1, 0, 0); +} +extern FX_BOOL GetIntersection(FX_FLOAT low1, FX_FLOAT high1, FX_FLOAT low2, FX_FLOAT high2, FX_FLOAT& interlow, FX_FLOAT& interhigh); +inline FX_BOOL _IsInsameline(const CFX_FloatRect& rectA, const CFX_FloatRect& rectB) +{ + if((rectA.top >= rectB.bottom && rectB.top >= rectA.bottom)) { + return TRUE; + } else { + return FALSE; + } +} +inline FX_BOOL _IsIntersect(const CFX_FloatRect& rectA, const CFX_FloatRect& rectB) +{ + FX_FLOAT interlow = .0f, interhigh = .0f; + if(GetIntersection(rectA.bottom, rectA.top, rectB.bottom, rectB.top, interlow, interhigh)) { + if(GetIntersection(rectA.left, rectA.right, rectB.left, rectB.right, interlow, interhigh)) { + return TRUE; + } else { + return FALSE; + } + } + return FALSE; +} +void CRF_TextPage::GetRectArray(int start, int nCount, CFX_RectArray& rectArray) const +{ + int indexlen = start + nCount; + FPDF_CHAR_INFO info; + FX_BOOL bstart = TRUE; + CFX_FloatRect recttmp; + int i; + for(i = start; i < indexlen; i++) { + GetCharInfo(i, info); + if(bstart) { + recttmp = info.m_CharBox; + bstart = FALSE; + } else if(_IsInsameline(recttmp, info.m_CharBox)) { + recttmp.right = info.m_CharBox.right; + if(info.m_CharBox.top > recttmp.top) { + recttmp.top = info.m_CharBox.top; + } + if(info.m_CharBox.bottom < recttmp.bottom) { + recttmp.bottom = info.m_CharBox.bottom; + } + } else { + rectArray.Add(recttmp); + recttmp = info.m_CharBox; + } + } + rectArray.Add(recttmp); +} +inline FX_FLOAT _GetDistance(CFX_FloatRect floatRect, CPDF_Point point) +{ + if(floatRect.right < point.x && floatRect.bottom > point.y) { + return FXSYS_sqrt(FXSYS_pow(point.x - floatRect.right, 2) + FXSYS_pow(floatRect.bottom - point.y, 2)); + } + if (floatRect.right < point.x && floatRect.top < point.y) { + return FXSYS_sqrt(FXSYS_pow(point.x - floatRect.right, 2) + FXSYS_pow(point.y - floatRect.top, 2)); + } + if(floatRect.left > point.x && floatRect.bottom > point.y) { + return FXSYS_sqrt(FXSYS_pow(floatRect.bottom - point.y, 2) + FXSYS_pow(floatRect.left - point.x, 2)); + } + if((floatRect.right > point.x || FXSYS_fabs(floatRect.right - point.x) <= 0.0001f) && + (floatRect.left < point.x || FXSYS_fabs(floatRect.left - point.x) <= 0.0001f) && floatRect.bottom > point.y) { + return FXSYS_fabs(floatRect.bottom - point.y); + } + if(floatRect.left > point.x && (floatRect.bottom < point.y || FXSYS_fabs(floatRect.bottom - point.y) <= 0.0001f) && + (floatRect.top > point.y || FXSYS_fabs(floatRect.top - point.y) <= 0.0001f)) { + return FXSYS_fabs(floatRect.left - point.x); + } + if(floatRect.left > point.x && floatRect.top < point.y) { + return FXSYS_sqrt(FXSYS_pow(floatRect.left - point.x, 2) + FXSYS_pow(point.y - floatRect.top, 2)); + } + if ((floatRect.left < point.x || FXSYS_fabs(floatRect.left - point.x) <= 0.0001f) && + (floatRect.right > point.x || FXSYS_fabs(floatRect.right - point.x) <= 0.0001f) && floatRect.top < point.y) { + return FXSYS_fabs(point.y - floatRect.top); + } + if(floatRect.right < point.x && (floatRect.top > point.y || FXSYS_fabs(floatRect.top - point.y) <= 0.0001f) && + (floatRect.bottom < point.y || FXSYS_fabs(floatRect.bottom - point.y) <= 0.0001f)) { + return point.x - floatRect.right; + } + return .0f; +} +int CRF_TextPage::GetIndexAtPos(CPDF_Point point, FX_FLOAT xTorelance, FX_FLOAT yTorelance) const +{ + int index = -1, i = 0, j = 0; + FPDF_CHAR_INFO info; + CFX_FloatRect rectTmp; + FX_FLOAT MinDistance = 1000, DistanceTmp = 0; + FX_FLOAT rect_bottom = point.x - xTorelance; + CFX_FloatRect TorelanceRect(rect_bottom <= 0 ? 0 : rect_bottom, point.y - yTorelance, point.x + xTorelance, point.y + yTorelance); + int count = CountChars(); + for(i = 0; i < count; i++) { + GetCharInfo(i, info); + rectTmp = info.m_CharBox; + if(rectTmp.Contains(point.x, point.y)) { + index = i; + break; + } else if(_IsIntersect(rectTmp, TorelanceRect)) { + DistanceTmp = _GetDistance(rectTmp, point); + if(DistanceTmp < MinDistance) { + MinDistance = DistanceTmp; + index = i; + } + } + } + return index; +} +int CRF_TextPage::GetIndexAtPos(FX_FLOAT x, FX_FLOAT y, FX_FLOAT xTorelance, FX_FLOAT yTorelance) const +{ + int index = 0; + CPDF_Point point(x, y); + if((index = GetIndexAtPos(point, xTorelance, yTorelance)) < 0) { + return -1; + } else { + return index; + } +} +int CRF_TextPage::GetOrderByDirection(int index, int direction) const +{ + return -1; +} +CFX_WideString CRF_TextPage::GetTextByRect(CFX_FloatRect rect) const +{ + int count; + FPDF_CHAR_INFO info; + CFX_WideString str; + CFX_FloatRect Recttmp; + FX_BOOL bstart = TRUE; + count = CountChars(); + if(rect.IsEmpty()) { + return L""; + } + for(int i = 0; i < count; i++) { + GetCharInfo(i, info); + if(_IsIntersect(rect, info.m_CharBox)) { + if(bstart) { + Recttmp = info.m_CharBox; + str += info.m_Unicode; + bstart = FALSE; + } else if(_IsInsameline(Recttmp, info.m_CharBox)) { + str += info.m_Unicode; + } else { + str += L"\r\n"; + Recttmp = info.m_CharBox; + str += info.m_Unicode; + } + } + } + if(str.IsEmpty()) { + return L""; + } else { + return str; + } +} +void CRF_TextPage::GetRectsArrayByRect(CFX_FloatRect rect, CFX_RectArray& resRectArray) const +{ + int count, i; + FX_BOOL bstart = TRUE; + FPDF_CHAR_INFO info; + CFX_FloatRect recttmp; + count = CountChars(); + for(i = 0; i < count; i++) { + GetCharInfo(i, info); + if(_IsIntersect(rect, info.m_CharBox)) { + if(bstart) { + recttmp = info.m_CharBox; + bstart = FALSE; + } else if(_IsInsameline(recttmp, info.m_CharBox)) { + recttmp.right = info.m_CharBox.right; + if(info.m_CharBox.top > recttmp.top) { + recttmp.top = info.m_CharBox.top; + } + if(info.m_CharBox.bottom < recttmp.bottom) { + recttmp.bottom = info.m_CharBox.bottom; + } + } else { + resRectArray.Add(recttmp); + recttmp = info.m_CharBox; + } + } + } + resRectArray.Add(recttmp); +} +int CRF_TextPage::CountRects(int start, int nCount) +{ + m_rectArray.RemoveAll(); + GetRectArray(start, nCount, m_rectArray); + return m_rectArray.GetSize(); +} +void CRF_TextPage::GetRect(int rectIndex, FX_FLOAT& left, FX_FLOAT& top, FX_FLOAT& right, FX_FLOAT &bottom) const +{ + if(m_rectArray.GetSize() <= rectIndex) { + return; + } + left = m_rectArray[rectIndex].left; + top = m_rectArray[rectIndex].top; + right = m_rectArray[rectIndex].right; + bottom = m_rectArray[rectIndex].bottom; +} +FX_BOOL CRF_TextPage::GetBaselineRotate(int rectIndex, int& Rotate) +{ + Rotate = 0; + return TRUE; +} +FX_BOOL CRF_TextPage::GetBaselineRotate(CFX_FloatRect rect, int& Rotate) +{ + Rotate = 0; + return TRUE; +} +int CRF_TextPage::CountBoundedSegments(FX_FLOAT left, FX_FLOAT top, FX_FLOAT right, FX_FLOAT bottom, FX_BOOL bContains) +{ + if (!m_CountBSArray) { + return -1; + } + m_CountBSArray->RemoveAll(); + CFX_FloatRect floatrect(left, bottom, right, top); + int totalcount, i, j = 0, counttmp = 0; + FX_BOOL bstart = TRUE; + FPDF_CHAR_INFO info; + CFX_FloatRect recttmp; + totalcount = CountChars(); + for(i = 0; i < totalcount; i++) { + GetCharInfo(i, info); + if(_IsIntersect(floatrect, info.m_CharBox)) { + if(bstart) { + m_CountBSArray->Add(i); + counttmp = 1; + recttmp = info.m_CharBox; + bstart = FALSE; + } else if(_IsInsameline(recttmp, info.m_CharBox)) { + recttmp.right = info.m_CharBox.right; + if(info.m_CharBox.top > recttmp.top) { + recttmp.top = info.m_CharBox.top; + } + if(info.m_CharBox.bottom < recttmp.bottom) { + recttmp.bottom = info.m_CharBox.bottom; + } + counttmp ++; + } else { + m_CountBSArray->Add(counttmp); + m_CountBSArray->Add(i); + counttmp = 1; + j++; + recttmp = info.m_CharBox; + } + } + } + m_CountBSArray->Add(counttmp); + j++; + return j; +} +void CRF_TextPage::GetBoundedSegment(int index, int& start, int& count) const +{ + if (!m_CountBSArray) { + return; + } + if(m_CountBSArray->GetSize() <= index * 2) { + start = 0; + count = 0; + return; + } + start = *(int *)m_CountBSArray->GetAt(index * 2); + count = *(int *)m_CountBSArray->GetAt(index * 2 + 1); +} + +int CRF_TextPage::GetWordBreak(int index, int direction) const +{ + return -1; +} +CFX_WideString CRF_TextPage::GetPageText(int start, int nCount ) const +{ + if(nCount == -1) { + nCount = CountChars(); + start = 0; + } else if(nCount < 1) { + return L""; + } else if(start >= CountChars()) { + return L""; + } + int i, index = start + nCount; + FPDF_CHAR_INFO info; + CFX_WideString str; + CFX_FloatRect recttmp; + FX_BOOL bstart = TRUE; + for(i = start; i < index; i++) { + GetCharInfo(i, info); + if(bstart) { + recttmp = info.m_CharBox; + str += info.m_Unicode; + bstart = FALSE; + } else if (_IsInsameline(recttmp, info.m_CharBox)) { + str += info.m_Unicode; + } else { + str += L"\r\n"; + recttmp = info.m_CharBox; + str += info.m_Unicode; + } + } + if(str.IsEmpty()) { + return L""; + } + return str; +} diff --git a/core/src/reflow/reflowedtextpage.h b/core/src/reflow/reflowedtextpage.h new file mode 100644 index 0000000000..397428d178 --- /dev/null +++ b/core/src/reflow/reflowedtextpage.h @@ -0,0 +1,71 @@ +// 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 + +#ifndef _REFLOWED_TEXT_PAGE_H +#define _REFLOWED_TEXT_PAGE_H +#include "../../include/reflow/reflowengine.h" +#include "../../src/reflow/reflowedpage.h" +typedef CFX_SegmentedArray<CRF_CharData*> CRF_CharDataPtrArray; +typedef CFX_SegmentedArray<FX_INT32> CFX_CountBSINT32Array; +class CRF_TextPage : public IPDF_TextPage +{ +public: + CRF_TextPage(IPDF_ReflowedPage* pRefPage); + + virtual ~CRF_TextPage() ; + FX_BOOL ParseTextPage(); + void NormalizeObjects(FX_BOOL bNormalize) + { + return; + }; + + FX_BOOL IsParsered() const; +public: + + int CharIndexFromTextIndex(int TextIndex) const; + + int TextIndexFromCharIndex(int CharIndex) const; + + + int CountChars() const; + + virtual void GetCharInfo(int index, FPDF_CHAR_INFO & info) const; + + void GetRectArray(int start, int nCount, CFX_RectArray& rectArray) const; + + + int GetIndexAtPos(CPDF_Point point, FX_FLOAT xTorelance, FX_FLOAT yTorelance) const; + + int GetIndexAtPos(FX_FLOAT x, FX_FLOAT y, FX_FLOAT xTorelance, FX_FLOAT yTorelance) const; + + virtual int GetOrderByDirection(int index, int direction) const; + + CFX_WideString GetTextByRect(CFX_FloatRect rect) const; + + void GetRectsArrayByRect(CFX_FloatRect rect, CFX_RectArray& resRectArray) const; + + + int CountRects(int start, int nCount); + + virtual void GetRect(int rectIndex, FX_FLOAT& left, FX_FLOAT& top, FX_FLOAT& right, FX_FLOAT &bottom) const; + virtual FX_BOOL GetBaselineRotate(int rectIndex, int& Rotate); + virtual FX_BOOL GetBaselineRotate(CFX_FloatRect rect, int& Rotate); + + virtual int CountBoundedSegments(FX_FLOAT left, FX_FLOAT top, FX_FLOAT right, FX_FLOAT bottom, FX_BOOL bContains = FALSE); + + virtual void GetBoundedSegment(int index, int& start, int& count) const; + + + int GetWordBreak(int index, int direction) const; + + CFX_WideString GetPageText(int start, int nCount = -1 ) const; +private: + CPDF_ReflowedPage* m_pRefPage; + CRF_CharDataPtrArray* m_pDataList; + CFX_RectArray m_rectArray; + CFX_CountBSINT32Array* m_CountBSArray; +}; +#endif diff --git a/core/src/reflow/reflowengine.cpp b/core/src/reflow/reflowengine.cpp new file mode 100644 index 0000000000..11007c904b --- /dev/null +++ b/core/src/reflow/reflowengine.cpp @@ -0,0 +1,38 @@ +// 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 "../../include/reflow/reflowengine.h" +#include "reflowedpage.h" +IPDF_ReflowedPage* IPDF_ReflowedPage::Create() +{ + CPDF_ReflowedPage* pRefPage = FX_NEW CPDF_ReflowedPage(NULL); + return pRefPage; +} +IPDF_ReflowedPage* Create_ReflowPage() +{ + return IPDF_ReflowedPage::Create(); +} +IPDF_ProgressiveReflowPageParser* Create_ReflowPageParser() +{ + return IPDF_ProgressiveReflowPageParser::Create(); +} +IPDF_ProgressiveReflowPageParser* IPDF_ProgressiveReflowPageParser::Create() +{ + CPDF_ProgressiveReflowPageParser* pParser = FX_NEW CPDF_ProgressiveReflowPageParser; + if (NULL == pParser) { + return NULL; + } + pParser->Init(); + return pParser; +} +IPDF_ProgressiveReflowPageRender* Create_ReflowPageRender() +{ + return IPDF_ProgressiveReflowPageRender::Create(); +} +IPDF_ProgressiveReflowPageRender* IPDF_ProgressiveReflowPageRender::Create() +{ + return FX_NEW CPDF_ProgressiveReflowPageRender; +} |