Commit 27b76ee7 authored by Albert Astals Cid's avatar Albert Astals Cid

TextDocumentGenerator: Support links that span more than one line

Summary:
If a link spans more than one line we need one rect for each of the lines

BUGS: 403247

Subscribers: okular-devel

Tags: #okular

Differential Revision: https://phabricator.kde.org/D18303
parent cc211129
......@@ -487,3 +487,16 @@ bool SourceRefObjectRect::contains( double x, double y, double xScale, double yS
{
return distanceSqr( x, y, xScale, yScale ) < ( pow( 7.0 / xScale, 2 ) + pow( 7.0 / yScale, 2 ) );
}
/** class NonOwningObjectRect **/
NonOwningObjectRect::NonOwningObjectRect( double left, double top, double right, double bottom, bool ellipse, ObjectType type, void *object )
: ObjectRect( left, top, right, bottom, ellipse, type, object )
{
}
NonOwningObjectRect::~NonOwningObjectRect()
{
// Set m_object so that ~ObjectRect() doesn't delete it
m_object = nullptr;
}
......@@ -518,6 +518,17 @@ class OKULARCORE_EXPORT SourceRefObjectRect : public ObjectRect
NormalizedPoint m_point;
};
/**
* This class is an object rect that doesn't own the given pointer, i.e. won't delete it on destruction
* @since 1.7
*/
class OKULARCORE_EXPORT NonOwningObjectRect : public ObjectRect
{
public:
NonOwningObjectRect( double left, double top, double right, double bottom, bool ellipse, ObjectType type, void *object );
~NonOwningObjectRect();
};
/// @cond PRIVATE
/** @internal */
/** @internal */
......
......@@ -172,14 +172,18 @@ QList<TextDocumentGeneratorPrivate::LinkInfo> TextDocumentGeneratorPrivate::gene
for ( int i = 0; i < mLinkPositions.count(); ++i ) {
const LinkPosition &linkPosition = mLinkPositions[ i ];
LinkInfo info;
info.link = linkPosition.link;
const QVector<QRectF> rects = TextDocumentUtils::calculateBoundingRects( mDocument, linkPosition.startPosition, linkPosition.endPosition );
TextDocumentUtils::calculateBoundingRect( mDocument, linkPosition.startPosition, linkPosition.endPosition,
info.boundingRect, info.page );
for ( int i = 0; i < rects.count(); ++i) {
const QRectF &rect = rects[ i ];
if ( info.page >= 0 )
LinkInfo info;
info.link = linkPosition.link;
info.ownsLink = i == 0;
info.page = std::floor( rect.y() );
info.boundingRect = QRectF( rect.x(), rect.y() - info.page, rect.width(), rect.height() );
result.append( info );
}
}
return result;
......@@ -332,8 +336,13 @@ Document::OpenResult TextDocumentGenerator::loadDocumentWithPassword( const QStr
continue;
const QRectF rect = info.boundingRect;
objects[ info.page ].append( new Okular::ObjectRect( rect.left(), rect.top(), rect.right(), rect.bottom(), false,
Okular::ObjectRect::Action, info.link ) );
if ( info.ownsLink ) {
objects[ info.page ].append( new Okular::ObjectRect( rect.left(), rect.top(), rect.right(), rect.bottom(), false,
Okular::ObjectRect::Action, info.link ) );
} else {
objects[ info.page ].append( new Okular::NonOwningObjectRect( rect.left(), rect.top(), rect.right(), rect.bottom(), false,
Okular::ObjectRect::Action, info.link ) );
}
}
QVector< QLinkedList<Okular::Annotation*> > annots( d->mDocument->pageCount() );
......
......@@ -67,6 +67,66 @@ namespace TextDocumentUtils {
(r - x) / pageSize.width(), (b - y) / pageSize.height() );
}
static QVector<QRectF> calculateBoundingRects( QTextDocument *document, int startPosition, int endPosition )
{
QVector<QRectF> result;
const QSizeF pageSize = document->pageSize();
const QTextBlock startBlock = document->findBlock( startPosition );
const QRectF startBoundingRect = document->documentLayout()->blockBoundingRect( startBlock );
const QTextBlock endBlock = document->findBlock( endPosition );
const QRectF endBoundingRect = document->documentLayout()->blockBoundingRect( endBlock );
const QTextLayout *startLayout = startBlock.layout();
const QTextLayout *endLayout = endBlock.layout();
if (!startLayout || !endLayout) {
qCWarning(OkularCoreDebug) << "Start or end layout not found" << startLayout << endLayout;
return {};
}
const int startPos = startPosition - startBlock.position();
const int endPos = endPosition - endBlock.position();
const QTextLine startLine = startLayout->lineForTextPosition( startPos );
const QTextLine endLine = endLayout->lineForTextPosition( endPos );
// This only works if both start and end layout are the same
if (startLayout == endLayout) {
Q_ASSERT( startBoundingRect == endBoundingRect );
for (int i = startLine.lineNumber(); i < endLine.lineNumber(); ++i) {
const QTextLine line = startLayout->lineAt( i );
// using startPos and endPos is fine, if the pos is out of bounds for that line, it'll return beginning and end of line respectively
const double x = endBoundingRect.x() + line.cursorToX( startPos );
const double y = endBoundingRect.y() + line.y();
const double r = endBoundingRect.x() + line.cursorToX( endPos );
const double b = endBoundingRect.y() + line.y() + endLine.height();
result.append( QRectF( x / pageSize.width(), y / pageSize.height(),
(r - x) / pageSize.width(), (b - y) / pageSize.height() ) );
}
// The last line
const double x = endBoundingRect.x() + endLine.cursorToX( startPos );
const double y = endBoundingRect.y() + endLine.y();
const double r = endBoundingRect.x() + endLine.cursorToX( endPos );
const double b = endBoundingRect.y() + endLine.y() + endLine.height();
result.append( QRectF( x / pageSize.width(), y / pageSize.height(),
(r - x) / pageSize.width(), (b - y) / pageSize.height() ) );
} else {
const double x = startBoundingRect.x() + startLine.cursorToX( startPos );
const double y = startBoundingRect.y() + startLine.y();
const double r = endBoundingRect.x() + endLine.cursorToX( endPos );
const double b = endBoundingRect.y() + endLine.y() + endLine.height();
result.append( QRectF( x / pageSize.width(), y / pageSize.height(),
(r - x) / pageSize.width(), (b - y) / pageSize.height() ) );
}
return result;
}
static void calculatePositions( QTextDocument *document, int page, int &start, int &end )
{
const QAbstractTextDocumentLayout *layout = document->documentLayout();
......@@ -133,6 +193,7 @@ class TextDocumentGeneratorPrivate : public GeneratorPrivate
int page;
QRectF boundingRect;
Action *link;
bool ownsLink;
};
struct AnnotationInfo
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment