| // 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; | |
| } |