Spaces:
Running
Running
/* poppler-link.cc: qt interface to poppler | |
* Copyright (C) 2006-2007, 2013, 2016-2021, Albert Astals Cid | |
* Copyright (C) 2007-2008, Pino Toscano <[email protected]> | |
* Copyright (C) 2010 Hib Eris <[email protected]> | |
* Copyright (C) 2012, Tobias Koenig <[email protected]> | |
* Copyright (C) 2012, Guillermo A. Amaral B. <[email protected]> | |
* Copyright (C) 2018 Intevation GmbH <[email protected]> | |
* Copyright (C) 2018 Adam Reichold <[email protected]> | |
* Copyright (C) 2020, 2021 Oliver Sander <[email protected]> | |
* Adapting code from | |
* Copyright (C) 2004 by Enrico Ros <[email protected]> | |
* | |
* This program is free software; you can redistribute it and/or modify | |
* it under the terms of the GNU General Public License as published by | |
* the Free Software Foundation; either version 2, or (at your option) | |
* any later version. | |
* | |
* This program is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU General Public License for more details. | |
* | |
* You should have received a copy of the GNU General Public License | |
* along with this program; if not, write to the Free Software | |
* Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. | |
*/ | |
namespace Poppler { | |
class LinkDestinationPrivate : public QSharedData | |
{ | |
public: | |
LinkDestinationPrivate(); | |
LinkDestination::Kind kind; // destination type | |
QString name; | |
int pageNum; // page number | |
double left, bottom; // position | |
double right, top; | |
double zoom; // zoom factor | |
bool changeLeft : 1, changeTop : 1; // for destXYZ links, which position | |
bool changeZoom : 1; // components to change | |
}; | |
LinkDestinationPrivate::LinkDestinationPrivate() | |
{ | |
// sane defaults | |
kind = LinkDestination::destXYZ; | |
pageNum = 0; | |
left = 0; | |
bottom = 0; | |
right = 0; | |
top = 0; | |
zoom = 1; | |
changeLeft = true; | |
changeTop = true; | |
changeZoom = false; | |
} | |
LinkPrivate::~LinkPrivate() = default; | |
LinkOCGStatePrivate::~LinkOCGStatePrivate() = default; | |
LinkHidePrivate::~LinkHidePrivate() = default; | |
class LinkGotoPrivate : public LinkPrivate | |
{ | |
public: | |
LinkGotoPrivate(const QRectF &area, const LinkDestination &dest); | |
~LinkGotoPrivate() override; | |
QString extFileName; | |
LinkDestination destination; | |
}; | |
LinkGotoPrivate::LinkGotoPrivate(const QRectF &area, const LinkDestination &dest) : LinkPrivate(area), destination(dest) { } | |
LinkGotoPrivate::~LinkGotoPrivate() = default; | |
class LinkExecutePrivate : public LinkPrivate | |
{ | |
public: | |
explicit LinkExecutePrivate(const QRectF &area); | |
~LinkExecutePrivate() override; | |
QString fileName; | |
QString parameters; | |
}; | |
LinkExecutePrivate::LinkExecutePrivate(const QRectF &area) : LinkPrivate(area) { } | |
LinkExecutePrivate::~LinkExecutePrivate() = default; | |
class LinkBrowsePrivate : public LinkPrivate | |
{ | |
public: | |
explicit LinkBrowsePrivate(const QRectF &area); | |
~LinkBrowsePrivate() override; | |
QString url; | |
}; | |
LinkBrowsePrivate::LinkBrowsePrivate(const QRectF &area) : LinkPrivate(area) { } | |
LinkBrowsePrivate::~LinkBrowsePrivate() = default; | |
class LinkActionPrivate : public LinkPrivate | |
{ | |
public: | |
explicit LinkActionPrivate(const QRectF &area); | |
~LinkActionPrivate() override; | |
LinkAction::ActionType type; | |
}; | |
LinkActionPrivate::LinkActionPrivate(const QRectF &area) : LinkPrivate(area) { } | |
LinkActionPrivate::~LinkActionPrivate() = default; | |
class LinkSoundPrivate : public LinkPrivate | |
{ | |
public: | |
explicit LinkSoundPrivate(const QRectF &area); | |
~LinkSoundPrivate() override; | |
double volume; | |
bool sync : 1; | |
bool repeat : 1; | |
bool mix : 1; | |
SoundObject *sound; | |
}; | |
LinkSoundPrivate::LinkSoundPrivate(const QRectF &area) : LinkPrivate(area), sound(nullptr) { } | |
LinkSoundPrivate::~LinkSoundPrivate() | |
{ | |
delete sound; | |
} | |
class LinkRenditionPrivate : public LinkPrivate | |
{ | |
public: | |
LinkRenditionPrivate(const QRectF &area, ::MediaRendition *rendition, ::LinkRendition::RenditionOperation operation, const QString &script, const Ref ref); | |
~LinkRenditionPrivate() override; | |
MediaRendition *rendition; | |
LinkRendition::RenditionAction action; | |
QString script; | |
Ref annotationReference; | |
}; | |
LinkRenditionPrivate::LinkRenditionPrivate(const QRectF &area, ::MediaRendition *r, ::LinkRendition::RenditionOperation operation, const QString &javaScript, const Ref ref) | |
: LinkPrivate(area), rendition(r ? new MediaRendition(r) : nullptr), action(LinkRendition::PlayRendition), script(javaScript), annotationReference(ref) | |
{ | |
switch (operation) { | |
case ::LinkRendition::NoRendition: | |
action = LinkRendition::NoRendition; | |
break; | |
case ::LinkRendition::PlayRendition: | |
action = LinkRendition::PlayRendition; | |
break; | |
case ::LinkRendition::StopRendition: | |
action = LinkRendition::StopRendition; | |
break; | |
case ::LinkRendition::PauseRendition: | |
action = LinkRendition::PauseRendition; | |
break; | |
case ::LinkRendition::ResumeRendition: | |
action = LinkRendition::ResumeRendition; | |
break; | |
} | |
} | |
LinkRenditionPrivate::~LinkRenditionPrivate() | |
{ | |
delete rendition; | |
} | |
class LinkJavaScriptPrivate : public LinkPrivate | |
{ | |
public: | |
explicit LinkJavaScriptPrivate(const QRectF &area); | |
~LinkJavaScriptPrivate() override; | |
QString js; | |
}; | |
LinkJavaScriptPrivate::LinkJavaScriptPrivate(const QRectF &area) : LinkPrivate(area) { } | |
LinkJavaScriptPrivate::~LinkJavaScriptPrivate() = default; | |
class LinkMoviePrivate : public LinkPrivate | |
{ | |
public: | |
LinkMoviePrivate(const QRectF &area, LinkMovie::Operation operation, const QString &title, const Ref reference); | |
~LinkMoviePrivate() override; | |
LinkMovie::Operation operation; | |
QString annotationTitle; | |
Ref annotationReference; | |
}; | |
LinkMoviePrivate::LinkMoviePrivate(const QRectF &area, LinkMovie::Operation _operation, const QString &title, const Ref reference) : LinkPrivate(area), operation(_operation), annotationTitle(title), annotationReference(reference) { } | |
LinkMoviePrivate::~LinkMoviePrivate() = default; | |
static void cvtUserToDev(::Page *page, double xu, double yu, int *xd, int *yd) | |
{ | |
double ctm[6]; | |
page->getDefaultCTM(ctm, 72.0, 72.0, 0, false, true); | |
*xd = (int)(ctm[0] * xu + ctm[2] * yu + ctm[4] + 0.5); | |
*yd = (int)(ctm[1] * xu + ctm[3] * yu + ctm[5] + 0.5); | |
} | |
LinkDestination::LinkDestination(const LinkDestinationData &data) : d(new LinkDestinationPrivate) | |
{ | |
bool deleteDest = false; | |
const LinkDest *ld = data.ld; | |
if (data.namedDest && !ld && !data.externalDest) { | |
deleteDest = true; | |
ld = data.doc->doc->findDest(data.namedDest).release(); | |
} | |
// in case this destination was named one, and it was not resolved | |
if (data.namedDest && !ld) { | |
d->name = QString::fromLatin1(data.namedDest->c_str()); | |
} | |
if (!ld) { | |
return; | |
} | |
if (ld->getKind() == ::destXYZ) { | |
d->kind = destXYZ; | |
} else if (ld->getKind() == ::destFit) { | |
d->kind = destFit; | |
} else if (ld->getKind() == ::destFitH) { | |
d->kind = destFitH; | |
} else if (ld->getKind() == ::destFitV) { | |
d->kind = destFitV; | |
} else if (ld->getKind() == ::destFitR) { | |
d->kind = destFitR; | |
} else if (ld->getKind() == ::destFitB) { | |
d->kind = destFitB; | |
} else if (ld->getKind() == ::destFitBH) { | |
d->kind = destFitBH; | |
} else if (ld->getKind() == ::destFitBV) { | |
d->kind = destFitBV; | |
} | |
if (!ld->isPageRef()) { | |
d->pageNum = ld->getPageNum(); | |
} else { | |
const Ref ref = ld->getPageRef(); | |
d->pageNum = data.doc->doc->findPage(ref); | |
} | |
double left = ld->getLeft(); | |
double bottom = ld->getBottom(); | |
double right = ld->getRight(); | |
double top = ld->getTop(); | |
d->zoom = ld->getZoom(); | |
d->changeLeft = ld->getChangeLeft(); | |
d->changeTop = ld->getChangeTop(); | |
d->changeZoom = ld->getChangeZoom(); | |
int leftAux = 0, topAux = 0, rightAux = 0, bottomAux = 0; | |
if (!data.externalDest) { | |
::Page *page; | |
if (d->pageNum > 0 && d->pageNum <= data.doc->doc->getNumPages() && (page = data.doc->doc->getPage(d->pageNum))) { | |
cvtUserToDev(page, left, top, &leftAux, &topAux); | |
cvtUserToDev(page, right, bottom, &rightAux, &bottomAux); | |
d->left = leftAux / (double)page->getCropWidth(); | |
d->top = topAux / (double)page->getCropHeight(); | |
d->right = rightAux / (double)page->getCropWidth(); | |
d->bottom = bottomAux / (double)page->getCropHeight(); | |
} else { | |
d->pageNum = 0; | |
} | |
} | |
if (deleteDest) { | |
delete ld; | |
} | |
} | |
LinkDestination::LinkDestination(const QString &description) : d(new LinkDestinationPrivate) | |
{ | |
const QStringList tokens = description.split(';'); | |
if (tokens.size() >= 10) { | |
d->kind = static_cast<Kind>(tokens.at(0).toInt()); | |
d->pageNum = tokens.at(1).toInt(); | |
d->left = tokens.at(2).toDouble(); | |
d->bottom = tokens.at(3).toDouble(); | |
d->right = tokens.at(4).toDouble(); | |
d->top = tokens.at(5).toDouble(); | |
d->zoom = tokens.at(6).toDouble(); | |
d->changeLeft = static_cast<bool>(tokens.at(7).toInt()); | |
d->changeTop = static_cast<bool>(tokens.at(8).toInt()); | |
d->changeZoom = static_cast<bool>(tokens.at(9).toInt()); | |
} | |
} | |
LinkDestination::LinkDestination(const LinkDestination &other) : d(other.d) { } | |
LinkDestination::~LinkDestination() { } | |
LinkDestination::Kind LinkDestination::kind() const | |
{ | |
return d->kind; | |
} | |
int LinkDestination::pageNumber() const | |
{ | |
return d->pageNum; | |
} | |
double LinkDestination::left() const | |
{ | |
return d->left; | |
} | |
double LinkDestination::bottom() const | |
{ | |
return d->bottom; | |
} | |
double LinkDestination::right() const | |
{ | |
return d->right; | |
} | |
double LinkDestination::top() const | |
{ | |
return d->top; | |
} | |
double LinkDestination::zoom() const | |
{ | |
return d->zoom; | |
} | |
bool LinkDestination::isChangeLeft() const | |
{ | |
return d->changeLeft; | |
} | |
bool LinkDestination::isChangeTop() const | |
{ | |
return d->changeTop; | |
} | |
bool LinkDestination::isChangeZoom() const | |
{ | |
return d->changeZoom; | |
} | |
QString LinkDestination::toString() const | |
{ | |
QString s = QString::number((qint8)d->kind); | |
s += ";" + QString::number(d->pageNum); | |
s += ";" + QString::number(d->left); | |
s += ";" + QString::number(d->bottom); | |
s += ";" + QString::number(d->right); | |
s += ";" + QString::number(d->top); | |
s += ";" + QString::number(d->zoom); | |
s += ";" + QString::number((qint8)d->changeLeft); | |
s += ";" + QString::number((qint8)d->changeTop); | |
s += ";" + QString::number((qint8)d->changeZoom); | |
return s; | |
} | |
QString LinkDestination::destinationName() const | |
{ | |
return d->name; | |
} | |
LinkDestination &LinkDestination::operator=(const LinkDestination &other) | |
{ | |
if (this == &other) { | |
return *this; | |
} | |
d = other.d; | |
return *this; | |
} | |
// Link | |
Link::~Link() | |
{ | |
delete d_ptr; | |
} | |
Link::Link(const QRectF &linkArea) : d_ptr(new LinkPrivate(linkArea)) { } | |
Link::Link(LinkPrivate &dd) : d_ptr(&dd) { } | |
Link::LinkType Link::linkType() const | |
{ | |
return None; | |
} | |
QRectF Link::linkArea() const | |
{ | |
Q_D(const Link); | |
return d->linkArea; | |
} | |
QVector<Link *> Link::nextLinks() const | |
{ | |
QVector<Link *> links(d_ptr->nextLinks.size()); | |
for (qsizetype i = 0; i < links.size(); i++) { | |
links[i] = d_ptr->nextLinks[i].get(); | |
} | |
return links; | |
} | |
// LinkGoto | |
LinkGoto::LinkGoto(const QRectF &linkArea, const QString &extFileName, const LinkDestination &destination) : Link(*new LinkGotoPrivate(linkArea, destination)) | |
{ | |
Q_D(LinkGoto); | |
d->extFileName = extFileName; | |
} | |
LinkGoto::~LinkGoto() { } | |
bool LinkGoto::isExternal() const | |
{ | |
Q_D(const LinkGoto); | |
return !d->extFileName.isEmpty(); | |
} | |
QString LinkGoto::fileName() const | |
{ | |
Q_D(const LinkGoto); | |
return d->extFileName; | |
} | |
LinkDestination LinkGoto::destination() const | |
{ | |
Q_D(const LinkGoto); | |
return d->destination; | |
} | |
Link::LinkType LinkGoto::linkType() const | |
{ | |
return Goto; | |
} | |
// LinkExecute | |
LinkExecute::LinkExecute(const QRectF &linkArea, const QString &file, const QString ¶ms) : Link(*new LinkExecutePrivate(linkArea)) | |
{ | |
Q_D(LinkExecute); | |
d->fileName = file; | |
d->parameters = params; | |
} | |
LinkExecute::~LinkExecute() { } | |
QString LinkExecute::fileName() const | |
{ | |
Q_D(const LinkExecute); | |
return d->fileName; | |
} | |
QString LinkExecute::parameters() const | |
{ | |
Q_D(const LinkExecute); | |
return d->parameters; | |
} | |
Link::LinkType LinkExecute::linkType() const | |
{ | |
return Execute; | |
} | |
// LinkBrowse | |
LinkBrowse::LinkBrowse(const QRectF &linkArea, const QString &url) : Link(*new LinkBrowsePrivate(linkArea)) | |
{ | |
Q_D(LinkBrowse); | |
d->url = url; | |
} | |
LinkBrowse::~LinkBrowse() { } | |
QString LinkBrowse::url() const | |
{ | |
Q_D(const LinkBrowse); | |
return d->url; | |
} | |
Link::LinkType LinkBrowse::linkType() const | |
{ | |
return Browse; | |
} | |
// LinkAction | |
LinkAction::LinkAction(const QRectF &linkArea, ActionType actionType) : Link(*new LinkActionPrivate(linkArea)) | |
{ | |
Q_D(LinkAction); | |
d->type = actionType; | |
} | |
LinkAction::~LinkAction() { } | |
LinkAction::ActionType LinkAction::actionType() const | |
{ | |
Q_D(const LinkAction); | |
return d->type; | |
} | |
Link::LinkType LinkAction::linkType() const | |
{ | |
return Action; | |
} | |
// LinkSound | |
LinkSound::LinkSound(const QRectF &linkArea, double volume, bool sync, bool repeat, bool mix, SoundObject *sound) : Link(*new LinkSoundPrivate(linkArea)) | |
{ | |
Q_D(LinkSound); | |
d->volume = volume; | |
d->sync = sync; | |
d->repeat = repeat; | |
d->mix = mix; | |
d->sound = sound; | |
} | |
LinkSound::~LinkSound() { } | |
Link::LinkType LinkSound::linkType() const | |
{ | |
return Sound; | |
} | |
double LinkSound::volume() const | |
{ | |
Q_D(const LinkSound); | |
return d->volume; | |
} | |
bool LinkSound::synchronous() const | |
{ | |
Q_D(const LinkSound); | |
return d->sync; | |
} | |
bool LinkSound::repeat() const | |
{ | |
Q_D(const LinkSound); | |
return d->repeat; | |
} | |
bool LinkSound::mix() const | |
{ | |
Q_D(const LinkSound); | |
return d->mix; | |
} | |
SoundObject *LinkSound::sound() const | |
{ | |
Q_D(const LinkSound); | |
return d->sound; | |
} | |
// LinkRendition | |
LinkRendition::LinkRendition(const QRectF &linkArea, ::MediaRendition *rendition, int operation, const QString &script, const Ref annotationReference) | |
: Link(*new LinkRenditionPrivate(linkArea, rendition, static_cast<enum ::LinkRendition::RenditionOperation>(operation), script, annotationReference)) | |
{ | |
} | |
LinkRendition::~LinkRendition() { } | |
Link::LinkType LinkRendition::linkType() const | |
{ | |
return Rendition; | |
} | |
MediaRendition *LinkRendition::rendition() const | |
{ | |
Q_D(const LinkRendition); | |
return d->rendition; | |
} | |
LinkRendition::RenditionAction LinkRendition::action() const | |
{ | |
Q_D(const LinkRendition); | |
return d->action; | |
} | |
QString LinkRendition::script() const | |
{ | |
Q_D(const LinkRendition); | |
return d->script; | |
} | |
bool LinkRendition::isReferencedAnnotation(const ScreenAnnotation *annotation) const | |
{ | |
Q_D(const LinkRendition); | |
if (d->annotationReference != Ref::INVALID() && d->annotationReference == annotation->d_ptr->pdfObjectReference()) { | |
return true; | |
} | |
return false; | |
} | |
// LinkJavaScript | |
LinkJavaScript::LinkJavaScript(const QRectF &linkArea, const QString &js) : Link(*new LinkJavaScriptPrivate(linkArea)) | |
{ | |
Q_D(LinkJavaScript); | |
d->js = js; | |
} | |
LinkJavaScript::~LinkJavaScript() { } | |
Link::LinkType LinkJavaScript::linkType() const | |
{ | |
return JavaScript; | |
} | |
QString LinkJavaScript::script() const | |
{ | |
Q_D(const LinkJavaScript); | |
return d->js; | |
} | |
// LinkMovie | |
LinkMovie::LinkMovie(const QRectF &linkArea, Operation operation, const QString &annotationTitle, const Ref annotationReference) : Link(*new LinkMoviePrivate(linkArea, operation, annotationTitle, annotationReference)) { } | |
LinkMovie::~LinkMovie() { } | |
Link::LinkType LinkMovie::linkType() const | |
{ | |
return Movie; | |
} | |
LinkMovie::Operation LinkMovie::operation() const | |
{ | |
Q_D(const LinkMovie); | |
return d->operation; | |
} | |
bool LinkMovie::isReferencedAnnotation(const MovieAnnotation *annotation) const | |
{ | |
Q_D(const LinkMovie); | |
if (d->annotationReference != Ref::INVALID() && d->annotationReference == annotation->d_ptr->pdfObjectReference()) { | |
return true; | |
} else if (!d->annotationTitle.isNull()) { | |
return (annotation->movieTitle() == d->annotationTitle); | |
} | |
return false; | |
} | |
LinkOCGState::LinkOCGState(LinkOCGStatePrivate *ocgp) : Link(*ocgp) { } | |
LinkOCGState::~LinkOCGState() { } | |
Link::LinkType LinkOCGState::linkType() const | |
{ | |
return OCGState; | |
} | |
// LinkHide | |
LinkHide::LinkHide(LinkHidePrivate *lhidep) : Link(*lhidep) { } | |
LinkHide::~LinkHide() { } | |
Link::LinkType LinkHide::linkType() const | |
{ | |
return Hide; | |
} | |
QVector<QString> LinkHide::targets() const | |
{ | |
Q_D(const LinkHide); | |
return QVector<QString>() << d->targetName; | |
} | |
bool LinkHide::isShowAction() const | |
{ | |
Q_D(const LinkHide); | |
return d->isShow; | |
} | |
} | |