summaryrefslogtreecommitdiffstats
path: root/src/pdf/qpdfdocument.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/pdf/qpdfdocument.cpp')
-rw-r--r--src/pdf/qpdfdocument.cpp133
1 files changed, 114 insertions, 19 deletions
diff --git a/src/pdf/qpdfdocument.cpp b/src/pdf/qpdfdocument.cpp
index 89b27da8b..e4ec363ce 100644
--- a/src/pdf/qpdfdocument.cpp
+++ b/src/pdf/qpdfdocument.cpp
@@ -54,7 +54,7 @@ QT_BEGIN_NAMESPACE
// The library is not thread-safe at all, it has a lot of global variables.
Q_GLOBAL_STATIC_WITH_ARGS(QMutex, pdfMutex, (QMutex::Recursive));
static int libraryRefCount;
-static const double CharacterHitTolerance = 6.0;
+static const double CharacterHitTolerance = 16.0;
Q_LOGGING_CATEGORY(qLcDoc, "qt.pdf.document")
QPdfMutexLocker::QPdfMutexLocker()
@@ -402,6 +402,50 @@ QString QPdfDocumentPrivate::getText(FPDF_TEXTPAGE textPage, int startIndex, int
return QString::fromUtf16(buf.constData(), len - 1);
}
+QPointF QPdfDocumentPrivate::getCharPosition(FPDF_TEXTPAGE textPage, double pageHeight, int charIndex)
+{
+ double x, y;
+ int count = FPDFText_CountChars(textPage);
+ bool ok = FPDFText_GetCharOrigin(textPage, qMin(count - 1, charIndex), &x, &y);
+ if (!ok)
+ return QPointF();
+ return QPointF(x, pageHeight - y);
+}
+
+QRectF QPdfDocumentPrivate::getCharBox(FPDF_TEXTPAGE textPage, double pageHeight, int charIndex)
+{
+ double l, t, r, b;
+ bool ok = FPDFText_GetCharBox(textPage, charIndex, &l, &r, &b, &t);
+ if (!ok)
+ return QRectF();
+ return QRectF(l, pageHeight - t, r - l, t - b);
+}
+
+QPdfDocumentPrivate::TextPosition QPdfDocumentPrivate::hitTest(int page, QPointF position)
+{
+ const QPdfMutexLocker lock;
+ FPDF_PAGE pdfPage = FPDF_LoadPage(doc, page);
+ double pageHeight = FPDF_GetPageHeight(pdfPage);
+ FPDF_TEXTPAGE textPage = FPDFText_LoadPage(pdfPage);
+ int hitIndex = FPDFText_GetCharIndexAtPos(textPage, position.x(), pageHeight - position.y(),
+ CharacterHitTolerance, CharacterHitTolerance);
+ if (hitIndex >= 0) {
+ QPointF charPos = getCharPosition(textPage, pageHeight, hitIndex);
+ if (!charPos.isNull()) {
+ QRectF charBox = getCharBox(textPage, pageHeight, hitIndex);
+ // If the given position is past the end of the line, i.e. if the right edge of the found character's
+ // bounding box is closer to it than the left edge is, we say that we "hit" the next character index after
+ if (qAbs(charBox.right() - position.x()) < qAbs(charPos.x() - position.x())) {
+ charPos.setX(charBox.right());
+ ++hitIndex;
+ }
+ qCDebug(qLcDoc) << "on page" << page << "@" << position << "got char position" << charPos << "index" << hitIndex;
+ return { charPos, charBox.height(), hitIndex };
+ }
+ }
+ return {};
+}
+
/*!
\class QPdfDocument
\since 5.10
@@ -748,29 +792,80 @@ QPdfSelection QPdfDocument::getSelection(int page, QPointF start, QPointF end)
if (startIndex >= 0 && endIndex != startIndex) {
if (startIndex > endIndex)
qSwap(startIndex, endIndex);
- int count = endIndex - startIndex + 1;
+
+ // If the given end position is past the end of the line, i.e. if the right edge of the last character's
+ // bounding box is closer to it than the left edge is, then extend the char range by one
+ QRectF endCharBox = d->getCharBox(textPage, pageHeight, endIndex);
+ if (qAbs(endCharBox.right() - end.x()) < qAbs(endCharBox.x() - end.x()))
+ ++endIndex;
+
+ int count = endIndex - startIndex;
QString text = d->getText(textPage, startIndex, count);
QVector<QPolygonF> bounds;
+ QRectF hull;
int rectCount = FPDFText_CountRects(textPage, startIndex, endIndex - startIndex);
for (int i = 0; i < rectCount; ++i) {
double l, r, b, t;
FPDFText_GetRect(textPage, i, &l, &t, &r, &b);
- QPolygonF poly;
- poly << QPointF(l, pageHeight - t);
- poly << QPointF(r, pageHeight - t);
- poly << QPointF(r, pageHeight - b);
- poly << QPointF(l, pageHeight - b);
- poly << QPointF(l, pageHeight - t);
- bounds << poly;
+ QRectF rect(l, pageHeight - t, r - l, t - b);
+ if (hull.isNull())
+ hull = rect;
+ else
+ hull = hull.united(rect);
+ bounds << QPolygonF(rect);
}
qCDebug(qLcDoc) << page << start << "->" << end << "found" << startIndex << "->" << endIndex << text;
- return QPdfSelection(text, bounds);
+ return QPdfSelection(text, bounds, hull, startIndex, endIndex);
}
qCDebug(qLcDoc) << page << start << "->" << end << "nothing found";
return QPdfSelection();
}
+/*!
+ Returns information about the text on the given \a page that can be found
+ beginning at the given \a startIndex with at most \l maxLength characters.
+*/
+QPdfSelection QPdfDocument::getSelectionAtIndex(int page, int startIndex, int maxLength)
+{
+
+ if (page < 0 || startIndex < 0 || maxLength < 0)
+ return {};
+ const QPdfMutexLocker lock;
+ FPDF_PAGE pdfPage = FPDF_LoadPage(d->doc, page);
+ double pageHeight = FPDF_GetPageHeight(pdfPage);
+ FPDF_TEXTPAGE textPage = FPDFText_LoadPage(pdfPage);
+ int pageCount = FPDFText_CountChars(textPage);
+ if (startIndex >= pageCount)
+ return QPdfSelection();
+ QVector<QPolygonF> bounds;
+ QRectF hull;
+ int rectCount = 0;
+ QString text;
+ if (maxLength > 0) {
+ text = d->getText(textPage, startIndex, maxLength);
+ rectCount = FPDFText_CountRects(textPage, startIndex, text.length());
+ for (int i = 0; i < rectCount; ++i) {
+ double l, r, b, t;
+ FPDFText_GetRect(textPage, i, &l, &t, &r, &b);
+ QRectF rect(l, pageHeight - t, r - l, t - b);
+ if (hull.isNull())
+ hull = rect;
+ else
+ hull = hull.united(rect);
+ bounds << QPolygonF(rect);
+ }
+ }
+ if (bounds.isEmpty())
+ hull = QRectF(d->getCharPosition(textPage, pageHeight, startIndex), QSizeF());
+ qCDebug(qLcDoc) << "on page" << page << "at index" << startIndex << "maxLength" << maxLength
+ << "got" << text.length() << "chars," << rectCount << "rects within" << hull;
+ return QPdfSelection(text, bounds, hull, startIndex, startIndex + text.length());
+}
+
+/*!
+ Returns all the text and its bounds on the given \a page.
+*/
QPdfSelection QPdfDocument::getAllText(int page)
{
const QPdfMutexLocker lock;
@@ -782,20 +877,20 @@ QPdfSelection QPdfDocument::getAllText(int page)
return QPdfSelection();
QString text = d->getText(textPage, 0, count);
QVector<QPolygonF> bounds;
+ QRectF hull;
int rectCount = FPDFText_CountRects(textPage, 0, count);
for (int i = 0; i < rectCount; ++i) {
double l, r, b, t;
FPDFText_GetRect(textPage, i, &l, &t, &r, &b);
- QPolygonF poly;
- poly << QPointF(l, pageHeight - t);
- poly << QPointF(r, pageHeight - t);
- poly << QPointF(r, pageHeight - b);
- poly << QPointF(l, pageHeight - b);
- poly << QPointF(l, pageHeight - t);
- bounds << poly;
+ QRectF rect(l, pageHeight - t, r - l, t - b);
+ if (hull.isNull())
+ hull = rect;
+ else
+ hull = hull.united(rect);
+ bounds << QPolygonF(rect);
}
- qCDebug(qLcDoc) << "on page" << page << "got" << count << "chars" << rectCount << "rects";
- return QPdfSelection(text, bounds);
+ qCDebug(qLcDoc) << "on page" << page << "got" << count << "chars," << rectCount << "rects within" << hull;
+ return QPdfSelection(text, bounds, hull, 0, count);
}
QT_END_NAMESPACE