173 if (!document || !document->d->doc)
175 auto doc = document->d->doc;
176 const QPdfMutexLocker lock;
177 FPDF_PAGE pdfPage = FPDF_LoadPage(doc,
page);
179 qCWarning(qLcLink) <<
"failed to load page" << page;
182 q->beginResetModel();
190 hasNext = FPDFLink_Enumerate(pdfPage, &linkStart, &linkAnnot);
194 bool ok = FPDFLink_GetAnnotRect(linkAnnot, &rect);
196 qCWarning(qLcLink) <<
"skipping link with invalid bounding box";
200 if (rect.right < rect.left)
201 std::swap(rect.right, rect.left);
202 if (rect.bottom > rect.top)
203 std::swap(rect.bottom, rect.top);
207 if (
int quadPointsCount = FPDFLink_CountQuadPoints(linkAnnot) > 0) {
208 for (
int i = 0; i < quadPointsCount; ++i) {
209 FS_QUADPOINTSF point;
210 if (FPDFLink_GetQuadPoints(linkAnnot, i, &point)) {
213 poly << QPointF(point.x1, point.y1);
214 poly << QPointF(point.x2, point.y2);
215 poly << QPointF(point.x3, point.y3);
216 poly << QPointF(point.x4, point.y4);
217 QRectF bounds = poly.boundingRect();
218 bounds = document->d->mapPageToView(pdfPage, bounds.left(), bounds.top(), bounds.right(), bounds.bottom());
219 qCDebug(qLcLink) <<
"quadpoints" << i <<
"of" << quadPointsCount <<
":" << poly <<
"mapped bounds" << bounds;
220 linkData.d->rects << bounds;
226 linkData.d->rects << document->d->mapPageToView(pdfPage, rect.left, rect.top, rect.right, rect.bottom);
228 FPDF_DEST dest = FPDFLink_GetDest(doc, linkAnnot);
229 FPDF_ACTION action = FPDFLink_GetAction(linkAnnot);
230 switch (FPDFAction_GetType(action)) {
231 case PDFACTION_UNSUPPORTED:
232 case PDFACTION_GOTO: {
233 linkData.d->page = FPDFDest_GetDestPageIndex(doc, dest);
234 if (linkData.d->page < 0) {
235 qCWarning(qLcLink) <<
"skipping link with invalid page number" << linkData.d->page;
238 FPDF_BOOL hasX, hasY, hasZoom;
240 ok = FPDFDest_GetLocationInPage(dest, &hasX, &hasY, &hasZoom, &x, &y, &zoom);
242 qCWarning(qLcLink) <<
"link with invalid location and/or zoom @" << linkData.d->rects;
246 linkData.d->location = document->d->mapPageToView(pdfPage, x, y);
248 linkData.d->zoom = zoom;
251 case PDFACTION_URI: {
252 unsigned long len = FPDFAction_GetURIPath(doc, action,
nullptr, 0);
254 qCWarning(qLcLink) <<
"skipping link with empty URI @" << linkData.d->rects;
257 QByteArray buf(len, 0);
258 unsigned long got = FPDFAction_GetURIPath(doc, action, buf.data(), len);
259 Q_ASSERT(got == len);
260 linkData.d->url = QString::fromLatin1(buf.data(), got - 1);
264 case PDFACTION_LAUNCH:
265 case PDFACTION_REMOTEGOTO: {
266 unsigned long len = FPDFAction_GetFilePath(action,
nullptr, 0);
268 qCWarning(qLcLink) <<
"skipping link with empty file path @" << linkData.d->rects;
271 QByteArray buf(len, 0);
272 unsigned long got = FPDFAction_GetFilePath(action, buf.data(), len);
273 Q_ASSERT(got == len);
274 linkData.d->url = QUrl::fromLocalFile(QString::fromLatin1(buf.data(), got - 1)).toString();
287 FPDF_TEXTPAGE textPage = FPDFText_LoadPage(pdfPage);
289 FPDF_PAGELINK webLinks = FPDFLink_LoadWebLinks(textPage);
291 int count = FPDFLink_CountWebLinks(webLinks);
292 for (
int i = 0; i < count; ++i) {
294 int len = FPDFLink_GetURL(webLinks, i,
nullptr, 0);
296 qCWarning(qLcLink) <<
"skipping link" << i <<
"with empty URL";
298 QList<
unsigned short> buf(len);
299 int got = FPDFLink_GetURL(webLinks, i, buf.data(), len);
300 Q_ASSERT(got == len);
301 linkData.d->url = QString::fromUtf16(
302 reinterpret_cast<
const char16_t *>(buf.data()), got - 1);
304 len = FPDFLink_CountRects(webLinks, i);
305 for (
int r = 0; r < len; ++r) {
306 double left, top, right, bottom;
307 bool success = FPDFLink_GetRect(webLinks, i, r, &left, &top, &right, &bottom);
309 linkData.d->rects << document->d->mapPageToView(pdfPage, left, top, right, bottom);
314 FPDFLink_CloseWebLinks(webLinks);
316 FPDFText_ClosePage(textPage);
320 FPDF_ClosePage(pdfPage);
321 if (Q_UNLIKELY(qLcLink().isDebugEnabled())) {
322 for (
const auto &l : links)
323 qCDebug(qLcLink) << l;