From bf9c33e60f810c328aca152e0548ece44c9fb93f Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Tue, 3 Oct 2023 08:01:55 +0200 Subject: [PATCH] Add support for "GoToE" actions with destinations (issue 17056) This shouldn't be very common in practice, since "GoToE" actions themselves seem quite uncommon; see PR 15537. --- src/core/catalog.js | 37 +++++++++++++++++++++----------- src/display/annotation_layer.js | 8 ++++--- test/pdfs/.gitignore | 1 + test/pdfs/issue17056.pdf | Bin 0 -> 13124 bytes test/unit/api_spec.js | 23 ++++++++++++++++++++ web/download_manager.js | 5 ++++- web/firefoxcom.js | 7 ++++-- 7 files changed, 62 insertions(+), 19 deletions(-) create mode 100644 test/pdfs/issue17056.pdf diff --git a/src/core/catalog.js b/src/core/catalog.js index 8f354775c..856e384fe 100644 --- a/src/core/catalog.js +++ b/src/core/catalog.js @@ -59,6 +59,21 @@ function fetchDestination(dest) { return Array.isArray(dest) ? dest : null; } +function fetchRemoteDest(action) { + let dest = action.get("D"); + if (dest) { + if (dest instanceof Name) { + dest = dest.name; + } + if (typeof dest === "string") { + return stringToPDFString(dest); + } else if (Array.isArray(dest)) { + return JSON.stringify(dest); + } + } + return null; +} + class Catalog { constructor(pdfManager, xref) { this.pdfManager = pdfManager; @@ -1514,19 +1529,9 @@ class Catalog { } // NOTE: the destination is relative to the *remote* document. - let remoteDest = action.get("D"); - if (remoteDest) { - if (remoteDest instanceof Name) { - remoteDest = remoteDest.name; - } - if (typeof url === "string") { - const baseUrl = url.split("#")[0]; - if (typeof remoteDest === "string") { - url = baseUrl + "#" + remoteDest; - } else if (Array.isArray(remoteDest)) { - url = baseUrl + "#" + JSON.stringify(remoteDest); - } - } + const remoteDest = fetchRemoteDest(action); + if (remoteDest && typeof url === "string") { + url = /* baseUrl = */ url.split("#", 1)[0] + "#" + remoteDest; } // The 'NewWindow' property, equal to `LinkTarget.BLANK`. const newWindow = action.get("NewWindow"); @@ -1550,6 +1555,12 @@ class Catalog { if (attachment) { resultObj.attachment = attachment; + + // NOTE: the destination is relative to the *attachment*. + const attachmentDest = fetchRemoteDest(action); + if (attachmentDest) { + resultObj.attachmentDest = attachmentDest; + } } else { warn(`parseDestDictionary - unimplemented "GoToE" action.`); } diff --git a/src/display/annotation_layer.js b/src/display/annotation_layer.js index 3c17538e2..32287337f 100644 --- a/src/display/annotation_layer.js +++ b/src/display/annotation_layer.js @@ -709,7 +709,7 @@ class LinkAnnotationElement extends AnnotationElement { this._bindNamedAction(link, data.action); isBound = true; } else if (data.attachment) { - this._bindAttachment(link, data.attachment); + this.#bindAttachment(link, data.attachment, data.attachmentDest); isBound = true; } else if (data.setOCGState) { this.#bindSetOCGState(link, data.setOCGState); @@ -793,14 +793,16 @@ class LinkAnnotationElement extends AnnotationElement { * Bind attachments to the link element. * @param {Object} link * @param {Object} attachment + * @param {str} [dest] */ - _bindAttachment(link, attachment) { + #bindAttachment(link, attachment, dest = null) { link.href = this.linkService.getAnchorUrl(""); link.onclick = () => { this.downloadManager?.openOrDownloadData( this.container, attachment.content, - attachment.filename + attachment.filename, + dest ); return false; }; diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore index 12d64ee27..bde07e5b3 100644 --- a/test/pdfs/.gitignore +++ b/test/pdfs/.gitignore @@ -51,6 +51,7 @@ !issue7439.pdf !issue7847_radial.pdf !issue8844.pdf +!issue17056.pdf !issue14953.pdf !issue15367.pdf !issue15372.pdf diff --git a/test/pdfs/issue17056.pdf b/test/pdfs/issue17056.pdf new file mode 100644 index 0000000000000000000000000000000000000000..a05dd21b1dc421d78702ac9f11616b4db6fbc2df GIT binary patch literal 13124 zcmbVzWmsIxvNj%q1eYLTaJRwTU4n-Ye3*g326uOY1VRWN0!eUpcPBUmcXx;2AK7xw z-skM+e)qXQW~RHk>h0>PYFX85Xw{@;SvlGG&}iF-2FE+6#)mt)&^Q4c0GO#Iny@f{ zUCqS7#KsZutEd7qlQwYz0~n+QfgC_CP7V$rCqE}IHzy;2T@&g725@q4aqs{{MFH$u z?si}RyNrz~*vt%UCJVKGtUZ1^fgK)ytsg<8!62B~BT*S_YwlzL;NjxneiTG=baDWj z*r2)1G`@by|H0tqB{anXr%XGpvSW`6()H2CjJY5CH4tJ#%oW*+T}Y*5maFwK$M7va z&&AuI%)MZ$*gdP)9^Y=|X7d;B7lkHWy^DAChj=#UhP)RyFXt}3eKwOedy;lmK4bt0 z{PbVjsA#$?Y0kH!!6Bf+15@?kEiJ`MIFk;(JHTg-h+|^<5k)A_)gS`I&5J@r#YwT? zRzHg~AcbYa#Q-ATqT!0b(Bbci0iOX#X#PQ&L}y0_;%|6Rkq{HrZh;%U|&+&kUODr#g9M}Qy0r)>~;WAj;2Lvp^qdC}T2CTuq?OPF-IEGta z%p+jHK#|Dw5m&!5XW*DxkwzXs#P3)UZ#{xTK6hmxo_ctJ_Q4Z+4EN-;xaCS{@uaKP zZfd1<+23tBtW${)YY$zH)zHb!*qGnrII|rQof;7FB=iZLY|A|@e=`T?2R>d|01>;O zFb7Z)e7tnj(uewerN#fat51Gwg~f>&RuCD){(|gBHH^n7IdFihJE|~Sk)rL`o*L7RU_oItB(m?X}WDTe0@^_C7@6x z(%<+tq3CIn3;;(rh{8AnHL?$(#xmI&3t=ScJAzr~XN{u);`9M`9nr@^HkG9nN>J^cJEyLmRFp!d z@qn}aB6kh7Gn9z19}ykp=K4CoYZ-tt_8g^9>?G_8do1_EU(*b|B z>4=`M9wj*#f_6U2cBXFS@;(;*1cX>;>t;f`s{Wcb+3im)eUS(?5k&X?hq z>ESi$OK18(-`LkcD9NDK$B62&gz0b$!HDk=0lY*S;N8s@(dH?gm{94_#gQ?`YZ9^7 zfm>@vtj)W3);2N_4{yw)m!=@RhI7~Fua4Ri*Y}0f*I-3N3s-qodn$=U_bcZq_?s&9 zgPTF(U&?NMYP;{Q8e8sVZ1X5jb2oO3oi~);74$c@pd(?> zeQNy-wJZJ3ZpQXvNp-237=9D<73E(0JfiSvp!Bz&tacY^C{5w_vt@U_`7RP8rcpgU zO&D~&yHQ-+7z<@_{|Dqh`!=Kb25w7)TG(BT5%)cr

!Mry>`iMMiEk;ttC3p5#k#{8>;i4=@B)n-(SXc#eejSFn;bwa_pP)?`GDP~iKJH= zCA`6Scd04ww$i!8sOHTJ?#?%F=ZjysgBKNYNknIxviPhLLTZETSFijA)9QDEI;)eR zEbB%Px`u`bL_IEUjTnIn{BbaIg&;4DbFkHS-mg{4%fUJH1THaeA*)?j7kQo}y<`LE zcQ0|7ybsfSDW-((IPJN;Z*q-Kt$tP&o#72*3NiP^7dWmVELI)~lTkGYfIh z=iGBE@O&zl_fmFa`^J2}g4Um@-n6`r8qN;${n5H7m`&Rh_bAE0Bsa8!XIQjzlA3Pn zv}_HHq*ab`*lu$4iBJ?Nyw40t>x!&Dlo^ZK>gm z+NDe#bCPYtIihT3t&-+9@T!A6K@e@5_0NGH1@FI~4`~W1Pu47a5_ouGNMB=FBa_6R zmVBOK26qU#E$uS3CkeoSp?MN=5@c9;d6H#1jGQ>EW z6QpW=n^FBb;ow-QPs^v+DpD%du4fCc4!8Db&bAFb#)&3zPh(U9$fFgewn9%Pqu3mY zv2_Ym;Rr+!Fe`3Uw>IMUvS9*7NUaBMuQqTCD_8?hfe9Q_q}Z4zWArWW3eBFs_Gq@} zt}s}hGO6_hdM7Nc7k*<)MGcTY&8jW?yy~qvi57QZ9sABl^~ zTHXsBH*1UN@N*oo2bXm&_sag}M;~|Xa0F9DYJu?6OC7BmTIx&ZgtUpp;`PRQCs2nLTfPYQ z$@E7Tqx~igH$9uDw{C$IR8j|PGe-^q7P?ufhP7jqXta9`rMvoUzxY5~6z(%W$fAUlD)o6KvdF1S)?I9ji?( zF~lb6ce}*iQqYuryK|_Ji9tZFoRW;=ZebWJynrGy*l;0fKaYFzJ`WKkF)m=U3kI`T zE$?rKn!k`CZp3c4EXc($GPFprtESEYe{XQ5xbb~gW6zS z2|8Wz^fFu8avP23hGQ)1H1-CEnG)Kz8;&KTAp1tY&q8=6##*{xV`5ddYA+?#w7+ib zyK(TsOr`Kz!MdSNv|sBqK8}Y_2y)jqZLOm8hEVa%Z9^@WXQkX7QS$w~{61ca@1FLr zT*OK0C>}GDAfTH~cCy7sPlHp-ZN`L9ZLUJLsKZ?p70%?z?bS1#MZYF{H_Hl|%MIyO z)-f%rdVJ$wxPoL9d;1IpC+4>WWH)dq)Y`v6Uwpv`$ur9v9jtXS4{Bn;VTh9VsfBK{ zxS%l;NbSIxgaq}Cd!YqIm4z-|pM`x_JS(Va#;9Jm4{BCfC!>JV$UjPnGFj%Ed#Hd1 z#FnK0TokGb^ueLh=e#!5^$o)%WwH32!;;cwKv0$9kb^R?kBi;CUSS+(<3o0nvBd}{ z%>D6P0YYlCs~>gxBY}Kgpby1W18#=Mm?U*5UCii*KB%zkIXt`e)IlVG?j~#sE1le_ z7rhhgdHIq(wt0j_@dvIz@=cEMN+*vH?a9toeNqhg`1afFac)Cux&N;-$>{-DSq-q4R(@?FWiwRJN~Z>deQi^h8z zjSEJVSfNBmxy@&z??>$Nezxr+$~(A(`q1d-QI{-Nz&PVDo2L2xOs=c1Pf5o{1VPMow*<@}Qw5pd z4!uy=aSV20Z?}ROc?p%QB*%ZOSn2Iei$<>Vt#C)aKNghN%>~hUDP#=xLAJiBDYS1g z=1-u38h4ZpY}yaxX z2aB7*$V9}TLl-hCGU0254)?L}+$SsSh^zs&Qz7H?UMT%Mb%{%kXKe>rM^8c_!I=*4 z#5UNqkMg~}N^47d^bStf1!te$IU)=d-sB0>;V)2U-5m;w4PckBOwl&n$#@c_6C8*% zt1m7T8SZu~cc1JPVM}#K!mFRFhVE8V(6QanxNRYV=Af2Y%~jn?9#h+5mxFMK9vJEZ zmOt*2-&R}i^7lhQ2YH?P>yDgem4K^H*qikh6F$ zC_7@}vvZ0iG%G9lHAI=VonAGyD|?jI+JBTNWEoQVlD*Q{$?hc-eOO@UR>|sr5 z+(EzC96?NP+#;}VvVM4)!bqdZK5Dmb(*b4lzc`rN{mx2)GU>kDK@W?0Q zdWVa=wmR}6GbO@A&5lY4+ao^h8FHV>D6%FNiQ!IR$Kebl$WdYn42iaio4_V>mpGxHv95PMnEcj{;&u{%2aUu9o{l;mQp3BpL)1=0ZB% zAJ*BROs!4ZE^`!_bHO6^;>80KKXs_S>*h__xPM@ID2u-;Wk$jdb=h~`!yd!AuHlVy zf+pp}Bz4Cc2>PAt)el_#WFF8yhlB4wd#R5STP(kiD%z+7Yj}#f^pa0(Lnk}X$b{sB z{rGNg$o{rI<-jR7+Gh$%b3LphqRGW#>RQ=5l&?2o3EQL3?XM0R$!9r}r^M<=1wVB@ zRnw!e9VlS%3~8cyO;t4)Hv#WlT~M}^V&)7tinKh_Nnef_820Krq!$NKNWz@uBFN_M zvp1!tl7hzGzH+A}P{<{RF9tCeJo>cjNeOrZ3OVrt-@SJm9Z0I0#2UNkQi%OQR)uFE z_WI4t_0NsvTDUCVik@VWbZ70mV@~k5^YwI%Y+Eb$ndC3s=dqd}pLK0BnNnz4p@`Y? zHe9wY8G3ZJ`Y-3~eCW$_$dWyY{OQr{>3)p@`hK92KoFPGOBK?4z8NhqntrikjHpWb zJmP7k`HuRt^qx2|pa`w{Dd!vpkl4s0>Y}!i&jsK81&oe{z-iJ4{aab=M@0PRAK$+{ zH8?C|ml>b54%ml!=qcU?B^nb6P8;1$q!?RSDf6tCleq`;?d0BfJB<3#V{>gs?R4<<;`zlPd?}Nuc z>AQTF^-HG8GTnQv%|H`kT_)UzszZtLJwj$RS#h>y@3Zoo`Zp4sA-$XiN$W+f-DL;D z-Q;Xfv511J`ueS2M8IZ2d*~t)8-bB^rA}Y!H50z~4ljpFcyFuDESRt4z9MyC%}E|L z_tGjaR23O??yI#FDPK3Ket8uyDzjyVeE&`Wy)*xAGOdg)bl=T(+v$tdB1gNF>Z$x~ z#8ANN0&lA7{q@1?j?PPtx8gdX6Nr#T&7K>{Lx}GdD%74Uo6w-z$3%yXBMvBbZ zskh!hgz2I$G)yKWspF)blb#INBAOG315X!J)F{B%Tf@C+Nt#eNjlVHsESY|R=$z{^ zU;BP-DHlVX)&thKiTrEy>Ps<)Pn6eX5egSbJ;MrYKSL_t%A(#j`+VohY=I z&nqe=RaYu3-`;{WtoP}DkQtNp)-{1N77jH55QeRlHfQ%oT73L%gn z=>z=>OZDNRAG=$SPLgLM#JJdd;Y1|T^#gjuUs6IdHDGg!vn(u>+CFP%mG+R!L4WCQ zvk6+Oa)BG%``pY0t!U{EY)Fl)T{fl(e9^h}%0+lwJAx;!qtficvwXwIGYAu()ofTX z^q!z~QmQeC5Cj#y(0_#-E@`z*$%)Oc_$H8uz_W-?Fc@BXsJu)7+j`Kr#Lr@C(jR#u z9YdPBxxB1WAPE8KaCHz9xveJQ&X>;O0H^)sEz8LkoAvW_JG;#roa+ygBQl=QLV(qP zP3YMe2@spWVK)7Yhmr0FYS-kYSnsCNnLd#|t!rnd&}aS1AABbbQPd{Vw@`SA#ap~Z7JB<-}TQ5 z*#yn5?gsm1J@33mu09QUg3y~P`(_GG1|xR=*!$-88P4`K*wgE}{fj@xZ4EY3M&#m) zH&Ml~xx1RUi61o<`B&$d-TWS_if;Pd(_F7Sn`inhDFzodb$!i$ssYj^T!6Mwk#FLc zpAF*isCF&%Oyy&w`GI=)2`*(j8}qOc#!y$%BSF0N#Kj;2;;$vLG81tlx*1x9YAMfl z*p}%7NuTS3JN$YH-F~1bP)p@u(8rkkv{J25&(ID=!_W@LH#B>RCSr842!A1H=->V< z0M~+1DK|lLP^%q&`3Zx)?Lew!)eem@rl$`eF@97(q^6$??}iFoy_J(6-T{L3RK zLqu`ZmL8q?OkZWl$v%bTYik2@fZWV$4fbrZJ}LxLHeS5VAK!CB%3@jprwZZae2#e; z-yPvXDV0{{QUoT{M5A9()@?Ay19=l1cs@*n&kG(VFh zVVyv^54J|46c+Ah(8iG?*At#@t+OTOa!HysYsGSoOW()WQXkrR;b`qhY`UBMr^e<35X9w%wAk9GR zU~8}q*w)FBos*68mnvo;K?uyj#>7d~#Lmtd3NrbH$8Ki^5oZ5)(=RU2SPTTHTg~G_p&hiFQxvXrqFK;|4IKlw-(d}{5XuiacVnQ zi<(27ESyb$>m3BMbppFNnVUG6fo<9UsQuCVpWwel{tlw)Y-a~^a1#BSG@C8h=|3d@ zWu0|Jw39tg^GoFXDfo{y~*>wgvt2 zyooi`$^B3CKiVFD{#i)v@rLSG@I3PWpPcPH?ysb8T7{&lDJ z*weoVFb6Fd%v$tOyI&LeacBT$z#pyv{IZcS`+u_jCi{3h2Zgx*1?ZS{htl5qVmrQ|7m&~n?J0tq9P~_13CX%G#+Q1voq98ki!IG2IS`EX61(Palw$F*7xVa0r+@&h!70{fCkN=DNpq^)Vd(wF-;=dli2?YKTy|KCaRK zuvhT><@oWhy+TSsTJ~|?|GK2*kouo5W;yw|x&E?sxXpOSL$&Z<5q9TW)S-Vv+OE20 zkjaC?Awrtw`{s{P7EVm4jv-COLDIhRxh-c)nOi+$+ax516K|uXhd8l!%`f$HtjtsS zFa{0=3qB>eI%vD8V=kDbA{G;CD?hmecbkDX$=!E*N{zk{qATcPtz!373T6@<}tXtX7N4hIKe znkcc*@1Y800Ccb;rT3T!X)`Kx$<`!);?9P7t$-wzW@3eUeP3Hw{OnnIqEPYG(6j`j zUnz$gd3Kh65w z&cp|mR1fP=@n@X@mITGM` zJ`sY!Bzdt^Rz5db=1DNQsITY!TECu{{}{=QpCG7&zle0UJ|M^yf;ye3hdVh zlT{0AK=$!X?=Bs~A6j1Dzc5R4nq(9|>4q59j*X~s*(Y)N995sp^y{otoS+!TTMW(b z>$#`F>s6u=EwAxYcjQSjc5cn{xlYQI*Yu&Yss~HNMH|n0mRD5=iiuOECzeq{Tn8Fm z`F*GB&}SxFJ_fh=OYpbeNbv`{2>GtACN*rCZVm_Kir^DOFvH{AE#=Y%v*O_{Q>8*) zG*4>G^+YvSUR`()8qCMGaA0`Wq5ME7JoHr`c+x}l?(4c-c~fbcc*4;zZ%59=rlJzR z^+y#Qujx}Bp&xhz9T7rP0PgTQ3A*s3Cbc%WeG_RkRo-5TEXai{Bsk%egdk5cB2Jy6Um@n1P)dED#Q7qfgG9i!$70r@@v|qD z;oNUF2N>}7sv&`=ogEhr7Smc=e+eYvkTCFLS zI5kJrU+$sGR%^we187kRne&dP8XS3sr|6jSD0EvJTu zzy+a|z`&|SPs_a~klW~|hS)d4j2qG$eeMCzfty!oXlQ914y=$YQ~!w%1vt?IZ4#VB z)q1R>;~1?bB-IW=lNw=Y>uLoaBW1V4O9dx@%OYIz~%6^K6A zr~Ir`ZoS%P2{n2#8nK-c87nbS#IwEqa&BuE*2sC51BTIDVtMr-?MR(9IAlBc1DTFXDD@f7|pUIXZP(~C* zsTLHGVQ+M{?lCtAl8p(qH8I}Hw{fYHHyByjo`sk4DFOKMP#-~&`G%)>0x8t5f_9kf znl!X&S3fGU1&=C?S2#b6D(p4^qp}Jb3K|qOFF$0772nExv5$R#GWBhPIhrJY#=fo* zfVPIa++FqEP#g$(;QYge$@`ZL^M8C^=i&U@z8I{zY&*k&eZQE^5BBASmLl3@OZY2( z`DXBHN^7gGS=B*-1y`s%jqb?urc`c*`8zzK4Sk^o{_N&qlhEQkA3scykaa{njFCv{ zaHx3k;?%EO>TubKM7f_6a_doO*Yt@s^BlO-xp1|GYCL?FlF2g6VewXf%ZKYsmqluC z*4rw}5WQTSfc~yNB0O+tUX>*0$Kmmd3+iILAD=gh6XIz6lE2}rHI z({~A>)6)pP`i1z0U*69&w^#HfkqmFzZQh3|&T`8xRx?|_ZW@@Ui=%tLf+I)+pl>V> zU{y~JS`)6g{OWjed^Ux17)A!8>5pH5LS$FxpVdhmEqmV_N>C9@v1F*=m2fiXnPV=a ziQ?3h&VQ&hbTFn0AqCQM#8vV*xLG-3aDvn? zeH4^IyoX`?iAVZ)ufp2<4H$8Cj=Xq0X7Hal^F7PXAAbI+de7KZyqpP~r<-)V)zZki zu6f~WQXiBjOjOV^;=5t?&R+D}I7FzT*u6>o#Xd@UQ=(Tk^G;BuI`w@2NY{KmN$`Zd z4e|{U%tfdEAL8wQn;+ul`+I&UIL-hz!+{@ictv1NByShnrNB@@@Ky`KDVBGJfZHa4 zQnWgzCb}@9Qrbx1w8xew1koc=TQtkUZ{b zN!7G(A%Q)ym-Xj(4U9>!Qh)XLY?|uaAXZfwA4`FYyxmOX7wGn}iGmz6%j}18bypWB zvt#M(X>G+hX8Vn+r6S-y5S_y-ZhG?LTH-U{oEjYI!^D+OW*$1@CqNA-ayvMFDV!y0 z-eal$W9y*`8Cq-nF6l*ACmaCPpUB-2^0~NSd<^j>QF^w>wnVv8qE5!|ip*YjK`bf~9ZI!xlu@0y_mm9s3O$YcO+W z&nOLLvTm{{?mV8r`UeXM?sD!FY?0xG+8y-F=jxJ9FDt%^N@WtLOIOfk zdcad>*0fxu;KnwGF(Iw7djP0>ajwvNj5_W~b5r!hmhLewvf)p37`>79{3{-oKyYE0b+tv;4T-i-*}u{rI87D_l=m(6|-GHrNKv-@8+&c%Q=O8M))AQ@?Tay~u^r)N&&QPAdNJ@Mxca{iC4&0&Hj;SXBSSuzQ-O3O z)i^>kW4WL?I_e6&Os{hm-}#tOTPO5Pu^U9nIuICSVIx zuvjt93=kcSV8cId6QmW6R?9Gs$f6^W^QRl+h+@-+B!wuhjM7*_?EoYQQVDtplB@5_ z_*dRP;~%9ZhHl}ajH2qFyjACv5<`)JrxoYGT{X@@Rh5!C1Las8uc`;lbBrJnN3mJU ziXo)?QS=tPKWi`Gef;=~BueZKW2qHNHA>-aia2U@2=hl#LvWfh<#F}I@*Yd z>@ePsc-X~M^SkC;>LS9&?Lu+jo~bm(9Au~aLh@Y`s_j#%!3O(H2}9QBl`|sU&R4o! z0fh@j!1uLg2oVP#8@-j*`@wTz0fjWL|D##@JIHYE4djAK$qp&ss&$KJLCD@ zR2ICw=KI0x2{&Il5qhn3_rfoYl~41w+S*x_Ff%kzr!-8bHcY27Os6qSr#wujK1`=N zOs6^QM@b|R%bI?_TY_#^V+Zh__M<&VX=G?PSYMfC6=eFH90Wi`1WMnRa?87e~B{a1@x7+SNgC{y1U@l0I4>pL`2@5K$}S-! zbTNDElA_A$Ya-e5A~4tBJ%h2!At6rU`=>{VTd^Jeh|8r8@V9yk_$~`zt?pxLsEmG! zQpAW5I}j3s{3-Z=+$oa7PlYP17F!v6j+p!?Swxn&g$`%U8dcS?p@^Bb87EWb4u*alQhBiKKIM``6LfC?yI()23fe z0zmBSKdIBn{8gwP`R%#ZWc6sHA5-(zxF%IoITg#Tq@HVW)I|yb(~{I}6x~JcpS@cC z)F$kxT`H?yt3AwkDOoy^mACIRzigVzQ1_pm3AT%v#t5M)QRt*YPHaXfsdZ3n-S03ic9h?{El?E4e0qG95)Y$W59mf9v(abOYG3WxHG+vn z#nh=4kC37`B14Pys<+=sZ(FdCHw~hntv=bSlUA|yRfe8b5IUj|p`fQcYWkiqt|IYk zCk-ndl=BZ#9AQeu)YncrR$eG&KGM3tXE`c?NpkR|4qVt?<-wuX;Z4Eh>!yeV=irft zp^1U>(1-g~rQ3_;Z{ZXm%|lh#Dx`UUw7@SvqCUZZG`%RVyKa{4ijOs>Y^EeGpGwDO zx@lNPVeUhHmAeW3;oEDL`L64jp%xwT<0FQqQTS6ccpV)-HbL@YEPW@wOl+0X1&UH9n^*$U34B= z58J0R0o^Jzk4$!a9=nOP~jrAUBam5`w z18(+b)s5p_5rNNB+|tB4Y!I5K#rErdD$%=E6oz*OaU$<{1L057Ev|KpT#vJg47<-c zu%GUciP%~d1RI%_x1W^~TvR;!Ol-|k{PCgOC&!}n@g?aH#gpYa=yY##)|y;>@A3^n zv8fR5^^Em&ZfFJmK<+ne0@bmn6=FrsuLjdfr z9{c7503Sb(vj5Z55+^VJ-=3BTh9;aP)$x&r9Vv^X4a0EggZS-TU*dg`WFCjR8%DeF z-s7>_fKgFtn5l=Ee)SL z$Fy-AYt?i{9~;j_PWcdgD4G5Dr`g>6tEuR0wJXV_wzaFDp1inPVgwJ|K5&UOe088d zJZw1m$kZr5q48CZc~R_YCB^9e=gTPDGx%*~oPhr}{bPpL!O6`53_;@r@&UQgXlZ3$ G%KkqL`!!hr literal 0 HcmV?d00001 diff --git a/test/unit/api_spec.js b/test/unit/api_spec.js index 3e7eea679..f569a6dd2 100644 --- a/test/unit/api_spec.js +++ b/test/unit/api_spec.js @@ -2855,6 +2855,29 @@ describe("api", function () { expect(content instanceof Uint8Array).toEqual(true); expect(content.length).toEqual(4508); + expect(annotations[0].attachmentDest).toEqual('[-1,{"name":"Fit"}]'); + + await loadingTask.destroy(); + }); + + it("gets annotations containing GoToE action with destination (issue 17056)", async function () { + const loadingTask = getDocument(buildGetDocumentParams("issue17056.pdf")); + const pdfDoc = await loadingTask.promise; + const pdfPage = await pdfDoc.getPage(1); + + const annotations = await pdfPage.getAnnotations(); + expect(annotations.length).toEqual(30); + + const { annotationType, attachment, attachmentDest } = annotations[0]; + expect(annotationType).toEqual(AnnotationType.LINK); + + const { filename, content } = attachment; + expect(filename).toEqual("destination-doc.pdf"); + expect(content instanceof Uint8Array).toEqual(true); + expect(content.length).toEqual(10305); + + expect(attachmentDest).toEqual('[0,{"name":"Fit"}]'); + await loadingTask.destroy(); }); diff --git a/web/download_manager.js b/web/download_manager.js index 6117297a8..26d655bc1 100644 --- a/web/download_manager.js +++ b/web/download_manager.js @@ -67,7 +67,7 @@ class DownloadManager { /** * @returns {boolean} Indicating if the data was opened. */ - openOrDownloadData(element, data, filename) { + openOrDownloadData(element, data, filename, dest = null) { const isPdfData = isPdfFile(filename); const contentType = isPdfData ? "application/pdf" : ""; @@ -93,6 +93,9 @@ class DownloadManager { "?file=" + encodeURIComponent(blobUrl + "#" + filename); } + if (dest) { + viewerUrl += `#${escape(dest)}`; + } try { window.open(viewerUrl); diff --git a/web/firefoxcom.js b/web/firefoxcom.js index 7c886fb7a..438fbf9fd 100644 --- a/web/firefoxcom.js +++ b/web/firefoxcom.js @@ -132,7 +132,7 @@ class DownloadManager { /** * @returns {boolean} Indicating if the data was opened. */ - openOrDownloadData(element, data, filename) { + openOrDownloadData(element, data, filename, dest = null) { const isPdfData = isPdfFile(filename); const contentType = isPdfData ? "application/pdf" : ""; @@ -143,7 +143,10 @@ class DownloadManager { this.#openBlobUrls.set(element, blobUrl); } // Let Firefox's content handler catch the URL and display the PDF. - const viewerUrl = blobUrl + "#filename=" + encodeURIComponent(filename); + let viewerUrl = blobUrl + "?filename=" + encodeURIComponent(filename); + if (dest) { + viewerUrl += `#${escape(dest)}`; + } try { window.open(viewerUrl);