From 71960bea649ffb20f1eafac24bf899afbb590855 Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Sun, 30 Jul 2023 15:52:27 +0200 Subject: [PATCH] Don't print hidden annotatons (bug 1815196) and handle correctly the NoView and NoPrint flags when they're changed from JS. --- src/core/annotation.js | 43 +++++++++++++++---- src/core/document.js | 3 +- src/display/annotation_layer.js | 19 +++++---- test/integration/scripting_spec.js | 56 +++++++++++++++++++++++++ test/pdfs/.gitignore | 3 ++ test/pdfs/annotation_hidden_noview.pdf | Bin 0 -> 12114 bytes test/pdfs/annotation_hidden_print.pdf | Bin 0 -> 6539 bytes test/pdfs/widget_hidden_print.pdf | Bin 0 -> 6995 bytes test/test_manifest.json | 18 +++++++- 9 files changed, 124 insertions(+), 18 deletions(-) create mode 100644 test/pdfs/annotation_hidden_noview.pdf create mode 100644 test/pdfs/annotation_hidden_print.pdf create mode 100644 test/pdfs/widget_hidden_print.pdf diff --git a/src/core/annotation.js b/src/core/annotation.js index 551f429e4..dd5ecbb67 100644 --- a/src/core/annotation.js +++ b/src/core/annotation.js @@ -628,8 +628,11 @@ class Annotation { * @private */ _isPrintable(flags) { + // In Acrobat, hidden flag cancels the print one + // (see annotation_hidden_print.pdf). return ( this._hasFlag(flags, AnnotationFlag.PRINT) && + !this._hasFlag(flags, AnnotationFlag.HIDDEN) && !this._hasFlag(flags, AnnotationFlag.INVISIBLE) ); } @@ -642,11 +645,13 @@ class Annotation { * @public * @memberof Annotation * @param {AnnotationStorage} [annotationStorage] - Storage for annotation + * @param {boolean} [_renderForms] - if true widgets are rendered thanks to + * the annotation layer. */ - mustBeViewed(annotationStorage) { - const hidden = annotationStorage?.get(this.data.id)?.hidden; - if (hidden !== undefined) { - return !hidden; + mustBeViewed(annotationStorage, _renderForms) { + const noView = annotationStorage?.get(this.data.id)?.noView; + if (noView !== undefined) { + return !noView; } return this.viewable && !this._hasFlag(this.flags, AnnotationFlag.HIDDEN); } @@ -661,9 +666,9 @@ class Annotation { * @param {AnnotationStorage} [annotationStorage] - Storage for annotation */ mustBePrinted(annotationStorage) { - const print = annotationStorage?.get(this.data.id)?.print; - if (print !== undefined) { - return print; + const noPrint = annotationStorage?.get(this.data.id)?.noPrint; + if (noPrint !== undefined) { + return !noPrint; } return this.printable; } @@ -1700,7 +1705,9 @@ class WidgetAnnotation extends Annotation { data.readOnly = this.hasFieldFlag(AnnotationFieldFlag.READONLY); data.required = this.hasFieldFlag(AnnotationFieldFlag.REQUIRED); - data.hidden = this._hasFlag(data.annotationFlags, AnnotationFlag.HIDDEN); + data.hidden = + this._hasFlag(data.annotationFlags, AnnotationFlag.HIDDEN) || + this._hasFlag(data.annotationFlags, AnnotationFlag.NOVIEW); } /** @@ -1739,6 +1746,26 @@ class WidgetAnnotation extends Annotation { return !!(this.data.fieldFlags & flag); } + /** @inheritdoc */ + _isViewable(flags) { + // We don't take into account the `NOVIEW` or `HIDDEN` flags here, + // since the visibility can be changed by js code, hence in case + // it's made viewable, we should render it (with visibility set to + // hidden). + return !this._hasFlag(flags, AnnotationFlag.INVISIBLE); + } + + /** @inheritdoc */ + mustBeViewed(annotationStorage, renderForms) { + if (renderForms) { + return this.viewable; + } + return ( + super.mustBeViewed(annotationStorage, renderForms) && + !this._hasFlag(this.flags, AnnotationFlag.NOVIEW) + ); + } + getRotationMatrix(annotationStorage) { let rotation = annotationStorage?.get(this.data.id)?.rotation; if (rotation === undefined) { diff --git a/src/core/document.js b/src/core/document.js index b8b3e3d7e..3909fea38 100644 --- a/src/core/document.js +++ b/src/core/document.js @@ -556,7 +556,8 @@ class Page { for (const annotation of annotations) { if ( intentAny || - (intentDisplay && annotation.mustBeViewed(annotationStorage)) || + (intentDisplay && + annotation.mustBeViewed(annotationStorage, renderForms)) || (intentPrint && annotation.mustBePrinted(annotationStorage)) ) { opListPromises.push( diff --git a/src/display/annotation_layer.js b/src/display/annotation_layer.js index 65d276263..bb341e6fd 100644 --- a/src/display/annotation_layer.js +++ b/src/display/annotation_layer.js @@ -342,24 +342,27 @@ class AnnotationElement { return shadow(this, "_commonActions", { display: event => { - const hidden = event.detail.display % 2 === 1; + const { display } = event.detail; + // See scripting/constants.js for the values of `Display`. + // 0 = visible, 1 = hidden, 2 = noPrint and 3 = noView. + const hidden = display % 2 === 1; this.container.style.visibility = hidden ? "hidden" : "visible"; this.annotationStorage.setValue(this.data.id, { - hidden, - print: event.detail.display === 0 || event.detail.display === 3, + noView: hidden, + noPrint: display === 1 || display === 2, }); }, print: event => { this.annotationStorage.setValue(this.data.id, { - print: event.detail.print, + noPrint: !event.detail.print, }); }, hidden: event => { - this.container.style.visibility = event.detail.hidden - ? "hidden" - : "visible"; + const { hidden } = event.detail; + this.container.style.visibility = hidden ? "hidden" : "visible"; this.annotationStorage.setValue(this.data.id, { - hidden: event.detail.hidden, + noPrint: hidden, + noView: hidden, }); }, focus: event => { diff --git a/test/integration/scripting_spec.js b/test/integration/scripting_spec.js index 887d8b7e7..d1e84fff5 100644 --- a/test/integration/scripting_spec.js +++ b/test/integration/scripting_spec.js @@ -2042,4 +2042,60 @@ describe("Interaction", () => { ); }); }); + + describe("in annotation_hidden_noview.pdf", () => { + let pages; + + beforeAll(async () => { + pages = await loadAndWait( + "annotation_hidden_noview.pdf", + getSelector("11R") + ); + }); + + afterAll(async () => { + await closePages(pages); + }); + + it("must check that invisible fields are made visible", async () => { + await Promise.all( + pages.map(async ([browserName, page]) => { + await page.waitForFunction( + "window.PDFViewerApplication.scriptingReady === true" + ); + + let visibility = await page.$eval( + getSelector("7R"), + el => getComputedStyle(el).visibility + ); + expect(visibility).withContext(`In ${browserName}`).toEqual("hidden"); + + visibility = await page.$eval( + getSelector("8R"), + el => getComputedStyle(el).visibility + ); + expect(visibility).withContext(`In ${browserName}`).toEqual("hidden"); + + await page.click(getSelector("11R")); + await page.waitForTimeout(10); + + visibility = await page.$eval( + getSelector("7R"), + el => getComputedStyle(el).visibility + ); + expect(visibility) + .withContext(`In ${browserName}`) + .toEqual("visible"); + + visibility = await page.$eval( + getSelector("8R"), + el => getComputedStyle(el).visibility + ); + expect(visibility) + .withContext(`In ${browserName}`) + .toEqual("visible"); + }) + ); + }); + }); }); diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore index 3bbc3766c..a396de778 100644 --- a/test/pdfs/.gitignore +++ b/test/pdfs/.gitignore @@ -606,3 +606,6 @@ !issue16633.pdf !bug1844576.pdf !bug1844583.pdf +!annotation_hidden_print.pdf +!annotation_hidden_noview.pdf +!widget_hidden_print.pdf diff --git a/test/pdfs/annotation_hidden_noview.pdf b/test/pdfs/annotation_hidden_noview.pdf new file mode 100644 index 0000000000000000000000000000000000000000..9475158b6c391bee87eb2fcd1b4d6f71fe906be6 GIT binary patch literal 12114 zcmeHNO>87b6}C44qJdQo5hxIXN=8c@*qQ#D?w%g(iN+o~@n*etY;U|-XAd>qHRImx znV#*RwY_H!+~CB4BN75}fp9|Nkbr^&QBVMpaO1#*OC*kwI3T{NuKuw-F;-Y{!M3`m ze%^ca>Z{-PUSHYlt=6@MRlD-$M?d&iO(QA^`*&*#3qCArWP1EEZb@GmyPNkk5t@la$i1A3ub6hSs0?oJ0X3SDjxJzE`IgK`W` zc4s$?0#9_u_%Hg?YUmp9vs%rDjzQ23Q9x|f68SUwqfhCN)JgVdiN;KfznDZU@m*S( zH*%6FH|Pj!T+E0PI}Q{UZ-$qUA!YXb!GJ|<>|&SL<3K6>h&_M+mqy_jKYrwW?(kLATG(|2PhGTY*C=s8(O5z6|BLc<((P}0miKxd$Gy(zx z9}oI)Jr0EC8!MQ=63W*+A4rRi-Ihf_G+=QIra&@;&?%O+53^ql+lsQ1Vw2RYCPpNU z_;?*52T1!-c#nSi?v(!zo^(&(kyQ3js_d}0Qm`tk6 zJU<99XE9q!CTKUJv77R93w-DVs_&;X0+&ed(*Wv;reraWHwWG5X7fqu%67Ze$=c1P zq0%iO>1Ok@i!oU)bXk!?R-}-Xs*shEc}>!-NxHQv-C9Yvg40sDAsgS2OdFDEqsp|A z6P3)PG)VkOa72_1IUjCH2{)yLn^g%nOU~D1{myUtTKf; zQOWH24}7k4C_zdke=7OYDt}t?9m#rZ1{|cLq6XV?wlx+;_~aS+@drtLDGadii~gTHP0+`4oF><{$vn>JRes-i zeSS_H({rys-|+l+63`>ENMx$ocYz`pr6vptB^XkD|LPQ7mp?7HgqP0#ClEk|>6xfR}uT=b-!+oT_h z&oQD3vz&5mD23^Q9vm;2LivD2F#zmf&6L!6p`>3>_$scf>TJsprPwpDUn#|gRhhlT zQh)S`vLlaPb|LYikphbIBrf1O4@w2i1zZIb=Sf_^bsm%onhUrJD9)3(fa^Rc6*OnT zRVz&%m{W^$2QX+(+g053&F!kpU_Kcq;O?ax1kRraDO_S8mqCvmA8s`=zZB5%J;Ea(+_uiV z+1$w~E&5xp-9}S3JV|3XBZVPNlo!LDaJo&&-Ro!e-GrO25+X4xJ?HV4z7!5%%LCW=_2v!_(`A zuZesn$}p>18Qaqgd}quVvdMjGi+k?#7%j$9+2xZI0XdB$zcwC(*o(zl+zJsR%R+w2 zw*Qb39)(%!k-Y_1ZJJHXbWGjSo3`pWrsGj-(Dyt|XAadn3!39O4q~_#wfY8Y+0@ZB z+cPX?IE-oowIhOva+jaM-|Wnjc;cB$_@ABK!~1dm%;LF(=P^8woK zgRkan_uMq53vXcN4Q#cw7CvhzJb4wrVR>KspLhdLY4ZQ-4Q%#ZQ?=beT{Rr7ZrM$v zPN`+o@nM4HQMF|mo_*mBEX;~enkc9DCzWsxzKcfA0a8hF0auB|IZ_vJodcwj^yO1}RU$4!xXvez-|hb^ItN{66^NSGaxl zj3z!=v2A=1gKvHDL7-vd+ZKFTY`64A%Qo*6?w`HyuBv}veDK&$?B@G_{^<7`zf#}&?XUlEX*{#Je9e!(e&eYRKb*PrxtYJc z_qD|-U`zia??k3JJYl04x#ciON8^|n$|gSE^IiUJwWb4;DSch*?JX>yw)cBoYjvsD z)ASXm3wyt-8_gvXzJONCZmw!Zx2xLAO^j5}?%Au(O6Lw-3m!Y%GlXM_I~;fl9tEA( ze{rwVw#-~TTCrxO0=?YEwJ_wBcS hap~LNx%BwcGtd6;vCY#c6{i1XO|zZWWnueY{x{R{9AN+e literal 0 HcmV?d00001 diff --git a/test/pdfs/annotation_hidden_print.pdf b/test/pdfs/annotation_hidden_print.pdf new file mode 100644 index 0000000000000000000000000000000000000000..827a9320b15961f52555ffd3dce60c1b16673dc2 GIT binary patch literal 6539 zcmeHLO>f)C8MagOP+{Bcp@;T1P!X&bt;qS{%y0x*3&&okZllDo4J2)l14UAfVu=(a z3Rd!S`Zs#mpVS@-^imXkUVcb&tnI=;_hu!OIh=XFo_XJgdgtl+$!SM;ruFo@fBp48 zEx|a;haXzK9`grj5hYO(u>cP*nEz^7OvYKdV5S$Eo3Rr{iqL`=Aw51p?T{*_680XnZ zRHW?Sq${~p+$t`t)PedPmtS%I)z>gj>+(4}IEv@_Fe=#jJZDmQ%7cW^STV?x9ZD?c z8zqoQmT~$&v{cd6KGty(NDXqA%VAN%@n-OX`Bl_wG@H1UuzV}j-Z!gR6yKx;8>ZLe z?6Cd!zkSzc4UWu%fg0m=)2g zlP!K*DQWbaq>Feyp3&Aa(i;u)WpUVUlcDve4s1GG8_E`58Kf8IQ-2lBeBp6_mrxR~ zWoFCyq;xHb{dAH})2vuPPVAHerh~y+bf>xLbf@HO3y(W;n1DIuuK_@OJ=p0YBgdnU zl$3n}zr$@u@hf4w(ss+V#COmCY~==^Qb(Eh=`J0*Th_-~$JWZvbTkRNOUpe^YHBFg zex|3c!K*x<^mmtG70vd#Efq=J9p&?BRP>|SY%-3^y7z%z&)-aKtuME#dy>aX+S0R= z{&G1^x?vhfITE}xie-vS4rC{k)^vtE4PzJUkqn2W8-u~N>^;3_*`kQDIBoO}1DQ&h z4m+vix)ZrTb(~6cCpJ-}BdJ|55{=$1*)6?@q}wpe_u_MBQ7zo_sY13YrYgtsDe4hi z;IGM`oLU#qk9D(&>c_GGy^ls71nwhTk8nK*fd?&q%&tec9)!Sy7C&a!{|&Czrky~4 za@f8_vw)ksEsNf2S$4N(MpJ91n$}F{t%ilVK+CjYA$mYvwQ2b>D>j{+#R~L|FCuhx z^?hxo=_JueQKxwX9p%#VXpSFoO@nzgE+%OAo=u|chEccqHJK-Y6ZVz~>Q$ls&7c25 zo;b;}2zcND9iE!9W=UJ3gmd6&z|Kg(x;SOeXZ}TAP&bWmH%`}(k%Qug8+TzOVTJa+>fEIz z`8vnSs6@a7(nBLdgkkhwNZCSw)sX@wDDrnz5}cD~bP`bI3iH7(=~w%nI%W4nyT} zqcD^hQaqs-@DO9|3G9t<+T$TDw_d0mHPBvwzgC2v<`!f0*%Cwiv4%-uyui@3!L(u$ zrxSpoF)pRW5Yt>BGL30CrH}~@%LKG5JXeMp^2$NGl28*cW0hxvpqv*bWX50~2P;y- zTc?@Pfv50XBBO#(G80&jlRk<;Ne z%3#cv$Z5}#bCw{%G(sic!T?IJ9GMwlbJwxdNEwG1*Pd9e5IH=nBexvV7Lf+<)B$%O zBVa^o;0s$0(;7e->p7&A3E=})+rZNlx3!+t5@Sr4u3=LNb~^JYT?Z~OW<$@At5B*+ zaqB_j1~x<_kpxBqCI{ny8_gbo0Zd>XsDe3cQviAL#tP3#0^=$)=UX4x!Fig+;|Ub5kGoJ-U=wx_ zN0adi6BV(PG)K%p<$Vf$I7*zQ85>2D1&$0Go~ln7YcDD?!xok`8KPQ1ZFPlK9u(yX zTNT1CORpKp>?C0#n1+O()s*|gQJ>;iqKpV^Gl+`$xTI>>*rugU17D}X58mG4UjN%w z@%*ynUIOHTm$Y|ucG&=Oht?_xHzIxxx;aw+!*nq zstuKZ=AH~}MP(ds8c-dIg9up=&nS&271@y#UfPN%C&X!UKra&QDZDVeX43xPG$#tAFn8|9ZZ69|IgJ&WqJN9kmSJW38u8zkPMu`Y*S+TBra3 literal 0 HcmV?d00001 diff --git a/test/pdfs/widget_hidden_print.pdf b/test/pdfs/widget_hidden_print.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ef9ebe4609dbd39502b68394d7b3fd85fc9c69c6 GIT binary patch literal 6995 zcmeHM%W~tm6}3CFNNE50$5cPI%4&mNQ}+WyNuk$5FyFVp?Uz37gB3Tb8Cb zOHSxMG-5F)ySpu(1k$z?Uim0xj%V-B@&%zUcrwo~h}m-peMwA052G~8i6fP>JmqZB zvWcOB+eaynL^5VMCtKs8WmvY+w>-;qY^VQ6!}`iFzIq1tQck2~OZH~Qa&nRiV%c50 z3k|aeiHQi-7#Wzo+6Z)l!snl{Qua>AsQc;sXg~X|B|F+%b<`R(dMZ(OiD{dpPfW)o z17bS{@rYyD3W4#6Y|*cI{1I}~5I=K*-i%L)9J_nc*)EuIl^l(b(^cth_jWi^ko)Amt*(vvPI5!7&*B$gp&-S`~r$=mCmt9kpza#Xl znB^+#&ZA(?bC@JsQ+}Pha8st*C`knB?*@SmN!a#S#uX?ESe{2dYhYP+jlN_HZMHAYk)3GFRV& zSxhL;m_syoa%X3qr$``Equ_ViCp4LCix~tBPqfzd(5rB?as(d758{ zB4bIQgMywX~6^EZ_^40)a5Xg+9EK~5OxMAP6sa7q877WV~;0^dZ<%nn*7n#N~ zzY1r(E9=b6q^NEhM-%&GJM`aq)Q4Ptc%+C?VWWS2#KpQ#GMh==r z4r=8iEqA2lj+$~uwcG*T5cH*Xeyo*_wbF4@>3AhnD=&&TkCyQbp~pHOUTF)jw1rnq z3$JR;H@ba#AyPRnc)CEg&thah(`2Q+S}tnJMYSB4FeTc#&`LrpiKdcR3DwF$^f8h_3k_1C^$V?EH1&&G??$&{ zF_0kLR4rJW%cZe;3$1%&s*S~JYf!D_uO}~7+SL|hwN=17pt(EPetx}V{w3DE875n@ z)Be}rzi*Q$*lC~lCdOpB&o82{Kc)Qa)61#<>C*Rt_H(TK*Td_@a)Ip)xn9IcHoV?x zGi+7(5YMujwuutSFL&A_*+5=TPRPDUvFdisj&B%vNqb$38Nnd%{)88oWmChZrqeOa zq3I1Bm*~ItZVOM_STKgC<3sHarJeRgo-c=#UR_;vuk5Z!=hXB(j~W)WtPUhP*-etO z>rRsWzBID3Gv=9}MoYC`OS^0)ihQTtmX4}F-Lb{8a+G9U)yb|e7WA4eso6E?I;Fs` zbe2ULtIz@;ZxO!0%9BCQT&o96CzDEbt-Hlyt>&_U$1OcHz@5ETi3JzJzp8<}rKop* zBPoM@$0c5LS7nFQc$6@0BjO>pgHd=RcZ9og7&}J4V|i1{96E!c+7k{9W1HTQtf5vm z)TWcKvtbX_=CrcWki27KmFnxP+>1o-%$4jNJ9+~=6(ZhUzXvXR)0AtN2>fA)GXTqX z*>V}VwV9{QnabWFbwJelKlJlE-W%o!UD zLem>?zpuiWOq#m)>>edq&ajnQ+4Ws+_=5rOuznbHLf5f6IHK^5=a|0Z`L2c5mEDGJ z!!CLl5z$AhXb0n zqUc@ICcOcONU*R75{ZOMGE^)ETo&-(9!|NSBVpkeP2lW*BF9E0%#mksKn zpn7o zcyF>#S|9KY1OLuI=1a<3=dGl*H*J-Cts9@u!?FGx&H8CGyuJqFV_9|-R+)ldiH>M%yfIEyoA2=Zg}gR#J;C)eTwiSd{I46EzxpTYzmyl+ zzI?Lz>wn-Gy1!w#{}T8AZfyScIj;X~Z2s;K8~2AF2fsAGPI=gJU2o8O`t;!Vu=Rf( CM7M4L literal 0 HcmV?d00001 diff --git a/test/test_manifest.json b/test/test_manifest.json index 89cfbb913..dbff94481 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -3420,7 +3420,7 @@ "print": true, "annotationStorage": { "427R": { - "hidden": false, + "noPrint": false, "value": "hello world" } } @@ -8054,5 +8054,21 @@ "rotation": 0 } } + }, + { + "id": "widget_hidden_print", + "file": "pdfs/widget_hidden_print.pdf", + "md5": "0b8d5a8e8c7c7598232a79044c312cbb", + "rounds": 1, + "type": "eq", + "print": true + }, + { + "id": "annotation_hidden_print", + "file": "pdfs/annotation_hidden_print.pdf", + "md5": "5cfa86df9b080feeb4aa320ad68d6cbd", + "rounds": 1, + "type": "eq", + "print": true } ]