Fix warnings in android build, fix font rendering issue, fix issue 357588: wrong...
[pdfium.git] / core / src / reflow / reflowedtextpage.cpp
1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4  
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "reflowedtextpage.h"
8 IPDF_TextPage*  IPDF_TextPage::CreateReflowTextPage(IPDF_ReflowedPage* pRefPage)
9 {
10     return FX_NEW CRF_TextPage(pRefPage);
11 }
12 CRF_TextPage::CRF_TextPage(IPDF_ReflowedPage* pRefPage)
13 {
14     m_pRefPage = (CPDF_ReflowedPage*)(pRefPage);
15     m_pDataList = NULL;
16     m_CountBSArray = NULL;
17 }
18 CRF_TextPage::~CRF_TextPage()
19 {
20     if(m_pDataList) {
21         delete m_pDataList;
22         m_pDataList = NULL;
23     }
24     if(m_CountBSArray) {
25         delete m_CountBSArray;
26         m_CountBSArray = NULL;
27     }
28 }
29 FX_BOOL CRF_TextPage::ParseTextPage()
30 {
31     if(!m_pRefPage) {
32         return FALSE;
33     }
34     int count = m_pRefPage->m_pReflowed->GetSize();
35     if(count < 500) {
36         m_pDataList = FX_NEW CRF_CharDataPtrArray(count);
37     } else {
38         m_pDataList = FX_NEW CRF_CharDataPtrArray(500);
39     }
40     if (NULL == m_pDataList) {
41         return FALSE;
42     }
43     for(int i = 0; i < count; i++) {
44         CRF_Data* pData = (*(m_pRefPage->m_pReflowed))[i];
45         if(pData->GetType() == CRF_Data::Text) {
46             m_pDataList->Add((CRF_CharData*)pData);
47         }
48     }
49     m_CountBSArray = FX_NEW CFX_CountBSINT32Array(20);
50     if(NULL == m_CountBSArray) {
51         return FALSE;
52     }
53     return TRUE;
54 }
55 FX_BOOL CRF_TextPage::IsParsered() const
56 {
57     if(m_pDataList) {
58         return TRUE;
59     }
60     return FALSE;
61 }
62 int CRF_TextPage::CharIndexFromTextIndex(int TextIndex) const
63 {
64     return TextIndex;
65 }
66 int CRF_TextPage::TextIndexFromCharIndex(int CharIndex) const
67 {
68     return CharIndex;
69 }
70
71 int     CRF_TextPage::CountChars() const
72 {
73     if (NULL == m_pDataList) {
74         return -1;
75     }
76     return m_pDataList->GetSize();
77 }
78 void CRF_TextPage::GetCharInfo(int index, FPDF_CHAR_INFO & info) const
79 {
80     if(index >= CountChars() || index < 0 || !m_pDataList) {
81         return;
82     }
83     CRF_CharData* pData = (*m_pDataList)[index];
84     FX_FLOAT ReltiveCorddDs = pData->m_pCharState->m_fDescent;
85     FX_FLOAT ReltiveCorddAs = pData->m_pCharState->m_fAscent;
86     info.m_Flag         = CHAR_NORMAL;
87     info.m_pTextObj     = pData->m_pCharState->m_pTextObj;
88     info.m_OriginX      = pData->m_PosX;
89     info.m_OriginY      = pData->m_PosY - ReltiveCorddDs;
90     info.m_FontSize     = pData->m_pCharState->m_fFontSize;
91     CFX_FloatRect FloatRectTmp(pData->m_PosX, pData->m_PosY, pData->m_PosX + pData->m_Width, pData->m_PosY + ReltiveCorddAs - ReltiveCorddDs);
92     info.m_CharBox      = FloatRectTmp;
93     CFX_WideString str = pData->m_pCharState->m_pFont->UnicodeFromCharCode(pData->m_CharCode);
94     if(!str.IsEmpty()) {
95         info.m_Unicode  = str.GetAt(0);
96     } else {
97         info.m_Unicode = -1;
98     }
99     info.m_Charcode = (FX_WCHAR)pData->m_CharCode;
100     info.m_Matrix = CFX_Matrix(1, 0, 0, 1, 0, 0);
101 }
102 extern FX_BOOL GetIntersection(FX_FLOAT low1, FX_FLOAT high1, FX_FLOAT low2, FX_FLOAT high2, FX_FLOAT& interlow, FX_FLOAT& interhigh);
103 inline FX_BOOL _IsInsameline(const CFX_FloatRect& rectA, const CFX_FloatRect& rectB)
104 {
105     if((rectA.top >= rectB.bottom && rectB.top >= rectA.bottom)) {
106         return TRUE;
107     } else {
108         return FALSE;
109     }
110 }
111 inline FX_BOOL _IsIntersect(const CFX_FloatRect& rectA, const CFX_FloatRect& rectB)
112 {
113     FX_FLOAT interlow = .0f, interhigh = .0f;
114     if(GetIntersection(rectA.bottom, rectA.top, rectB.bottom, rectB.top, interlow, interhigh)) {
115         if(GetIntersection(rectA.left, rectA.right, rectB.left, rectB.right, interlow, interhigh)) {
116             return TRUE;
117         } else {
118             return FALSE;
119         }
120     }
121     return FALSE;
122 }
123 void CRF_TextPage::GetRectArray(int start, int nCount, CFX_RectArray& rectArray) const
124 {
125     int indexlen = start + nCount;
126     FPDF_CHAR_INFO info;
127     FX_BOOL bstart = TRUE;
128     CFX_FloatRect recttmp;
129     int i;
130     for(i = start; i < indexlen; i++) {
131         GetCharInfo(i, info);
132         if(bstart) {
133             recttmp = info.m_CharBox;
134             bstart = FALSE;
135         } else if(_IsInsameline(recttmp, info.m_CharBox)) {
136             recttmp.right = info.m_CharBox.right;
137             if(info.m_CharBox.top > recttmp.top) {
138                 recttmp.top = info.m_CharBox.top;
139             }
140             if(info.m_CharBox.bottom < recttmp.bottom) {
141                 recttmp.bottom = info.m_CharBox.bottom;
142             }
143         } else {
144             rectArray.Add(recttmp);
145             recttmp = info.m_CharBox;
146         }
147     }
148     rectArray.Add(recttmp);
149 }
150 inline FX_FLOAT _GetDistance(CFX_FloatRect floatRect, CPDF_Point point)
151 {
152     if(floatRect.right < point.x && floatRect.bottom > point.y) {
153         return FXSYS_sqrt(FXSYS_pow(point.x - floatRect.right, 2) + FXSYS_pow(floatRect.bottom - point.y, 2));
154     }
155     if (floatRect.right < point.x && floatRect.top < point.y) {
156         return FXSYS_sqrt(FXSYS_pow(point.x - floatRect.right, 2) + FXSYS_pow(point.y - floatRect.top, 2));
157     }
158     if(floatRect.left > point.x && floatRect.bottom > point.y) {
159         return FXSYS_sqrt(FXSYS_pow(floatRect.bottom - point.y, 2) + FXSYS_pow(floatRect.left - point.x, 2));
160     }
161     if((floatRect.right > point.x || FXSYS_fabs(floatRect.right - point.x) <= 0.0001f) &&
162             (floatRect.left < point.x || FXSYS_fabs(floatRect.left - point.x) <= 0.0001f) && floatRect.bottom > point.y) {
163         return FXSYS_fabs(floatRect.bottom - point.y);
164     }
165     if(floatRect.left > point.x && (floatRect.bottom < point.y || FXSYS_fabs(floatRect.bottom - point.y) <= 0.0001f) &&
166             (floatRect.top > point.y || FXSYS_fabs(floatRect.top - point.y) <= 0.0001f)) {
167         return FXSYS_fabs(floatRect.left - point.x);
168     }
169     if(floatRect.left > point.x && floatRect.top < point.y) {
170         return FXSYS_sqrt(FXSYS_pow(floatRect.left - point.x, 2) + FXSYS_pow(point.y - floatRect.top, 2));
171     }
172     if ((floatRect.left < point.x || FXSYS_fabs(floatRect.left - point.x) <= 0.0001f) &&
173             (floatRect.right > point.x || FXSYS_fabs(floatRect.right - point.x) <= 0.0001f) && floatRect.top < point.y) {
174         return FXSYS_fabs(point.y - floatRect.top);
175     }
176     if(floatRect.right < point.x && (floatRect.top > point.y || FXSYS_fabs(floatRect.top - point.y) <= 0.0001f) &&
177             (floatRect.bottom < point.y || FXSYS_fabs(floatRect.bottom - point.y) <= 0.0001f)) {
178         return point.x - floatRect.right;
179     }
180     return .0f;
181 }
182 int CRF_TextPage::GetIndexAtPos(CPDF_Point point, FX_FLOAT xTorelance, FX_FLOAT yTorelance) const
183 {
184     int index = -1, i = 0, j = 0;
185     FPDF_CHAR_INFO info;
186     CFX_FloatRect rectTmp;
187     FX_FLOAT MinDistance = 1000, DistanceTmp = 0;
188     FX_FLOAT rect_bottom = point.x - xTorelance;
189     CFX_FloatRect TorelanceRect(rect_bottom <= 0 ? 0 : rect_bottom, point.y - yTorelance, point.x + xTorelance, point.y + yTorelance);
190     int count = CountChars();
191     for(i = 0; i < count; i++) {
192         GetCharInfo(i, info);
193         rectTmp = info.m_CharBox;
194         if(rectTmp.Contains(point.x, point.y)) {
195             index = i;
196             break;
197         } else if(_IsIntersect(rectTmp, TorelanceRect)) {
198             DistanceTmp = _GetDistance(rectTmp, point);
199             if(DistanceTmp < MinDistance) {
200                 MinDistance = DistanceTmp;
201                 index = i;
202             }
203         }
204     }
205     return index;
206 }
207 int CRF_TextPage::GetIndexAtPos(FX_FLOAT x, FX_FLOAT y, FX_FLOAT xTorelance, FX_FLOAT yTorelance) const
208 {
209     int index = 0;
210     CPDF_Point point(x, y);
211     if((index = GetIndexAtPos(point, xTorelance, yTorelance)) < 0) {
212         return -1;
213     } else {
214         return index;
215     }
216 }
217 int CRF_TextPage::GetOrderByDirection(int index, int direction) const
218 {
219     return -1;
220 }
221 CFX_WideString CRF_TextPage::GetTextByRect(CFX_FloatRect rect) const
222 {
223     int count;
224     FPDF_CHAR_INFO info;
225     CFX_WideString str;
226     CFX_FloatRect  Recttmp;
227     FX_BOOL bstart = TRUE;
228     count = CountChars();
229     if(rect.IsEmpty()) {
230         return L"";
231     }
232     for(int i = 0; i < count; i++) {
233         GetCharInfo(i, info);
234         if(_IsIntersect(rect, info.m_CharBox)) {
235             if(bstart) {
236                 Recttmp = info.m_CharBox;
237                 str += info.m_Unicode;
238                 bstart = FALSE;
239             } else if(_IsInsameline(Recttmp, info.m_CharBox)) {
240                 str += info.m_Unicode;
241             } else {
242                 str += L"\r\n";
243                 Recttmp = info.m_CharBox;
244                 str += info.m_Unicode;
245             }
246         }
247     }
248     if(str.IsEmpty()) {
249         return L"";
250     } else {
251         return str;
252     }
253 }
254 void CRF_TextPage::GetRectsArrayByRect(CFX_FloatRect rect, CFX_RectArray& resRectArray) const
255 {
256     int count, i;
257     FX_BOOL bstart = TRUE;
258     FPDF_CHAR_INFO info;
259     CFX_FloatRect recttmp;
260     count = CountChars();
261     for(i = 0; i < count; i++) {
262         GetCharInfo(i, info);
263         if(_IsIntersect(rect, info.m_CharBox)) {
264             if(bstart) {
265                 recttmp = info.m_CharBox;
266                 bstart = FALSE;
267             } else if(_IsInsameline(recttmp, info.m_CharBox)) {
268                 recttmp.right = info.m_CharBox.right;
269                 if(info.m_CharBox.top > recttmp.top) {
270                     recttmp.top = info.m_CharBox.top;
271                 }
272                 if(info.m_CharBox.bottom < recttmp.bottom) {
273                     recttmp.bottom = info.m_CharBox.bottom;
274                 }
275             } else {
276                 resRectArray.Add(recttmp);
277                 recttmp = info.m_CharBox;
278             }
279         }
280     }
281     resRectArray.Add(recttmp);
282 }
283 int CRF_TextPage::CountRects(int start, int nCount)
284 {
285     m_rectArray.RemoveAll();
286     GetRectArray(start, nCount, m_rectArray);
287     return m_rectArray.GetSize();
288 }
289 void CRF_TextPage::GetRect(int rectIndex, FX_FLOAT& left, FX_FLOAT& top, FX_FLOAT& right, FX_FLOAT &bottom) const
290 {
291     if(m_rectArray.GetSize() <= rectIndex) {
292         return;
293     }
294     left   = m_rectArray[rectIndex].left;
295     top    = m_rectArray[rectIndex].top;
296     right  = m_rectArray[rectIndex].right;
297     bottom = m_rectArray[rectIndex].bottom;
298 }
299 FX_BOOL CRF_TextPage::GetBaselineRotate(int rectIndex, int& Rotate)
300 {
301     Rotate = 0;
302     return TRUE;
303 }
304 FX_BOOL CRF_TextPage::GetBaselineRotate(CFX_FloatRect rect, int& Rotate)
305 {
306     Rotate = 0;
307     return TRUE;
308 }
309 int CRF_TextPage::CountBoundedSegments(FX_FLOAT left, FX_FLOAT top, FX_FLOAT right, FX_FLOAT bottom, FX_BOOL bContains)
310 {
311     if (!m_CountBSArray) {
312         return -1;
313     }
314     m_CountBSArray->RemoveAll();
315     CFX_FloatRect floatrect(left, bottom, right, top);
316     int totalcount, i, j = 0, counttmp = 0;
317     FX_BOOL bstart = TRUE;
318     FPDF_CHAR_INFO info;
319     CFX_FloatRect recttmp;
320     totalcount = CountChars();
321     for(i = 0; i < totalcount; i++) {
322         GetCharInfo(i, info);
323         if(_IsIntersect(floatrect, info.m_CharBox)) {
324             if(bstart) {
325                 m_CountBSArray->Add(i);
326                 counttmp = 1;
327                 recttmp = info.m_CharBox;
328                 bstart = FALSE;
329             } else if(_IsInsameline(recttmp, info.m_CharBox)) {
330                 recttmp.right = info.m_CharBox.right;
331                 if(info.m_CharBox.top > recttmp.top) {
332                     recttmp.top = info.m_CharBox.top;
333                 }
334                 if(info.m_CharBox.bottom < recttmp.bottom) {
335                     recttmp.bottom = info.m_CharBox.bottom;
336                 }
337                 counttmp ++;
338             } else {
339                 m_CountBSArray->Add(counttmp);
340                 m_CountBSArray->Add(i);
341                 counttmp = 1;
342                 j++;
343                 recttmp = info.m_CharBox;
344             }
345         }
346     }
347     m_CountBSArray->Add(counttmp);
348     j++;
349     return j;
350 }
351 void CRF_TextPage::GetBoundedSegment(int index, int& start, int& count) const
352 {
353     if (!m_CountBSArray) {
354         return;
355     }
356     if(m_CountBSArray->GetSize() <= index * 2) {
357         start = 0;
358         count = 0;
359         return;
360     }
361     start = *(int *)m_CountBSArray->GetAt(index * 2);
362     count = *(int *)m_CountBSArray->GetAt(index * 2 + 1);
363 }
364
365 int CRF_TextPage::GetWordBreak(int index, int direction) const
366 {
367     return -1;
368 }
369 CFX_WideString CRF_TextPage::GetPageText(int start, int nCount ) const
370 {
371     if(nCount == -1) {
372         nCount = CountChars();
373         start = 0;
374     } else if(nCount < 1) {
375         return L"";
376     } else if(start >= CountChars()) {
377         return L"";
378     }
379     int i, index = start + nCount;
380     FPDF_CHAR_INFO info;
381     CFX_WideString str;
382     CFX_FloatRect recttmp;
383     FX_BOOL bstart = TRUE;
384     for(i = start; i < index; i++) {
385         GetCharInfo(i, info);
386         if(bstart) {
387             recttmp = info.m_CharBox;
388             str += info.m_Unicode;
389             bstart = FALSE;
390         } else if (_IsInsameline(recttmp, info.m_CharBox)) {
391             str += info.m_Unicode;
392         } else {
393             str += L"\r\n";
394             recttmp = info.m_CharBox;
395             str += info.m_Unicode;
396         }
397     }
398     if(str.IsEmpty()) {
399         return L"";
400     }
401     return str;
402 }