1+ import {
2+ createParagraphCompaction ,
3+ mapCompactY ,
4+ } from '../features/reader/paragraph-compaction.mjs' ;
15import { installRenderDiagnostics } from '../features/reader/render-diagnostics.mjs' ;
26import { installReaderViewObservers } from '../features/reader/view-observers.mjs' ;
37import { installReaderPreferenceObservers } from '../features/settings/preference-observers.mjs' ;
@@ -59,6 +63,7 @@ export function useReaderWindow() {
5963 layoutVisible,
6064 reuseTranslations,
6165 interactionMode,
66+ optimizeParagraphGaps,
6267 restoreDocuments,
6368 documentOpenMode,
6469 defaultPageCropEnabled,
@@ -327,6 +332,7 @@ export function useReaderWindow() {
327332 viewportPages : featureActions . viewportPages ,
328333 scheduleViewport : featureActions . scheduleViewport ,
329334 scheduleReadingSave : featureActions . scheduleReadingSave ,
335+ mapDisplayPage : ( p ) => displayedPage ( p ) ,
330336 importFile : featureActions . importFile ,
331337 ensurePDF : featureActions . ensurePDF ,
332338 active,
@@ -347,7 +353,7 @@ export function useReaderWindow() {
347353 searchPages,
348354 searchPageCount,
349355 searchHit,
350- displayedPage,
356+ displayedPage : searchedPage ,
351357 openSearch,
352358 closeSearch,
353359 scheduleSearch,
@@ -431,6 +437,44 @@ export function useReaderWindow() {
431437
432438 // Display-only, total fraction removed symmetrically from each axis.
433439 const pageCrop = ref ( { x : 0 , y : 0 } ) ;
440+ const compactParagraphPage = createParagraphCompaction ( {
441+ enabled : computed (
442+ ( ) =>
443+ preferences . optimizeParagraphGaps . value &&
444+ direction . value === 'vertical' &&
445+ columns . value === 1 &&
446+ interactionMode . value === 'reading' &&
447+ showTranslations . value ,
448+ ) ,
449+ pages,
450+ sourceDocument : ( ) => session . pdf ,
451+ getDocument : ( options ) => session . getDocument ( options ) ,
452+ changing : ( page , result ) => {
453+ const el = reader . value ,
454+ number = active . value ;
455+ const host = renderState . pageEls . get ( number ) ;
456+ if ( ! el || ! host ) return ( ) => { } ;
457+ const top = el . getBoundingClientRect ( ) . top ;
458+ const offset = top - host . getBoundingClientRect ( ) . top ;
459+ const mapped =
460+ page . number === number
461+ ? mapCompactY ( offset / zoom . value , result . cuts ) * zoom . value
462+ : offset ;
463+ return ( ) => {
464+ const current = renderState . pageEls . get ( number ) ;
465+ if ( current && reader . value === el )
466+ el . scrollTop += current . getBoundingClientRect ( ) . top + mapped - top ;
467+ } ;
468+ } ,
469+ changed : ( restore ) =>
470+ nextTick ( ( ) => {
471+ restore ?. ( ) ;
472+ featureActions . renderPages ( false , true ) ;
473+ } ) ,
474+ } ) ;
475+ function displayedPage ( p ) {
476+ return compactParagraphPage ( searchedPage ( p ) ) ;
477+ }
434478 // Read geometry only: spreading a reactive page subscribes the full-document
435479 // layout to visibility, translation and annotation updates on every scroll.
436480
@@ -482,6 +526,11 @@ export function useReaderWindow() {
482526 labelKey : 'translation.reading' ,
483527 descriptionKey : 'translation.readingDescription' ,
484528 } ,
529+ {
530+ id : 'reading-ahead' ,
531+ labelKey : 'translation.readingAhead' ,
532+ descriptionKey : 'translation.readingAheadDescription' ,
533+ } ,
485534 ] ;
486535
487536 watch ( translationMode , ( ) => {
@@ -808,6 +857,7 @@ export function useReaderWindow() {
808857 emphasizeTopicSentences,
809858 showKernelToolbarShortcut,
810859 autoHideHeader,
860+ optimizeParagraphGaps,
811861 kernelAdvancedOptions,
812862 translationServices,
813863 glossaries,
@@ -1013,6 +1063,7 @@ export function useReaderWindow() {
10131063 informationCategories,
10141064 informationCategorySettings,
10151065 interactionMode,
1066+ optimizeParagraphGaps,
10161067 kernelAdvancedOptions,
10171068 kernelErrorVisible,
10181069 kernelFailure,
0 commit comments