// 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 <algorithm> #include "reflowedtextpage.h" IPDF_TextPage* IPDF_TextPage::CreateReflowTextPage(IPDF_ReflowedPage* pRefPage) { return 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(); m_pDataList = new CRF_CharDataPtrArray(std::min(count, 500)); 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 = new CFX_CountBSINT32Array(20); 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; }