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