[{"data":1,"prerenderedAt":4475},["ShallowReactive",2],{"navigation_docs":3,"-use-cases-performance-report":139,"-use-cases-performance-report-surround":4470},[4,55,89],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":54},"API","i-lucide-braces","\u002Fapi","api",[10,14,18,22,26,30,34,38,42,46,50],{"title":11,"path":12,"stem":13},"Html2Pdf Component","\u002Fapi\u002Fcomponent","api\u002F01.component",{"title":15,"path":16,"stem":17},"Core Props","\u002Fapi\u002Fprops","api\u002F02.props",{"title":19,"path":20,"stem":21},"Headers","\u002Fapi\u002Fheaders","api\u002F03.headers",{"title":23,"path":24,"stem":25},"Footers","\u002Fapi\u002Ffooters","api\u002F04.footers",{"title":27,"path":28,"stem":29},"Security","\u002Fapi\u002Fsecurity","api\u002F05.security",{"title":31,"path":32,"stem":33},"Watermarks","\u002Fapi\u002Fwatermarks","api\u002F06.watermarks",{"title":35,"path":36,"stem":37},"Metadata & Compression","\u002Fapi\u002Fmetadata-compression","api\u002F07.metadata-compression",{"title":39,"path":40,"stem":41},"Programmatic API","\u002Fapi\u002Fprogrammatic-api","api\u002F08.programmatic-api",{"title":43,"path":44,"stem":45},"Loader, Progress, Events & Slots","\u002Fapi\u002Fevents-slots","api\u002F09.events-slots",{"title":47,"path":48,"stem":49},"TypeScript","\u002Fapi\u002Ftypescript","api\u002F10.typescript",{"title":51,"path":52,"stem":53},"Full README Reference","\u002Fapi\u002Ffull-reference","api\u002F11.full-reference",false,{"title":56,"icon":57,"path":58,"stem":59,"children":60,"page":54},"Get Started","i-lucide-book-open","\u002Fget-started","get-started",[61,65,69,73,77,81,85],{"title":62,"path":63,"stem":64},"Introduction","\u002Fget-started\u002Fintroduction","get-started\u002F01.introduction",{"title":66,"path":67,"stem":68},"Installation","\u002Fget-started\u002Finstallation","get-started\u002F02.installation",{"title":70,"path":71,"stem":72},"Quick Start","\u002Fget-started\u002Fquick-start","get-started\u002F03.quick-start",{"title":74,"path":75,"stem":76},"Rendering Modes","\u002Fget-started\u002Frendering-modes","get-started\u002F04.rendering-modes",{"title":78,"path":79,"stem":80},"Component Registration","\u002Fget-started\u002Fregistration","get-started\u002F05.registration",{"title":82,"path":83,"stem":84},"Preview & Download","\u002Fget-started\u002Fpreview-download","get-started\u002F06.preview-download",{"title":86,"path":87,"stem":88},"Pagination","\u002Fget-started\u002Fpagination","get-started\u002F07.pagination",{"title":90,"icon":91,"path":92,"stem":93,"children":94,"page":54},"Use Cases","i-lucide-flask-conical","\u002Fuse-cases","use-cases",[95,99,103,107,111,115,119,123,127,131,135],{"title":96,"path":97,"stem":98},"Playground","\u002Fuse-cases\u002Fplayground","use-cases\u002F01.playground",{"title":100,"path":101,"stem":102},"Selectable Text","\u002Fuse-cases\u002Fselectable-text","use-cases\u002F02.selectable-text",{"title":104,"path":105,"stem":106},"Clickable PDF Links","\u002Fuse-cases\u002Fclickable-links","use-cases\u002F03.clickable-links",{"title":108,"path":109,"stem":110},"Images & CORS","\u002Fuse-cases\u002Fimages-cors","use-cases\u002F04.images-cors",{"title":112,"path":113,"stem":114},"Production Guide","\u002Fuse-cases\u002Fproduction-guide","use-cases\u002F05.production-guide",{"title":116,"path":117,"stem":118},"Troubleshooting","\u002Fuse-cases\u002Ftroubleshooting","use-cases\u002F06.troubleshooting",{"title":120,"path":121,"stem":122},"Testing & Browser Support","\u002Fuse-cases\u002Ftesting-browser-support","use-cases\u002F07.testing-browser-support",{"title":124,"path":125,"stem":126},"Performance Engineering","\u002Fuse-cases\u002Fperformance-engineering","use-cases\u002F08.performance-engineering",{"title":128,"path":129,"stem":130},"Full Performance Engineering Report","\u002Fuse-cases\u002Fperformance-report","use-cases\u002F09.performance-report",{"title":132,"path":133,"stem":134},"Community & Feedback","\u002Fuse-cases\u002Fcommunity","use-cases\u002F10.community",{"title":136,"path":137,"stem":138},"Acknowledgements","\u002Fuse-cases\u002Facknowledgements","use-cases\u002F11.acknowledgements",{"id":140,"title":128,"body":141,"description":430,"extension":4463,"links":4464,"meta":4465,"navigation":4466,"path":129,"seo":4467,"stem":130,"__hash__":4469},"docs\u002Fuse-cases\u002F09.performance-report.md",{"type":142,"value":143,"toc":4375},"minimark",[144,149,183,186,191,197,200,253,256,261,264,273,276,281,283,287,290,360,363,372,375,377,381,384,420,423,433,436,439,483,486,488,492,495,498,543,546,549,555,559,562,565,571,574,577,579,583,586,589,595,598,600,604,608,611,670,673,676,682,685,688,692,695,701,704,707,713,717,720,831,834,840,847,851,871,874,876,880,883,886,892,896,899,913,916,920,923,926,929,931,935,938,964,968,1029,1034,1037,1058,1061,1064,1068,1071,1074,1080,1083,1086,1088,1092,1095,1171,1174,1177,1182,1185,1187,1191,1194,1197,1203,1206,1209,1212,1215,1221,1225,1228,1231,1234,1245,1247,1251,1254,1257,1328,1331,1334,1338,1341,1347,1350,1356,1359,1365,1367,1371,1374,1377,1380,1389,1392,1395,1397,1401,1404,1408,1411,1417,1420,1426,1429,1435,1438,1442,1445,1451,1455,1458,1464,1467,1479,1482,1485,1502,1505,1509,1512,1518,1521,1525,1528,1652,1655,1658,1660,1664,1667,1670,1676,1679,1683,1686,1693,1696,1704,1706,1710,1713,1716,1720,1766,1769,1788,1792,1836,1839,1843,1846,1849,1856,1859,1862,1875,1877,1881,1884,1887,1920,1924,1927,1944,1947,1951,1954,1971,1975,1978,1981,1987,1990,1994,2005,2007,2011,2014,2017,2096,2099,2105,2108,2114,2117,2119,2123,2126,2129,2142,2145,2148,2151,2190,2194,2197,2211,2214,2216,2220,2223,2240,2243,2246,2250,2256,2260,2263,2266,2274,2280,2287,2291,2294,2300,2303,2309,2312,2318,2322,2325,2385,2388,2391,2405,2407,2411,2414,2420,2426,2429,2435,2439,2446,2449,2483,2486,2489,2500,2502,2506,2509,2512,2530,2533,2549,2555,2558,2564,2567,2571,2574,2580,2583,2587,2590,2596,2600,2603,2609,2612,2615,2626,2628,2632,2635,2910,2913,2919,2922,2928,2931,2933,2937,2940,2942,2948,2951,2954,2957,2959,2963,2966,2972,2975,2981,2984,2990,2993,2996,3013,3016,3018,3022,3028,3044,3047,3053,3055,3061,3075,3078,3083,3085,3091,3105,3108,3113,3115,3121,3135,3138,3143,3145,3151,3165,3168,3173,3175,3181,3195,3198,3203,3205,3211,3214,3216,3222,3236,3239,3244,3246,3252,3255,3257,3263,3277,3280,3288,3290,3296,3299,3304,3306,3312,3315,3320,3322,3328,3330,3338,3340,3346,3349,3354,3356,3362,3365,3367,3373,3387,3390,3395,3397,3403,3406,3411,3413,3419,3422,3427,3429,3435,3438,3443,3445,3449,3452,3456,3460,3463,3469,3472,3478,3480,3484,3487,3493,3496,3502,3504,3508,3511,3513,3517,3520,3548,3550,3554,3557,3559,3563,3569,3571,3575,3578,3580,3584,3587,3589,3593,3596,3598,3602,3609,3611,3615,3618,3620,3624,3629,3631,3635,3839,3842,3844,3848,3851,3855,3860,3864,3869,3873,3878,3882,3887,3891,3896,3900,3905,3909,3914,3918,3923,3925,3929,3932,3938,3941,3944,3964,3971,3973,3977,3981,3992,3995,4019,4023,4037,4041,4044,4046,4050,4053,4058,4061,4067,4070,4076,4079,4085,4088,4091,4117,4123,4125,4129,4275,4277,4281,4284,4287,4297,4300,4317,4319,4323,4326,4340,4343,4346,4349,4361,4364,4366,4371],[145,146,148],"h1",{"id":147},"vue-pdf-export-large-document-performance-engineering-report","vue-pdf-export - Large Document Performance Engineering Report",[150,151,152],"blockquote",{},[153,154,155,159,160,163,166,167,171,173,176,177,179,182],"p",{},[156,157,158],"strong",{},"Maintainer:"," Saurabh Choudhary",[161,162],"br",{},[156,164,165],{},"Package:"," ",[168,169,170],"code",{},"vue-pdf-export",[161,172],{},[156,174,175],{},"Milestone covered:"," Large-document performance, memory behavior, reliability, cancellation, progress, image reuse, cleanup, and regression hardening",[161,178],{},[156,180,181],{},"Primary target:"," 50–100+ page browser-generated PDFs with images, headers, footers, watermarks, links, metadata, compression, and password protection",[184,185],"hr",{},[187,188,190],"h2",{"id":189},"executive-summary","Executive summary",[153,192,193,194,196],{},"The performance work changed ",[168,195,170],{}," in a meaningful way. This was not only a benchmark exercise.",[153,198,199],{},"The project moved from a package that mainly depended on whole-document HTML-to-canvas behavior to one with explicit large-document engineering:",[201,202,203,207,210,213,216,226,229,232,235,238,241,244,247,250],"ul",{},[204,205,206],"li",{},"page-by-page Canvas rendering for paginated documents",[204,208,209],{},"real 50-page and 100-page Canvas correctness regression coverage",[204,211,212],{},"static HTML footer reuse instead of rasterizing the same footer on every page",[204,214,215],{},"page-level cancellation and recovery",[204,217,218,221,222,225],{},[168,219,220],{},"currentPage"," \u002F ",[168,223,224],{},"totalPages"," progress",[204,227,228],{},"cooperative browser yielding during long generation",[204,230,231],{},"shorter lifetime for temporary DOM, canvas and encoded image data",[204,233,234],{},"repeated-image caching in selectable-text mode",[204,236,237],{},"detailed stress telemetry for actual page count, Blob size and canvas dimensions",[204,239,240],{},"fresh-context and same-page memory isolation",[204,242,243],{},"a reproducible security + raster memory-retention investigation",[204,245,246],{},"a raw jsPDF reproduction proving the strongest encrypted-raster retention pattern is not explained only by the Vue component lifecycle",[204,248,249],{},"an upstream jsPDF issue filed for the dependency-level behavior",[204,251,252],{},"expanded Playwright regression coverage for large documents and cleanup",[153,254,255],{},"The biggest user-visible result is simple:",[150,257,258],{},[153,259,260],{},"50-page and 100-page Canvas exports are now verified as real, non-empty PDFs on the incremental page-by-page path instead of relying on one giant whole-document canvas.",[153,262,263],{},"The biggest architecture result is:",[150,265,266],{},[153,267,268,269,272],{},"For Canvas documents with ",[168,270,271],{},".html2pdf__page-break"," markers, peak capture geometry is page-bounded instead of document-height-bounded.",[153,274,275],{},"The biggest diagnostic result is:",[150,277,278],{},[153,279,280],{},"Large encrypted raster PDFs remain a higher-memory workload because jsPDF encryption retains substantially more raster-related memory in Chromium. The behavior was reproduced with raw jsPDF and is tracked upstream rather than mislabeled as a Vue memory leak.",[184,282],{},[145,284,286],{"id":285},"_1-evidence-reviewed-for-this-report","1. Evidence reviewed for this report",[153,288,289],{},"This report is based on the complete performance material supplied for this milestone, including:",[201,291,292,299,302,305,312,315,318,321,324,327,330,333,336,339,342,345,348,351,354,357],{},[204,293,294,295,298],{},"the full ",[168,296,297],{},"performance:everything"," terminal run",[204,300,301],{},"the historical project\u002Fperformance discussion and implementation record",[204,303,304],{},"Phase 2.2 \u002F 2.3 \u002F 2.4 benchmark logs",[204,306,307,308,311],{},"both ",[168,309,310],{},"benchmark-results"," archives",[204,313,314],{},"the latest and historical JSON benchmark output",[204,316,317],{},"Canvas bottleneck isolation results",[204,319,320],{},"general stress benchmark results",[204,322,323],{},"Phase 2.2 fresh-context memory isolation",[204,325,326],{},"Phase 2.3A security isolation",[204,328,329],{},"Phase 2.3B large Canvas correctness",[204,331,332],{},"Phase 2.4A security payload scaling",[204,334,335],{},"Phase 2.4B Canvas-threshold diagnostics",[204,337,338],{},"Phase 3.2 incremental Canvas + security re-test data",[204,340,341],{},"Phase 3.2 same-page protected repeat data",[204,343,344],{},"Phase 3.2.1 raw jsPDF reproduction data",[204,346,347],{},"Phase 3.3 cancellation\u002Frecovery results",[204,349,350],{},"Phase 3.4A selectable-image-cache regression",[204,352,353],{},"Phase 3.4B Canvas cleanup\u002Fimage-heavy regression",[204,355,356],{},"Phase 3.5 long-Canvas routing regression and final 50\u002F100-page fix",[204,358,359],{},"final unit, build and Playwright release-gate results",[153,361,362],{},"Where a percentage is shown below, it is either:",[364,365,366,369],"ol",{},[204,367,368],{},"calculated from a directly comparable before\u002Fafter benchmark pair, or",[204,370,371],{},"explicitly labeled as a ratio\u002Fcomparison rather than an overall package speedup.",[153,373,374],{},"No unsupported “overall package is X% faster” claim is made.",[184,376],{},[145,378,380],{"id":379},"_2-original-problem","2. Original problem",[153,382,383],{},"Browser-side PDF generation becomes difficult when a document combines:",[201,385,386,389,392,395,402,405,408,411,414,417],{},[204,387,388],{},"many pages",[204,390,391],{},"rasterized HTML",[204,393,394],{},"large decoded images",[204,396,397,398,401],{},"high ",[168,399,400],{},"html2canvas"," scale",[204,403,404],{},"repeated headers\u002Ffooters",[204,406,407],{},"watermarks",[204,409,410],{},"password encryption",[204,412,413],{},"compression",[204,415,416],{},"preview Blob URLs",[204,418,419],{},"repeated generation in the same browser session",[153,421,422],{},"For a Canvas workflow, a rough pipeline is:",[424,425,431],"pre",{"className":426,"code":428,"language":429,"meta":430},[427],"language-text","Vue DOM\n→ browser layout\n→ html2canvas\n→ raster image\n→ jsPDF\n→ PDF Blob\n","text","",[168,432,428],{"__ignoreMap":430},[153,434,435],{},"A 100-page document is therefore fundamentally different from a two-page invoice.",[153,437,438],{},"The original engineering goals were:",[201,440,441,444,447,450,453,456,459,462,465,468,471,474,477,480],{},[204,442,443],{},"benchmark 10 \u002F 25 \u002F 50 \u002F 100 pages",[204,445,446],{},"measure generation time and output size",[204,448,449],{},"measure peak and retained browser heap",[204,451,452],{},"distinguish high peak memory from a real leak",[204,454,455],{},"identify the actual bottleneck instead of guessing",[204,457,458],{},"reduce Canvas peak memory",[204,460,461],{},"investigate page-by-page rendering",[204,463,464],{},"improve repeated-image handling",[204,466,467],{},"add cancellation",[204,469,470],{},"add current-page progress",[204,472,473],{},"improve UI responsiveness during long work",[204,475,476],{},"test cleanup after generation\u002Fcancellation",[204,478,479],{},"stress-test complex feature combinations",[204,481,482],{},"build repeatable regression coverage",[153,484,485],{},"Most of those goals are now implemented or covered by repeatable tests.",[184,487],{},[145,489,491],{"id":490},"_3-phase-1-benchmark-and-stress-foundation","3. Phase 1 - benchmark and stress foundation",[153,493,494],{},"The first step was measurement, not optimization.",[153,496,497],{},"The project added a stress harness capable of exercising:",[201,499,500,503,506,509,512,515,518,521,524,527,530,532,535,537,540],{},[204,501,502],{},"Canvas mode",[204,504,505],{},"selectable-text mode",[204,507,508],{},"text-heavy content",[204,510,511],{},"mixed content",[204,513,514],{},"image-heavy content",[204,516,517],{},"multiple page counts",[204,519,520],{},"different Canvas quality levels",[204,522,523],{},"security on\u002Foff",[204,525,526],{},"headers",[204,528,529],{},"footers",[204,531,407],{},[204,533,534],{},"metadata",[204,536,413],{},[204,538,539],{},"links",[204,541,542],{},"logos",[153,544,545],{},"The harness records more than “did the Promise resolve?”",[153,547,548],{},"It can observe:",[424,550,553],{"className":551,"code":552,"language":429,"meta":430},[427],"requested pages\nactual PDF pages\nBlob size\ngeneration duration\nDOM nodes\nimage count\nmanual break count\ntoDataURL calls\nlargest canvas width\nlargest canvas height\nlargest canvas pixel area\nprogress stage\ncurrent page\ntotal pages\nsuccess\u002Fcancelled state\n",[168,554,552],{"__ignoreMap":430},[187,556,558],{"id":557},"why-this-mattered","Why this mattered",[153,560,561],{},"A long PDF can “succeed” while still being wrong.",[153,563,564],{},"For example:",[424,566,569],{"className":567,"code":568,"language":429,"meta":430},[427],"requested = 50 pages\nactual PDF page objects = 50\nBlob size = ~42 KB\n",[168,570,568],{"__ignoreMap":430},[153,572,573],{},"That is technically a returned Blob, but it is clearly not a healthy 50-page raster PDF.",[153,575,576],{},"The telemetry therefore became a correctness tool, not only a benchmark tool.",[184,578],{},[145,580,582],{"id":581},"_4-phase-2-bottleneck-isolation","4. Phase 2 - bottleneck isolation",[153,584,585],{},"Instead of optimizing everything at once, major features were isolated.",[153,587,588],{},"The Canvas isolation matrix included:",[424,590,593],{"className":591,"code":592,"language":429,"meta":430},[427],"minimal text\nimages only\nheader without logo\nheader with logo\nfooter text\nfooter HTML\nfooter HTML + logo\nsingle watermark\nrepeated watermark\nmetadata\nsecurity\ncompression\nlinks\nall features without images\nall features mixed\n",[168,594,592],{"__ignoreMap":430},[153,596,597],{},"This immediately found the first real performance bug.",[184,599],{},[145,601,603],{"id":602},"_5-phase-21-static-html-footer-optimization","5. Phase 2.1 - static HTML footer optimization",[187,605,607],{"id":606},"problem-discovered","Problem discovered",[153,609,610],{},"The pre-optimization 25-page Canvas benchmark showed:",[612,613,614,628],"table",{},[615,616,617],"thead",{},[618,619,620,624],"tr",{},[621,622,623],"th",{},"Scenario",[621,625,627],{"align":626},"right","Before",[629,630,631,640,650,660],"tbody",{},[618,632,633,637],{},[634,635,636],"td",{},"Footer text",[634,638,639],{"align":626},"~1.10 s",[618,641,642,645],{},[634,643,644],{},"HTML footer, no logo",[634,646,647],{"align":626},[156,648,649],{},"7.82 s",[618,651,652,655],{},[634,653,654],{},"HTML footer + logo",[634,656,657],{"align":626},[156,658,659],{},"11.81 s",[618,661,662,665],{},[634,663,664],{},"HTML-footer PDF size",[634,666,667],{"align":626},[156,668,669],{},"~46.7 MB",[153,671,672],{},"The reason was repeated rasterization.",[153,674,675],{},"The old behavior was effectively:",[424,677,680],{"className":678,"code":679,"language":429,"meta":430},[427],"Page 1 footer → html2canvas → PNG\nPage 2 footer → html2canvas → PNG\nPage 3 footer → html2canvas → PNG\n...\nPage 25 footer → html2canvas → PNG\n",[168,681,679],{"__ignoreMap":430},[153,683,684],{},"The footer body was static, yet the same HTML was being rasterized repeatedly.",[153,686,687],{},"For a 100-page document this could mean rasterizing the same footer approximately 100 times.",[187,689,691],{"id":690},"change-implemented","Change implemented",[153,693,694],{},"The static HTML footer is rendered once:",[424,696,699],{"className":697,"code":698,"language":429,"meta":430},[427],"static footer HTML\n→ html2canvas once\n→ reusable PNG\n",[168,700,698],{"__ignoreMap":430},[153,702,703],{},"Then that same raster is reused across pages.",[153,705,706],{},"Dynamic page numbering remains vector\u002Ftext work:",[424,708,711],{"className":709,"code":710,"language":429,"meta":430},[427],"Page {n} of {total}\n→ jsPDF text per page\n",[168,712,710],{"__ignoreMap":430},[187,714,716],{"id":715},"measured-result","Measured result",[153,718,719],{},"Recorded before\u002Fafter benchmark:",[612,721,722,737],{},[615,723,724],{},[618,725,726,729,731,734],{},[621,727,728],{},"Metric",[621,730,627],{"align":626},[621,732,733],{"align":626},"After",[621,735,736],{"align":626},"Improvement",[629,738,739,753,767,783,799,815],{},[618,740,741,743,745,748],{},[634,742,644],{},[634,744,649],{"align":626},[634,746,747],{"align":626},"1.43 s",[634,749,750],{"align":626},[156,751,752],{},"81.7% less time \u002F 5.47× faster",[618,754,755,757,759,762],{},[634,756,654],{},[634,758,659],{"align":626},[634,760,761],{"align":626},"1.29 s",[634,763,764],{"align":626},[156,765,766],{},"89.1% less time \u002F 9.16× faster",[618,768,769,772,775,778],{},[634,770,771],{},"Footer PDF size",[634,773,774],{"align":626},"46.7 MB",[634,776,777],{"align":626},"~1.0 MB",[634,779,780],{"align":626},[156,781,782],{},"~97.9% smaller",[618,784,785,788,791,794],{},[634,786,787],{},"No-logo peak heap",[634,789,790],{"align":626},"102.6 MB",[634,792,793],{"align":626},"26.5 MB",[634,795,796],{"align":626},[156,797,798],{},"~74.2% lower",[618,800,801,804,807,810],{},[634,802,803],{},"No-logo retained heap",[634,805,806],{"align":626},"47.0 MB",[634,808,809],{"align":626},"1.0 MB",[634,811,812],{"align":626},[156,813,814],{},"~97.9% lower",[618,816,817,820,823,826],{},[634,818,819],{},"Logo peak heap",[634,821,822],{"align":626},"57.7 MB",[634,824,825],{"align":626},"13.7 MB",[634,827,828],{"align":626},[156,829,830],{},"~76.3% lower",[153,832,833],{},"A broader all-features\u002Fno-images run moved from approximately:",[424,835,838],{"className":836,"code":837,"language":429,"meta":430},[427],"12.63 s → 1.64 s\n",[168,839,837],{"__ignoreMap":430},[153,841,842,843,846],{},"which is about ",[156,844,845],{},"87.0% less generation time"," in that recorded benchmark pair.",[187,848,850],{"id":849},"what-users-gained","What users gained",[201,852,853,856,859,862,865,868],{},[204,854,855],{},"much faster repeated static footer handling",[204,857,858],{},"far smaller PDF output in that pathological footer case",[204,860,861],{},"less repeated Canvas allocation",[204,863,864],{},"less Base64\u002FPNG churn",[204,866,867],{},"dynamic page numbers preserved",[204,869,870],{},"no change to the public footer API",[153,872,873],{},"This was the first large clear performance win.",[184,875],{},[145,877,879],{"id":878},"_6-phase-22-clean-memory-isolation","6. Phase 2.2 - clean memory isolation",[153,881,882],{},"Early benchmark rows could influence one another because browser caches, native Canvas memory and garbage collection are not deterministic.",[153,884,885],{},"Phase 2.2 changed the method:",[424,887,890],{"className":888,"code":889,"language":429,"meta":430},[427],"fresh Chromium context\n→ fresh page\n→ GC\n→ run one scenario\n→ cleanup\n→ GC\n→ wait 500 ms\n→ GC\n→ wait 2 s\n→ GC\n→ close page\n",[168,891,889],{"__ignoreMap":430},[187,893,895],{"id":894},"why-this-was-important","Why this was important",[153,897,898],{},"It separated:",[201,900,901,904,907,910],{},[204,902,903],{},"high temporary memory",[204,905,906],{},"retained JS heap",[204,908,909],{},"previous-test contamination",[204,911,912],{},"actual repeatable trends",[153,914,915],{},"It also prevented the project from calling every positive heap delta a “memory leak.”",[187,917,919],{"id":918},"important-finding","Important finding",[153,921,922],{},"Normal image use was not the primary leak-like signal.",[153,924,925],{},"Representative fresh-context results showed that ordinary text\u002Fimages\u002Fheader\u002Ffooter\u002Fwatermark\u002Fcompression scenarios retained relatively modest amounts compared with the security scenarios.",[153,927,928],{},"The investigation therefore moved away from “images are the problem” and toward encryption behavior.",[184,930],{},[145,932,934],{"id":933},"_7-phase-23a-security-isolation","7. Phase 2.3A - security isolation",[153,936,937],{},"Security was split into individual variants:",[201,939,940,943,946,949,952,955,958,961],{},[204,941,942],{},"security off",[204,944,945],{},"user password only",[204,947,948],{},"user + owner password",[204,950,951],{},"print permission",[204,953,954],{},"copy permission",[204,956,957],{},"all permissions",[204,959,960],{},"Canvas text control",[204,962,963],{},"selectable-text encrypted control",[187,965,967],{"id":966},"latest-comparable-25-page-mixed-results","Latest comparable 25-page mixed results",[612,969,970,985],{},[615,971,972],{},[618,973,974,976,979,982],{},[621,975,623],{},[621,977,978],{"align":626},"Time",[621,980,981],{"align":626},"Peak increase",[621,983,984],{"align":626},"Retained after 2s + GC",[629,986,987,1001,1015],{},[618,988,989,992,995,998],{},[634,990,991],{},"Canvas mixed, security off",[634,993,994],{"align":626},"4.18 s",[634,996,997],{"align":626},"17.6 MB",[634,999,1000],{"align":626},"5.5 MB",[618,1002,1003,1006,1009,1012],{},[634,1004,1005],{},"Canvas mixed, user password",[634,1007,1008],{"align":626},"4.60 s",[634,1010,1011],{"align":626},"121.4 MB",[634,1013,1014],{"align":626},"84.1 MB",[618,1016,1017,1020,1023,1026],{},[634,1018,1019],{},"Selectable mixed, user password",[634,1021,1022],{"align":626},"2.37 s",[634,1024,1025],{"align":626},"13.3 MB",[634,1027,1028],{"align":626},"11.1 MB",[1030,1031,1033],"h3",{"id":1032},"security-overhead-in-canvas-for-this-fixture","Security overhead in Canvas for this fixture",[153,1035,1036],{},"Turning on a user password changed:",[201,1038,1039,1045,1052],{},[204,1040,1041,1042],{},"time: ",[156,1043,1044],{},"+10.0%",[204,1046,1047,1048,1051],{},"peak JS heap: ",[156,1049,1050],{},"6.9×"," the unencrypted run",[204,1053,1054,1055,1051],{},"retained heap: ",[156,1056,1057],{},"15.3×",[153,1059,1060],{},"The PDF size itself remained about the same.",[153,1062,1063],{},"That was a strong indication that the memory behavior was not caused by a larger visible document.",[187,1065,1067],{"id":1066},"permissions-were-not-the-main-culprit","Permissions were not the main culprit",[153,1069,1070],{},"User-only, owner-password and permission variants produced broadly similar high-retention behavior.",[153,1072,1073],{},"Therefore the problem was not traced to:",[424,1075,1078],{"className":1076,"code":1077,"language":429,"meta":430},[427],"permissions: ['print', 'copy']\n",[168,1079,1077],{"__ignoreMap":430},[153,1081,1082],{},"or owner-password mapping.",[153,1084,1085],{},"The trigger was already present with a basic user password.",[184,1087],{},[145,1089,1091],{"id":1090},"_8-selectable-text-mode-as-the-lower-raster-alternative","8. Selectable-text mode as the lower-raster alternative",[153,1093,1094],{},"For the comparable 25-page encrypted mixed fixture:",[612,1096,1097,1112],{},[615,1098,1099],{},[618,1100,1101,1103,1106,1109],{},[621,1102,728],{},[621,1104,1105],{"align":626},"Encrypted Canvas",[621,1107,1108],{"align":626},"Encrypted selectable text",[621,1110,1111],{"align":626},"Difference",[629,1113,1114,1127,1143,1157],{},[618,1115,1116,1118,1120,1122],{},[634,1117,978],{},[634,1119,1008],{"align":626},[634,1121,1022],{"align":626},[634,1123,1124],{"align":626},[156,1125,1126],{},"48.5% less time",[618,1128,1129,1132,1135,1138],{},[634,1130,1131],{},"PDF size",[634,1133,1134],{"align":626},"3.9 MB",[634,1136,1137],{"align":626},"0.4 MB",[634,1139,1140],{"align":626},[156,1141,1142],{},"89.7% smaller",[618,1144,1145,1148,1150,1152],{},[634,1146,1147],{},"Peak heap",[634,1149,1011],{"align":626},[634,1151,1025],{"align":626},[634,1153,1154],{"align":626},[156,1155,1156],{},"89.0% lower",[618,1158,1159,1162,1164,1166],{},[634,1160,1161],{},"Retained heap",[634,1163,1014],{"align":626},[634,1165,1028],{"align":626},[634,1167,1168],{"align":626},[156,1169,1170],{},"86.8% lower",[153,1172,1173],{},"This is not a universal renderer benchmark because Canvas and selectable-text mode produce different kinds of PDF output.",[153,1175,1176],{},"However, it strongly supports the architectural guidance:",[150,1178,1179],{},[153,1180,1181],{},"For large text-heavy documents whose CSS is supported by the vector renderer, selectable-text mode can be much lighter than raster Canvas mode.",[153,1183,1184],{},"Canvas remains the visual-fidelity option.",[184,1186],{},[145,1188,1190],{"id":1189},"_9-phase-23b-actual-large-pdf-correctness","9. Phase 2.3B - actual large-PDF correctness",[153,1192,1193],{},"A critical anomaly appeared in long Canvas output.",[153,1195,1196],{},"Earlier observations included:",[424,1198,1201],{"className":1199,"code":1200,"language":429,"meta":430},[427],"25 pages → multi-megabyte PDF\n50 pages → tens of kilobytes\n100 pages → similarly tiny output\n",[168,1202,1200],{"__ignoreMap":430},[153,1204,1205],{},"That is not normal scaling.",[153,1207,1208],{},"The first question was whether pages were missing.",[153,1210,1211],{},"The PDF Blob was inspected for actual PDF page dictionaries.",[153,1213,1214],{},"Result:",[424,1216,1219],{"className":1217,"code":1218,"language":429,"meta":430},[427],"10 requested  → 10 actual\n25 requested  → 25 actual\n40 requested  → 40 actual\n50 requested  → 50 actual\n75 requested  → 75 actual\n100 requested → 100 actual\n",[168,1220,1218],{"__ignoreMap":430},[187,1222,1224],{"id":1223},"important-conclusion","Important conclusion",[153,1226,1227],{},"The PDF could contain the correct number of page objects while raster payload was missing\u002Fcollapsed.",[153,1229,1230],{},"So a correct page count alone was not enough.",[153,1232,1233],{},"This is why the long-document tests now check multiple signals:",[201,1235,1236,1239,1242],{},[204,1237,1238],{},"actual page count",[204,1240,1241],{},"Blob size",[204,1243,1244],{},"canvas telemetry",[184,1246],{},[145,1248,1250],{"id":1249},"_10-phase-24a-security-retention-scales-with-raster-payload","10. Phase 2.4A - security retention scales with raster payload",[153,1252,1253],{},"The protected Canvas memory behavior was measured across page counts.",[153,1255,1256],{},"Latest representative mixed results:",[612,1258,1259,1272],{},[615,1260,1261],{},[618,1262,1263,1266,1269],{},[621,1264,1265],{"align":626},"Pages",[621,1267,1268],{"align":626},"Security off retained",[621,1270,1271],{"align":626},"User-password retained",[629,1273,1274,1285,1296,1307,1318],{},[618,1275,1276,1279,1282],{},[634,1277,1278],{"align":626},"5",[634,1280,1281],{"align":626},"2.0 MB",[634,1283,1284],{"align":626},"17.7 MB",[618,1286,1287,1290,1293],{},[634,1288,1289],{"align":626},"10",[634,1291,1292],{"align":626},"2.9 MB",[634,1294,1295],{"align":626},"34.3 MB",[618,1297,1298,1301,1304],{},[634,1299,1300],{"align":626},"15",[634,1302,1303],{"align":626},"3.8 MB",[634,1305,1306],{"align":626},"50.9 MB",[618,1308,1309,1312,1315],{},[634,1310,1311],{"align":626},"20",[634,1313,1314],{"align":626},"4.6 MB",[634,1316,1317],{"align":626},"67.5 MB",[618,1319,1320,1323,1326],{},[634,1321,1322],{"align":626},"25",[634,1324,1325],{"align":626},"5.4 MB",[634,1327,1014],{"align":626},[153,1329,1330],{},"The encrypted result grows almost linearly with raster payload\u002Fpage count.",[153,1332,1333],{},"That is much stronger evidence than a single noisy heap sample.",[187,1335,1337],{"id":1336},"what-we-learned","What we learned",[153,1339,1340],{},"The problematic combination is approximately:",[424,1342,1345],{"className":1343,"code":1344,"language":429,"meta":430},[427],"large raster\u002Fimage streams\n+\njsPDF encryption\n",[168,1346,1344],{"__ignoreMap":430},[153,1348,1349],{},"rather than simply:",[424,1351,1354],{"className":1352,"code":1353,"language":429,"meta":430},[427],"many PDF pages\n",[168,1355,1353],{"__ignoreMap":430},[153,1357,1358],{},"or:",[424,1360,1363],{"className":1361,"code":1362,"language":429,"meta":430},[427],"Vue component lifecycle\n",[168,1364,1362],{"__ignoreMap":430},[184,1366],{},[145,1368,1370],{"id":1369},"_11-phase-24b-long-canvas-cliff-investigation","11. Phase 2.4B - long-canvas cliff investigation",[153,1372,1373],{},"During the investigation, long Canvas output showed a sharp collapse around a high page count in the legacy whole-document path.",[153,1375,1376],{},"This was initially treated as a browser\u002Fcanvas threshold problem and instrumented specifically.",[153,1378,1379],{},"The later Phase 3.5 diagnosis found the more actionable package-level reason for the reintroduced failure:",[150,1381,1382],{},[153,1383,1384,1385,1388],{},"the incremental Canvas renderer existed, but ",[168,1386,1387],{},"generatePdf.ts"," was no longer routing paginated Canvas documents into it.",[153,1390,1391],{},"That discovery changed the solution from “lower the test threshold” to “restore the correct renderer path.”",[153,1393,1394],{},"The project deliberately kept the existing Blob-size correctness threshold instead of weakening it.",[184,1396],{},[145,1398,1400],{"id":1399},"_12-phase-31-page-by-page-incremental-canvas-rendering","12. Phase 3.1 - page-by-page incremental Canvas rendering",[153,1402,1403],{},"This was the most important architectural change for large Canvas documents.",[187,1405,1407],{"id":1406},"old-risk","Old risk",[153,1409,1410],{},"A 50-page diagnostic showed one huge source element:",[424,1412,1415],{"className":1413,"code":1414,"language":429,"meta":430},[427],"794 × 55,952 CSS px\n",[168,1416,1414],{"__ignoreMap":430},[153,1418,1419],{},"with:",[424,1421,1424],{"className":1422,"code":1423,"language":429,"meta":430},[427],"html2canvas scale = 1.5\n",[168,1425,1423],{"__ignoreMap":430},[153,1427,1428],{},"That implies an effective raster geometry around:",[424,1430,1433],{"className":1431,"code":1432,"language":429,"meta":430},[427],"1,191 × 83,928 px\n≈ 99.96 million pixels\n",[168,1434,1432],{"__ignoreMap":430},[153,1436,1437],{},"for one giant capture.",[187,1439,1441],{"id":1440},"new-page-bounded-geometry","New page-bounded geometry",[153,1443,1444],{},"The incremental Canvas benchmark reports a largest encoded page canvas of:",[424,1446,1449],{"className":1447,"code":1448,"language":429,"meta":430},[427],"1,191 × 1,461 px\n≈ 1.74 million pixels\n",[168,1450,1448],{"__ignoreMap":430},[1030,1452,1454],{"id":1453},"derived-improvement-in-capture-geometry","Derived improvement in capture geometry",[153,1456,1457],{},"Compared with the diagnosed giant 50-page capture:",[424,1459,1462],{"className":1460,"code":1461,"language":429,"meta":430},[427],"~99.96M pixels → ~1.74M pixels\n",[168,1463,1461],{"__ignoreMap":430},[153,1465,1466],{},"That is approximately:",[201,1468,1469,1474],{},[204,1470,1471],{},[156,1472,1473],{},"57.4× smaller peak raster surface",[204,1475,1476],{},[156,1477,1478],{},"98.26% lower peak canvas pixel area",[153,1480,1481],{},"This is an architectural geometry reduction, not a claim that total browser memory is 98.26% lower.",[153,1483,1484],{},"The browser still has:",[201,1486,1487,1490,1493,1496,1499],{},[204,1488,1489],{},"jsPDF data",[204,1491,1492],{},"decoded images",[204,1494,1495],{},"JavaScript objects",[204,1497,1498],{},"encryption buffers",[204,1500,1501],{},"temporary strings\u002FBlobs",[153,1503,1504],{},"But the largest HTML capture itself is now page-bounded.",[187,1506,1508],{"id":1507},"incremental-flow","Incremental flow",[153,1510,1511],{},"For documents containing manual page-break markers:",[424,1513,1516],{"className":1514,"code":1515,"language":429,"meta":430},[427],"Page 1\n→ clone fragment\n→ html2canvas(page)\n→ add to jsPDF\n→ remove temporary DOM\n→ release canvas\n→ yield\n\nPage 2\n→ repeat\n\n...\n",[168,1517,1515],{"__ignoreMap":430},[153,1519,1520],{},"One jsPDF document is kept while page raster resources are short-lived.",[187,1522,1524],{"id":1523},"current-benchmark-correctness","Current benchmark correctness",[153,1526,1527],{},"Latest Phase 2.3B-style correctness run on the page-bounded path:",[612,1529,1530,1547],{},[615,1531,1532],{},[618,1533,1534,1537,1540,1542,1544],{},[621,1535,1536],{"align":626},"Requested",[621,1538,1539],{"align":626},"Actual",[621,1541,978],{"align":626},[621,1543,1131],{"align":626},[621,1545,1546],{},"Largest canvas",[629,1548,1549,1564,1577,1592,1607,1622,1637],{},[618,1550,1551,1553,1555,1558,1561],{},[634,1552,1289],{"align":626},[634,1554,1289],{"align":626},[634,1556,1557],{"align":626},"1.53 s",[634,1559,1560],{"align":626},"1.5 MB",[634,1562,1563],{},"1191 × 1461",[618,1565,1566,1568,1570,1573,1575],{},[634,1567,1322],{"align":626},[634,1569,1322],{"align":626},[634,1571,1572],{"align":626},"4.33 s",[634,1574,1134],{"align":626},[634,1576,1563],{},[618,1578,1579,1582,1584,1587,1590],{},[634,1580,1581],{"align":626},"40",[634,1583,1581],{"align":626},[634,1585,1586],{"align":626},"7.54 s",[634,1588,1589],{"align":626},"6.2 MB",[634,1591,1563],{},[618,1593,1594,1597,1599,1602,1605],{},[634,1595,1596],{"align":626},"50",[634,1598,1596],{"align":626},[634,1600,1601],{"align":626},"9.68 s",[634,1603,1604],{"align":626},"7.8 MB",[634,1606,1563],{},[618,1608,1609,1612,1614,1617,1620],{},[634,1610,1611],{"align":626},"60",[634,1613,1611],{"align":626},[634,1615,1616],{"align":626},"12.56 s",[634,1618,1619],{"align":626},"9.3 MB",[634,1621,1563],{},[618,1623,1624,1627,1629,1632,1635],{},[634,1625,1626],{"align":626},"75",[634,1628,1626],{"align":626},[634,1630,1631],{"align":626},"16.87 s",[634,1633,1634],{"align":626},"11.7 MB",[634,1636,1563],{},[618,1638,1639,1642,1644,1647,1650],{},[634,1640,1641],{"align":626},"100",[634,1643,1641],{"align":626},[634,1645,1646],{"align":626},"25.25 s",[634,1648,1649],{"align":626},"15.8 MB",[634,1651,1563],{},[153,1653,1654],{},"The maximum encoded canvas stayed page-sized while requested pages increased from 10 to 100.",[153,1656,1657],{},"That is exactly the desired property.",[184,1659],{},[145,1661,1663],{"id":1662},"_13-phase-32-security-re-test-after-incremental-canvas","13. Phase 3.2 - security re-test after incremental Canvas",[153,1665,1666],{},"Incremental Canvas fixes the giant-canvas problem, but it does not magically eliminate all downstream jsPDF memory behavior.",[153,1668,1669],{},"The security re-test showed:",[424,1671,1674],{"className":1672,"code":1673,"language":429,"meta":430},[427],"5p encrypted  → ~17.7 MB retained\n10p encrypted → ~34.3 MB\n15p encrypted → ~51 MB\n20p encrypted → ~67.6 MB\n25p encrypted → ~84.2 MB\n",[168,1675,1673],{"__ignoreMap":430},[153,1677,1678],{},"while equivalent unencrypted runs remained much lower.",[187,1680,1682],{"id":1681},"conclusion","Conclusion",[153,1684,1685],{},"Page-by-page Canvas rendering solved the package's large-capture architecture problem.",[153,1687,1688,1689,1692],{},"It did ",[156,1690,1691],{},"not"," eliminate the encryption\u002Fraster retention pattern.",[153,1694,1695],{},"That distinction is important:",[201,1697,1698,1701],{},[204,1699,1700],{},"package-level giant Canvas issue: addressed",[204,1702,1703],{},"dependency-level encrypted raster retention: still relevant",[184,1705],{},[145,1707,1709],{"id":1708},"_14-phase-321-raw-jspdf-reproduction","14. Phase 3.2.1 - raw jsPDF reproduction",[153,1711,1712],{},"To determine whether Vue, html2pdf or the component lifecycle was responsible, a minimal raw jsPDF benchmark was created.",[153,1714,1715],{},"No Vue component architecture was required for the core reproduction.",[187,1717,1719],{"id":1718},"_25-page-jpeg-data-url-result","25-page JPEG data-URL result",[612,1721,1722,1734],{},[615,1723,1724],{},[618,1725,1726,1728,1731],{},[621,1727,728],{},[621,1729,1730],{"align":626},"Security off",[621,1732,1733],{"align":626},"Security on",[629,1735,1736,1746,1756],{},[618,1737,1738,1740,1743],{},[634,1739,978],{},[634,1741,1742],{"align":626},"36.3 ms",[634,1744,1745],{"align":626},"355.2 ms",[618,1747,1748,1750,1753],{},[634,1749,1161],{},[634,1751,1752],{"align":626},"~0.47 MB",[634,1754,1755],{"align":626},"~93.36 MB",[618,1757,1758,1760,1763],{},[634,1759,981],{},[634,1761,1762],{"align":626},"~5.38 MB",[634,1764,1765],{"align":626},"~67.07 MB",[153,1767,1768],{},"Derived comparison:",[201,1770,1771,1777,1782],{},[204,1772,1773,1774],{},"encrypted generation: ",[156,1775,1776],{},"~9.8× slower",[204,1778,1054,1779],{},[156,1780,1781],{},"~200× larger",[204,1783,1784,1785],{},"peak increase: ",[156,1786,1787],{},"~12.5× larger",[187,1789,1791],{"id":1790},"_25-page-png-data-url-stress-result","25-page PNG data-URL stress result",[612,1793,1794,1804],{},[615,1795,1796],{},[618,1797,1798,1800,1802],{},[621,1799,728],{},[621,1801,1730],{"align":626},[621,1803,1733],{"align":626},[629,1805,1806,1816,1826],{},[618,1807,1808,1810,1813],{},[634,1809,978],{},[634,1811,1812],{"align":626},"~4.95 s",[634,1814,1815],{"align":626},"~23.76 s",[618,1817,1818,1820,1823],{},[634,1819,1161],{},[634,1821,1822],{"align":626},"~125.6 MB",[634,1824,1825],{"align":626},"~2.55 GB",[618,1827,1828,1830,1833],{},[634,1829,981],{},[634,1831,1832],{"align":626},"~272 MB",[634,1834,1835],{"align":626},"~2.68 GB",[153,1837,1838],{},"The encrypted PNG case was an intentionally extreme stress case, but it showed the same dependency-level direction.",[187,1840,1842],{"id":1841},"why-this-was-valuable","Why this was valuable",[153,1844,1845],{},"It demonstrated that the strongest encrypted-raster retention behavior could occur even when the normal Vue component lifecycle was removed from the reproduction.",[153,1847,1848],{},"Therefore the project uses careful wording:",[150,1850,1851],{},[153,1852,1853],{},[156,1854,1855],{},"memory retention",[153,1857,1858],{},"rather than claiming a proven permanent Vue memory leak.",[153,1860,1861],{},"An upstream issue was filed:",[153,1863,1864,1867,1869],{},[156,1865,1866],{},"jsPDF #4017 - encrypted raster PDF memory retention",[161,1868],{},[1870,1871,1872],"a",{"href":1872,"rel":1873},"https:\u002F\u002Fgithub.com\u002Fparallax\u002FjsPDF\u002Fissues\u002F4017",[1874],"nofollow",[184,1876],{},[145,1878,1880],{"id":1879},"_15-phase-33-cancellation","15. Phase 3.3 - cancellation",[153,1882,1883],{},"Large browser PDFs need a way to stop.",[153,1885,1886],{},"The component now exposes:",[424,1888,1892],{"className":1889,"code":1890,"language":1891,"meta":430,"style":430},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","pdfRef.value?.cancelGeneration()\n","ts",[168,1893,1894],{"__ignoreMap":430},[1895,1896,1899,1903,1907,1910,1913,1917],"span",{"class":1897,"line":1898},"line",1,[1895,1900,1902],{"class":1901},"sTEyZ","pdfRef",[1895,1904,1906],{"class":1905},"sMK4o",".",[1895,1908,1909],{"class":1901},"value",[1895,1911,1912],{"class":1905},"?.",[1895,1914,1916],{"class":1915},"s2Zo4","cancelGeneration",[1895,1918,1919],{"class":1901},"()\n",[187,1921,1923],{"id":1922},"canvas-cancellation","Canvas cancellation",[153,1925,1926],{},"Incremental Canvas checks cancellation around safe checkpoints such as:",[201,1928,1929,1932,1935,1938,1941],{},[204,1930,1931],{},"before page work",[204,1933,1934],{},"around page capture",[204,1936,1937],{},"before\u002Fafter expensive encoding boundaries",[204,1939,1940],{},"between pages",[204,1942,1943],{},"around browser-yield points",[153,1945,1946],{},"A synchronous operation already executing cannot be interrupted in the middle, but the next page can be prevented from starting.",[187,1948,1950],{"id":1949},"selectable-text-cancellation","Selectable-text cancellation",[153,1952,1953],{},"The vector renderer was adapted to cooperate with cancellation during:",[201,1955,1956,1959,1962,1965,1968],{},[204,1957,1958],{},"DOM walking",[204,1960,1961],{},"image materialization",[204,1963,1964],{},"pagination",[204,1966,1967],{},"page rendering",[204,1969,1970],{},"long loops",[187,1972,1974],{"id":1973},"recovery-is-part-of-the-feature","Recovery is part of the feature",[153,1976,1977],{},"The E2E contract is not merely “AbortError was thrown.”",[153,1979,1980],{},"It verifies:",[424,1982,1985],{"className":1983,"code":1984,"language":429,"meta":430},[427],"start long PDF\n→ cancel\n→ generation reports cancelled\n→ no successful Blob for cancelled run\n→ temporary rendering DOM is gone\n→ start another PDF\n→ recovery generation succeeds\n",[168,1986,1984],{"__ignoreMap":430},[153,1988,1989],{},"Both Canvas and selectable-text recovery paths passed.",[187,1991,1993],{"id":1992},"user-benefit","User benefit",[201,1995,1996,1999,2002],{},[204,1997,1998],{},"accidental 50\u002F100-page export no longer has to run to completion",[204,2000,2001],{},"UI can provide a meaningful Cancel action",[204,2003,2004],{},"package does not remain stuck after a cancellation",[184,2006],{},[145,2008,2010],{"id":2009},"_16-phase-33-page-aware-progress","16. Phase 3.3 - page-aware progress",[153,2012,2013],{},"Long generation now has richer progress.",[153,2015,2016],{},"The public state can include:",[424,2018,2020],{"className":1889,"code":2019,"language":1891,"meta":430,"style":430},"{\n  stage: 'rendering',\n  progress: 57,\n  currentPage: 21,\n  totalPages: 100,\n}\n",[168,2021,2022,2027,2050,2064,2077,2090],{"__ignoreMap":430},[1895,2023,2024],{"class":1897,"line":1898},[1895,2025,2026],{"class":1905},"{\n",[1895,2028,2030,2034,2037,2040,2044,2047],{"class":1897,"line":2029},2,[1895,2031,2033],{"class":2032},"sBMFI","  stage",[1895,2035,2036],{"class":1905},":",[1895,2038,2039],{"class":1905}," '",[1895,2041,2043],{"class":2042},"sfazB","rendering",[1895,2045,2046],{"class":1905},"'",[1895,2048,2049],{"class":1905},",\n",[1895,2051,2053,2056,2058,2062],{"class":1897,"line":2052},3,[1895,2054,2055],{"class":2032},"  progress",[1895,2057,2036],{"class":1905},[1895,2059,2061],{"class":2060},"sbssI"," 57",[1895,2063,2049],{"class":1905},[1895,2065,2067,2070,2072,2075],{"class":1897,"line":2066},4,[1895,2068,2069],{"class":2032},"  currentPage",[1895,2071,2036],{"class":1905},[1895,2073,2074],{"class":2060}," 21",[1895,2076,2049],{"class":1905},[1895,2078,2080,2083,2085,2088],{"class":1897,"line":2079},5,[1895,2081,2082],{"class":2032},"  totalPages",[1895,2084,2036],{"class":1905},[1895,2086,2087],{"class":2060}," 100",[1895,2089,2049],{"class":1905},[1895,2091,2093],{"class":1897,"line":2092},6,[1895,2094,2095],{"class":1905},"}\n",[153,2097,2098],{},"Applications can show:",[424,2100,2103],{"className":2101,"code":2102,"language":429,"meta":430},[427],"Rendering page 21 of 100\n",[168,2104,2102],{"__ignoreMap":430},[153,2106,2107],{},"instead of only:",[424,2109,2112],{"className":2110,"code":2111,"language":429,"meta":430},[427],"57%\n",[168,2113,2111],{"__ignoreMap":430},[153,2115,2116],{},"This is particularly useful when individual pages vary in complexity.",[184,2118],{},[145,2120,2122],{"id":2121},"_17-cooperative-browser-yielding","17. Cooperative browser yielding",[153,2124,2125],{},"Long PDF generation contains unavoidable synchronous work.",[153,2127,2128],{},"Examples:",[201,2130,2131,2134,2139],{},[204,2132,2133],{},"html2canvas operations",[204,2135,2136],{},[168,2137,2138],{},"canvas.toDataURL()",[204,2140,2141],{},"jsPDF image insertion\u002Fserialization",[153,2143,2144],{},"The project therefore did not pretend the entire renderer had become background-thread work.",[153,2146,2147],{},"Instead, cooperative browser yields were introduced between expensive chunks.",[153,2149,2150],{},"Conceptually:",[424,2152,2154],{"className":1889,"code":2153,"language":1891,"meta":430,"style":430},"await new Promise((resolve) => requestAnimationFrame(resolve))\n",[168,2155,2156],{"__ignoreMap":430},[1895,2157,2158,2162,2165,2168,2171,2173,2177,2180,2184,2187],{"class":1897,"line":1898},[1895,2159,2161],{"class":2160},"s7zQu","await",[1895,2163,2164],{"class":1905}," new",[1895,2166,2167],{"class":2032}," Promise",[1895,2169,2170],{"class":1901},"(",[1895,2172,2170],{"class":1905},[1895,2174,2176],{"class":2175},"sHdIc","resolve",[1895,2178,2179],{"class":1905},")",[1895,2181,2183],{"class":2182},"spNyl"," =>",[1895,2185,2186],{"class":1915}," requestAnimationFrame",[1895,2188,2189],{"class":1901},"(resolve))\n",[187,2191,2193],{"id":2192},"benefit","Benefit",[153,2195,2196],{},"The browser gets opportunities to:",[201,2198,2199,2202,2205,2208],{},[204,2200,2201],{},"repaint progress UI",[204,2203,2204],{},"process a Cancel click",[204,2206,2207],{},"update loader state",[204,2209,2210],{},"avoid one enormous uninterrupted JavaScript loop",[153,2212,2213],{},"This improves perceived responsiveness without changing the public PDF API.",[184,2215],{},[145,2217,2219],{"id":2218},"_18-phase-34a-repeated-image-caching-in-selectable-text-mode","18. Phase 3.4A - repeated image caching in selectable-text mode",[153,2221,2222],{},"Repeated assets are common in PDFs:",[201,2224,2225,2228,2231,2234,2237],{},[204,2226,2227],{},"company logos",[204,2229,2230],{},"product thumbnails",[204,2232,2233],{},"signatures",[204,2235,2236],{},"badges",[204,2238,2239],{},"decorative images",[153,2241,2242],{},"The selectable renderer previously had to materialize image content repeatedly.",[153,2244,2245],{},"A per-generation cache was introduced.",[187,2247,2249],{"id":2248},"cache-key-includes","Cache key includes",[424,2251,2254],{"className":2252,"code":2253,"language":429,"meta":430},[427],"image source\u002FcurrentSrc\ntarget raster width\ntarget raster height\nformat\nJPEG quality\n",[168,2255,2253],{"__ignoreMap":430},[187,2257,2259],{"id":2258},"why-per-generation-only","Why per-generation only",[153,2261,2262],{},"The cache is cleared after the current PDF.",[153,2264,2265],{},"This avoids creating a global image cache that could keep old customer\u002Fdocument assets alive indefinitely.",[187,2267,2269,2270,2273],{"id":2268},"why-canvas-is-not-cached","Why ",[168,2271,2272],{},"\u003Ccanvas>"," is not cached",[153,2275,2276,2277,2279],{},"A ",[168,2278,2272],{}," can change its pixels while keeping the same dimensions.",[153,2281,2282,2283,2286],{},"Therefore only real ",[168,2284,2285],{},"\u003Cimg>"," sources are safe for this reuse strategy.",[187,2288,2290],{"id":2289},"regression-fixture","Regression fixture",[153,2292,2293],{},"The image-heavy selectable test uses:",[424,2295,2298],{"className":2296,"code":2297,"language":429,"meta":430},[427],"4 image elements per page\nonly 2 actual source URLs\n",[168,2299,2297],{"__ignoreMap":430},[153,2301,2302],{},"and tests:",[424,2304,2307],{"className":2305,"code":2306,"language":429,"meta":430},[427],"10 pages\n25 pages\n50 pages\n",[168,2308,2306],{"__ignoreMap":430},[153,2310,2311],{},"The regression bounds image encoding calls to:",[424,2313,2316],{"className":2314,"code":2315,"language":429,"meta":430},[427],"toDataURL calls \u003C= 4\n",[168,2317,2315],{"__ignoreMap":430},[1030,2319,2321],{"id":2320},"work-avoided-versus-naive-per-element-encoding","Work avoided versus naive per-element encoding",[153,2323,2324],{},"If every image element were encoded separately:",[612,2326,2327,2342],{},[615,2328,2329],{},[618,2330,2331,2333,2336,2339],{},[621,2332,1265],{"align":626},[621,2334,2335],{"align":626},"Image elements",[621,2337,2338],{"align":626},"Encodes bounded by test",[621,2340,2341],{"align":626},"Reduction vs naive per-element work",[629,2343,2344,2358,2371],{},[618,2345,2346,2348,2350,2353],{},[634,2347,1289],{"align":626},[634,2349,1581],{"align":626},[634,2351,2352],{"align":626},"≤4",[634,2354,2355],{"align":626},[156,2356,2357],{},"≥90% fewer",[618,2359,2360,2362,2364,2366],{},[634,2361,1322],{"align":626},[634,2363,1641],{"align":626},[634,2365,2352],{"align":626},[634,2367,2368],{"align":626},[156,2369,2370],{},"≥96% fewer",[618,2372,2373,2375,2378,2380],{},[634,2374,1596],{"align":626},[634,2376,2377],{"align":626},"200",[634,2379,2352],{"align":626},[634,2381,2382],{"align":626},[156,2383,2384],{},"≥98% fewer",[153,2386,2387],{},"This percentage describes the test fixture's avoided repeated encoding work, not a universal whole-PDF speedup.",[187,2389,1993],{"id":2390},"user-benefit-1",[201,2392,2393,2396,2399,2402],{},[204,2394,2395],{},"repeated logos\u002Fassets scale much better",[204,2397,2398],{},"less temporary Canvas encoding work",[204,2400,2401],{},"less CPU churn",[204,2403,2404],{},"bounded cache lifetime",[184,2406],{},[145,2408,2410],{"id":2409},"_19-phase-34b-canvas-cleanup-and-resource-lifetime","19. Phase 3.4B - Canvas cleanup and resource lifetime",[153,2412,2413],{},"The incremental Canvas renderer was tightened so expensive objects do not overlap longer than necessary.",[153,2415,2416,2417,2419],{},"After ",[168,2418,400],{}," finishes reading a temporary page:",[424,2421,2424],{"className":2422,"code":2423,"language":429,"meta":430},[427],"measure links\u002Fdimensions\n→ remove cloned page DOM\n→ remove host\n→ yield\n",[168,2425,2423],{"__ignoreMap":430},[153,2427,2428],{},"After encoding\u002Finserting the raster:",[424,2430,2433],{"className":2431,"code":2432,"language":429,"meta":430},[427],"release data URL reference\n→ canvas.width = 0\n→ canvas.height = 0\n→ release canvas reference\n→ yield\n",[168,2434,2432],{"__ignoreMap":430},[187,2436,2438],{"id":2437},"why-zero-the-canvas-dimensions","Why zero the canvas dimensions?",[153,2440,2441,2442,2445],{},"A JavaScript reference becoming ",[168,2443,2444],{},"null"," does not guarantee that a browser immediately releases the native Canvas backing allocation.",[153,2447,2448],{},"Resetting:",[424,2450,2452],{"className":1889,"code":2451,"language":1891,"meta":430,"style":430},"canvas.width = 0\ncanvas.height = 0\n",[168,2453,2454,2470],{"__ignoreMap":430},[1895,2455,2456,2459,2461,2464,2467],{"class":1897,"line":1898},[1895,2457,2458],{"class":1901},"canvas",[1895,2460,1906],{"class":1905},[1895,2462,2463],{"class":1901},"width ",[1895,2465,2466],{"class":1905},"=",[1895,2468,2469],{"class":2060}," 0\n",[1895,2471,2472,2474,2476,2479,2481],{"class":1897,"line":2029},[1895,2473,2458],{"class":1901},[1895,2475,1906],{"class":1905},[1895,2477,2478],{"class":1901},"height ",[1895,2480,2466],{"class":1905},[1895,2482,2469],{"class":2060},[153,2484,2485],{},"actively discards the backing store.",[187,2487,1993],{"id":2488},"user-benefit-2",[201,2490,2491,2494,2497],{},[204,2492,2493],{},"shorter overlap between temporary DOM and large raster memory",[204,2495,2496],{},"lower risk of old page canvases surviving unnecessarily while new pages render",[204,2498,2499],{},"cleaner cancellation\u002Frecovery",[184,2501],{},[145,2503,2505],{"id":2504},"_20-phase-35-the-50100-page-routing-regression","20. Phase 3.5 - the 50\u002F100-page routing regression",[153,2507,2508],{},"A later regression was extremely informative.",[153,2510,2511],{},"The project contained:",[424,2513,2515],{"className":1889,"code":2514,"language":1891,"meta":430,"style":430},"renderIncrementalCanvasPdf(...)\n",[168,2516,2517],{"__ignoreMap":430},[1895,2518,2519,2522,2524,2527],{"class":1897,"line":1898},[1895,2520,2521],{"class":1915},"renderIncrementalCanvasPdf",[1895,2523,2170],{"class":1901},[1895,2525,2526],{"class":1905},"...",[1895,2528,2529],{"class":1901},")\n",[153,2531,2532],{},"and:",[424,2534,2536],{"className":1889,"code":2535,"language":1891,"meta":430,"style":430},"shouldUseIncrementalCanvasRenderer(...)\n",[168,2537,2538],{"__ignoreMap":430},[1895,2539,2540,2543,2545,2547],{"class":1897,"line":1898},[1895,2541,2542],{"class":1915},"shouldUseIncrementalCanvasRenderer",[1895,2544,2170],{"class":1901},[1895,2546,2526],{"class":1905},[1895,2548,2529],{"class":1901},[153,2550,2551,2552,2554],{},"but ",[168,2553,1387],{}," had accidentally lost the branch that actually routed paginated Canvas documents into that renderer.",[153,2556,2557],{},"So runtime behavior was effectively:",[424,2559,2562],{"className":2560,"code":2561,"language":429,"meta":430},[427],"text → selectable renderer\ncanvas → legacy whole-document html2pdf worker\n",[168,2563,2561],{"__ignoreMap":430},[153,2565,2566],{},"even though diagnostics suggested incremental mode should be applicable.",[187,2568,2570],{"id":2569},"symptom","Symptom",[153,2572,2573],{},"50-page Canvas:",[424,2575,2578],{"className":2576,"code":2577,"language":429,"meta":430},[427],"element size: 794 × 55,952\none giant html2canvas capture\nBlob: ~42,671 bytes\n",[168,2579,2577],{"__ignoreMap":430},[153,2581,2582],{},"The test expected a meaningful non-empty raster PDF and failed.",[187,2584,2586],{"id":2585},"fix","Fix",[153,2588,2589],{},"Routing was restored:",[424,2591,2594],{"className":2592,"code":2593,"language":429,"meta":430},[427],"text\n→ selectable renderer\n\ncanvas + page-break markers\n→ incremental Canvas renderer\n\ncanvas without markers\n→ legacy html2pdf worker\n",[168,2595,2593],{"__ignoreMap":430},[187,2597,2599],{"id":2598},"final-regression-gate","Final regression gate",[153,2601,2602],{},"After the routing fix:",[424,2604,2607],{"className":2605,"code":2606,"language":429,"meta":430},[427],"50-page Canvas test  → PASS (20.1 s)\n100-page Canvas test → PASS (32.2 s)\n",[168,2608,2606],{"__ignoreMap":430},[153,2610,2611],{},"These are release-gate E2E timings for that specific fixture\u002Fenvironment, not universal performance promises.",[153,2613,2614],{},"The important point is:",[201,2616,2617,2620,2623],{},[204,2618,2619],{},"no Blob threshold was lowered",[204,2621,2622],{},"the test did not get weakened",[204,2624,2625],{},"the renderer path was fixed",[184,2627],{},[145,2629,2631],{"id":2630},"_21-final-stress-results","21. Final stress results",[153,2633,2634],{},"The latest heavy stress summary included successful cases such as:",[612,2636,2637,2664],{},[615,2638,2639],{},[618,2640,2641,2644,2646,2649,2652,2654,2656,2658,2661],{},[621,2642,2643],{},"Mode",[621,2645,1265],{"align":626},[621,2647,2648],{},"Content",[621,2650,2651],{"align":626},"Quality",[621,2653,27],{},[621,2655,978],{"align":626},[621,2657,1131],{"align":626},[621,2659,2660],{"align":626},"Peak heap increase",[621,2662,2663],{"align":626},"Retained",[629,2665,2666,2692,2718,2743,2766,2790,2814,2839,2863,2888],{},[618,2667,2668,2671,2673,2675,2678,2681,2684,2687,2690],{},[634,2669,2670],{},"Canvas",[634,2672,1289],{"align":626},[634,2674,429],{},[634,2676,2677],{"align":626},"1.5",[634,2679,2680],{},"off",[634,2682,2683],{"align":626},"1.91 s",[634,2685,2686],{"align":626},"2.3 MB",[634,2688,2689],{"align":626},"15.2 MB",[634,2691,1134],{"align":626},[618,2693,2694,2696,2698,2701,2703,2706,2709,2712,2715],{},[634,2695,2670],{},[634,2697,1322],{"align":626},[634,2699,2700],{},"mixed",[634,2702,2677],{"align":626},[634,2704,2705],{},"on",[634,2707,2708],{"align":626},"4.44 s",[634,2710,2711],{"align":626},"4.0 MB",[634,2713,2714],{"align":626},"24.3 MB",[634,2716,2717],{"align":626},"5.7 MB",[618,2719,2720,2723,2725,2727,2730,2732,2735,2738,2741],{},[634,2721,2722],{},"Text",[634,2724,1289],{"align":626},[634,2726,429],{},[634,2728,2729],{"align":626},"1",[634,2731,2680],{},[634,2733,2734],{"align":626},"1.24 s",[634,2736,2737],{"align":626},"0.2 MB",[634,2739,2740],{"align":626},"6.4 MB",[634,2742,2686],{"align":626},[618,2744,2745,2747,2749,2751,2753,2755,2758,2760,2763],{},[634,2746,2722],{},[634,2748,1322],{"align":626},[634,2750,2700],{},[634,2752,2729],{"align":626},[634,2754,2705],{},[634,2756,2757],{"align":626},"2.23 s",[634,2759,1137],{"align":626},[634,2761,2762],{"align":626},"5.0 MB",[634,2764,2765],{"align":626},"3.4 MB",[618,2767,2768,2770,2772,2774,2776,2778,2781,2784,2787],{},[634,2769,2722],{},[634,2771,1596],{"align":626},[634,2773,2700],{},[634,2775,2729],{"align":626},[634,2777,2680],{},[634,2779,2780],{"align":626},"4.42 s",[634,2782,2783],{"align":626},"0.7 MB",[634,2785,2786],{"align":626},"7.1 MB",[634,2788,2789],{"align":626},"4.7 MB",[618,2791,2792,2794,2796,2798,2800,2802,2805,2808,2811],{},[634,2793,2722],{},[634,2795,1641],{"align":626},[634,2797,429],{},[634,2799,2729],{"align":626},[634,2801,2680],{},[634,2803,2804],{"align":626},"11.97 s",[634,2806,2807],{"align":626},"2.1 MB",[634,2809,2810],{"align":626},"27.5 MB",[634,2812,2813],{"align":626},"10.2 MB",[618,2815,2816,2818,2820,2822,2825,2827,2830,2833,2836],{},[634,2817,2670],{},[634,2819,1596],{"align":626},[634,2821,2700],{},[634,2823,2824],{"align":626},"2",[634,2826,2680],{},[634,2828,2829],{"align":626},"10.77 s",[634,2831,2832],{"align":626},"11.8 MB",[634,2834,2835],{"align":626},"24.0 MB",[634,2837,2838],{"align":626},"13.6 MB",[618,2840,2841,2843,2845,2847,2849,2851,2854,2857,2860],{},[634,2842,2670],{},[634,2844,1641],{"align":626},[634,2846,2700],{},[634,2848,2824],{"align":626},[634,2850,2705],{},[634,2852,2853],{"align":626},"28.50 s",[634,2855,2856],{"align":626},"23.7 MB",[634,2858,2859],{"align":626},"43.7 MB",[634,2861,2862],{"align":626},"25.6 MB",[618,2864,2865,2867,2869,2872,2874,2876,2879,2882,2885],{},[634,2866,2670],{},[634,2868,1641],{"align":626},[634,2870,2871],{},"image-heavy",[634,2873,2824],{"align":626},[634,2875,2680],{},[634,2877,2878],{"align":626},"21.64 s",[634,2880,2881],{"align":626},"22.3 MB",[634,2883,2884],{"align":626},"46.0 MB",[634,2886,2887],{"align":626},"24.2 MB",[618,2889,2890,2892,2894,2896,2898,2900,2903,2905,2908],{},[634,2891,2722],{},[634,2893,1641],{"align":626},[634,2895,2871],{},[634,2897,2729],{"align":626},[634,2899,2705],{},[634,2901,2902],{"align":626},"4.89 s",[634,2904,809],{"align":626},[634,2906,2907],{"align":626},"6.9 MB",[634,2909,1000],{"align":626},[153,2911,2912],{},"The repeated cleanup probe in that stress run retained:",[424,2914,2917],{"className":2915,"code":2916,"language":429,"meta":430},[427],"2.2 MB across 5 cycles\n",[168,2918,2916],{"__ignoreMap":430},[153,2920,2921],{},"and reported:",[424,2923,2926],{"className":2924,"code":2925,"language":429,"meta":430},[427],"Potential leak signal: no obvious signal\n",[168,2927,2925],{"__ignoreMap":430},[153,2929,2930],{},"This is separate from the protected-raster security-specific retention investigation.",[184,2932],{},[145,2934,2936],{"id":2935},"_22-repeated-generation-cleanup-result","22. Repeated-generation cleanup result",[153,2938,2939],{},"The latest general Canvas isolation repeated probe ran six generate\u002Fcleanup cycles in the same page\u002Fcontext.",[153,2941,1214],{},[424,2943,2946],{"className":2944,"code":2945,"language":429,"meta":430},[427],"Retained heap across all cycles: 0.3 MB\n",[168,2947,2945],{"__ignoreMap":430},[153,2949,2950],{},"This is a useful control.",[153,2952,2953],{},"It shows that ordinary repeated generation\u002Fcleanup does not automatically produce the same large baseline growth seen in the encrypted-raster scenarios.",[153,2955,2956],{},"Again, that distinction helped isolate the security-specific behavior.",[184,2958],{},[145,2960,2962],{"id":2961},"_23-final-automated-verification-status","23. Final automated verification status",[153,2964,2965],{},"The final package verification reached:",[424,2967,2970],{"className":2968,"code":2969,"language":429,"meta":430},[427],"TypeScript type-check ✅\nProduction build ✅\n19 \u002F 19 unit-test files ✅\n106 \u002F 106 unit tests ✅\n\n50-page Canvas regression ✅\n100-page Canvas regression ✅\n\nCanvas cancellation + recovery ✅\nSelectable-text cancellation + recovery ✅\n\nSelectable image-cache regression: 3 \u002F 3 ✅\nCanvas image-heavy cleanup regression: 2 \u002F 2 ✅\n",[168,2971,2969],{"__ignoreMap":430},[153,2973,2974],{},"General E2E:",[424,2976,2979],{"className":2977,"code":2978,"language":429,"meta":430},[427],"44 passed\n2 skipped\n2 Firefox timeouts under long suite load\n",[168,2980,2978],{"__ignoreMap":430},[153,2982,2983],{},"Both Firefox failures passed immediately when rerun individually:",[424,2985,2988],{"className":2986,"code":2987,"language":429,"meta":430},[427],"footer-logo-disabled Firefox rerun ✅\nexcept-first watermark Firefox rerun ✅\n",[168,2989,2987],{"__ignoreMap":430},[153,2991,2992],{},"Therefore they were treated as suite-load\u002Ftiming flakes rather than reproducible functional regressions.",[153,2994,2995],{},"Heavy PDF suites are intentionally run with low worker counts, typically:",[424,2997,3001],{"className":2998,"code":2999,"language":3000,"meta":430,"style":430},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","--workers=1\n","bash",[168,3002,3003],{"__ignoreMap":430},[1895,3004,3005,3008,3010],{"class":1897,"line":1898},[1895,3006,3007],{"class":1901},"--workers",[1895,3009,2466],{"class":1905},[1895,3011,3012],{"class":2042},"1\n",[153,3014,3015],{},"to avoid creating artificial browser resource contention.",[184,3017],{},[145,3019,3021],{"id":3020},"_24-what-the-performance-scripts-are-for","24. What the performance scripts are for",[187,3023,3025],{"id":3024},"teste2estress",[168,3026,3027],{},"test:e2e:stress",[424,3029,3031],{"className":2998,"code":3030,"language":3000,"meta":430,"style":430},"npm run test:e2e:stress\n",[168,3032,3033],{"__ignoreMap":430},[1895,3034,3035,3038,3041],{"class":1897,"line":1898},[1895,3036,3037],{"class":2032},"npm",[1895,3039,3040],{"class":2042}," run",[1895,3042,3043],{"class":2042}," test:e2e:stress\n",[153,3045,3046],{},"Runs the heavy Playwright stress matrix.",[153,3048,3049,3052],{},[156,3050,3051],{},"Why:"," separates expensive performance\u002Fregression work from ordinary UI E2E.",[184,3054],{},[187,3056,3058],{"id":3057},"benchmarkpdf",[168,3059,3060],{},"benchmark:pdf",[424,3062,3064],{"className":2998,"code":3063,"language":3000,"meta":430,"style":430},"npm run benchmark:pdf\n",[168,3065,3066],{"__ignoreMap":430},[1895,3067,3068,3070,3072],{"class":1897,"line":1898},[1895,3069,3037],{"class":2032},[1895,3071,3040],{"class":2042},[1895,3073,3074],{"class":2042}," benchmark:pdf\n",[153,3076,3077],{},"Runs the baseline PDF benchmark.",[153,3079,3080,3082],{},[156,3081,3051],{}," establishes repeatable generation-time\u002Foutput\u002Fmemory data.",[184,3084],{},[187,3086,3088],{"id":3087},"benchmarkpdfheavy",[168,3089,3090],{},"benchmark:pdf:heavy",[424,3092,3094],{"className":2998,"code":3093,"language":3000,"meta":430,"style":430},"npm run benchmark:pdf:heavy\n",[168,3095,3096],{"__ignoreMap":430},[1895,3097,3098,3100,3102],{"class":1897,"line":1898},[1895,3099,3037],{"class":2032},[1895,3101,3040],{"class":2042},[1895,3103,3104],{"class":2042}," benchmark:pdf:heavy\n",[153,3106,3107],{},"Adds heavier long-document scenarios.",[153,3109,3110,3112],{},[156,3111,3051],{}," reveals failures that 10\u002F25-page smoke cases can hide.",[184,3114],{},[187,3116,3118],{"id":3117},"benchmarkpdfheadful",[168,3119,3120],{},"benchmark:pdf:headful",[424,3122,3124],{"className":2998,"code":3123,"language":3000,"meta":430,"style":430},"npm run benchmark:pdf:headful\n",[168,3125,3126],{"__ignoreMap":430},[1895,3127,3128,3130,3132],{"class":1897,"line":1898},[1895,3129,3037],{"class":2032},[1895,3131,3040],{"class":2042},[1895,3133,3134],{"class":2042}," benchmark:pdf:headful\n",[153,3136,3137],{},"Runs with a visible browser.",[153,3139,3140,3142],{},[156,3141,3051],{}," useful for observing browser responsiveness and comparing headless\u002Fheadful behavior.",[184,3144],{},[187,3146,3148],{"id":3147},"benchmarksummary",[168,3149,3150],{},"benchmark:summary",[424,3152,3154],{"className":2998,"code":3153,"language":3000,"meta":430,"style":430},"npm run benchmark:summary\n",[168,3155,3156],{"__ignoreMap":430},[1895,3157,3158,3160,3162],{"class":1897,"line":1898},[1895,3159,3037],{"class":2032},[1895,3161,3040],{"class":2042},[1895,3163,3164],{"class":2042}," benchmark:summary\n",[153,3166,3167],{},"Builds a human-readable summary from raw benchmark JSON.",[153,3169,3170,3172],{},[156,3171,3051],{}," makes trend comparison easier and keeps raw evidence reproducible.",[184,3174],{},[187,3176,3178],{"id":3177},"benchmarkcanvas-isolation",[168,3179,3180],{},"benchmark:canvas-isolation",[424,3182,3184],{"className":2998,"code":3183,"language":3000,"meta":430,"style":430},"npm run benchmark:canvas-isolation\n",[168,3185,3186],{"__ignoreMap":430},[1895,3187,3188,3190,3192],{"class":1897,"line":1898},[1895,3189,3037],{"class":2032},[1895,3191,3040],{"class":2042},[1895,3193,3194],{"class":2042}," benchmark:canvas-isolation\n",[153,3196,3197],{},"Tests one Canvas feature at a time.",[153,3199,3200,3202],{},[156,3201,3051],{}," identified the repeated HTML-footer rasterization bottleneck and later helped separate security from other features.",[184,3204],{},[187,3206,3208],{"id":3207},"benchmarkcanvas-isolationheadful",[168,3209,3210],{},"benchmark:canvas-isolation:headful",[153,3212,3213],{},"Same isolation benchmark in a visible browser.",[184,3215],{},[187,3217,3219],{"id":3218},"benchmarkphase2-2",[168,3220,3221],{},"benchmark:phase2-2",[424,3223,3225],{"className":2998,"code":3224,"language":3000,"meta":430,"style":430},"npm run benchmark:phase2-2\n",[168,3226,3227],{"__ignoreMap":430},[1895,3228,3229,3231,3233],{"class":1897,"line":1898},[1895,3230,3037],{"class":2032},[1895,3232,3040],{"class":2042},[1895,3234,3235],{"class":2042}," benchmark:phase2-2\n",[153,3237,3238],{},"Runs fresh-context memory isolation and same-page repeat probes.",[153,3240,3241,3243],{},[156,3242,3051],{}," distinguishes real trends from previous-test\u002FGC contamination.",[184,3245],{},[187,3247,3249],{"id":3248},"benchmarkphase2-2headful",[168,3250,3251],{},"benchmark:phase2-2:headful",[153,3253,3254],{},"Visible-browser version of the clean memory isolation run.",[184,3256],{},[187,3258,3260],{"id":3259},"benchmarkphase2-3",[168,3261,3262],{},"benchmark:phase2-3",[424,3264,3266],{"className":2998,"code":3265,"language":3000,"meta":430,"style":430},"npm run benchmark:phase2-3\n",[168,3267,3268],{"__ignoreMap":430},[1895,3269,3270,3272,3274],{"class":1897,"line":1898},[1895,3271,3037],{"class":2032},[1895,3273,3040],{"class":2042},[1895,3275,3276],{"class":2042}," benchmark:phase2-3\n",[153,3278,3279],{},"Runs:",[201,3281,3282,3285],{},[204,3283,3284],{},"security memory isolation",[204,3286,3287],{},"large Canvas output correctness",[184,3289],{},[187,3291,3293],{"id":3292},"benchmarkphase2-3security",[168,3294,3295],{},"benchmark:phase2-3:security",[153,3297,3298],{},"Runs only the security-isolation side.",[153,3300,3301,3303],{},[156,3302,3051],{}," compares password\u002Fpermission variants and renderer controls.",[184,3305],{},[187,3307,3309],{"id":3308},"benchmarkphase2-3canvas",[168,3310,3311],{},"benchmark:phase2-3:canvas",[153,3313,3314],{},"Runs only large Canvas correctness.",[153,3316,3317,3319],{},[156,3318,3051],{}," checks actual PDF pages, Blob size and maximum raster geometry.",[184,3321],{},[187,3323,3325],{"id":3324},"benchmarkphase2-4",[168,3326,3327],{},"benchmark:phase2-4",[153,3329,3279],{},[201,3331,3332,3335],{},[204,3333,3334],{},"security payload scaling",[204,3336,3337],{},"Canvas-threshold diagnostics",[184,3339],{},[187,3341,3343],{"id":3342},"benchmarkphase2-4security",[168,3344,3345],{},"benchmark:phase2-4:security",[153,3347,3348],{},"Runs only security scaling.",[153,3350,3351,3353],{},[156,3352,3051],{}," demonstrated that retained heap grows with encrypted raster payload\u002Fpage count.",[184,3355],{},[187,3357,3359],{"id":3358},"benchmarkphase2-4canvas",[168,3360,3361],{},"benchmark:phase2-4:canvas",[153,3363,3364],{},"Runs only the long-Canvas threshold\u002Fcorrectness investigation.",[184,3366],{},[187,3368,3370],{"id":3369},"teste2ephase3-1",[168,3371,3372],{},"test:e2e:phase3-1",[424,3374,3376],{"className":2998,"code":3375,"language":3000,"meta":430,"style":430},"npm run test:e2e:phase3-1\n",[168,3377,3378],{"__ignoreMap":430},[1895,3379,3380,3382,3384],{"class":1897,"line":1898},[1895,3381,3037],{"class":2032},[1895,3383,3040],{"class":2042},[1895,3385,3386],{"class":2042}," test:e2e:phase3-1\n",[153,3388,3389],{},"Runs the Phase 3.1 large-document regression matrix.",[153,3391,3392,3394],{},[156,3393,3051],{}," protects page-by-page Canvas behavior and selectable-mode long-document behavior from future regressions.",[184,3396],{},[187,3398,3400],{"id":3399},"benchmarkphase3-2",[168,3401,3402],{},"benchmark:phase3-2",[153,3404,3405],{},"Re-tests security memory behavior after the incremental Canvas architecture.",[153,3407,3408,3410],{},[156,3409,3051],{}," verifies what the package fix solved and what remains downstream.",[184,3412],{},[187,3414,3416],{"id":3415},"benchmarkphase3-2repeat",[168,3417,3418],{},"benchmark:phase3-2:repeat",[153,3420,3421],{},"Repeats protected generation in the same browser page.",[153,3423,3424,3426],{},[156,3425,3051],{}," observes whether encrypted-raster retained memory changes the session baseline over repeated use.",[184,3428],{},[187,3430,3432],{"id":3431},"benchmarkphase3-2-1",[168,3433,3434],{},"benchmark:phase3-2-1",[153,3436,3437],{},"Runs the raw jsPDF reproduction.",[153,3439,3440,3442],{},[156,3441,3051],{}," removes Vue\u002Fcomponent lifecycle from the strongest security-memory reproduction and provides upstream evidence.",[184,3444],{},[145,3446,3448],{"id":3447},"_25-what-was-actually-improved-in-production-code","25. What was actually improved in production code",[153,3450,3451],{},"The benchmark program resulted in production changes, not only test files.",[187,3453,3455],{"id":3454},"production-improvements","Production improvements",[1030,3457,3459],{"id":3458},"_1-static-footer-reuse","1. Static footer reuse",[153,3461,3462],{},"Before:",[424,3464,3467],{"className":3465,"code":3466,"language":429,"meta":430},[427],"same HTML footer rasterized on every page\n",[168,3468,3466],{"__ignoreMap":430},[153,3470,3471],{},"After:",[424,3473,3476],{"className":3474,"code":3475,"language":429,"meta":430},[427],"static footer rasterized once and reused\n",[168,3477,3475],{"__ignoreMap":430},[184,3479],{},[1030,3481,3483],{"id":3482},"_2-incremental-page-by-page-canvas-rendering","2. Incremental page-by-page Canvas rendering",[153,3485,3486],{},"Before risk:",[424,3488,3491],{"className":3489,"code":3490,"language":429,"meta":430},[427],"entire long document → one giant html2canvas capture\n",[168,3492,3490],{"__ignoreMap":430},[153,3494,3495],{},"After for paginated Canvas:",[424,3497,3500],{"className":3498,"code":3499,"language":429,"meta":430},[427],"one page → capture → add → cleanup → next page\n",[168,3501,3499],{"__ignoreMap":430},[184,3503],{},[1030,3505,3507],{"id":3506},"_3-temporary-dom-cleanup","3. Temporary DOM cleanup",[153,3509,3510],{},"Off-screen page DOM is removed as soon as html2canvas no longer needs it.",[184,3512],{},[1030,3514,3516],{"id":3515},"_4-canvas-backing-store-release","4. Canvas backing-store release",[153,3518,3519],{},"After page insertion:",[424,3521,3522],{"className":1889,"code":2451,"language":1891,"meta":430,"style":430},[168,3523,3524,3536],{"__ignoreMap":430},[1895,3525,3526,3528,3530,3532,3534],{"class":1897,"line":1898},[1895,3527,2458],{"class":1901},[1895,3529,1906],{"class":1905},[1895,3531,2463],{"class":1901},[1895,3533,2466],{"class":1905},[1895,3535,2469],{"class":2060},[1895,3537,3538,3540,3542,3544,3546],{"class":1897,"line":2029},[1895,3539,2458],{"class":1901},[1895,3541,1906],{"class":1905},[1895,3543,2478],{"class":1901},[1895,3545,2466],{"class":1905},[1895,3547,2469],{"class":2060},[184,3549],{},[1030,3551,3553],{"id":3552},"_5-data-url-lifetime-reduction","5. Data URL lifetime reduction",[153,3555,3556],{},"Temporary encoded page strings are not intentionally retained after insertion.",[184,3558],{},[1030,3560,3562],{"id":3561},"_6-selectable-repeated-image-cache","6. Selectable repeated-image cache",[153,3564,3565,3566,3568],{},"Repeated real ",[168,3567,2285],{}," sources reuse materialized raster data within one generation.",[184,3570],{},[1030,3572,3574],{"id":3573},"_7-cache-cleanup","7. Cache cleanup",[153,3576,3577],{},"The image cache is cleared at the end of the generation phase.",[184,3579],{},[1030,3581,3583],{"id":3582},"_8-browser-yielding","8. Browser yielding",[153,3585,3586],{},"Long loops periodically yield to the browser.",[184,3588],{},[1030,3590,3592],{"id":3591},"_9-cancellation","9. Cancellation",[153,3594,3595],{},"Both renderer families have cooperative abort support.",[184,3597],{},[1030,3599,3601],{"id":3600},"_10-page-aware-progress","10. Page-aware progress",[153,3603,3604,221,3606,3608],{},[168,3605,220],{},[168,3607,224],{}," are available in page-aware rendering.",[184,3610],{},[1030,3612,3614],{"id":3613},"_11-recovery-verification","11. Recovery verification",[153,3616,3617],{},"A cancelled generation is followed by a successful new generation in E2E.",[184,3619],{},[1030,3621,3623],{"id":3622},"_12-long-document-routing-protection","12. Long-document routing protection",[153,3625,3626,3628],{},[168,3627,1387],{}," explicitly routes paginated Canvas documents into the incremental renderer.",[184,3630],{},[145,3632,3634],{"id":3633},"_26-goal-by-goal-completion-matrix","26. Goal-by-goal completion matrix",[612,3636,3637,3650],{},[615,3638,3639],{},[618,3640,3641,3644,3647],{},[621,3642,3643],{},"Original goal",[621,3645,3646],{},"Status",[621,3648,3649],{},"Result",[629,3651,3652,3663,3673,3683,3693,3703,3713,3723,3733,3743,3756,3766,3776,3786,3796,3806,3817,3828],{},[618,3653,3654,3657,3660],{},[634,3655,3656],{},"Benchmark 10 \u002F 25 \u002F 50 \u002F 100 pages",[634,3658,3659],{},"✅ Completed",[634,3661,3662],{},"Repeatable stress and correctness matrices",[618,3664,3665,3668,3670],{},[634,3666,3667],{},"Measure generation time",[634,3669,3659],{},[634,3671,3672],{},"JSON + Markdown summaries",[618,3674,3675,3678,3680],{},[634,3676,3677],{},"Measure PDF size",[634,3679,3659],{},[634,3681,3682],{},"Blob-size tracking",[618,3684,3685,3688,3690],{},[634,3686,3687],{},"Measure browser memory",[634,3689,3659],{},[634,3691,3692],{},"Peak\u002Fretained JS heap probes",[618,3694,3695,3698,3700],{},[634,3696,3697],{},"Detect repeated memory growth",[634,3699,3659],{},[634,3701,3702],{},"Fresh-context and same-page repeat probes",[618,3704,3705,3708,3710],{},[634,3706,3707],{},"Reduce giant Canvas pressure",[634,3709,3659],{},[634,3711,3712],{},"Page-by-page incremental Canvas",[618,3714,3715,3718,3720],{},[634,3716,3717],{},"Explore page-by-page rendering",[634,3719,3659],{},[634,3721,3722],{},"Production renderer implemented",[618,3724,3725,3728,3730],{},[634,3726,3727],{},"Improve image reuse",[634,3729,3659],{},[634,3731,3732],{},"Per-generation selectable image cache",[618,3734,3735,3738,3740],{},[634,3736,3737],{},"Add cancellation",[634,3739,3659],{},[634,3741,3742],{},"Canvas + selectable cancellation\u002Frecovery",[618,3744,3745,3748,3750],{},[634,3746,3747],{},"Add current\u002Ftotal page progress",[634,3749,3659],{},[634,3751,3752,3755],{},[168,3753,3754],{},"PdfProgressState"," page fields",[618,3757,3758,3761,3763],{},[634,3759,3760],{},"Improve responsiveness",[634,3762,3659],{},[634,3764,3765],{},"Cooperative browser yields",[618,3767,3768,3771,3773],{},[634,3769,3770],{},"Expand large-document E2E",[634,3772,3659],{},[634,3774,3775],{},"Phase 3 regression suites",[618,3777,3778,3781,3783],{},[634,3779,3780],{},"Verify cleanup",[634,3782,3659],{},[634,3784,3785],{},"DOM\u002Fcanvas\u002Fcache\u002Fcancel cleanup assertions",[618,3787,3788,3791,3793],{},[634,3789,3790],{},"Isolate encrypted memory behavior",[634,3792,3659],{},[634,3794,3795],{},"Package + raw jsPDF reproduction",[618,3797,3798,3801,3803],{},[634,3799,3800],{},"File upstream dependency issue",[634,3802,3659],{},[634,3804,3805],{},"jsPDF #4017",[618,3807,3808,3811,3814],{},[634,3809,3810],{},"Warn user before risky document",[634,3812,3813],{},"⏳ Not implemented as a public warning API",[634,3815,3816],{},"Documentation guidance exists",[618,3818,3819,3822,3825],{},[634,3820,3821],{},"Web Worker whole renderer",[634,3823,3824],{},"❌ Not implemented",[634,3826,3827],{},"DOM\u002Fhtml2canvas cannot simply move wholesale to a Worker",[618,3829,3830,3833,3836],{},[634,3831,3832],{},"Direct structured-PDF API",[634,3834,3835],{},"❌ Deliberately deferred",[634,3837,3838],{},"Package philosophy remains HTML\u002FVue-first",[153,3840,3841],{},"This distinction matters: the project should not claim features that were only discussed but never shipped.",[184,3843],{},[145,3845,3847],{"id":3846},"_27-safe-performance-claims-for-readmerelease-notes","27. Safe performance claims for README\u002Frelease notes",[153,3849,3850],{},"These statements are supported by the recorded work:",[1030,3852,3854],{"id":3853},"safe-claim-1","Safe claim 1",[150,3856,3857],{},[153,3858,3859],{},"Large paginated Canvas documents use page-by-page rendering instead of requiring one full-document raster capture.",[1030,3861,3863],{"id":3862},"safe-claim-2","Safe claim 2",[150,3865,3866],{},[153,3867,3868],{},"The large-document regression suite covers real 50-page and 100-page Canvas output.",[1030,3870,3872],{"id":3871},"safe-claim-3","Safe claim 3",[150,3874,3875],{},[153,3876,3877],{},"Static HTML footers are rasterized once and reused across pages.",[1030,3879,3881],{"id":3880},"safe-claim-4","Safe claim 4",[150,3883,3884],{},[153,3885,3886],{},"The recorded footer bottleneck benchmark improved from 7.82 s to 1.43 s without a logo and from 11.81 s to 1.29 s with a logo.",[1030,3888,3890],{"id":3889},"safe-claim-5","Safe claim 5",[150,3892,3893],{},[153,3894,3895],{},"Repeated selectable-mode image assets are cached per generation to avoid unnecessary repeated encoding.",[1030,3897,3899],{"id":3898},"safe-claim-6","Safe claim 6",[150,3901,3902],{},[153,3903,3904],{},"Long generation supports cooperative cancellation and page-aware progress.",[1030,3906,3908],{"id":3907},"safe-claim-7","Safe claim 7",[150,3910,3911],{},[153,3912,3913],{},"Browser memory behavior is stress-tested with fresh-context and repeated-generation probes.",[1030,3915,3917],{"id":3916},"safe-claim-8","Safe claim 8",[150,3919,3920],{},[153,3921,3922],{},"Encrypted raster PDFs are documented as a higher-memory workload; the dependency-level retention pattern was reproduced with raw jsPDF and reported upstream.",[184,3924],{},[145,3926,3928],{"id":3927},"_28-claims-that-should-not-be-made","28. Claims that should NOT be made",[153,3930,3931],{},"Do not publish claims such as:",[424,3933,3936],{"className":3934,"code":3935,"language":429,"meta":430},[427],"\"100 pages will work on every device\"\n\"the package has zero memory leaks\"\n\"memory use is 98% lower overall\"\n\"the package is 80% faster overall\"\n\"encryption is fully low-memory\"\n\"Canvas mode never freezes the browser\"\n",[168,3937,3935],{"__ignoreMap":430},[153,3939,3940],{},"Why?",[153,3942,3943],{},"Because:",[201,3945,3946,3949,3952,3955,3958,3961],{},[204,3947,3948],{},"arbitrary HTML complexity differs",[204,3950,3951],{},"device memory differs",[204,3953,3954],{},"image dimensions differ",[204,3956,3957],{},"Canvas scale differs",[204,3959,3960],{},"browser GC differs",[204,3962,3963],{},"encrypted raster retention remains dependency-sensitive",[153,3965,3966,3967,3970],{},"The 98.26% figure in this report refers specifically to the ",[156,3968,3969],{},"largest raster capture geometry"," in the diagnosed giant-canvas case versus the page-bounded capture, not total end-to-end browser memory.",[184,3972],{},[145,3974,3976],{"id":3975},"_29-practical-guidance-for-users","29. Practical guidance for users",[187,3978,3980],{"id":3979},"prefer-canvas-when","Prefer Canvas when",[201,3982,3983,3986,3989],{},[204,3984,3985],{},"CSS fidelity is the priority",[204,3987,3988],{},"gradients\u002Fshadows\u002Ftransforms matter",[204,3990,3991],{},"browser-like appearance matters more than selectable body text",[153,3993,3994],{},"For long Canvas documents:",[201,3996,3997,4000,4007,4010,4013,4016],{},[204,3998,3999],{},"use deterministic page boundaries",[204,4001,4002,4003,4006],{},"keep ",[168,4004,4005],{},"pdfQuality"," reasonable",[204,4008,4009],{},"avoid enormous source images",[204,4011,4012],{},"generate one very large PDF at a time",[204,4014,4015],{},"provide a Cancel button",[204,4017,4018],{},"test encryption on representative hardware",[187,4020,4022],{"id":4021},"prefer-selectable-text-when","Prefer selectable text when",[201,4024,4025,4028,4031,4034],{},[204,4026,4027],{},"real selectable\u002Fsearchable\u002Fcopyable text matters",[204,4029,4030],{},"the document is text-heavy",[204,4032,4033],{},"supported vector CSS is sufficient",[204,4035,4036],{},"lower raster workload is desirable",[187,4038,4040],{"id":4039},"for-repeated-assets","For repeated assets",[153,4042,4043],{},"Use normal image URLs\u002Fdata URLs consistently so per-generation reuse can work.",[184,4045],{},[145,4047,4049],{"id":4048},"_30-final-outcome","30. Final outcome",[153,4051,4052],{},"The large-document milestone achieved the original core objective:",[150,4054,4055],{},[153,4056,4057],{},"Make large PDF generation safer, more measurable, more interruptible and more reliable without replacing the existing Vue HTML-to-PDF developer experience.",[153,4059,4060],{},"The package now has:",[424,4062,4065],{"className":4063,"code":4064,"language":429,"meta":430},[427],"two rendering strategies\n+\npage-by-page Canvas for paginated long documents\n+\nselectable\u002Fvector rendering\n+\nimage reuse\n+\ncancellation\n+\npage progress\n+\nbrowser yielding\n+\ncleanup discipline\n+\nmemory isolation benchmarks\n+\n50\u002F100-page correctness gates\n+\nupstream dependency diagnostics\n",[168,4066,4064],{"__ignoreMap":430},[153,4068,4069],{},"The most important transformation is architectural:",[424,4071,4074],{"className":4072,"code":4073,"language":429,"meta":430},[427],"BEFORE\nlong paginated Canvas document\n→ risk of one enormous full-document capture\n\nAFTER\nlong paginated Canvas document\n→ render one logical page\n→ add it\n→ release temporary resources\n→ continue\n",[168,4075,4073],{"__ignoreMap":430},[153,4077,4078],{},"And the most important measurable proof is:",[424,4080,4083],{"className":4081,"code":4082,"language":429,"meta":430},[427],"50-page Canvas regression: PASS\n100-page Canvas regression: PASS\nlargest encoded page canvas remains 1191 × 1461 in the benchmark matrix\n",[168,4084,4082],{"__ignoreMap":430},[153,4086,4087],{},"The project did not solve every browser\u002FPDF memory problem, and it should not claim that it did.",[153,4089,4090],{},"What it did achieve is stronger:",[201,4092,4093,4096,4099,4102,4105,4108,4111,4114],{},[204,4094,4095],{},"real bottlenecks were measured",[204,4097,4098],{},"one major footer bottleneck was removed",[204,4100,4101],{},"long Canvas capture architecture was improved",[204,4103,4104],{},"the 50\u002F100-page collapse regression was fixed correctly",[204,4106,4107],{},"repeated-image work was bounded",[204,4109,4110],{},"users gained cancellation and meaningful page progress",[204,4112,4113],{},"memory cleanup was made more deliberate",[204,4115,4116],{},"the remaining encrypted-raster retention issue was isolated below the Vue layer and reported upstream",[153,4118,4119,4120,4122],{},"That makes ",[168,4121,170],{}," substantially more credible for serious multi-page browser PDF workloads than it was before this performance milestone.",[184,4124],{},[145,4126,4128],{"id":4127},"appendix-a-headline-measured-improvements","Appendix A - headline measured improvements",[612,4130,4131,4140],{},[615,4132,4133],{},[618,4134,4135,4137],{},[621,4136,736],{},[621,4138,4139],{},"Recorded result",[629,4141,4142,4155,4167,4179,4191,4204,4217,4228,4238,4247,4257,4266],{},[618,4143,4144,4146],{},[634,4145,644],{},[634,4147,4148,4151,4152,2179],{},[156,4149,4150],{},"7.82 s → 1.43 s"," (",[156,4153,4154],{},"81.7% less time",[618,4156,4157,4159],{},[634,4158,654],{},[634,4160,4161,4151,4164,2179],{},[156,4162,4163],{},"11.81 s → 1.29 s",[156,4165,4166],{},"89.1% less time",[618,4168,4169,4172],{},[634,4170,4171],{},"Pathological footer PDF size",[634,4173,4174,4151,4177,2179],{},[156,4175,4176],{},"~46.7 MB → ~1 MB",[156,4178,782],{},[618,4180,4181,4184],{},[634,4182,4183],{},"No-logo footer peak heap",[634,4185,4186,4151,4189,2179],{},[156,4187,4188],{},"102.6 MB → 26.5 MB",[156,4190,798],{},[618,4192,4193,4196],{},[634,4194,4195],{},"Giant Canvas raster geometry",[634,4197,4198,4151,4201,2179],{},[156,4199,4200],{},"~99.96M px → ~1.74M px\u002Fpage",[156,4202,4203],{},"~98.26% smaller peak capture surface",[618,4205,4206,4209],{},[634,4207,4208],{},"Selectable image fixture, 50p",[634,4210,4211,4151,4214,2179],{},[156,4212,4213],{},"200 image elements → ≤4 encode calls",[156,4215,4216],{},"≥98% fewer than naive per-element encoding",[618,4218,4219,4222],{},[634,4220,4221],{},"Encrypted selectable vs encrypted Canvas, 25p mixed",[634,4223,4224,4227],{},[156,4225,4226],{},"~86.8% lower retained heap"," in the recorded comparison",[618,4229,4230,4233],{},[634,4231,4232],{},"50-page Canvas release regression",[634,4234,4235],{},[156,4236,4237],{},"PASS",[618,4239,4240,4243],{},[634,4241,4242],{},"100-page Canvas release regression",[634,4244,4245],{},[156,4246,4237],{},[618,4248,4249,4252],{},[634,4250,4251],{},"Unit suite",[634,4253,4254],{},[156,4255,4256],{},"106 \u002F 106 PASS",[618,4258,4259,4262],{},[634,4260,4261],{},"Canvas cancellation\u002Frecovery",[634,4263,4264],{},[156,4265,4237],{},[618,4267,4268,4271],{},[634,4269,4270],{},"Selectable cancellation\u002Frecovery",[634,4272,4273],{},[156,4274,4237],{},[184,4276],{},[145,4278,4280],{"id":4279},"appendix-b-known-limitation","Appendix B - known limitation",[153,4282,4283],{},"Large encrypted Canvas\u002Fraster PDFs remain a special high-memory case.",[153,4285,4286],{},"Upstream tracking:",[153,4288,4289,4292,4294],{},[156,4290,4291],{},"jsPDF issue #4017",[161,4293],{},[1870,4295,1872],{"href":1872,"rel":4296},[1874],[153,4298,4299],{},"The package documentation should continue to recommend representative testing for:",[201,4301,4302,4305,4308,4311,4314],{},[204,4303,4304],{},"encrypted reports",[204,4306,4307],{},"image-heavy reports",[204,4309,4310],{},"very high Canvas quality",[204,4312,4313],{},"lower-memory devices",[204,4315,4316],{},"repeated generation in one browser session",[184,4318],{},[145,4320,4322],{"id":4321},"appendix-c-one-command-regression-workflow","Appendix C - one-command regression workflow",[153,4324,4325],{},"The project now supports a reproducible high-level performance run:",[424,4327,4329],{"className":2998,"code":4328,"language":3000,"meta":430,"style":430},"npm run performance:everything\n",[168,4330,4331],{"__ignoreMap":430},[1895,4332,4333,4335,4337],{"class":1897,"line":1898},[1895,4334,3037],{"class":2032},[1895,4336,3040],{"class":2042},[1895,4338,4339],{"class":2042}," performance:everything\n",[153,4341,4342],{},"The run is intentionally sequential for heavy PDF work.",[153,4344,4345],{},"Running many long-PDF browser jobs in parallel would measure resource contention as much as it measures the package.",[153,4347,4348],{},"For release-critical long-document E2E, keep:",[424,4350,4351],{"className":2998,"code":2999,"language":3000,"meta":430,"style":430},[168,4352,4353],{"__ignoreMap":430},[1895,4354,4355,4357,4359],{"class":1897,"line":1898},[1895,4356,3007],{"class":1901},[1895,4358,2466],{"class":1905},[1895,4360,3012],{"class":2042},[153,4362,4363],{},"where appropriate.",[184,4365],{},[153,4367,4368],{},[156,4369,4370],{},"End of report.",[4372,4373,4374],"style",{},"html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}",{"title":430,"searchDepth":2029,"depth":2029,"links":4376},[4377,4378,4379,4380,4381,4382,4383,4384,4385,4388,4389,4390,4391,4392,4395,4396,4397,4398,4399,4400,4401,4402,4403,4404,4405,4406,4407,4408,4410,4413,4414,4415,4416,4417,4418,4419,4420,4421,4422,4423,4424,4425,4426,4427,4428,4429,4430,4431,4432,4433,4434,4435,4436,4437,4438,4460,4461,4462],{"id":189,"depth":2029,"text":190},{"id":557,"depth":2029,"text":558},{"id":606,"depth":2029,"text":607},{"id":690,"depth":2029,"text":691},{"id":715,"depth":2029,"text":716},{"id":849,"depth":2029,"text":850},{"id":894,"depth":2029,"text":895},{"id":918,"depth":2029,"text":919},{"id":966,"depth":2029,"text":967,"children":4386},[4387],{"id":1032,"depth":2052,"text":1033},{"id":1066,"depth":2029,"text":1067},{"id":1223,"depth":2029,"text":1224},{"id":1336,"depth":2029,"text":1337},{"id":1406,"depth":2029,"text":1407},{"id":1440,"depth":2029,"text":1441,"children":4393},[4394],{"id":1453,"depth":2052,"text":1454},{"id":1507,"depth":2029,"text":1508},{"id":1523,"depth":2029,"text":1524},{"id":1681,"depth":2029,"text":1682},{"id":1718,"depth":2029,"text":1719},{"id":1790,"depth":2029,"text":1791},{"id":1841,"depth":2029,"text":1842},{"id":1922,"depth":2029,"text":1923},{"id":1949,"depth":2029,"text":1950},{"id":1973,"depth":2029,"text":1974},{"id":1992,"depth":2029,"text":1993},{"id":2192,"depth":2029,"text":2193},{"id":2248,"depth":2029,"text":2249},{"id":2258,"depth":2029,"text":2259},{"id":2268,"depth":2029,"text":4409},"Why \u003Ccanvas> is not cached",{"id":2289,"depth":2029,"text":2290,"children":4411},[4412],{"id":2320,"depth":2052,"text":2321},{"id":2390,"depth":2029,"text":1993},{"id":2437,"depth":2029,"text":2438},{"id":2488,"depth":2029,"text":1993},{"id":2569,"depth":2029,"text":2570},{"id":2585,"depth":2029,"text":2586},{"id":2598,"depth":2029,"text":2599},{"id":3024,"depth":2029,"text":3027},{"id":3057,"depth":2029,"text":3060},{"id":3087,"depth":2029,"text":3090},{"id":3117,"depth":2029,"text":3120},{"id":3147,"depth":2029,"text":3150},{"id":3177,"depth":2029,"text":3180},{"id":3207,"depth":2029,"text":3210},{"id":3218,"depth":2029,"text":3221},{"id":3248,"depth":2029,"text":3251},{"id":3259,"depth":2029,"text":3262},{"id":3292,"depth":2029,"text":3295},{"id":3308,"depth":2029,"text":3311},{"id":3324,"depth":2029,"text":3327},{"id":3342,"depth":2029,"text":3345},{"id":3358,"depth":2029,"text":3361},{"id":3369,"depth":2029,"text":3372},{"id":3399,"depth":2029,"text":3402},{"id":3415,"depth":2029,"text":3418},{"id":3431,"depth":2029,"text":3434},{"id":3454,"depth":2029,"text":3455,"children":4439},[4440,4441,4442,4443,4444,4445,4446,4447,4448,4449,4450,4451,4452,4453,4454,4455,4456,4457,4458,4459],{"id":3458,"depth":2052,"text":3459},{"id":3482,"depth":2052,"text":3483},{"id":3506,"depth":2052,"text":3507},{"id":3515,"depth":2052,"text":3516},{"id":3552,"depth":2052,"text":3553},{"id":3561,"depth":2052,"text":3562},{"id":3573,"depth":2052,"text":3574},{"id":3582,"depth":2052,"text":3583},{"id":3591,"depth":2052,"text":3592},{"id":3600,"depth":2052,"text":3601},{"id":3613,"depth":2052,"text":3614},{"id":3622,"depth":2052,"text":3623},{"id":3853,"depth":2052,"text":3854},{"id":3862,"depth":2052,"text":3863},{"id":3871,"depth":2052,"text":3872},{"id":3880,"depth":2052,"text":3881},{"id":3889,"depth":2052,"text":3890},{"id":3898,"depth":2052,"text":3899},{"id":3907,"depth":2052,"text":3908},{"id":3916,"depth":2052,"text":3917},{"id":3979,"depth":2029,"text":3980},{"id":4021,"depth":2029,"text":4022},{"id":4039,"depth":2029,"text":4040},"md",null,{},true,{"description":4468,"title":128},"Complete phase-by-phase large-document performance engineering report for vue-pdf-export.","lymxst0d3U4H0KJM4nHwlngn9z3ETiloO53DgAGf1ek",[4471,4473],{"title":124,"path":125,"stem":126,"description":4472,"children":-1},"The large-document milestone was not only a benchmark exercise. It changed the runtime architecture and added repeatable correctness, cleanup and memory diagnostics.",{"title":132,"path":133,"stem":134,"description":4474,"children":-1},"The package source is currently maintained privately, but feedback and feature requests are welcome.",1788876783599]