1 // Copyright 2014 The PDFium Authors
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 "public/fpdf_text.h"
8
9 #include <algorithm>
10 #include <memory>
11 #include <vector>
12
13 #include "build/build_config.h"
14 #include "core/fpdfapi/font/cpdf_font.h"
15 #include "core/fpdfapi/page/cpdf_page.h"
16 #include "core/fpdfapi/page/cpdf_textobject.h"
17 #include "core/fpdfdoc/cpdf_viewerpreferences.h"
18 #include "core/fpdftext/cpdf_linkextract.h"
19 #include "core/fpdftext/cpdf_textpage.h"
20 #include "core/fpdftext/cpdf_textpagefind.h"
21 #include "core/fxcrt/stl_util.h"
22 #include "fpdfsdk/cpdfsdk_helpers.h"
23 #include "third_party/base/check_op.h"
24 #include "third_party/base/numerics/safe_conversions.h"
25
26 namespace {
27
28 constexpr size_t kBytesPerCharacter = sizeof(unsigned short);
29
GetTextPageForValidIndex(FPDF_TEXTPAGE text_page,int index)30 CPDF_TextPage* GetTextPageForValidIndex(FPDF_TEXTPAGE text_page, int index) {
31 if (!text_page || index < 0)
32 return nullptr;
33
34 CPDF_TextPage* textpage = CPDFTextPageFromFPDFTextPage(text_page);
35 return static_cast<size_t>(index) < textpage->size() ? textpage : nullptr;
36 }
37
38 } // namespace
39
FPDFText_LoadPage(FPDF_PAGE page)40 FPDF_EXPORT FPDF_TEXTPAGE FPDF_CALLCONV FPDFText_LoadPage(FPDF_PAGE page) {
41 CPDF_Page* pPDFPage = CPDFPageFromFPDFPage(page);
42 if (!pPDFPage)
43 return nullptr;
44
45 CPDF_ViewerPreferences viewRef(pPDFPage->GetDocument());
46 auto textpage =
47 std::make_unique<CPDF_TextPage>(pPDFPage, viewRef.IsDirectionR2L());
48
49 // Caller takes ownership.
50 return FPDFTextPageFromCPDFTextPage(textpage.release());
51 }
52
FPDFText_ClosePage(FPDF_TEXTPAGE text_page)53 FPDF_EXPORT void FPDF_CALLCONV FPDFText_ClosePage(FPDF_TEXTPAGE text_page) {
54 // PDFium takes ownership.
55 std::unique_ptr<CPDF_TextPage> textpage_deleter(
56 CPDFTextPageFromFPDFTextPage(text_page));
57 }
58
FPDFText_CountChars(FPDF_TEXTPAGE text_page)59 FPDF_EXPORT int FPDF_CALLCONV FPDFText_CountChars(FPDF_TEXTPAGE text_page) {
60 CPDF_TextPage* textpage = CPDFTextPageFromFPDFTextPage(text_page);
61 return textpage ? textpage->CountChars() : -1;
62 }
63
64 FPDF_EXPORT unsigned int FPDF_CALLCONV
FPDFText_GetUnicode(FPDF_TEXTPAGE text_page,int index)65 FPDFText_GetUnicode(FPDF_TEXTPAGE text_page, int index) {
66 CPDF_TextPage* textpage = GetTextPageForValidIndex(text_page, index);
67 if (!textpage)
68 return 0;
69
70 const CPDF_TextPage::CharInfo& charinfo = textpage->GetCharInfo(index);
71 return charinfo.m_Unicode;
72 }
73
FPDFText_IsGenerated(FPDF_TEXTPAGE text_page,int index)74 FPDF_EXPORT int FPDF_CALLCONV FPDFText_IsGenerated(FPDF_TEXTPAGE text_page,
75 int index) {
76 CPDF_TextPage* textpage = GetTextPageForValidIndex(text_page, index);
77 if (!textpage)
78 return -1;
79
80 const CPDF_TextPage::CharInfo& charinfo = textpage->GetCharInfo(index);
81 return charinfo.m_CharType == CPDF_TextPage::CharType::kGenerated ? 1 : 0;
82 }
83
84 FPDF_EXPORT int FPDF_CALLCONV
FPDFText_HasUnicodeMapError(FPDF_TEXTPAGE text_page,int index)85 FPDFText_HasUnicodeMapError(FPDF_TEXTPAGE text_page, int index) {
86 CPDF_TextPage* textpage = GetTextPageForValidIndex(text_page, index);
87 if (!textpage)
88 return -1;
89
90 const CPDF_TextPage::CharInfo& charinfo = textpage->GetCharInfo(index);
91 return charinfo.m_CharType == CPDF_TextPage::CharType::kNotUnicode;
92 }
93
FPDFText_GetFontSize(FPDF_TEXTPAGE text_page,int index)94 FPDF_EXPORT double FPDF_CALLCONV FPDFText_GetFontSize(FPDF_TEXTPAGE text_page,
95 int index) {
96 CPDF_TextPage* textpage = GetTextPageForValidIndex(text_page, index);
97 if (!textpage)
98 return 0;
99
100 return textpage->GetCharFontSize(index);
101 }
102
103 FPDF_EXPORT unsigned long FPDF_CALLCONV
FPDFText_GetFontInfo(FPDF_TEXTPAGE text_page,int index,void * buffer,unsigned long buflen,int * flags)104 FPDFText_GetFontInfo(FPDF_TEXTPAGE text_page,
105 int index,
106 void* buffer,
107 unsigned long buflen,
108 int* flags) {
109 CPDF_TextPage* textpage = GetTextPageForValidIndex(text_page, index);
110 if (!textpage)
111 return 0;
112
113 const CPDF_TextPage::CharInfo& charinfo = textpage->GetCharInfo(index);
114 if (!charinfo.m_pTextObj)
115 return 0;
116
117 RetainPtr<CPDF_Font> font = charinfo.m_pTextObj->GetFont();
118 if (flags)
119 *flags = font->GetFontFlags();
120
121 ByteString basefont = font->GetBaseFontName();
122 const unsigned long length =
123 pdfium::base::checked_cast<unsigned long>(basefont.GetLength() + 1);
124 if (buffer && buflen >= length)
125 memcpy(buffer, basefont.c_str(), length);
126
127 return length;
128 }
129
FPDFText_GetFontWeight(FPDF_TEXTPAGE text_page,int index)130 FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetFontWeight(FPDF_TEXTPAGE text_page,
131 int index) {
132 CPDF_TextPage* textpage = GetTextPageForValidIndex(text_page, index);
133 if (!textpage)
134 return -1;
135
136 const CPDF_TextPage::CharInfo& charinfo = textpage->GetCharInfo(index);
137 if (!charinfo.m_pTextObj)
138 return -1;
139
140 return charinfo.m_pTextObj->GetFont()->GetFontWeight();
141 }
142
143 FPDF_EXPORT FPDF_TEXT_RENDERMODE FPDF_CALLCONV
FPDFText_GetTextRenderMode(FPDF_TEXTPAGE text_page,int index)144 FPDFText_GetTextRenderMode(FPDF_TEXTPAGE text_page, int index) {
145 CPDF_TextPage* textpage = GetTextPageForValidIndex(text_page, index);
146 if (!textpage)
147 return FPDF_TEXTRENDERMODE_UNKNOWN;
148
149 const CPDF_TextPage::CharInfo& charinfo = textpage->GetCharInfo(index);
150 if (!charinfo.m_pTextObj)
151 return FPDF_TEXTRENDERMODE_UNKNOWN;
152
153 return static_cast<FPDF_TEXT_RENDERMODE>(
154 charinfo.m_pTextObj->GetTextRenderMode());
155 }
156
157 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFText_GetFillColor(FPDF_TEXTPAGE text_page,int index,unsigned int * R,unsigned int * G,unsigned int * B,unsigned int * A)158 FPDFText_GetFillColor(FPDF_TEXTPAGE text_page,
159 int index,
160 unsigned int* R,
161 unsigned int* G,
162 unsigned int* B,
163 unsigned int* A) {
164 CPDF_TextPage* textpage = GetTextPageForValidIndex(text_page, index);
165 if (!textpage || !R || !G || !B || !A)
166 return false;
167
168 const CPDF_TextPage::CharInfo& charinfo = textpage->GetCharInfo(index);
169 if (!charinfo.m_pTextObj)
170 return false;
171
172 FX_COLORREF fill_color = charinfo.m_pTextObj->m_ColorState.GetFillColorRef();
173 *R = FXSYS_GetRValue(fill_color);
174 *G = FXSYS_GetGValue(fill_color);
175 *B = FXSYS_GetBValue(fill_color);
176 *A = FXSYS_GetUnsignedAlpha(
177 charinfo.m_pTextObj->m_GeneralState.GetFillAlpha());
178 return true;
179 }
180
181 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFText_GetStrokeColor(FPDF_TEXTPAGE text_page,int index,unsigned int * R,unsigned int * G,unsigned int * B,unsigned int * A)182 FPDFText_GetStrokeColor(FPDF_TEXTPAGE text_page,
183 int index,
184 unsigned int* R,
185 unsigned int* G,
186 unsigned int* B,
187 unsigned int* A) {
188 CPDF_TextPage* textpage = GetTextPageForValidIndex(text_page, index);
189 if (!textpage || !R || !G || !B || !A)
190 return false;
191
192 const CPDF_TextPage::CharInfo& charinfo = textpage->GetCharInfo(index);
193 if (!charinfo.m_pTextObj)
194 return false;
195
196 FX_COLORREF stroke_color =
197 charinfo.m_pTextObj->m_ColorState.GetStrokeColorRef();
198 *R = FXSYS_GetRValue(stroke_color);
199 *G = FXSYS_GetGValue(stroke_color);
200 *B = FXSYS_GetBValue(stroke_color);
201 *A = FXSYS_GetUnsignedAlpha(
202 charinfo.m_pTextObj->m_GeneralState.GetStrokeAlpha());
203 return true;
204 }
205
FPDFText_GetCharAngle(FPDF_TEXTPAGE text_page,int index)206 FPDF_EXPORT float FPDF_CALLCONV FPDFText_GetCharAngle(FPDF_TEXTPAGE text_page,
207 int index) {
208 CPDF_TextPage* textpage = GetTextPageForValidIndex(text_page, index);
209 if (!textpage)
210 return -1.0f;
211
212 const CPDF_TextPage::CharInfo& charinfo = textpage->GetCharInfo(index);
213 // On the left is our current Matrix and on the right a generic rotation
214 // matrix for our coordinate space.
215 // | a b 0 | | cos(t) -sin(t) 0 |
216 // | c d 0 | | sin(t) cos(t) 0 |
217 // | e f 1 | | 0 0 1 |
218 // Calculate the angle of the vector
219 float angle = atan2f(charinfo.m_Matrix.c, charinfo.m_Matrix.a);
220 if (angle < 0)
221 angle = 2 * FXSYS_PI + angle;
222
223 return angle;
224 }
225
FPDFText_GetCharBox(FPDF_TEXTPAGE text_page,int index,double * left,double * right,double * bottom,double * top)226 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetCharBox(FPDF_TEXTPAGE text_page,
227 int index,
228 double* left,
229 double* right,
230 double* bottom,
231 double* top) {
232 if (!left || !right || !bottom || !top)
233 return false;
234
235 CPDF_TextPage* textpage = GetTextPageForValidIndex(text_page, index);
236 if (!textpage)
237 return false;
238
239 const CPDF_TextPage::CharInfo& charinfo = textpage->GetCharInfo(index);
240 *left = charinfo.m_CharBox.left;
241 *right = charinfo.m_CharBox.right;
242 *bottom = charinfo.m_CharBox.bottom;
243 *top = charinfo.m_CharBox.top;
244 return true;
245 }
246
247 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFText_GetLooseCharBox(FPDF_TEXTPAGE text_page,int index,FS_RECTF * rect)248 FPDFText_GetLooseCharBox(FPDF_TEXTPAGE text_page, int index, FS_RECTF* rect) {
249 if (!rect)
250 return false;
251
252 CPDF_TextPage* textpage = GetTextPageForValidIndex(text_page, index);
253 if (!textpage)
254 return false;
255
256 *rect = FSRectFFromCFXFloatRect(textpage->GetCharLooseBounds(index));
257 return true;
258 }
259
FPDFText_GetMatrix(FPDF_TEXTPAGE text_page,int index,FS_MATRIX * matrix)260 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetMatrix(FPDF_TEXTPAGE text_page,
261 int index,
262 FS_MATRIX* matrix) {
263 if (!matrix)
264 return false;
265
266 CPDF_TextPage* textpage = GetTextPageForValidIndex(text_page, index);
267 if (!textpage)
268 return false;
269
270 const CPDF_TextPage::CharInfo& charinfo = textpage->GetCharInfo(index);
271 *matrix = FSMatrixFromCFXMatrix(charinfo.m_Matrix);
272 return true;
273 }
274
275 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFText_GetCharOrigin(FPDF_TEXTPAGE text_page,int index,double * x,double * y)276 FPDFText_GetCharOrigin(FPDF_TEXTPAGE text_page,
277 int index,
278 double* x,
279 double* y) {
280 CPDF_TextPage* textpage = GetTextPageForValidIndex(text_page, index);
281 if (!textpage)
282 return false;
283
284 const CPDF_TextPage::CharInfo& charinfo = textpage->GetCharInfo(index);
285 *x = charinfo.m_Origin.x;
286 *y = charinfo.m_Origin.y;
287 return true;
288 }
289
290 FPDF_EXPORT int FPDF_CALLCONV
FPDFText_GetCharIndexAtPos(FPDF_TEXTPAGE text_page,double x,double y,double xTolerance,double yTolerance)291 FPDFText_GetCharIndexAtPos(FPDF_TEXTPAGE text_page,
292 double x,
293 double y,
294 double xTolerance,
295 double yTolerance) {
296 CPDF_TextPage* textpage = CPDFTextPageFromFPDFTextPage(text_page);
297 if (!textpage)
298 return -3;
299
300 return textpage->GetIndexAtPos(
301 CFX_PointF(static_cast<float>(x), static_cast<float>(y)),
302 CFX_SizeF(static_cast<float>(xTolerance),
303 static_cast<float>(yTolerance)));
304 }
305
FPDFText_GetText(FPDF_TEXTPAGE page,int start_index,int char_count,unsigned short * result)306 FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetText(FPDF_TEXTPAGE page,
307 int start_index,
308 int char_count,
309 unsigned short* result) {
310 CPDF_TextPage* textpage = CPDFTextPageFromFPDFTextPage(page);
311 if (!textpage || start_index < 0 || char_count < 0 || !result)
312 return 0;
313
314 int char_available = textpage->CountChars() - start_index;
315 if (char_available <= 0)
316 return 0;
317
318 char_count = std::min(char_count, char_available);
319 if (char_count == 0) {
320 // Writing out "", which has a character count of 1 due to the NUL.
321 *result = '\0';
322 return 1;
323 }
324
325 WideString str = textpage->GetPageText(start_index, char_count);
326
327 if (str.GetLength() > static_cast<size_t>(char_count))
328 str = str.First(static_cast<size_t>(char_count));
329
330 // UFT16LE_Encode doesn't handle surrogate pairs properly, so it is expected
331 // the number of items to stay the same.
332 ByteString byte_str = str.ToUTF16LE();
333 size_t byte_str_len = byte_str.GetLength();
334 size_t ret_count = byte_str_len / kBytesPerCharacter;
335
336 // +1 to account for the NUL terminator.
337 DCHECK_LE(ret_count, static_cast<size_t>(char_count) + 1);
338
339 memcpy(result, byte_str.c_str(), byte_str_len);
340 return pdfium::base::checked_cast<int>(ret_count);
341 }
342
FPDFText_CountRects(FPDF_TEXTPAGE text_page,int start,int count)343 FPDF_EXPORT int FPDF_CALLCONV FPDFText_CountRects(FPDF_TEXTPAGE text_page,
344 int start,
345 int count) {
346 CPDF_TextPage* textpage = CPDFTextPageFromFPDFTextPage(text_page);
347 return textpage ? textpage->CountRects(start, count) : 0;
348 }
349
FPDFText_GetRect(FPDF_TEXTPAGE text_page,int rect_index,double * left,double * top,double * right,double * bottom)350 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_GetRect(FPDF_TEXTPAGE text_page,
351 int rect_index,
352 double* left,
353 double* top,
354 double* right,
355 double* bottom) {
356 CPDF_TextPage* textpage = CPDFTextPageFromFPDFTextPage(text_page);
357 if (!textpage)
358 return false;
359
360 CFX_FloatRect rect;
361 bool result = textpage->GetRect(rect_index, &rect);
362
363 *left = rect.left;
364 *top = rect.top;
365 *right = rect.right;
366 *bottom = rect.bottom;
367 return result;
368 }
369
FPDFText_GetBoundedText(FPDF_TEXTPAGE text_page,double left,double top,double right,double bottom,unsigned short * buffer,int buflen)370 FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetBoundedText(FPDF_TEXTPAGE text_page,
371 double left,
372 double top,
373 double right,
374 double bottom,
375 unsigned short* buffer,
376 int buflen) {
377 CPDF_TextPage* textpage = CPDFTextPageFromFPDFTextPage(text_page);
378 if (!textpage)
379 return 0;
380
381 CFX_FloatRect rect((float)left, (float)bottom, (float)right, (float)top);
382 WideString str = textpage->GetTextByRect(rect);
383
384 if (buflen <= 0 || !buffer)
385 return pdfium::base::checked_cast<int>(str.GetLength());
386
387 ByteString cbUTF16Str = str.ToUTF16LE();
388 int len = pdfium::base::checked_cast<int>(cbUTF16Str.GetLength()) /
389 sizeof(unsigned short);
390 int size = buflen > len ? len : buflen;
391 memcpy(buffer, cbUTF16Str.c_str(), size * sizeof(unsigned short));
392 cbUTF16Str.ReleaseBuffer(size * sizeof(unsigned short));
393 return size;
394 }
395
396 FPDF_EXPORT FPDF_SCHHANDLE FPDF_CALLCONV
FPDFText_FindStart(FPDF_TEXTPAGE text_page,FPDF_WIDESTRING findwhat,unsigned long flags,int start_index)397 FPDFText_FindStart(FPDF_TEXTPAGE text_page,
398 FPDF_WIDESTRING findwhat,
399 unsigned long flags,
400 int start_index) {
401 CPDF_TextPage* textpage = CPDFTextPageFromFPDFTextPage(text_page);
402 if (!textpage)
403 return nullptr;
404
405 CPDF_TextPageFind::Options options;
406 options.bMatchCase = !!(flags & FPDF_MATCHCASE);
407 options.bMatchWholeWord = !!(flags & FPDF_MATCHWHOLEWORD);
408 options.bConsecutive = !!(flags & FPDF_CONSECUTIVE);
409 auto find = CPDF_TextPageFind::Create(
410 textpage, WideStringFromFPDFWideString(findwhat), options,
411 start_index >= 0 ? absl::optional<size_t>(start_index) : absl::nullopt);
412
413 // Caller takes ownership.
414 return FPDFSchHandleFromCPDFTextPageFind(find.release());
415 }
416
FPDFText_FindNext(FPDF_SCHHANDLE handle)417 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_FindNext(FPDF_SCHHANDLE handle) {
418 if (!handle)
419 return false;
420
421 CPDF_TextPageFind* textpageFind = CPDFTextPageFindFromFPDFSchHandle(handle);
422 return textpageFind->FindNext();
423 }
424
FPDFText_FindPrev(FPDF_SCHHANDLE handle)425 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFText_FindPrev(FPDF_SCHHANDLE handle) {
426 if (!handle)
427 return false;
428
429 CPDF_TextPageFind* textpageFind = CPDFTextPageFindFromFPDFSchHandle(handle);
430 return textpageFind->FindPrev();
431 }
432
433 FPDF_EXPORT int FPDF_CALLCONV
FPDFText_GetSchResultIndex(FPDF_SCHHANDLE handle)434 FPDFText_GetSchResultIndex(FPDF_SCHHANDLE handle) {
435 if (!handle)
436 return 0;
437
438 CPDF_TextPageFind* textpageFind = CPDFTextPageFindFromFPDFSchHandle(handle);
439 return textpageFind->GetCurOrder();
440 }
441
FPDFText_GetSchCount(FPDF_SCHHANDLE handle)442 FPDF_EXPORT int FPDF_CALLCONV FPDFText_GetSchCount(FPDF_SCHHANDLE handle) {
443 if (!handle)
444 return 0;
445
446 CPDF_TextPageFind* textpageFind = CPDFTextPageFindFromFPDFSchHandle(handle);
447 return textpageFind->GetMatchedCount();
448 }
449
FPDFText_FindClose(FPDF_SCHHANDLE handle)450 FPDF_EXPORT void FPDF_CALLCONV FPDFText_FindClose(FPDF_SCHHANDLE handle) {
451 if (!handle)
452 return;
453
454 // Take ownership back from caller and destroy.
455 std::unique_ptr<CPDF_TextPageFind> textpageFind(
456 CPDFTextPageFindFromFPDFSchHandle(handle));
457 }
458
459 // web link
460 FPDF_EXPORT FPDF_PAGELINK FPDF_CALLCONV
FPDFLink_LoadWebLinks(FPDF_TEXTPAGE text_page)461 FPDFLink_LoadWebLinks(FPDF_TEXTPAGE text_page) {
462 CPDF_TextPage* textpage = CPDFTextPageFromFPDFTextPage(text_page);
463 if (!textpage)
464 return nullptr;
465
466 auto pagelink = std::make_unique<CPDF_LinkExtract>(textpage);
467 pagelink->ExtractLinks();
468
469 // Caller takes ownership.
470 return FPDFPageLinkFromCPDFLinkExtract(pagelink.release());
471 }
472
FPDFLink_CountWebLinks(FPDF_PAGELINK link_page)473 FPDF_EXPORT int FPDF_CALLCONV FPDFLink_CountWebLinks(FPDF_PAGELINK link_page) {
474 if (!link_page)
475 return 0;
476
477 CPDF_LinkExtract* pageLink = CPDFLinkExtractFromFPDFPageLink(link_page);
478 return pdfium::base::checked_cast<int>(pageLink->CountLinks());
479 }
480
FPDFLink_GetURL(FPDF_PAGELINK link_page,int link_index,unsigned short * buffer,int buflen)481 FPDF_EXPORT int FPDF_CALLCONV FPDFLink_GetURL(FPDF_PAGELINK link_page,
482 int link_index,
483 unsigned short* buffer,
484 int buflen) {
485 WideString wsUrl(L"");
486 if (link_page && link_index >= 0) {
487 CPDF_LinkExtract* pageLink = CPDFLinkExtractFromFPDFPageLink(link_page);
488 wsUrl = pageLink->GetURL(link_index);
489 }
490 ByteString cbUTF16URL = wsUrl.ToUTF16LE();
491 int required = pdfium::base::checked_cast<int>(cbUTF16URL.GetLength() /
492 sizeof(unsigned short));
493 if (!buffer || buflen <= 0)
494 return required;
495
496 int size = std::min(required, buflen);
497 if (size > 0) {
498 int buf_size = size * sizeof(unsigned short);
499 memcpy(buffer, cbUTF16URL.c_str(), buf_size);
500 }
501 return size;
502 }
503
FPDFLink_CountRects(FPDF_PAGELINK link_page,int link_index)504 FPDF_EXPORT int FPDF_CALLCONV FPDFLink_CountRects(FPDF_PAGELINK link_page,
505 int link_index) {
506 if (!link_page || link_index < 0)
507 return 0;
508
509 CPDF_LinkExtract* pageLink = CPDFLinkExtractFromFPDFPageLink(link_page);
510 return fxcrt::CollectionSize<int>(pageLink->GetRects(link_index));
511 }
512
FPDFLink_GetRect(FPDF_PAGELINK link_page,int link_index,int rect_index,double * left,double * top,double * right,double * bottom)513 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_GetRect(FPDF_PAGELINK link_page,
514 int link_index,
515 int rect_index,
516 double* left,
517 double* top,
518 double* right,
519 double* bottom) {
520 if (!link_page || link_index < 0 || rect_index < 0)
521 return false;
522
523 CPDF_LinkExtract* pageLink = CPDFLinkExtractFromFPDFPageLink(link_page);
524 std::vector<CFX_FloatRect> rectArray = pageLink->GetRects(link_index);
525 if (rect_index >= fxcrt::CollectionSize<int>(rectArray))
526 return false;
527
528 *left = rectArray[rect_index].left;
529 *right = rectArray[rect_index].right;
530 *top = rectArray[rect_index].top;
531 *bottom = rectArray[rect_index].bottom;
532 return true;
533 }
534
535 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFLink_GetTextRange(FPDF_PAGELINK link_page,int link_index,int * start_char_index,int * char_count)536 FPDFLink_GetTextRange(FPDF_PAGELINK link_page,
537 int link_index,
538 int* start_char_index,
539 int* char_count) {
540 if (!link_page || link_index < 0)
541 return false;
542
543 CPDF_LinkExtract* page_link = CPDFLinkExtractFromFPDFPageLink(link_page);
544 auto maybe_range = page_link->GetTextRange(link_index);
545 if (!maybe_range.has_value())
546 return false;
547
548 *start_char_index =
549 pdfium::base::checked_cast<int>(maybe_range.value().m_Start);
550 *char_count = pdfium::base::checked_cast<int>(maybe_range.value().m_Count);
551 return true;
552 }
553
FPDFLink_CloseWebLinks(FPDF_PAGELINK link_page)554 FPDF_EXPORT void FPDF_CALLCONV FPDFLink_CloseWebLinks(FPDF_PAGELINK link_page) {
555 delete CPDFLinkExtractFromFPDFPageLink(link_page);
556 }
557