From 4d36e992f65c86fbc5cf58e927cd10563714146a Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Sun, 8 Dec 2024 12:16:57 +0100 Subject: [PATCH 01/88] Add a rough reflowable navigator --- .../java/org/readium/navigator/demo/DemoUi.kt | 4 +- .../readium/navigator/demo/DemoViewModel.kt | 6 +- .../demo/preferences/PreferenceViews.kt | 14 +- .../demo/preferences/PreferencesManager.kt | 2 +- .../demo/preferences/UserPreferences.kt | 4 +- .../navigator/demo/reader/ReaderOpener.kt | 67 +- .../readium/navigator/demo/reader/ReaderUi.kt | 21 +- .../navigator/demo/util/Fullscreenable.kt | 2 +- .../org/readium/navigator/demo/util/Theme.kt | 2 +- .../navigator/demo/util/ToggleButton.kt | 4 +- ...tures-bridge.ts => all-gestures-bridge.ts} | 0 ...bridge.ts => all-initialization-bridge.ts} | 1 + .../scripts/src/bridge/fixed-double-bridge.ts | 2 +- .../scripts/src/bridge/fixed-single-bridge.ts | 2 +- .../src/bridge/reflowable-css-bridge.ts | 31 + .../web/scripts/src/index-fixed-double.ts | 8 +- .../web/scripts/src/index-fixed-single.ts | 8 +- .../src/index-reflowable-injectable.ts | 50 ++ .../navigators/web/scripts/webpack.config.js | 1 + .../navigators/web/fixed-double-script.js | 2 +- .../navigators/web/fixed-double-script.js.map | 2 +- .../navigators/web/fixed-single-script.js | 2 +- .../navigators/web/fixed-single-script.js.map | 2 +- .../navigators/web/readium-css/ReadMe.md | 112 ++++ .../web/readium-css/ReadiumCSS-after.css | 7 + .../web/readium-css/ReadiumCSS-before.css | 7 + .../web/readium-css/ReadiumCSS-default.css | 7 + .../ReadiumCSS-ebpaj_fonts_patch.css | 80 +++ .../cjk-horizontal/ReadiumCSS-after.css | 7 + .../cjk-horizontal/ReadiumCSS-before.css | 7 + .../cjk-horizontal/ReadiumCSS-default.css | 7 + .../cjk-vertical/ReadiumCSS-after.css | 7 + .../cjk-vertical/ReadiumCSS-before.css | 7 + .../cjk-vertical/ReadiumCSS-default.css | 7 + .../web/readium-css/fonts/AccessibleDfA.otf | Bin 0 -> 145384 bytes .../readium-css/fonts/LICENSE-AccessibleDfa | 95 +++ .../fonts/LICENSE-IaWriterDuospace.md | 110 ++++ .../fonts/iAWriterDuospace-Regular.ttf | Bin 0 -> 81636 bytes .../web/readium-css/rtl/ReadiumCSS-after.css | 7 + .../web/readium-css/rtl/ReadiumCSS-before.css | 7 + .../readium-css/rtl/ReadiumCSS-default.css | 7 + .../web/reflowable-injectable-script.js | 2 + .../web/reflowable-injectable-script.js.map | 1 + .../navigator/web/FixedWebRendition.kt | 16 +- .../navigator/web/FixedWebRenditionState.kt | 14 +- .../web/ReflowableWebNavigatorFactory.kt | 119 ++++ .../navigator/web/ReflowableWebRendition.kt | 142 +++++ .../web/ReflowableWebRenditionState.kt | 212 +++++++ .../web/css/FontFamilyDeclaration.kt | 207 ++++++ .../org/readium/navigator/web/css/Layout.kt | 70 +++ .../readium/navigator/web/css/Properties.kt | 590 ++++++++++++++++++ .../readium/navigator/web/css/ReadiumCss.kt | 268 ++++++++ .../{spread => fixed}/DoubleViewportSpread.kt | 6 +- .../{spread => fixed}/SingleViewportSpread.kt | 6 +- .../SpreadNestedScrollConnection.kt | 2 +- .../web/{spread => fixed}/SpreadWebView.kt | 23 +- .../web/gestures/DragGestureDetector.kt | 17 +- .../navigator/web/gestures/Draggable.kt | 12 +- .../navigator/web/gestures/Fling2DBehavior.kt | 12 +- .../navigator/web/gestures/Scrollable2D.kt | 145 +++-- .../web/gestures/Scrollable2DState.kt | 46 +- .../navigator/web/layout/LayoutResolver.kt | 1 + .../navigator/web/location/LocationTypes.kt | 20 +- .../navigator/web/location/LocatorAdapters.kt | 10 +- .../pager/LoggingNestedScrollConnection.kt | 1 + .../web/pager/LoggingTargetedFlingBehavior.kt | 1 + .../web/preferences/ReflowableWebDefaults.kt | 18 + .../preferences/ReflowableWebPreferences.kt | 33 + .../ReflowableWebPreferencesEditor.kt | 98 +++ .../ReflowableWebPreferencesFilters.kt | 38 ++ .../web/preferences/ReflowableWebSettings.kt | 19 + .../ReflowableWebSettingsResolver.kt | 41 ++ .../ReflowableNestedScrollConnection.kt | 52 ++ .../web/reflowable/ReflowableResource.kt | 233 +++++++ .../LazyListSnapLayoutInfoProvider.kt | 45 ++ .../snapping/PagerSnapLayoutInfoProvider.kt | 243 ++++++++ .../web/snapping/PagingFlingBehavior.kt | 117 ++++ .../navigator/web/util/HtmlInjector.kt | 104 ++- .../readium/navigator/web/util/Language.kt | 27 + .../navigator/web/util/WebViewServer.kt | 10 +- .../readium/navigator/web/webapi/CssApi.kt | 31 + .../navigator/web/webapi/InitializationApi.kt | 6 + .../web/webview/ComposableWebView.kt | 107 ++-- .../navigator/web/webview/RelaxedWebView.kt | 6 + .../web/webview/WebViewLayoutInfoProvider.kt | 57 ++ .../web/webview/WebViewScrollable2DState.kt | 10 +- 86 files changed, 3674 insertions(+), 282 deletions(-) rename readium/navigators/web/scripts/src/bridge/{fixed-gestures-bridge.ts => all-gestures-bridge.ts} (100%) rename readium/navigators/web/scripts/src/bridge/{fixed-initialization-bridge.ts => all-initialization-bridge.ts} (69%) create mode 100644 readium/navigators/web/scripts/src/bridge/reflowable-css-bridge.ts create mode 100644 readium/navigators/web/scripts/src/index-reflowable-injectable.ts create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadMe.md create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadiumCSS-after.css create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadiumCSS-before.css create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadiumCSS-default.css create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadiumCSS-ebpaj_fonts_patch.css create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-horizontal/ReadiumCSS-after.css create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-horizontal/ReadiumCSS-before.css create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-horizontal/ReadiumCSS-default.css create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-vertical/ReadiumCSS-after.css create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-vertical/ReadiumCSS-before.css create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-vertical/ReadiumCSS-default.css create mode 100755 readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/fonts/AccessibleDfA.otf create mode 100755 readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/fonts/LICENSE-AccessibleDfa create mode 100755 readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/fonts/LICENSE-IaWriterDuospace.md create mode 100755 readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/fonts/iAWriterDuospace-Regular.ttf create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/rtl/ReadiumCSS-after.css create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/rtl/ReadiumCSS-before.css create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/rtl/ReadiumCSS-default.css create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/reflowable-injectable-script.js create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/reflowable-injectable-script.js.map create mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebNavigatorFactory.kt create mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt create mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt create mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/css/FontFamilyDeclaration.kt create mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/css/Layout.kt create mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/css/Properties.kt create mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCss.kt rename readium/navigators/web/src/main/java/org/readium/navigator/web/{spread => fixed}/DoubleViewportSpread.kt (94%) rename readium/navigators/web/src/main/java/org/readium/navigator/web/{spread => fixed}/SingleViewportSpread.kt (94%) rename readium/navigators/web/src/main/java/org/readium/navigator/web/{spread => fixed}/SpreadNestedScrollConnection.kt (98%) rename readium/navigators/web/src/main/java/org/readium/navigator/web/{spread => fixed}/SpreadWebView.kt (82%) create mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebDefaults.kt create mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferences.kt create mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesEditor.kt create mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesFilters.kt create mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettings.kt create mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettingsResolver.kt create mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableNestedScrollConnection.kt create mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt create mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/LazyListSnapLayoutInfoProvider.kt create mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/PagerSnapLayoutInfoProvider.kt create mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/PagingFlingBehavior.kt create mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/util/Language.kt create mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/webapi/CssApi.kt create mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewLayoutInfoProvider.kt diff --git a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/DemoUi.kt b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/DemoUi.kt index 89e136bae9..4f7ccb15d6 100644 --- a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/DemoUi.kt +++ b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/DemoUi.kt @@ -30,7 +30,7 @@ fun Scaffold( fullscreenState: State, insetsController: WindowInsetsControllerCompat, snackbarHostState: SnackbarHostState, - content: @Composable () -> Unit + content: @Composable () -> Unit, ) { Fullscreenable( fullscreenState = fullscreenState, @@ -56,7 +56,7 @@ fun MainContent( viewmodel: DemoViewModel, launchBookSelection: () -> Unit, snackbarHostState: SnackbarHostState, - fullscreenState: MutableState + fullscreenState: MutableState, ) { val viewmodelState = viewmodel.state.collectAsState().value diff --git a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/DemoViewModel.kt b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/DemoViewModel.kt index 4971099095..555695ad84 100644 --- a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/DemoViewModel.kt +++ b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/DemoViewModel.kt @@ -20,7 +20,7 @@ import org.readium.r2.shared.util.toDebugDescription import timber.log.Timber class DemoViewModel( - application: Application + application: Application, ) : AndroidViewModel(application) { sealed interface State { @@ -32,11 +32,11 @@ class DemoViewModel( State data class Error( - val error: org.readium.r2.shared.util.Error + val error: org.readium.r2.shared.util.Error, ) : State data class Reader( - val readerState: ReaderState<*, *> + val readerState: ReaderState<*, *>, ) : State } diff --git a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/preferences/PreferenceViews.kt b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/preferences/PreferenceViews.kt index 70ec33cdac..7fe9ca04c1 100644 --- a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/preferences/PreferenceViews.kt +++ b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/preferences/PreferenceViews.kt @@ -41,7 +41,7 @@ import org.readium.r2.navigator.preferences.toggle fun ButtonGroupItem( title: String, preference: EnumPreference, - formatValue: (T) -> String + formatValue: (T) -> String, ) { ButtonGroupItem( title = title, @@ -74,7 +74,7 @@ private fun ButtonGroupItem( selectedOption: T?, formatValue: (T) -> String, onClear: (() -> Unit)?, - onSelectedOptionChanged: (T) -> Unit + onSelectedOptionChanged: (T) -> Unit, ) { Item(title, isActive = isActive, onClear = onClear) { ToggleButtonGroup( @@ -97,7 +97,7 @@ private fun ButtonGroupItem( @Composable fun > StepperItem( title: String, - preference: RangePreference + preference: RangePreference, ) { StepperItem( title = title, @@ -122,7 +122,7 @@ private fun StepperItem( formatValue: (T) -> String, onDecrement: () -> Unit, onIncrement: () -> Unit, - onClear: (() -> Unit)? + onClear: (() -> Unit)?, ) { Item(title, isActive = isActive, onClear = onClear) { Row( @@ -158,7 +158,7 @@ private fun StepperItem( @Composable fun SwitchItem( title: String, - preference: Preference + preference: Preference, ) { SwitchItem( title = title, @@ -181,7 +181,7 @@ private fun SwitchItem( isActive: Boolean, onCheckedChange: (Boolean) -> Unit, onToggle: () -> Unit, - onClear: (() -> Unit)? + onClear: (() -> Unit)?, ) { Item( title = title, @@ -202,7 +202,7 @@ private fun Item( isActive: Boolean = true, onClick: (() -> Unit)? = null, onClear: (() -> Unit)? = null, - content: @Composable () -> Unit + content: @Composable () -> Unit, ) { ListItem( modifier = diff --git a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/preferences/PreferencesManager.kt b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/preferences/PreferencesManager.kt index da7d10bf28..9fea509820 100644 --- a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/preferences/PreferencesManager.kt +++ b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/preferences/PreferencesManager.kt @@ -13,7 +13,7 @@ import org.readium.r2.navigator.preferences.Configurable * Trivial user preferences manager. You can add persistence. */ class PreferencesManager

>( - initialPreferences: P + initialPreferences: P, ) { private val preferencesMutable: MutableStateFlow

= MutableStateFlow(initialPreferences) diff --git a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/preferences/UserPreferences.kt b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/preferences/UserPreferences.kt index 24f1df1954..abff2f9038 100644 --- a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/preferences/UserPreferences.kt +++ b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/preferences/UserPreferences.kt @@ -43,7 +43,7 @@ import org.readium.r2.shared.ExperimentalReadiumApi @Composable fun

, S : Settings, E : PreferencesEditor> UserPreferences( editor: E, - title: String + title: String, ) { val scrollState = rememberScrollState() @@ -97,7 +97,7 @@ private fun FixedLayoutUserPreferences( fit: EnumPreference? = null, spreads: Preference? = null, offsetFirstPage: Preference? = null, - pageSpacing: RangePreference? = null + pageSpacing: RangePreference? = null, ) { if (readingProgression != null) { ButtonGroupItem( diff --git a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/reader/ReaderOpener.kt b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/reader/ReaderOpener.kt index 683a7d3bc4..2465077161 100644 --- a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/reader/ReaderOpener.kt +++ b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/reader/ReaderOpener.kt @@ -17,11 +17,17 @@ import org.readium.navigator.demo.persistence.LocatorRepository import org.readium.navigator.demo.preferences.PreferencesManager import org.readium.navigator.web.FixedWebNavigatorFactory import org.readium.navigator.web.FixedWebRenditionController +import org.readium.navigator.web.ReflowableWebNavigatorFactory +import org.readium.navigator.web.ReflowableWebRenditionController import org.readium.navigator.web.location.FixedWebLocation +import org.readium.navigator.web.location.ReflowableWebLocation import org.readium.navigator.web.preferences.FixedWebPreferences +import org.readium.navigator.web.preferences.ReflowableWebPreferences import org.readium.r2.shared.ExperimentalReadiumApi import org.readium.r2.shared.publication.Locator import org.readium.r2.shared.publication.Publication +import org.readium.r2.shared.publication.epub.EpubLayout +import org.readium.r2.shared.publication.presentation.presentation import org.readium.r2.shared.util.AbsoluteUrl import org.readium.r2.shared.util.DebugError import org.readium.r2.shared.util.Error @@ -33,7 +39,7 @@ import org.readium.r2.streamer.PublicationOpener import org.readium.r2.streamer.parser.DefaultPublicationParser class ReaderOpener( - private val application: Application + private val application: Application, ) { private val httpClient = @@ -62,7 +68,12 @@ class ReaderOpener( val readerState = when { publication.conformsTo(Publication.Profile.EPUB) -> - createFixedWebReader(url, publication, initialLocator) + when (publication.metadata.presentation.layout) { + EpubLayout.FIXED -> + createFixedWebReader(url, publication, initialLocator) + EpubLayout.REFLOWABLE, null -> + createReflowableWebReader(url, publication, initialLocator) + } /* publication.conformsTo(Publication.Profile.PDF) -> createPdfReader(url, publication, initialLocator) */ @@ -77,10 +88,60 @@ class ReaderOpener( return Try.success(readerState) } + private suspend fun createReflowableWebReader( + url: AbsoluteUrl, + publication: Publication, + initialLocator: Locator?, + ): Try, Error> { + val navigatorFactory = ReflowableWebNavigatorFactory(application, publication) + ?: return Try.failure(DebugError("Publication not supported")) + + val locatorAdapter = navigatorFactory.createLocatorAdapter() + + val initialLocation = with(locatorAdapter) { initialLocator?.toGoLocation() } + + val coroutineScope = MainScope() + + val initialPreferences = ReflowableWebPreferences() + + val preferencesManager = PreferencesManager(initialPreferences) + + val settingsEditor = navigatorFactory.createPreferencesEditor(initialPreferences) + + snapshotFlow { settingsEditor.preferences } + .onEach { preferencesManager.setPreferences(it) } + .launchIn(coroutineScope) + + val navigatorState = navigatorFactory.createRenditionState( + initialSettings = settingsEditor.settings, + initialLocation = initialLocation + ).getOrElse { + return Try.failure(it) + } + + val onNavigatorCreated: (ReflowableWebRenditionController) -> Unit = { navigator -> + snapshotFlow { settingsEditor.settings } + .onEach { navigator.settings.value = it } + .launchIn(coroutineScope) + } + + val readerState = ReaderState( + url = url, + coroutineScope = coroutineScope, + publication = publication, + renditionState = navigatorState, + preferencesEditor = settingsEditor, + locatorAdapter = locatorAdapter, + onNavigatorCreated = onNavigatorCreated + ) + + return Try.success(readerState) + } + private suspend fun createFixedWebReader( url: AbsoluteUrl, publication: Publication, - initialLocator: Locator? + initialLocator: Locator?, ): Try, Error> { val navigatorFactory = FixedWebNavigatorFactory(application, publication) ?: return Try.failure(DebugError("Publication not supported")) diff --git a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/reader/ReaderUi.kt b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/reader/ReaderUi.kt index 2469392bb1..caf98957f6 100644 --- a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/reader/ReaderUi.kt +++ b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/reader/ReaderUi.kt @@ -54,6 +54,8 @@ import org.readium.navigator.demo.preferences.UserPreferences import org.readium.navigator.demo.util.launchWebBrowser import org.readium.navigator.web.FixedWebRendition import org.readium.navigator.web.FixedWebRenditionState +import org.readium.navigator.web.ReflowableWebRendition +import org.readium.navigator.web.ReflowableWebRenditionState import org.readium.r2.shared.ExperimentalReadiumApi import org.readium.r2.shared.publication.Publication import org.readium.r2.shared.util.AbsoluteUrl @@ -66,7 +68,7 @@ data class ReaderState>( val renditionState: RenditionState, val preferencesEditor: PreferencesEditor<*, *>, val locatorAdapter: LocatorAdapter, - val onNavigatorCreated: (N) -> Unit + val onNavigatorCreated: (N) -> Unit, ) { fun close() { @@ -79,7 +81,7 @@ data class ReaderState>( @Composable fun > Reader( readerState: ReaderState, - fullScreenState: MutableState + fullScreenState: MutableState, ) { val showPreferences = remember { mutableStateOf(false) } val preferencesSheetState = rememberModalBottomSheetState() @@ -159,7 +161,10 @@ fun > Reader( defaultHyperlinkListener( controller = controllerNow, - shouldFollowReadingOrderLink = { _, _ -> onFollowingLink(); true }, + shouldFollowReadingOrderLink = { _, _ -> + onFollowingLink() + true + }, onExternalLinkActivated = { url, _ -> launchWebBrowser(context, url.toUri()) } ) } @@ -173,6 +178,14 @@ fun > Reader( hyperlinkListener = hyperlinkListener ) } + is ReflowableWebRenditionState -> { + ReflowableWebRendition( + modifier = Modifier.fillMaxSize(), + state = readerState.renditionState, + inputListener = inputListener, + hyperlinkListener = hyperlinkListener + ) + } /* is PdfNavigatorState<*, *> -> { PdfNavigator( modifier = Modifier.fillMaxSize(), @@ -189,7 +202,7 @@ fun > Reader( private fun TopBar( modifier: Modifier, visible: Boolean, - onPreferencesActivated: () -> Unit + onPreferencesActivated: () -> Unit, ) { AnimatedVisibility( modifier = modifier, diff --git a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/util/Fullscreenable.kt b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/util/Fullscreenable.kt index 24ba274450..024395b84a 100644 --- a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/util/Fullscreenable.kt +++ b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/util/Fullscreenable.kt @@ -19,7 +19,7 @@ import androidx.core.view.WindowInsetsControllerCompat fun Fullscreenable( fullscreenState: State, insetsController: WindowInsetsControllerCompat, - content: @Composable () -> Unit + content: @Composable () -> Unit, ) { insetsController.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE diff --git a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/util/Theme.kt b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/util/Theme.kt index 0965f29764..fe43d8884a 100644 --- a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/util/Theme.kt +++ b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/util/Theme.kt @@ -15,7 +15,7 @@ import androidx.compose.runtime.Composable @Composable fun Theme( darkTheme: Boolean = isSystemInDarkTheme(), - content: @Composable () -> Unit + content: @Composable () -> Unit, ) { val colors = if (darkTheme) { darkColorScheme() diff --git a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/util/ToggleButton.kt b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/util/ToggleButton.kt index 8650c78f7a..e0a2ca955a 100644 --- a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/util/ToggleButton.kt +++ b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/util/ToggleButton.kt @@ -28,7 +28,7 @@ fun ToggleButtonGroup( selectedOption: T?, onSelectOption: (T) -> Unit, enabled: (T) -> Boolean = { true }, - content: @Composable RowScope.(T) -> Unit + content: @Composable RowScope.(T) -> Unit, ) { Row { for (option in options) { @@ -50,7 +50,7 @@ fun ToggleButton( enabled: Boolean = true, active: Boolean = false, selected: Boolean = false, - content: @Composable RowScope.() -> Unit + content: @Composable RowScope.() -> Unit, ) { OutlinedButton( modifier = modifier, diff --git a/readium/navigators/web/scripts/src/bridge/fixed-gestures-bridge.ts b/readium/navigators/web/scripts/src/bridge/all-gestures-bridge.ts similarity index 100% rename from readium/navigators/web/scripts/src/bridge/fixed-gestures-bridge.ts rename to readium/navigators/web/scripts/src/bridge/all-gestures-bridge.ts diff --git a/readium/navigators/web/scripts/src/bridge/fixed-initialization-bridge.ts b/readium/navigators/web/scripts/src/bridge/all-initialization-bridge.ts similarity index 69% rename from readium/navigators/web/scripts/src/bridge/fixed-initialization-bridge.ts rename to readium/navigators/web/scripts/src/bridge/all-initialization-bridge.ts index 059196892f..5bd2e3d6b7 100644 --- a/readium/navigators/web/scripts/src/bridge/fixed-initialization-bridge.ts +++ b/readium/navigators/web/scripts/src/bridge/all-initialization-bridge.ts @@ -1,3 +1,4 @@ export interface InitializationBridge { onScriptsLoaded: () => void + onDocumentLoaded: () => void } diff --git a/readium/navigators/web/scripts/src/bridge/fixed-double-bridge.ts b/readium/navigators/web/scripts/src/bridge/fixed-double-bridge.ts index d5be6cd6f1..b011a24fcc 100644 --- a/readium/navigators/web/scripts/src/bridge/fixed-double-bridge.ts +++ b/readium/navigators/web/scripts/src/bridge/fixed-double-bridge.ts @@ -1,6 +1,6 @@ import { Insets, Size } from "../common/types" import { DoubleAreaManager } from "../fixed/double-area-manager" -import { GesturesBridge, BridgeGesturesAdapter } from "./fixed-gestures-bridge" +import { GesturesBridge, BridgeGesturesAdapter } from "./all-gestures-bridge" import { Fit } from "../util/fit" export class FixedDoubleBridge { diff --git a/readium/navigators/web/scripts/src/bridge/fixed-single-bridge.ts b/readium/navigators/web/scripts/src/bridge/fixed-single-bridge.ts index 96e8fb7fb0..97488a7737 100644 --- a/readium/navigators/web/scripts/src/bridge/fixed-single-bridge.ts +++ b/readium/navigators/web/scripts/src/bridge/fixed-single-bridge.ts @@ -1,7 +1,7 @@ import { Insets, Size } from "../common/types" import { SingleAreaManager } from "../fixed/single-area-manager" import { Fit } from "../util/fit" -import { GesturesBridge, BridgeGesturesAdapter } from "./fixed-gestures-bridge" +import { GesturesBridge, BridgeGesturesAdapter } from "./all-gestures-bridge" export class FixedSingleBridge { private readonly manager: SingleAreaManager diff --git a/readium/navigators/web/scripts/src/bridge/reflowable-css-bridge.ts b/readium/navigators/web/scripts/src/bridge/reflowable-css-bridge.ts new file mode 100644 index 0000000000..a5c38a451c --- /dev/null +++ b/readium/navigators/web/scripts/src/bridge/reflowable-css-bridge.ts @@ -0,0 +1,31 @@ +export class CssBridge { + readonly document: Document + + constructor(document: Document) { + this.document = document + } + + setProperties(properties: Map) { + for (const [key, value] of properties) { + this.setProperty(key, value) + } + } + + // For setting user setting. + setProperty(key: string, value: string) { + if (value === null || value === "") { + this.removeProperty(key) + } else { + const root = document.documentElement + // The `!important` annotation is added with `setProperty()` because if it's part of the + // `value`, it will be ignored by the Web View. + root.style.setProperty(key, value, "important") + } + } + + // For removing user setting. + removeProperty(key: string) { + const root = document.documentElement + root.style.removeProperty(key) + } +} diff --git a/readium/navigators/web/scripts/src/index-fixed-double.ts b/readium/navigators/web/scripts/src/index-fixed-double.ts index e8f9e61b6f..f7e1ff4e01 100644 --- a/readium/navigators/web/scripts/src/index-fixed-double.ts +++ b/readium/navigators/web/scripts/src/index-fixed-double.ts @@ -8,9 +8,9 @@ * Script loaded by the single area HTML wrapper for fixed layout resources. */ -import { GesturesBridge } from "./bridge/fixed-gestures-bridge" +import { GesturesBridge } from "./bridge/all-gestures-bridge" import { FixedDoubleBridge } from "./bridge/fixed-double-bridge" -import { InitializationBridge } from "./bridge/fixed-initialization-bridge" +import { InitializationBridge } from "./bridge/all-initialization-bridge" declare global { interface Window { @@ -37,3 +37,7 @@ Window.prototype.doubleArea = new FixedDoubleBridge( ) window.initialization.onScriptsLoaded() +// eslint-disable-next-line @typescript-eslint/no-unused-vars +window.addEventListener("load", (event) => { + window.initialization.onDocumentLoaded() +}) diff --git a/readium/navigators/web/scripts/src/index-fixed-single.ts b/readium/navigators/web/scripts/src/index-fixed-single.ts index 4901130417..8ba427871a 100644 --- a/readium/navigators/web/scripts/src/index-fixed-single.ts +++ b/readium/navigators/web/scripts/src/index-fixed-single.ts @@ -8,8 +8,8 @@ * Script loaded by the single area HTML wrapper for fixed layout resources. */ -import { GesturesBridge } from "./bridge/fixed-gestures-bridge" -import { InitializationBridge } from "./bridge/fixed-initialization-bridge" +import { GesturesBridge } from "./bridge/all-gestures-bridge" +import { InitializationBridge } from "./bridge/all-initialization-bridge" import { FixedSingleBridge } from "./bridge/fixed-single-bridge" declare global { @@ -34,3 +34,7 @@ window.singleArea = new FixedSingleBridge( ) window.initialization.onScriptsLoaded() +// eslint-disable-next-line @typescript-eslint/no-unused-vars +window.addEventListener("load", (event) => { + window.initialization.onDocumentLoaded() +}) diff --git a/readium/navigators/web/scripts/src/index-reflowable-injectable.ts b/readium/navigators/web/scripts/src/index-reflowable-injectable.ts new file mode 100644 index 0000000000..1c42c5c145 --- /dev/null +++ b/readium/navigators/web/scripts/src/index-reflowable-injectable.ts @@ -0,0 +1,50 @@ +// +// Copyright 2024 Readium Foundation. All rights reserved. +// Use of this source code is governed by the BSD-style license +// available in the top-level LICENSE file of the project. +// + +/** + * Script loaded by reflowable resources. + */ + +import { + BridgeGesturesAdapter, + GesturesBridge, +} from "./bridge/all-gestures-bridge" +import { InitializationBridge } from "./bridge/all-initialization-bridge" +import { CssBridge } from "./bridge/reflowable-css-bridge" +import { GesturesDetector } from "./common/gestures" + +declare global { + interface Window { + initialization: InitializationBridge + gestures: GesturesBridge + readiumcss: CssBridge + } +} + +const bridgeListener = new BridgeGesturesAdapter(window.gestures) + +const gesturesListener = { + onTap: (event: MouseEvent) => { + const tapEvent = { + x: event.clientX * visualViewport!.scale, + y: event.clientY * visualViewport!.scale, + } + bridgeListener.onTap(tapEvent) + }, + onLinkActivated: (href: string, outerHtml: string) => { + bridgeListener.onLinkActivated(href, outerHtml) + }, +} + +new GesturesDetector(window, gesturesListener) + +Window.prototype.readiumcss = new CssBridge(window.document) + +window.initialization.onScriptsLoaded() +// eslint-disable-next-line @typescript-eslint/no-unused-vars +window.addEventListener("load", (event) => { + window.initialization.onDocumentLoaded() +}) diff --git a/readium/navigators/web/scripts/webpack.config.js b/readium/navigators/web/scripts/webpack.config.js index a811aba7f1..67619f3fb8 100644 --- a/readium/navigators/web/scripts/webpack.config.js +++ b/readium/navigators/web/scripts/webpack.config.js @@ -8,6 +8,7 @@ module.exports = { "fixed-single-script": "./src/index-fixed-single.ts", "fixed-double-script": "./src/index-fixed-double.ts", "fixed-injectable-script": "./src/index-fixed-injectable.ts", + "reflowable-injectable-script": "./src/index-reflowable-injectable.ts", }, resolve: { // Add '.ts' and '.tsx' as resolvable extensions. diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/fixed-double-script.js b/readium/navigators/web/src/main/assets/readium/navigators/web/fixed-double-script.js index ec7736c608..d49a066db1 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/fixed-double-script.js +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/fixed-double-script.js @@ -1,2 +1,2 @@ -!function(){"use strict";class t{constructor(t,e,i){if(this.margins={top:0,right:0,bottom:0,left:0},!e.contentWindow)throw Error("Iframe argument must have been attached to DOM.");this.listener=i,this.iframe=e}setMessagePort(t){t.onmessage=t=>{this.onMessageFromIframe(t)}}show(){this.iframe.style.display="unset"}hide(){this.iframe.style.display="none"}setMargins(t){this.margins!=t&&(this.iframe.style.marginTop=this.margins.top+"px",this.iframe.style.marginLeft=this.margins.left+"px",this.iframe.style.marginBottom=this.margins.bottom+"px",this.iframe.style.marginRight=this.margins.right+"px")}loadPage(t){this.iframe.src=t}setPlaceholder(t){this.iframe.style.visibility="hidden",this.iframe.style.width=t.width+"px",this.iframe.style.height=t.height+"px",this.size=t}onMessageFromIframe(t){const e=t.data;switch(e.kind){case"contentSize":return this.onContentSizeAvailable(e.size);case"tap":return this.listener.onTap({x:e.x,y:e.y});case"linkActivated":return this.onLinkActivated(e)}}onLinkActivated(t){try{const e=new URL(t.href,this.iframe.src);this.listener.onLinkActivated(e.toString(),t.outerHtml)}catch(t){}}onContentSizeAvailable(t){t&&(this.iframe.style.width=t.width+"px",this.iframe.style.height=t.height+"px",this.size=t,this.listener.onIframeLoaded())}}class e{setInitialScale(t){return this.initialScale=t,this}setMinimumScale(t){return this.minimumScale=t,this}setWidth(t){return this.width=t,this}setHeight(t){return this.height=t,this}build(){const t=[];return this.initialScale&&t.push("initial-scale="+this.initialScale),this.minimumScale&&t.push("minimum-scale="+this.minimumScale),this.width&&t.push("width="+this.width),this.height&&t.push("height="+this.height),t.join(", ")}}class i{constructor(t,e){this.window=t,this.listener=e,document.addEventListener("click",(t=>{this.onClick(t)}),!1)}onClick(t){if(t.defaultPrevented)return;const e=this.window.getSelection();if(e&&"Range"==e.type)return;let i;i=t.target instanceof HTMLElement?this.nearestInteractiveElement(t.target):null,i?i instanceof HTMLAnchorElement&&this.listener.onLinkActivated(i.href,i.outerHTML):this.listener.onTap(t),t.stopPropagation(),t.preventDefault()}nearestInteractiveElement(t){return null==t?null:-1!=["a","audio","button","canvas","details","input","label","option","select","submit","textarea","video"].indexOf(t.nodeName.toLowerCase())||t.hasAttribute("contenteditable")&&"false"!=t.getAttribute("contenteditable").toLowerCase()?t:t.parentElement?this.nearestInteractiveElement(t.parentElement):null}}class s{constructor(e,s,n,a,h){this.fit="contain",this.insets={top:0,right:0,bottom:0,left:0},e.addEventListener("message",(t=>{t.ports[0]&&(t.source===s.contentWindow?this.leftPage.setMessagePort(t.ports[0]):t.source==n.contentWindow&&this.rightPage.setMessagePort(t.ports[0]))})),new i(e,{onTap:t=>{const e={x:(t.clientX-visualViewport.offsetLeft)*visualViewport.scale,y:(t.clientY-visualViewport.offsetTop)*visualViewport.scale};h.onTap(e)},onLinkActivated:t=>{throw Error("No interactive element in the root document.")}});const o={onIframeLoaded:()=>{this.layout()},onTap:t=>{const e=s.getBoundingClientRect(),i={x:(t.x+e.left-visualViewport.offsetLeft)*visualViewport.scale,y:(t.y+e.top-visualViewport.offsetTop)*visualViewport.scale};h.onTap(i)},onLinkActivated:(t,e)=>{h.onLinkActivated(t,e)}},r={onIframeLoaded:()=>{this.layout()},onTap:t=>{const e=n.getBoundingClientRect(),i={x:(t.x+e.left-visualViewport.offsetLeft)*visualViewport.scale,y:(t.y+e.top-visualViewport.offsetTop)*visualViewport.scale};h.onTap(i)},onLinkActivated:(t,e)=>{h.onLinkActivated(t,e)}};this.leftPage=new t(e,s,o),this.rightPage=new t(e,n,r),this.metaViewport=a}loadSpread(t){this.leftPage.hide(),this.rightPage.hide(),this.spread=t,t.left&&this.leftPage.loadPage(t.left),t.right&&this.rightPage.loadPage(t.right)}setViewport(t,e){this.viewport==t&&this.insets==e||(this.viewport=t,this.insets=e,this.layout())}setFit(t){this.fit!=t&&(this.fit=t,this.layout())}layout(){if(!this.viewport||!this.leftPage.size&&this.spread.left||!this.rightPage.size&&this.spread.right)return;const t={top:this.insets.top,right:0,bottom:this.insets.bottom,left:this.insets.left};this.leftPage.setMargins(t);const i={top:this.insets.top,right:this.insets.right,bottom:this.insets.bottom,left:0};this.rightPage.setMargins(i),this.spread.right?this.spread.left||this.leftPage.setPlaceholder(this.rightPage.size):this.rightPage.setPlaceholder(this.leftPage.size);const s=this.leftPage.size.width+this.rightPage.size.width,n=Math.max(this.leftPage.size.height,this.rightPage.size.height),a={width:s,height:n},h={width:this.viewport.width-this.insets.left-this.insets.right,height:this.viewport.height-this.insets.top-this.insets.bottom},o=function(t,e,i){switch(t){case"contain":return function(t,e){const i=e.width/t.width,s=e.height/t.height;return Math.min(i,s)}(e,i);case"width":return function(t,e){return e.width/t.width}(e,i);case"height":return function(t,e){return e.height/t.height}(e,i)}}(this.fit,a,h);this.metaViewport.content=(new e).setInitialScale(o).setMinimumScale(o).setWidth(s).setHeight(n).build(),this.leftPage.show(),this.rightPage.show()}}class n{constructor(t){this.nativeApi=t}onTap(t){this.nativeApi.onTap(JSON.stringify(t))}onLinkActivated(t,e){this.nativeApi.onLinkActivated(t,e)}}const a=document.getElementById("page-left"),h=document.getElementById("page-right"),o=document.querySelector("meta[name=viewport]");Window.prototype.doubleArea=new class{constructor(t,e,i,a,h){const o=new n(h);this.manager=new s(t,e,i,a,o)}loadSpread(t){this.manager.loadSpread(t)}setViewport(t,e,i,s,n,a){const h={width:t,height:e},o={top:i,left:a,bottom:n,right:s};this.manager.setViewport(h,o)}setFit(t){if("contain"!=t&&"width"!=t&&"height"!=t)throw Error(`Invalid fit value: ${t}`);this.manager.setFit(t)}}(window,a,h,o,window.gestures),window.initialization.onScriptsLoaded()}(); +!function(){"use strict";class t{constructor(t,e,i){if(this.margins={top:0,right:0,bottom:0,left:0},!e.contentWindow)throw Error("Iframe argument must have been attached to DOM.");this.listener=i,this.iframe=e}setMessagePort(t){t.onmessage=t=>{this.onMessageFromIframe(t)}}show(){this.iframe.style.display="unset"}hide(){this.iframe.style.display="none"}setMargins(t){this.margins!=t&&(this.iframe.style.marginTop=this.margins.top+"px",this.iframe.style.marginLeft=this.margins.left+"px",this.iframe.style.marginBottom=this.margins.bottom+"px",this.iframe.style.marginRight=this.margins.right+"px")}loadPage(t){this.iframe.src=t}setPlaceholder(t){this.iframe.style.visibility="hidden",this.iframe.style.width=t.width+"px",this.iframe.style.height=t.height+"px",this.size=t}onMessageFromIframe(t){const e=t.data;switch(e.kind){case"contentSize":return this.onContentSizeAvailable(e.size);case"tap":return this.listener.onTap({x:e.x,y:e.y});case"linkActivated":return this.onLinkActivated(e)}}onLinkActivated(t){try{const e=new URL(t.href,this.iframe.src);this.listener.onLinkActivated(e.toString(),t.outerHtml)}catch(t){}}onContentSizeAvailable(t){t&&(this.iframe.style.width=t.width+"px",this.iframe.style.height=t.height+"px",this.size=t,this.listener.onIframeLoaded())}}class e{setInitialScale(t){return this.initialScale=t,this}setMinimumScale(t){return this.minimumScale=t,this}setWidth(t){return this.width=t,this}setHeight(t){return this.height=t,this}build(){const t=[];return this.initialScale&&t.push("initial-scale="+this.initialScale),this.minimumScale&&t.push("minimum-scale="+this.minimumScale),this.width&&t.push("width="+this.width),this.height&&t.push("height="+this.height),t.join(", ")}}class i{constructor(t,e){this.window=t,this.listener=e,document.addEventListener("click",(t=>{this.onClick(t)}),!1)}onClick(t){if(t.defaultPrevented)return;const e=this.window.getSelection();if(e&&"Range"==e.type)return;let i;i=t.target instanceof HTMLElement?this.nearestInteractiveElement(t.target):null,i?i instanceof HTMLAnchorElement&&this.listener.onLinkActivated(i.href,i.outerHTML):this.listener.onTap(t),t.stopPropagation(),t.preventDefault()}nearestInteractiveElement(t){return null==t?null:-1!=["a","audio","button","canvas","details","input","label","option","select","submit","textarea","video"].indexOf(t.nodeName.toLowerCase())||t.hasAttribute("contenteditable")&&"false"!=t.getAttribute("contenteditable").toLowerCase()?t:t.parentElement?this.nearestInteractiveElement(t.parentElement):null}}class s{constructor(e,s,n,a,h){this.fit="contain",this.insets={top:0,right:0,bottom:0,left:0},e.addEventListener("message",(t=>{t.ports[0]&&(t.source===s.contentWindow?this.leftPage.setMessagePort(t.ports[0]):t.source==n.contentWindow&&this.rightPage.setMessagePort(t.ports[0]))})),new i(e,{onTap:t=>{const e={x:(t.clientX-visualViewport.offsetLeft)*visualViewport.scale,y:(t.clientY-visualViewport.offsetTop)*visualViewport.scale};h.onTap(e)},onLinkActivated:t=>{throw Error("No interactive element in the root document.")}});const o={onIframeLoaded:()=>{this.layout()},onTap:t=>{const e=s.getBoundingClientRect(),i={x:(t.x+e.left-visualViewport.offsetLeft)*visualViewport.scale,y:(t.y+e.top-visualViewport.offsetTop)*visualViewport.scale};h.onTap(i)},onLinkActivated:(t,e)=>{h.onLinkActivated(t,e)}},r={onIframeLoaded:()=>{this.layout()},onTap:t=>{const e=n.getBoundingClientRect(),i={x:(t.x+e.left-visualViewport.offsetLeft)*visualViewport.scale,y:(t.y+e.top-visualViewport.offsetTop)*visualViewport.scale};h.onTap(i)},onLinkActivated:(t,e)=>{h.onLinkActivated(t,e)}};this.leftPage=new t(e,s,o),this.rightPage=new t(e,n,r),this.metaViewport=a}loadSpread(t){this.leftPage.hide(),this.rightPage.hide(),this.spread=t,t.left&&this.leftPage.loadPage(t.left),t.right&&this.rightPage.loadPage(t.right)}setViewport(t,e){this.viewport==t&&this.insets==e||(this.viewport=t,this.insets=e,this.layout())}setFit(t){this.fit!=t&&(this.fit=t,this.layout())}layout(){if(!this.viewport||!this.leftPage.size&&this.spread.left||!this.rightPage.size&&this.spread.right)return;const t={top:this.insets.top,right:0,bottom:this.insets.bottom,left:this.insets.left};this.leftPage.setMargins(t);const i={top:this.insets.top,right:this.insets.right,bottom:this.insets.bottom,left:0};this.rightPage.setMargins(i),this.spread.right?this.spread.left||this.leftPage.setPlaceholder(this.rightPage.size):this.rightPage.setPlaceholder(this.leftPage.size);const s=this.leftPage.size.width+this.rightPage.size.width,n=Math.max(this.leftPage.size.height,this.rightPage.size.height),a={width:s,height:n},h={width:this.viewport.width-this.insets.left-this.insets.right,height:this.viewport.height-this.insets.top-this.insets.bottom},o=function(t,e,i){switch(t){case"contain":return function(t,e){const i=e.width/t.width,s=e.height/t.height;return Math.min(i,s)}(e,i);case"width":return function(t,e){return e.width/t.width}(e,i);case"height":return function(t,e){return e.height/t.height}(e,i)}}(this.fit,a,h);this.metaViewport.content=(new e).setInitialScale(o).setMinimumScale(o).setWidth(s).setHeight(n).build(),this.leftPage.show(),this.rightPage.show()}}class n{constructor(t){this.nativeApi=t}onTap(t){this.nativeApi.onTap(JSON.stringify(t))}onLinkActivated(t,e){this.nativeApi.onLinkActivated(t,e)}}const a=document.getElementById("page-left"),h=document.getElementById("page-right"),o=document.querySelector("meta[name=viewport]");Window.prototype.doubleArea=new class{constructor(t,e,i,a,h){const o=new n(h);this.manager=new s(t,e,i,a,o)}loadSpread(t){this.manager.loadSpread(t)}setViewport(t,e,i,s,n,a){const h={width:t,height:e},o={top:i,left:a,bottom:n,right:s};this.manager.setViewport(h,o)}setFit(t){if("contain"!=t&&"width"!=t&&"height"!=t)throw Error(`Invalid fit value: ${t}`);this.manager.setFit(t)}}(window,a,h,o,window.gestures),window.initialization.onScriptsLoaded(),window.addEventListener("load",(t=>{window.initialization.onDocumentLoaded()}))}(); //# sourceMappingURL=fixed-double-script.js.map \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/fixed-double-script.js.map b/readium/navigators/web/src/main/assets/readium/navigators/web/fixed-double-script.js.map index 64252e2400..b82a829c21 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/fixed-double-script.js.map +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/fixed-double-script.js.map @@ -1 +1 @@ -{"version":3,"file":"fixed-double-script.js","mappings":"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","sources":["webpack://readium-js/./src/fixed/page-manager.ts","webpack://readium-js/./src/util/viewport.ts","webpack://readium-js/./src/common/gestures.ts","webpack://readium-js/./src/fixed/double-area-manager.ts","webpack://readium-js/./src/util/fit.ts","webpack://readium-js/./src/bridge/fixed-gestures-bridge.ts","webpack://readium-js/./src/index-fixed-double.ts","webpack://readium-js/./src/bridge/fixed-double-bridge.ts"],"sourcesContent":["/** Manages a fixed layout resource embedded in an iframe. */\nexport class PageManager {\n constructor(window, iframe, listener) {\n this.margins = { top: 0, right: 0, bottom: 0, left: 0 };\n if (!iframe.contentWindow) {\n throw Error(\"Iframe argument must have been attached to DOM.\");\n }\n this.listener = listener;\n this.iframe = iframe;\n }\n setMessagePort(messagePort) {\n messagePort.onmessage = (message) => {\n this.onMessageFromIframe(message);\n };\n }\n show() {\n this.iframe.style.display = \"unset\";\n }\n hide() {\n this.iframe.style.display = \"none\";\n }\n /** Sets page margins. */\n setMargins(margins) {\n if (this.margins == margins) {\n return;\n }\n this.iframe.style.marginTop = this.margins.top + \"px\";\n this.iframe.style.marginLeft = this.margins.left + \"px\";\n this.iframe.style.marginBottom = this.margins.bottom + \"px\";\n this.iframe.style.marginRight = this.margins.right + \"px\";\n }\n /** Loads page content. */\n loadPage(url) {\n this.iframe.src = url;\n }\n /** Sets the size of this page without content. */\n setPlaceholder(size) {\n this.iframe.style.visibility = \"hidden\";\n this.iframe.style.width = size.width + \"px\";\n this.iframe.style.height = size.height + \"px\";\n this.size = size;\n }\n onMessageFromIframe(event) {\n const message = event.data;\n switch (message.kind) {\n case \"contentSize\":\n return this.onContentSizeAvailable(message.size);\n case \"tap\":\n return this.listener.onTap({ x: message.x, y: message.y });\n case \"linkActivated\":\n return this.onLinkActivated(message);\n }\n }\n onLinkActivated(message) {\n try {\n const url = new URL(message.href, this.iframe.src);\n this.listener.onLinkActivated(url.toString(), message.outerHtml);\n }\n catch (_a) {\n // Do nothing if url is not valid.\n }\n }\n onContentSizeAvailable(size) {\n if (!size) {\n //FIXME: handle edge case\n return;\n }\n this.iframe.style.width = size.width + \"px\";\n this.iframe.style.height = size.height + \"px\";\n this.size = size;\n this.listener.onIframeLoaded();\n }\n}\n","export class ViewportStringBuilder {\n setInitialScale(scale) {\n this.initialScale = scale;\n return this;\n }\n setMinimumScale(scale) {\n this.minimumScale = scale;\n return this;\n }\n setWidth(width) {\n this.width = width;\n return this;\n }\n setHeight(height) {\n this.height = height;\n return this;\n }\n build() {\n const components = [];\n if (this.initialScale) {\n components.push(\"initial-scale=\" + this.initialScale);\n }\n if (this.minimumScale) {\n components.push(\"minimum-scale=\" + this.minimumScale);\n }\n if (this.width) {\n components.push(\"width=\" + this.width);\n }\n if (this.height) {\n components.push(\"height=\" + this.height);\n }\n return components.join(\", \");\n }\n}\nexport function parseViewportString(viewportString) {\n const regex = /(\\w+) *= *([^\\s,]+)/g;\n const properties = new Map();\n let match;\n while ((match = regex.exec(viewportString))) {\n if (match != null) {\n properties.set(match[1], match[2]);\n }\n }\n const width = parseFloat(properties.get(\"width\"));\n const height = parseFloat(properties.get(\"height\"));\n if (width && height) {\n return { width, height };\n }\n else {\n return undefined;\n }\n}\n","export class GesturesDetector {\n constructor(window, listener) {\n this.window = window;\n this.listener = listener;\n document.addEventListener(\"click\", (event) => {\n this.onClick(event);\n }, false);\n }\n onClick(event) {\n if (event.defaultPrevented) {\n return;\n }\n const selection = this.window.getSelection();\n if (selection && selection.type == \"Range\") {\n // There's an on-going selection, the tap will dismiss it so we don't forward it.\n // selection.type might be None (collapsed) or Caret with a collapsed range\n // when there is not true selection.\n return;\n }\n let nearestElement;\n if (event.target instanceof HTMLElement) {\n nearestElement = this.nearestInteractiveElement(event.target);\n }\n else {\n nearestElement = null;\n }\n if (nearestElement) {\n if (nearestElement instanceof HTMLAnchorElement) {\n this.listener.onLinkActivated(nearestElement.href, nearestElement.outerHTML);\n }\n }\n else {\n this.listener.onTap(event);\n }\n event.stopPropagation();\n event.preventDefault();\n }\n // See. https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling\n nearestInteractiveElement(element) {\n if (element == null) {\n return null;\n }\n const interactiveTags = [\n \"a\",\n \"audio\",\n \"button\",\n \"canvas\",\n \"details\",\n \"input\",\n \"label\",\n \"option\",\n \"select\",\n \"submit\",\n \"textarea\",\n \"video\",\n ];\n if (interactiveTags.indexOf(element.nodeName.toLowerCase()) != -1) {\n return element;\n }\n // Checks whether the element is editable by the user.\n if (element.hasAttribute(\"contenteditable\") &&\n element.getAttribute(\"contenteditable\").toLowerCase() != \"false\") {\n return element;\n }\n // Checks parents recursively because the touch might be for example on an inside a .\n if (element.parentElement) {\n return this.nearestInteractiveElement(element.parentElement);\n }\n return null;\n }\n}\n","import { computeScale } from \"../util/fit\";\nimport { PageManager } from \"./page-manager\";\nimport { ViewportStringBuilder } from \"../util/viewport\";\nimport { GesturesDetector } from \"../common/gestures\";\nexport class DoubleAreaManager {\n constructor(window, leftIframe, rightIframe, metaViewport, listener) {\n this.fit = \"contain\" /* Fit.Contain */;\n this.insets = { top: 0, right: 0, bottom: 0, left: 0 };\n window.addEventListener(\"message\", (event) => {\n if (!event.ports[0]) {\n return;\n }\n if (event.source === leftIframe.contentWindow) {\n this.leftPage.setMessagePort(event.ports[0]);\n }\n else if (event.source == rightIframe.contentWindow) {\n this.rightPage.setMessagePort(event.ports[0]);\n }\n });\n const wrapperGesturesListener = {\n onTap: (event) => {\n const tapEvent = {\n x: (event.clientX - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.clientY - visualViewport.offsetTop) * visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onLinkActivated: (_) => {\n throw Error(\"No interactive element in the root document.\");\n },\n };\n new GesturesDetector(window, wrapperGesturesListener);\n const leftPageListener = {\n onIframeLoaded: () => {\n this.layout();\n },\n onTap: (event) => {\n const boundingRect = leftIframe.getBoundingClientRect();\n const tapEvent = {\n x: (event.x + boundingRect.left - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.y + boundingRect.top - visualViewport.offsetTop) *\n visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n listener.onLinkActivated(href, outerHtml);\n },\n };\n const rightPageListener = {\n onIframeLoaded: () => {\n this.layout();\n },\n onTap: (event) => {\n const boundingRect = rightIframe.getBoundingClientRect();\n const tapEvent = {\n x: (event.x + boundingRect.left - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.y + boundingRect.top - visualViewport.offsetTop) *\n visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n listener.onLinkActivated(href, outerHtml);\n },\n };\n this.leftPage = new PageManager(window, leftIframe, leftPageListener);\n this.rightPage = new PageManager(window, rightIframe, rightPageListener);\n this.metaViewport = metaViewport;\n }\n loadSpread(spread) {\n this.leftPage.hide();\n this.rightPage.hide();\n this.spread = spread;\n if (spread.left) {\n this.leftPage.loadPage(spread.left);\n }\n if (spread.right) {\n this.rightPage.loadPage(spread.right);\n }\n }\n setViewport(size, insets) {\n if (this.viewport == size && this.insets == insets) {\n return;\n }\n this.viewport = size;\n this.insets = insets;\n this.layout();\n }\n setFit(fit) {\n if (this.fit == fit) {\n return;\n }\n this.fit = fit;\n this.layout();\n }\n layout() {\n if (!this.viewport ||\n (!this.leftPage.size && this.spread.left) ||\n (!this.rightPage.size && this.spread.right)) {\n return;\n }\n const leftMargins = {\n top: this.insets.top,\n right: 0,\n bottom: this.insets.bottom,\n left: this.insets.left,\n };\n this.leftPage.setMargins(leftMargins);\n const rightMargins = {\n top: this.insets.top,\n right: this.insets.right,\n bottom: this.insets.bottom,\n left: 0,\n };\n this.rightPage.setMargins(rightMargins);\n if (!this.spread.right) {\n this.rightPage.setPlaceholder(this.leftPage.size);\n }\n else if (!this.spread.left) {\n this.leftPage.setPlaceholder(this.rightPage.size);\n }\n const contentWidth = this.leftPage.size.width + this.rightPage.size.width;\n const contentHeight = Math.max(this.leftPage.size.height, this.rightPage.size.height);\n const contentSize = { width: contentWidth, height: contentHeight };\n const safeDrawingSize = {\n width: this.viewport.width - this.insets.left - this.insets.right,\n height: this.viewport.height - this.insets.top - this.insets.bottom,\n };\n const scale = computeScale(this.fit, contentSize, safeDrawingSize);\n this.metaViewport.content = new ViewportStringBuilder()\n .setInitialScale(scale)\n .setMinimumScale(scale)\n .setWidth(contentWidth)\n .setHeight(contentHeight)\n .build();\n this.leftPage.show();\n this.rightPage.show();\n }\n}\n","export function computeScale(fit, content, container) {\n switch (fit) {\n case \"contain\" /* Fit.Contain */:\n return fitContain(content, container);\n case \"width\" /* Fit.Width */:\n return fitWidth(content, container);\n case \"height\" /* Fit.Height */:\n return fitHeight(content, container);\n }\n}\nfunction fitContain(content, container) {\n const widthRatio = container.width / content.width;\n const heightRatio = container.height / content.height;\n return Math.min(widthRatio, heightRatio);\n}\nfunction fitWidth(content, container) {\n return container.width / content.width;\n}\nfunction fitHeight(content, container) {\n return container.height / content.height;\n}\n","export class BridgeGesturesAdapter {\n constructor(gesturesApi) {\n this.nativeApi = gesturesApi;\n }\n onTap(event) {\n this.nativeApi.onTap(JSON.stringify(event));\n }\n onLinkActivated(href, outerHtml) {\n this.nativeApi.onLinkActivated(href, outerHtml);\n }\n}\n","//\n// Copyright 2024 Readium Foundation. All rights reserved.\n// Use of this source code is governed by the BSD-style license\n// available in the top-level LICENSE file of the project.\n//\nimport { FixedDoubleBridge } from \"./bridge/fixed-double-bridge\";\nconst leftIframe = document.getElementById(\"page-left\");\nconst rightIframe = document.getElementById(\"page-right\");\nconst metaViewport = document.querySelector(\"meta[name=viewport]\");\nWindow.prototype.doubleArea = new FixedDoubleBridge(window, leftIframe, rightIframe, metaViewport, window.gestures);\nwindow.initialization.onScriptsLoaded();\n","import { DoubleAreaManager } from \"../fixed/double-area-manager\";\nimport { BridgeGesturesAdapter } from \"./fixed-gestures-bridge\";\nexport class FixedDoubleBridge {\n constructor(window, leftIframe, rightIframe, metaViewport, gestures) {\n const listener = new BridgeGesturesAdapter(gestures);\n this.manager = new DoubleAreaManager(window, leftIframe, rightIframe, metaViewport, listener);\n }\n loadSpread(spread) {\n this.manager.loadSpread(spread);\n }\n setViewport(viewporttWidth, viewportHeight, insetTop, insetRight, insetBottom, insetLeft) {\n const viewport = { width: viewporttWidth, height: viewportHeight };\n const insets = {\n top: insetTop,\n left: insetLeft,\n bottom: insetBottom,\n right: insetRight,\n };\n this.manager.setViewport(viewport, insets);\n }\n setFit(fit) {\n if (fit != \"contain\" && fit != \"width\" && fit != \"height\") {\n throw Error(`Invalid fit value: ${fit}`);\n }\n this.manager.setFit(fit);\n }\n}\n"],"names":["PageManager","constructor","window","iframe","listener","this","margins","top","right","bottom","left","contentWindow","Error","setMessagePort","messagePort","onmessage","message","onMessageFromIframe","show","style","display","hide","setMargins","marginTop","marginLeft","marginBottom","marginRight","loadPage","url","src","setPlaceholder","size","visibility","width","height","event","data","kind","onContentSizeAvailable","onTap","x","y","onLinkActivated","URL","href","toString","outerHtml","_a","onIframeLoaded","ViewportStringBuilder","setInitialScale","scale","initialScale","setMinimumScale","minimumScale","setWidth","setHeight","build","components","push","join","GesturesDetector","document","addEventListener","onClick","defaultPrevented","selection","getSelection","type","nearestElement","target","HTMLElement","nearestInteractiveElement","HTMLAnchorElement","outerHTML","stopPropagation","preventDefault","element","indexOf","nodeName","toLowerCase","hasAttribute","getAttribute","parentElement","DoubleAreaManager","leftIframe","rightIframe","metaViewport","fit","insets","ports","source","leftPage","rightPage","tapEvent","clientX","visualViewport","offsetLeft","clientY","offsetTop","_","leftPageListener","layout","boundingRect","getBoundingClientRect","rightPageListener","loadSpread","spread","setViewport","viewport","setFit","leftMargins","rightMargins","contentWidth","contentHeight","Math","max","contentSize","safeDrawingSize","content","container","widthRatio","heightRatio","min","fitContain","fitWidth","fitHeight","computeScale","BridgeGesturesAdapter","gesturesApi","nativeApi","JSON","stringify","getElementById","querySelector","Window","prototype","doubleArea","gestures","manager","viewporttWidth","viewportHeight","insetTop","insetRight","insetBottom","insetLeft","initialization","onScriptsLoaded"],"sourceRoot":""} \ No newline at end of file +{"version":3,"file":"fixed-double-script.js","mappings":"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","sources":["webpack://readium-js/./src/fixed/page-manager.ts","webpack://readium-js/./src/util/viewport.ts","webpack://readium-js/./src/common/gestures.ts","webpack://readium-js/./src/fixed/double-area-manager.ts","webpack://readium-js/./src/util/fit.ts","webpack://readium-js/./src/bridge/all-gestures-bridge.ts","webpack://readium-js/./src/index-fixed-double.ts","webpack://readium-js/./src/bridge/fixed-double-bridge.ts"],"sourcesContent":["/** Manages a fixed layout resource embedded in an iframe. */\nexport class PageManager {\n constructor(window, iframe, listener) {\n this.margins = { top: 0, right: 0, bottom: 0, left: 0 };\n if (!iframe.contentWindow) {\n throw Error(\"Iframe argument must have been attached to DOM.\");\n }\n this.listener = listener;\n this.iframe = iframe;\n }\n setMessagePort(messagePort) {\n messagePort.onmessage = (message) => {\n this.onMessageFromIframe(message);\n };\n }\n show() {\n this.iframe.style.display = \"unset\";\n }\n hide() {\n this.iframe.style.display = \"none\";\n }\n /** Sets page margins. */\n setMargins(margins) {\n if (this.margins == margins) {\n return;\n }\n this.iframe.style.marginTop = this.margins.top + \"px\";\n this.iframe.style.marginLeft = this.margins.left + \"px\";\n this.iframe.style.marginBottom = this.margins.bottom + \"px\";\n this.iframe.style.marginRight = this.margins.right + \"px\";\n }\n /** Loads page content. */\n loadPage(url) {\n this.iframe.src = url;\n }\n /** Sets the size of this page without content. */\n setPlaceholder(size) {\n this.iframe.style.visibility = \"hidden\";\n this.iframe.style.width = size.width + \"px\";\n this.iframe.style.height = size.height + \"px\";\n this.size = size;\n }\n onMessageFromIframe(event) {\n const message = event.data;\n switch (message.kind) {\n case \"contentSize\":\n return this.onContentSizeAvailable(message.size);\n case \"tap\":\n return this.listener.onTap({ x: message.x, y: message.y });\n case \"linkActivated\":\n return this.onLinkActivated(message);\n }\n }\n onLinkActivated(message) {\n try {\n const url = new URL(message.href, this.iframe.src);\n this.listener.onLinkActivated(url.toString(), message.outerHtml);\n }\n catch (_a) {\n // Do nothing if url is not valid.\n }\n }\n onContentSizeAvailable(size) {\n if (!size) {\n //FIXME: handle edge case\n return;\n }\n this.iframe.style.width = size.width + \"px\";\n this.iframe.style.height = size.height + \"px\";\n this.size = size;\n this.listener.onIframeLoaded();\n }\n}\n","export class ViewportStringBuilder {\n setInitialScale(scale) {\n this.initialScale = scale;\n return this;\n }\n setMinimumScale(scale) {\n this.minimumScale = scale;\n return this;\n }\n setWidth(width) {\n this.width = width;\n return this;\n }\n setHeight(height) {\n this.height = height;\n return this;\n }\n build() {\n const components = [];\n if (this.initialScale) {\n components.push(\"initial-scale=\" + this.initialScale);\n }\n if (this.minimumScale) {\n components.push(\"minimum-scale=\" + this.minimumScale);\n }\n if (this.width) {\n components.push(\"width=\" + this.width);\n }\n if (this.height) {\n components.push(\"height=\" + this.height);\n }\n return components.join(\", \");\n }\n}\nexport function parseViewportString(viewportString) {\n const regex = /(\\w+) *= *([^\\s,]+)/g;\n const properties = new Map();\n let match;\n while ((match = regex.exec(viewportString))) {\n if (match != null) {\n properties.set(match[1], match[2]);\n }\n }\n const width = parseFloat(properties.get(\"width\"));\n const height = parseFloat(properties.get(\"height\"));\n if (width && height) {\n return { width, height };\n }\n else {\n return undefined;\n }\n}\n","export class GesturesDetector {\n constructor(window, listener) {\n this.window = window;\n this.listener = listener;\n document.addEventListener(\"click\", (event) => {\n this.onClick(event);\n }, false);\n }\n onClick(event) {\n if (event.defaultPrevented) {\n return;\n }\n const selection = this.window.getSelection();\n if (selection && selection.type == \"Range\") {\n // There's an on-going selection, the tap will dismiss it so we don't forward it.\n // selection.type might be None (collapsed) or Caret with a collapsed range\n // when there is not true selection.\n return;\n }\n let nearestElement;\n if (event.target instanceof HTMLElement) {\n nearestElement = this.nearestInteractiveElement(event.target);\n }\n else {\n nearestElement = null;\n }\n if (nearestElement) {\n if (nearestElement instanceof HTMLAnchorElement) {\n this.listener.onLinkActivated(nearestElement.href, nearestElement.outerHTML);\n }\n }\n else {\n this.listener.onTap(event);\n }\n event.stopPropagation();\n event.preventDefault();\n }\n // See. https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling\n nearestInteractiveElement(element) {\n if (element == null) {\n return null;\n }\n const interactiveTags = [\n \"a\",\n \"audio\",\n \"button\",\n \"canvas\",\n \"details\",\n \"input\",\n \"label\",\n \"option\",\n \"select\",\n \"submit\",\n \"textarea\",\n \"video\",\n ];\n if (interactiveTags.indexOf(element.nodeName.toLowerCase()) != -1) {\n return element;\n }\n // Checks whether the element is editable by the user.\n if (element.hasAttribute(\"contenteditable\") &&\n element.getAttribute(\"contenteditable\").toLowerCase() != \"false\") {\n return element;\n }\n // Checks parents recursively because the touch might be for example on an inside a .\n if (element.parentElement) {\n return this.nearestInteractiveElement(element.parentElement);\n }\n return null;\n }\n}\n","import { computeScale } from \"../util/fit\";\nimport { PageManager } from \"./page-manager\";\nimport { ViewportStringBuilder } from \"../util/viewport\";\nimport { GesturesDetector } from \"../common/gestures\";\nexport class DoubleAreaManager {\n constructor(window, leftIframe, rightIframe, metaViewport, listener) {\n this.fit = \"contain\" /* Fit.Contain */;\n this.insets = { top: 0, right: 0, bottom: 0, left: 0 };\n window.addEventListener(\"message\", (event) => {\n if (!event.ports[0]) {\n return;\n }\n if (event.source === leftIframe.contentWindow) {\n this.leftPage.setMessagePort(event.ports[0]);\n }\n else if (event.source == rightIframe.contentWindow) {\n this.rightPage.setMessagePort(event.ports[0]);\n }\n });\n const wrapperGesturesListener = {\n onTap: (event) => {\n const tapEvent = {\n x: (event.clientX - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.clientY - visualViewport.offsetTop) * visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onLinkActivated: (_) => {\n throw Error(\"No interactive element in the root document.\");\n },\n };\n new GesturesDetector(window, wrapperGesturesListener);\n const leftPageListener = {\n onIframeLoaded: () => {\n this.layout();\n },\n onTap: (event) => {\n const boundingRect = leftIframe.getBoundingClientRect();\n const tapEvent = {\n x: (event.x + boundingRect.left - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.y + boundingRect.top - visualViewport.offsetTop) *\n visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n listener.onLinkActivated(href, outerHtml);\n },\n };\n const rightPageListener = {\n onIframeLoaded: () => {\n this.layout();\n },\n onTap: (event) => {\n const boundingRect = rightIframe.getBoundingClientRect();\n const tapEvent = {\n x: (event.x + boundingRect.left - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.y + boundingRect.top - visualViewport.offsetTop) *\n visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n listener.onLinkActivated(href, outerHtml);\n },\n };\n this.leftPage = new PageManager(window, leftIframe, leftPageListener);\n this.rightPage = new PageManager(window, rightIframe, rightPageListener);\n this.metaViewport = metaViewport;\n }\n loadSpread(spread) {\n this.leftPage.hide();\n this.rightPage.hide();\n this.spread = spread;\n if (spread.left) {\n this.leftPage.loadPage(spread.left);\n }\n if (spread.right) {\n this.rightPage.loadPage(spread.right);\n }\n }\n setViewport(size, insets) {\n if (this.viewport == size && this.insets == insets) {\n return;\n }\n this.viewport = size;\n this.insets = insets;\n this.layout();\n }\n setFit(fit) {\n if (this.fit == fit) {\n return;\n }\n this.fit = fit;\n this.layout();\n }\n layout() {\n if (!this.viewport ||\n (!this.leftPage.size && this.spread.left) ||\n (!this.rightPage.size && this.spread.right)) {\n return;\n }\n const leftMargins = {\n top: this.insets.top,\n right: 0,\n bottom: this.insets.bottom,\n left: this.insets.left,\n };\n this.leftPage.setMargins(leftMargins);\n const rightMargins = {\n top: this.insets.top,\n right: this.insets.right,\n bottom: this.insets.bottom,\n left: 0,\n };\n this.rightPage.setMargins(rightMargins);\n if (!this.spread.right) {\n this.rightPage.setPlaceholder(this.leftPage.size);\n }\n else if (!this.spread.left) {\n this.leftPage.setPlaceholder(this.rightPage.size);\n }\n const contentWidth = this.leftPage.size.width + this.rightPage.size.width;\n const contentHeight = Math.max(this.leftPage.size.height, this.rightPage.size.height);\n const contentSize = { width: contentWidth, height: contentHeight };\n const safeDrawingSize = {\n width: this.viewport.width - this.insets.left - this.insets.right,\n height: this.viewport.height - this.insets.top - this.insets.bottom,\n };\n const scale = computeScale(this.fit, contentSize, safeDrawingSize);\n this.metaViewport.content = new ViewportStringBuilder()\n .setInitialScale(scale)\n .setMinimumScale(scale)\n .setWidth(contentWidth)\n .setHeight(contentHeight)\n .build();\n this.leftPage.show();\n this.rightPage.show();\n }\n}\n","export function computeScale(fit, content, container) {\n switch (fit) {\n case \"contain\" /* Fit.Contain */:\n return fitContain(content, container);\n case \"width\" /* Fit.Width */:\n return fitWidth(content, container);\n case \"height\" /* Fit.Height */:\n return fitHeight(content, container);\n }\n}\nfunction fitContain(content, container) {\n const widthRatio = container.width / content.width;\n const heightRatio = container.height / content.height;\n return Math.min(widthRatio, heightRatio);\n}\nfunction fitWidth(content, container) {\n return container.width / content.width;\n}\nfunction fitHeight(content, container) {\n return container.height / content.height;\n}\n","export class BridgeGesturesAdapter {\n constructor(gesturesApi) {\n this.nativeApi = gesturesApi;\n }\n onTap(event) {\n this.nativeApi.onTap(JSON.stringify(event));\n }\n onLinkActivated(href, outerHtml) {\n this.nativeApi.onLinkActivated(href, outerHtml);\n }\n}\n","//\n// Copyright 2024 Readium Foundation. All rights reserved.\n// Use of this source code is governed by the BSD-style license\n// available in the top-level LICENSE file of the project.\n//\nimport { FixedDoubleBridge } from \"./bridge/fixed-double-bridge\";\nconst leftIframe = document.getElementById(\"page-left\");\nconst rightIframe = document.getElementById(\"page-right\");\nconst metaViewport = document.querySelector(\"meta[name=viewport]\");\nWindow.prototype.doubleArea = new FixedDoubleBridge(window, leftIframe, rightIframe, metaViewport, window.gestures);\nwindow.initialization.onScriptsLoaded();\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nwindow.addEventListener(\"load\", (event) => {\n window.initialization.onDocumentLoaded();\n});\n","import { DoubleAreaManager } from \"../fixed/double-area-manager\";\nimport { BridgeGesturesAdapter } from \"./all-gestures-bridge\";\nexport class FixedDoubleBridge {\n constructor(window, leftIframe, rightIframe, metaViewport, gestures) {\n const listener = new BridgeGesturesAdapter(gestures);\n this.manager = new DoubleAreaManager(window, leftIframe, rightIframe, metaViewport, listener);\n }\n loadSpread(spread) {\n this.manager.loadSpread(spread);\n }\n setViewport(viewporttWidth, viewportHeight, insetTop, insetRight, insetBottom, insetLeft) {\n const viewport = { width: viewporttWidth, height: viewportHeight };\n const insets = {\n top: insetTop,\n left: insetLeft,\n bottom: insetBottom,\n right: insetRight,\n };\n this.manager.setViewport(viewport, insets);\n }\n setFit(fit) {\n if (fit != \"contain\" && fit != \"width\" && fit != \"height\") {\n throw Error(`Invalid fit value: ${fit}`);\n }\n this.manager.setFit(fit);\n }\n}\n"],"names":["PageManager","constructor","window","iframe","listener","this","margins","top","right","bottom","left","contentWindow","Error","setMessagePort","messagePort","onmessage","message","onMessageFromIframe","show","style","display","hide","setMargins","marginTop","marginLeft","marginBottom","marginRight","loadPage","url","src","setPlaceholder","size","visibility","width","height","event","data","kind","onContentSizeAvailable","onTap","x","y","onLinkActivated","URL","href","toString","outerHtml","_a","onIframeLoaded","ViewportStringBuilder","setInitialScale","scale","initialScale","setMinimumScale","minimumScale","setWidth","setHeight","build","components","push","join","GesturesDetector","document","addEventListener","onClick","defaultPrevented","selection","getSelection","type","nearestElement","target","HTMLElement","nearestInteractiveElement","HTMLAnchorElement","outerHTML","stopPropagation","preventDefault","element","indexOf","nodeName","toLowerCase","hasAttribute","getAttribute","parentElement","DoubleAreaManager","leftIframe","rightIframe","metaViewport","fit","insets","ports","source","leftPage","rightPage","tapEvent","clientX","visualViewport","offsetLeft","clientY","offsetTop","_","leftPageListener","layout","boundingRect","getBoundingClientRect","rightPageListener","loadSpread","spread","setViewport","viewport","setFit","leftMargins","rightMargins","contentWidth","contentHeight","Math","max","contentSize","safeDrawingSize","content","container","widthRatio","heightRatio","min","fitContain","fitWidth","fitHeight","computeScale","BridgeGesturesAdapter","gesturesApi","nativeApi","JSON","stringify","getElementById","querySelector","Window","prototype","doubleArea","gestures","manager","viewporttWidth","viewportHeight","insetTop","insetRight","insetBottom","insetLeft","initialization","onScriptsLoaded","onDocumentLoaded"],"sourceRoot":""} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/fixed-single-script.js b/readium/navigators/web/src/main/assets/readium/navigators/web/fixed-single-script.js index cebd75000c..bf256593b4 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/fixed-single-script.js +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/fixed-single-script.js @@ -1,2 +1,2 @@ -!function(){"use strict";class t{constructor(t,e,i){if(this.margins={top:0,right:0,bottom:0,left:0},!e.contentWindow)throw Error("Iframe argument must have been attached to DOM.");this.listener=i,this.iframe=e}setMessagePort(t){t.onmessage=t=>{this.onMessageFromIframe(t)}}show(){this.iframe.style.display="unset"}hide(){this.iframe.style.display="none"}setMargins(t){this.margins!=t&&(this.iframe.style.marginTop=this.margins.top+"px",this.iframe.style.marginLeft=this.margins.left+"px",this.iframe.style.marginBottom=this.margins.bottom+"px",this.iframe.style.marginRight=this.margins.right+"px")}loadPage(t){this.iframe.src=t}setPlaceholder(t){this.iframe.style.visibility="hidden",this.iframe.style.width=t.width+"px",this.iframe.style.height=t.height+"px",this.size=t}onMessageFromIframe(t){const e=t.data;switch(e.kind){case"contentSize":return this.onContentSizeAvailable(e.size);case"tap":return this.listener.onTap({x:e.x,y:e.y});case"linkActivated":return this.onLinkActivated(e)}}onLinkActivated(t){try{const e=new URL(t.href,this.iframe.src);this.listener.onLinkActivated(e.toString(),t.outerHtml)}catch(t){}}onContentSizeAvailable(t){t&&(this.iframe.style.width=t.width+"px",this.iframe.style.height=t.height+"px",this.size=t,this.listener.onIframeLoaded())}}class e{setInitialScale(t){return this.initialScale=t,this}setMinimumScale(t){return this.minimumScale=t,this}setWidth(t){return this.width=t,this}setHeight(t){return this.height=t,this}build(){const t=[];return this.initialScale&&t.push("initial-scale="+this.initialScale),this.minimumScale&&t.push("minimum-scale="+this.minimumScale),this.width&&t.push("width="+this.width),this.height&&t.push("height="+this.height),t.join(", ")}}class i{constructor(t,e){this.window=t,this.listener=e,document.addEventListener("click",(t=>{this.onClick(t)}),!1)}onClick(t){if(t.defaultPrevented)return;const e=this.window.getSelection();if(e&&"Range"==e.type)return;let i;i=t.target instanceof HTMLElement?this.nearestInteractiveElement(t.target):null,i?i instanceof HTMLAnchorElement&&this.listener.onLinkActivated(i.href,i.outerHTML):this.listener.onTap(t),t.stopPropagation(),t.preventDefault()}nearestInteractiveElement(t){return null==t?null:-1!=["a","audio","button","canvas","details","input","label","option","select","submit","textarea","video"].indexOf(t.nodeName.toLowerCase())||t.hasAttribute("contenteditable")&&"false"!=t.getAttribute("contenteditable").toLowerCase()?t:t.parentElement?this.nearestInteractiveElement(t.parentElement):null}}class s{constructor(e,s,n,a){this.fit="contain",this.insets={top:0,right:0,bottom:0,left:0},this.scale=1,e.addEventListener("message",(t=>{t.source===s.contentWindow&&t.ports[0]&&this.page.setMessagePort(t.ports[0])})),new i(e,{onTap:t=>{const e={x:(t.clientX-visualViewport.offsetLeft)*visualViewport.scale,y:(t.clientY-visualViewport.offsetTop)*visualViewport.scale};a.onTap(e)},onLinkActivated:t=>{throw Error("No interactive element in the root document.")}}),this.metaViewport=n;const o={onIframeLoaded:()=>{this.onIframeLoaded()},onTap:t=>{const e=s.getBoundingClientRect(),i={x:(t.x+e.left-visualViewport.offsetLeft)*visualViewport.scale,y:(t.y+e.top-visualViewport.offsetTop)*visualViewport.scale};a.onTap(i)},onLinkActivated:(t,e)=>{a.onLinkActivated(t,e)}};this.page=new t(e,s,o)}setViewport(t,e){this.viewport==t&&this.insets==e||(this.viewport=t,this.insets=e,this.layout())}setFit(t){this.fit!=t&&(this.fit=t,this.layout())}loadResource(t){this.page.hide(),this.page.loadPage(t)}onIframeLoaded(){this.page.size&&this.layout()}layout(){if(!this.page.size||!this.viewport)return;const t={top:this.insets.top,right:this.insets.right,bottom:this.insets.bottom,left:this.insets.left};this.page.setMargins(t);const i={width:this.viewport.width-this.insets.left-this.insets.right,height:this.viewport.height-this.insets.top-this.insets.bottom},s=function(t,e,i){switch(t){case"contain":return function(t,e){const i=e.width/t.width,s=e.height/t.height;return Math.min(i,s)}(e,i);case"width":return function(t,e){return e.width/t.width}(e,i);case"height":return function(t,e){return e.height/t.height}(e,i)}}(this.fit,this.page.size,i);this.metaViewport.content=(new e).setInitialScale(s).setMinimumScale(s).setWidth(this.page.size.width).setHeight(this.page.size.height).build(),this.scale=s,this.page.show()}}class n{constructor(t){this.nativeApi=t}onTap(t){this.nativeApi.onTap(JSON.stringify(t))}onLinkActivated(t,e){this.nativeApi.onLinkActivated(t,e)}}const a=document.getElementById("page"),o=document.querySelector("meta[name=viewport]");window.singleArea=new class{constructor(t,e,i,a){const o=new n(a);this.manager=new s(t,e,i,o)}loadResource(t){this.manager.loadResource(t)}setViewport(t,e,i,s,n,a){const o={width:t,height:e},h={top:i,left:a,bottom:n,right:s};this.manager.setViewport(o,h)}setFit(t){if("contain"!=t&&"width"!=t&&"height"!=t)throw Error(`Invalid fit value: ${t}`);this.manager.setFit(t)}}(window,a,o,window.gestures),window.initialization.onScriptsLoaded()}(); +!function(){"use strict";class t{constructor(t,e,i){if(this.margins={top:0,right:0,bottom:0,left:0},!e.contentWindow)throw Error("Iframe argument must have been attached to DOM.");this.listener=i,this.iframe=e}setMessagePort(t){t.onmessage=t=>{this.onMessageFromIframe(t)}}show(){this.iframe.style.display="unset"}hide(){this.iframe.style.display="none"}setMargins(t){this.margins!=t&&(this.iframe.style.marginTop=this.margins.top+"px",this.iframe.style.marginLeft=this.margins.left+"px",this.iframe.style.marginBottom=this.margins.bottom+"px",this.iframe.style.marginRight=this.margins.right+"px")}loadPage(t){this.iframe.src=t}setPlaceholder(t){this.iframe.style.visibility="hidden",this.iframe.style.width=t.width+"px",this.iframe.style.height=t.height+"px",this.size=t}onMessageFromIframe(t){const e=t.data;switch(e.kind){case"contentSize":return this.onContentSizeAvailable(e.size);case"tap":return this.listener.onTap({x:e.x,y:e.y});case"linkActivated":return this.onLinkActivated(e)}}onLinkActivated(t){try{const e=new URL(t.href,this.iframe.src);this.listener.onLinkActivated(e.toString(),t.outerHtml)}catch(t){}}onContentSizeAvailable(t){t&&(this.iframe.style.width=t.width+"px",this.iframe.style.height=t.height+"px",this.size=t,this.listener.onIframeLoaded())}}class e{setInitialScale(t){return this.initialScale=t,this}setMinimumScale(t){return this.minimumScale=t,this}setWidth(t){return this.width=t,this}setHeight(t){return this.height=t,this}build(){const t=[];return this.initialScale&&t.push("initial-scale="+this.initialScale),this.minimumScale&&t.push("minimum-scale="+this.minimumScale),this.width&&t.push("width="+this.width),this.height&&t.push("height="+this.height),t.join(", ")}}class i{constructor(t,e){this.window=t,this.listener=e,document.addEventListener("click",(t=>{this.onClick(t)}),!1)}onClick(t){if(t.defaultPrevented)return;const e=this.window.getSelection();if(e&&"Range"==e.type)return;let i;i=t.target instanceof HTMLElement?this.nearestInteractiveElement(t.target):null,i?i instanceof HTMLAnchorElement&&this.listener.onLinkActivated(i.href,i.outerHTML):this.listener.onTap(t),t.stopPropagation(),t.preventDefault()}nearestInteractiveElement(t){return null==t?null:-1!=["a","audio","button","canvas","details","input","label","option","select","submit","textarea","video"].indexOf(t.nodeName.toLowerCase())||t.hasAttribute("contenteditable")&&"false"!=t.getAttribute("contenteditable").toLowerCase()?t:t.parentElement?this.nearestInteractiveElement(t.parentElement):null}}class s{constructor(e,s,n,a){this.fit="contain",this.insets={top:0,right:0,bottom:0,left:0},this.scale=1,e.addEventListener("message",(t=>{t.source===s.contentWindow&&t.ports[0]&&this.page.setMessagePort(t.ports[0])})),new i(e,{onTap:t=>{const e={x:(t.clientX-visualViewport.offsetLeft)*visualViewport.scale,y:(t.clientY-visualViewport.offsetTop)*visualViewport.scale};a.onTap(e)},onLinkActivated:t=>{throw Error("No interactive element in the root document.")}}),this.metaViewport=n;const o={onIframeLoaded:()=>{this.onIframeLoaded()},onTap:t=>{const e=s.getBoundingClientRect(),i={x:(t.x+e.left-visualViewport.offsetLeft)*visualViewport.scale,y:(t.y+e.top-visualViewport.offsetTop)*visualViewport.scale};a.onTap(i)},onLinkActivated:(t,e)=>{a.onLinkActivated(t,e)}};this.page=new t(e,s,o)}setViewport(t,e){this.viewport==t&&this.insets==e||(this.viewport=t,this.insets=e,this.layout())}setFit(t){this.fit!=t&&(this.fit=t,this.layout())}loadResource(t){this.page.hide(),this.page.loadPage(t)}onIframeLoaded(){this.page.size&&this.layout()}layout(){if(!this.page.size||!this.viewport)return;const t={top:this.insets.top,right:this.insets.right,bottom:this.insets.bottom,left:this.insets.left};this.page.setMargins(t);const i={width:this.viewport.width-this.insets.left-this.insets.right,height:this.viewport.height-this.insets.top-this.insets.bottom},s=function(t,e,i){switch(t){case"contain":return function(t,e){const i=e.width/t.width,s=e.height/t.height;return Math.min(i,s)}(e,i);case"width":return function(t,e){return e.width/t.width}(e,i);case"height":return function(t,e){return e.height/t.height}(e,i)}}(this.fit,this.page.size,i);this.metaViewport.content=(new e).setInitialScale(s).setMinimumScale(s).setWidth(this.page.size.width).setHeight(this.page.size.height).build(),this.scale=s,this.page.show()}}class n{constructor(t){this.nativeApi=t}onTap(t){this.nativeApi.onTap(JSON.stringify(t))}onLinkActivated(t,e){this.nativeApi.onLinkActivated(t,e)}}const a=document.getElementById("page"),o=document.querySelector("meta[name=viewport]");window.singleArea=new class{constructor(t,e,i,a){const o=new n(a);this.manager=new s(t,e,i,o)}loadResource(t){this.manager.loadResource(t)}setViewport(t,e,i,s,n,a){const o={width:t,height:e},h={top:i,left:a,bottom:n,right:s};this.manager.setViewport(o,h)}setFit(t){if("contain"!=t&&"width"!=t&&"height"!=t)throw Error(`Invalid fit value: ${t}`);this.manager.setFit(t)}}(window,a,o,window.gestures),window.initialization.onScriptsLoaded(),window.addEventListener("load",(t=>{window.initialization.onDocumentLoaded()}))}(); //# sourceMappingURL=fixed-single-script.js.map \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/fixed-single-script.js.map b/readium/navigators/web/src/main/assets/readium/navigators/web/fixed-single-script.js.map index 86f1264391..a05d3d5ee3 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/fixed-single-script.js.map +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/fixed-single-script.js.map @@ -1 +1 @@ -{"version":3,"file":"fixed-single-script.js","mappings":"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","sources":["webpack://readium-js/./src/fixed/page-manager.ts","webpack://readium-js/./src/util/viewport.ts","webpack://readium-js/./src/common/gestures.ts","webpack://readium-js/./src/fixed/single-area-manager.ts","webpack://readium-js/./src/util/fit.ts","webpack://readium-js/./src/bridge/fixed-gestures-bridge.ts","webpack://readium-js/./src/index-fixed-single.ts","webpack://readium-js/./src/bridge/fixed-single-bridge.ts"],"sourcesContent":["/** Manages a fixed layout resource embedded in an iframe. */\nexport class PageManager {\n constructor(window, iframe, listener) {\n this.margins = { top: 0, right: 0, bottom: 0, left: 0 };\n if (!iframe.contentWindow) {\n throw Error(\"Iframe argument must have been attached to DOM.\");\n }\n this.listener = listener;\n this.iframe = iframe;\n }\n setMessagePort(messagePort) {\n messagePort.onmessage = (message) => {\n this.onMessageFromIframe(message);\n };\n }\n show() {\n this.iframe.style.display = \"unset\";\n }\n hide() {\n this.iframe.style.display = \"none\";\n }\n /** Sets page margins. */\n setMargins(margins) {\n if (this.margins == margins) {\n return;\n }\n this.iframe.style.marginTop = this.margins.top + \"px\";\n this.iframe.style.marginLeft = this.margins.left + \"px\";\n this.iframe.style.marginBottom = this.margins.bottom + \"px\";\n this.iframe.style.marginRight = this.margins.right + \"px\";\n }\n /** Loads page content. */\n loadPage(url) {\n this.iframe.src = url;\n }\n /** Sets the size of this page without content. */\n setPlaceholder(size) {\n this.iframe.style.visibility = \"hidden\";\n this.iframe.style.width = size.width + \"px\";\n this.iframe.style.height = size.height + \"px\";\n this.size = size;\n }\n onMessageFromIframe(event) {\n const message = event.data;\n switch (message.kind) {\n case \"contentSize\":\n return this.onContentSizeAvailable(message.size);\n case \"tap\":\n return this.listener.onTap({ x: message.x, y: message.y });\n case \"linkActivated\":\n return this.onLinkActivated(message);\n }\n }\n onLinkActivated(message) {\n try {\n const url = new URL(message.href, this.iframe.src);\n this.listener.onLinkActivated(url.toString(), message.outerHtml);\n }\n catch (_a) {\n // Do nothing if url is not valid.\n }\n }\n onContentSizeAvailable(size) {\n if (!size) {\n //FIXME: handle edge case\n return;\n }\n this.iframe.style.width = size.width + \"px\";\n this.iframe.style.height = size.height + \"px\";\n this.size = size;\n this.listener.onIframeLoaded();\n }\n}\n","export class ViewportStringBuilder {\n setInitialScale(scale) {\n this.initialScale = scale;\n return this;\n }\n setMinimumScale(scale) {\n this.minimumScale = scale;\n return this;\n }\n setWidth(width) {\n this.width = width;\n return this;\n }\n setHeight(height) {\n this.height = height;\n return this;\n }\n build() {\n const components = [];\n if (this.initialScale) {\n components.push(\"initial-scale=\" + this.initialScale);\n }\n if (this.minimumScale) {\n components.push(\"minimum-scale=\" + this.minimumScale);\n }\n if (this.width) {\n components.push(\"width=\" + this.width);\n }\n if (this.height) {\n components.push(\"height=\" + this.height);\n }\n return components.join(\", \");\n }\n}\nexport function parseViewportString(viewportString) {\n const regex = /(\\w+) *= *([^\\s,]+)/g;\n const properties = new Map();\n let match;\n while ((match = regex.exec(viewportString))) {\n if (match != null) {\n properties.set(match[1], match[2]);\n }\n }\n const width = parseFloat(properties.get(\"width\"));\n const height = parseFloat(properties.get(\"height\"));\n if (width && height) {\n return { width, height };\n }\n else {\n return undefined;\n }\n}\n","export class GesturesDetector {\n constructor(window, listener) {\n this.window = window;\n this.listener = listener;\n document.addEventListener(\"click\", (event) => {\n this.onClick(event);\n }, false);\n }\n onClick(event) {\n if (event.defaultPrevented) {\n return;\n }\n const selection = this.window.getSelection();\n if (selection && selection.type == \"Range\") {\n // There's an on-going selection, the tap will dismiss it so we don't forward it.\n // selection.type might be None (collapsed) or Caret with a collapsed range\n // when there is not true selection.\n return;\n }\n let nearestElement;\n if (event.target instanceof HTMLElement) {\n nearestElement = this.nearestInteractiveElement(event.target);\n }\n else {\n nearestElement = null;\n }\n if (nearestElement) {\n if (nearestElement instanceof HTMLAnchorElement) {\n this.listener.onLinkActivated(nearestElement.href, nearestElement.outerHTML);\n }\n }\n else {\n this.listener.onTap(event);\n }\n event.stopPropagation();\n event.preventDefault();\n }\n // See. https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling\n nearestInteractiveElement(element) {\n if (element == null) {\n return null;\n }\n const interactiveTags = [\n \"a\",\n \"audio\",\n \"button\",\n \"canvas\",\n \"details\",\n \"input\",\n \"label\",\n \"option\",\n \"select\",\n \"submit\",\n \"textarea\",\n \"video\",\n ];\n if (interactiveTags.indexOf(element.nodeName.toLowerCase()) != -1) {\n return element;\n }\n // Checks whether the element is editable by the user.\n if (element.hasAttribute(\"contenteditable\") &&\n element.getAttribute(\"contenteditable\").toLowerCase() != \"false\") {\n return element;\n }\n // Checks parents recursively because the touch might be for example on an inside a .\n if (element.parentElement) {\n return this.nearestInteractiveElement(element.parentElement);\n }\n return null;\n }\n}\n","import { computeScale } from \"../util/fit\";\nimport { PageManager } from \"./page-manager\";\nimport { ViewportStringBuilder } from \"../util/viewport\";\nimport { GesturesDetector } from \"../common/gestures\";\nexport class SingleAreaManager {\n constructor(window, iframe, metaViewport, listener) {\n this.fit = \"contain\" /* Fit.Contain */;\n this.insets = { top: 0, right: 0, bottom: 0, left: 0 };\n this.scale = 1;\n window.addEventListener(\"message\", (event) => {\n if (event.source === iframe.contentWindow && event.ports[0]) {\n this.page.setMessagePort(event.ports[0]);\n }\n });\n const wrapperGesturesListener = {\n onTap: (event) => {\n const tapEvent = {\n x: (event.clientX - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.clientY - visualViewport.offsetTop) * visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onLinkActivated: (_) => {\n throw Error(\"No interactive element in the root document.\");\n },\n };\n new GesturesDetector(window, wrapperGesturesListener);\n this.metaViewport = metaViewport;\n const pageListener = {\n onIframeLoaded: () => {\n this.onIframeLoaded();\n },\n onTap: (event) => {\n const boundingRect = iframe.getBoundingClientRect();\n const tapEvent = {\n x: (event.x + boundingRect.left - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.y + boundingRect.top - visualViewport.offsetTop) *\n visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n listener.onLinkActivated(href, outerHtml);\n },\n };\n this.page = new PageManager(window, iframe, pageListener);\n }\n setViewport(viewport, insets) {\n if (this.viewport == viewport && this.insets == insets) {\n return;\n }\n this.viewport = viewport;\n this.insets = insets;\n this.layout();\n }\n setFit(fit) {\n if (this.fit == fit) {\n return;\n }\n this.fit = fit;\n this.layout();\n }\n loadResource(url) {\n this.page.hide();\n this.page.loadPage(url);\n }\n onIframeLoaded() {\n if (!this.page.size) {\n // FIXME: raise error\n }\n else {\n this.layout();\n }\n }\n layout() {\n if (!this.page.size || !this.viewport) {\n return;\n }\n const margins = {\n top: this.insets.top,\n right: this.insets.right,\n bottom: this.insets.bottom,\n left: this.insets.left,\n };\n this.page.setMargins(margins);\n const safeDrawingSize = {\n width: this.viewport.width - this.insets.left - this.insets.right,\n height: this.viewport.height - this.insets.top - this.insets.bottom,\n };\n const scale = computeScale(this.fit, this.page.size, safeDrawingSize);\n this.metaViewport.content = new ViewportStringBuilder()\n .setInitialScale(scale)\n .setMinimumScale(scale)\n .setWidth(this.page.size.width)\n .setHeight(this.page.size.height)\n .build();\n this.scale = scale;\n this.page.show();\n }\n}\n","export function computeScale(fit, content, container) {\n switch (fit) {\n case \"contain\" /* Fit.Contain */:\n return fitContain(content, container);\n case \"width\" /* Fit.Width */:\n return fitWidth(content, container);\n case \"height\" /* Fit.Height */:\n return fitHeight(content, container);\n }\n}\nfunction fitContain(content, container) {\n const widthRatio = container.width / content.width;\n const heightRatio = container.height / content.height;\n return Math.min(widthRatio, heightRatio);\n}\nfunction fitWidth(content, container) {\n return container.width / content.width;\n}\nfunction fitHeight(content, container) {\n return container.height / content.height;\n}\n","export class BridgeGesturesAdapter {\n constructor(gesturesApi) {\n this.nativeApi = gesturesApi;\n }\n onTap(event) {\n this.nativeApi.onTap(JSON.stringify(event));\n }\n onLinkActivated(href, outerHtml) {\n this.nativeApi.onLinkActivated(href, outerHtml);\n }\n}\n","//\n// Copyright 2024 Readium Foundation. All rights reserved.\n// Use of this source code is governed by the BSD-style license\n// available in the top-level LICENSE file of the project.\n//\nimport { FixedSingleBridge } from \"./bridge/fixed-single-bridge\";\nconst iframe = document.getElementById(\"page\");\nconst metaViewport = document.querySelector(\"meta[name=viewport]\");\nwindow.singleArea = new FixedSingleBridge(window, iframe, metaViewport, window.gestures);\nwindow.initialization.onScriptsLoaded();\n","import { SingleAreaManager } from \"../fixed/single-area-manager\";\nimport { BridgeGesturesAdapter } from \"./fixed-gestures-bridge\";\nexport class FixedSingleBridge {\n constructor(window, iframe, metaViewport, gestures) {\n const listener = new BridgeGesturesAdapter(gestures);\n this.manager = new SingleAreaManager(window, iframe, metaViewport, listener);\n }\n loadResource(url) {\n this.manager.loadResource(url);\n }\n setViewport(viewporttWidth, viewportHeight, insetTop, insetRight, insetBottom, insetLeft) {\n const viewport = { width: viewporttWidth, height: viewportHeight };\n const insets = {\n top: insetTop,\n left: insetLeft,\n bottom: insetBottom,\n right: insetRight,\n };\n this.manager.setViewport(viewport, insets);\n }\n setFit(fit) {\n if (fit != \"contain\" && fit != \"width\" && fit != \"height\") {\n throw Error(`Invalid fit value: ${fit}`);\n }\n this.manager.setFit(fit);\n }\n}\n"],"names":["PageManager","constructor","window","iframe","listener","this","margins","top","right","bottom","left","contentWindow","Error","setMessagePort","messagePort","onmessage","message","onMessageFromIframe","show","style","display","hide","setMargins","marginTop","marginLeft","marginBottom","marginRight","loadPage","url","src","setPlaceholder","size","visibility","width","height","event","data","kind","onContentSizeAvailable","onTap","x","y","onLinkActivated","URL","href","toString","outerHtml","_a","onIframeLoaded","ViewportStringBuilder","setInitialScale","scale","initialScale","setMinimumScale","minimumScale","setWidth","setHeight","build","components","push","join","GesturesDetector","document","addEventListener","onClick","defaultPrevented","selection","getSelection","type","nearestElement","target","HTMLElement","nearestInteractiveElement","HTMLAnchorElement","outerHTML","stopPropagation","preventDefault","element","indexOf","nodeName","toLowerCase","hasAttribute","getAttribute","parentElement","SingleAreaManager","metaViewport","fit","insets","source","ports","page","tapEvent","clientX","visualViewport","offsetLeft","clientY","offsetTop","_","pageListener","boundingRect","getBoundingClientRect","setViewport","viewport","layout","setFit","loadResource","safeDrawingSize","content","container","widthRatio","heightRatio","Math","min","fitContain","fitWidth","fitHeight","computeScale","BridgeGesturesAdapter","gesturesApi","nativeApi","JSON","stringify","getElementById","querySelector","singleArea","gestures","manager","viewporttWidth","viewportHeight","insetTop","insetRight","insetBottom","insetLeft","initialization","onScriptsLoaded"],"sourceRoot":""} \ No newline at end of file +{"version":3,"file":"fixed-single-script.js","mappings":"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","sources":["webpack://readium-js/./src/fixed/page-manager.ts","webpack://readium-js/./src/util/viewport.ts","webpack://readium-js/./src/common/gestures.ts","webpack://readium-js/./src/fixed/single-area-manager.ts","webpack://readium-js/./src/util/fit.ts","webpack://readium-js/./src/bridge/all-gestures-bridge.ts","webpack://readium-js/./src/index-fixed-single.ts","webpack://readium-js/./src/bridge/fixed-single-bridge.ts"],"sourcesContent":["/** Manages a fixed layout resource embedded in an iframe. */\nexport class PageManager {\n constructor(window, iframe, listener) {\n this.margins = { top: 0, right: 0, bottom: 0, left: 0 };\n if (!iframe.contentWindow) {\n throw Error(\"Iframe argument must have been attached to DOM.\");\n }\n this.listener = listener;\n this.iframe = iframe;\n }\n setMessagePort(messagePort) {\n messagePort.onmessage = (message) => {\n this.onMessageFromIframe(message);\n };\n }\n show() {\n this.iframe.style.display = \"unset\";\n }\n hide() {\n this.iframe.style.display = \"none\";\n }\n /** Sets page margins. */\n setMargins(margins) {\n if (this.margins == margins) {\n return;\n }\n this.iframe.style.marginTop = this.margins.top + \"px\";\n this.iframe.style.marginLeft = this.margins.left + \"px\";\n this.iframe.style.marginBottom = this.margins.bottom + \"px\";\n this.iframe.style.marginRight = this.margins.right + \"px\";\n }\n /** Loads page content. */\n loadPage(url) {\n this.iframe.src = url;\n }\n /** Sets the size of this page without content. */\n setPlaceholder(size) {\n this.iframe.style.visibility = \"hidden\";\n this.iframe.style.width = size.width + \"px\";\n this.iframe.style.height = size.height + \"px\";\n this.size = size;\n }\n onMessageFromIframe(event) {\n const message = event.data;\n switch (message.kind) {\n case \"contentSize\":\n return this.onContentSizeAvailable(message.size);\n case \"tap\":\n return this.listener.onTap({ x: message.x, y: message.y });\n case \"linkActivated\":\n return this.onLinkActivated(message);\n }\n }\n onLinkActivated(message) {\n try {\n const url = new URL(message.href, this.iframe.src);\n this.listener.onLinkActivated(url.toString(), message.outerHtml);\n }\n catch (_a) {\n // Do nothing if url is not valid.\n }\n }\n onContentSizeAvailable(size) {\n if (!size) {\n //FIXME: handle edge case\n return;\n }\n this.iframe.style.width = size.width + \"px\";\n this.iframe.style.height = size.height + \"px\";\n this.size = size;\n this.listener.onIframeLoaded();\n }\n}\n","export class ViewportStringBuilder {\n setInitialScale(scale) {\n this.initialScale = scale;\n return this;\n }\n setMinimumScale(scale) {\n this.minimumScale = scale;\n return this;\n }\n setWidth(width) {\n this.width = width;\n return this;\n }\n setHeight(height) {\n this.height = height;\n return this;\n }\n build() {\n const components = [];\n if (this.initialScale) {\n components.push(\"initial-scale=\" + this.initialScale);\n }\n if (this.minimumScale) {\n components.push(\"minimum-scale=\" + this.minimumScale);\n }\n if (this.width) {\n components.push(\"width=\" + this.width);\n }\n if (this.height) {\n components.push(\"height=\" + this.height);\n }\n return components.join(\", \");\n }\n}\nexport function parseViewportString(viewportString) {\n const regex = /(\\w+) *= *([^\\s,]+)/g;\n const properties = new Map();\n let match;\n while ((match = regex.exec(viewportString))) {\n if (match != null) {\n properties.set(match[1], match[2]);\n }\n }\n const width = parseFloat(properties.get(\"width\"));\n const height = parseFloat(properties.get(\"height\"));\n if (width && height) {\n return { width, height };\n }\n else {\n return undefined;\n }\n}\n","export class GesturesDetector {\n constructor(window, listener) {\n this.window = window;\n this.listener = listener;\n document.addEventListener(\"click\", (event) => {\n this.onClick(event);\n }, false);\n }\n onClick(event) {\n if (event.defaultPrevented) {\n return;\n }\n const selection = this.window.getSelection();\n if (selection && selection.type == \"Range\") {\n // There's an on-going selection, the tap will dismiss it so we don't forward it.\n // selection.type might be None (collapsed) or Caret with a collapsed range\n // when there is not true selection.\n return;\n }\n let nearestElement;\n if (event.target instanceof HTMLElement) {\n nearestElement = this.nearestInteractiveElement(event.target);\n }\n else {\n nearestElement = null;\n }\n if (nearestElement) {\n if (nearestElement instanceof HTMLAnchorElement) {\n this.listener.onLinkActivated(nearestElement.href, nearestElement.outerHTML);\n }\n }\n else {\n this.listener.onTap(event);\n }\n event.stopPropagation();\n event.preventDefault();\n }\n // See. https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling\n nearestInteractiveElement(element) {\n if (element == null) {\n return null;\n }\n const interactiveTags = [\n \"a\",\n \"audio\",\n \"button\",\n \"canvas\",\n \"details\",\n \"input\",\n \"label\",\n \"option\",\n \"select\",\n \"submit\",\n \"textarea\",\n \"video\",\n ];\n if (interactiveTags.indexOf(element.nodeName.toLowerCase()) != -1) {\n return element;\n }\n // Checks whether the element is editable by the user.\n if (element.hasAttribute(\"contenteditable\") &&\n element.getAttribute(\"contenteditable\").toLowerCase() != \"false\") {\n return element;\n }\n // Checks parents recursively because the touch might be for example on an inside a .\n if (element.parentElement) {\n return this.nearestInteractiveElement(element.parentElement);\n }\n return null;\n }\n}\n","import { computeScale } from \"../util/fit\";\nimport { PageManager } from \"./page-manager\";\nimport { ViewportStringBuilder } from \"../util/viewport\";\nimport { GesturesDetector } from \"../common/gestures\";\nexport class SingleAreaManager {\n constructor(window, iframe, metaViewport, listener) {\n this.fit = \"contain\" /* Fit.Contain */;\n this.insets = { top: 0, right: 0, bottom: 0, left: 0 };\n this.scale = 1;\n window.addEventListener(\"message\", (event) => {\n if (event.source === iframe.contentWindow && event.ports[0]) {\n this.page.setMessagePort(event.ports[0]);\n }\n });\n const wrapperGesturesListener = {\n onTap: (event) => {\n const tapEvent = {\n x: (event.clientX - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.clientY - visualViewport.offsetTop) * visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onLinkActivated: (_) => {\n throw Error(\"No interactive element in the root document.\");\n },\n };\n new GesturesDetector(window, wrapperGesturesListener);\n this.metaViewport = metaViewport;\n const pageListener = {\n onIframeLoaded: () => {\n this.onIframeLoaded();\n },\n onTap: (event) => {\n const boundingRect = iframe.getBoundingClientRect();\n const tapEvent = {\n x: (event.x + boundingRect.left - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.y + boundingRect.top - visualViewport.offsetTop) *\n visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n listener.onLinkActivated(href, outerHtml);\n },\n };\n this.page = new PageManager(window, iframe, pageListener);\n }\n setViewport(viewport, insets) {\n if (this.viewport == viewport && this.insets == insets) {\n return;\n }\n this.viewport = viewport;\n this.insets = insets;\n this.layout();\n }\n setFit(fit) {\n if (this.fit == fit) {\n return;\n }\n this.fit = fit;\n this.layout();\n }\n loadResource(url) {\n this.page.hide();\n this.page.loadPage(url);\n }\n onIframeLoaded() {\n if (!this.page.size) {\n // FIXME: raise error\n }\n else {\n this.layout();\n }\n }\n layout() {\n if (!this.page.size || !this.viewport) {\n return;\n }\n const margins = {\n top: this.insets.top,\n right: this.insets.right,\n bottom: this.insets.bottom,\n left: this.insets.left,\n };\n this.page.setMargins(margins);\n const safeDrawingSize = {\n width: this.viewport.width - this.insets.left - this.insets.right,\n height: this.viewport.height - this.insets.top - this.insets.bottom,\n };\n const scale = computeScale(this.fit, this.page.size, safeDrawingSize);\n this.metaViewport.content = new ViewportStringBuilder()\n .setInitialScale(scale)\n .setMinimumScale(scale)\n .setWidth(this.page.size.width)\n .setHeight(this.page.size.height)\n .build();\n this.scale = scale;\n this.page.show();\n }\n}\n","export function computeScale(fit, content, container) {\n switch (fit) {\n case \"contain\" /* Fit.Contain */:\n return fitContain(content, container);\n case \"width\" /* Fit.Width */:\n return fitWidth(content, container);\n case \"height\" /* Fit.Height */:\n return fitHeight(content, container);\n }\n}\nfunction fitContain(content, container) {\n const widthRatio = container.width / content.width;\n const heightRatio = container.height / content.height;\n return Math.min(widthRatio, heightRatio);\n}\nfunction fitWidth(content, container) {\n return container.width / content.width;\n}\nfunction fitHeight(content, container) {\n return container.height / content.height;\n}\n","export class BridgeGesturesAdapter {\n constructor(gesturesApi) {\n this.nativeApi = gesturesApi;\n }\n onTap(event) {\n this.nativeApi.onTap(JSON.stringify(event));\n }\n onLinkActivated(href, outerHtml) {\n this.nativeApi.onLinkActivated(href, outerHtml);\n }\n}\n","//\n// Copyright 2024 Readium Foundation. All rights reserved.\n// Use of this source code is governed by the BSD-style license\n// available in the top-level LICENSE file of the project.\n//\nimport { FixedSingleBridge } from \"./bridge/fixed-single-bridge\";\nconst iframe = document.getElementById(\"page\");\nconst metaViewport = document.querySelector(\"meta[name=viewport]\");\nwindow.singleArea = new FixedSingleBridge(window, iframe, metaViewport, window.gestures);\nwindow.initialization.onScriptsLoaded();\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nwindow.addEventListener(\"load\", (event) => {\n window.initialization.onDocumentLoaded();\n});\n","import { SingleAreaManager } from \"../fixed/single-area-manager\";\nimport { BridgeGesturesAdapter } from \"./all-gestures-bridge\";\nexport class FixedSingleBridge {\n constructor(window, iframe, metaViewport, gestures) {\n const listener = new BridgeGesturesAdapter(gestures);\n this.manager = new SingleAreaManager(window, iframe, metaViewport, listener);\n }\n loadResource(url) {\n this.manager.loadResource(url);\n }\n setViewport(viewporttWidth, viewportHeight, insetTop, insetRight, insetBottom, insetLeft) {\n const viewport = { width: viewporttWidth, height: viewportHeight };\n const insets = {\n top: insetTop,\n left: insetLeft,\n bottom: insetBottom,\n right: insetRight,\n };\n this.manager.setViewport(viewport, insets);\n }\n setFit(fit) {\n if (fit != \"contain\" && fit != \"width\" && fit != \"height\") {\n throw Error(`Invalid fit value: ${fit}`);\n }\n this.manager.setFit(fit);\n }\n}\n"],"names":["PageManager","constructor","window","iframe","listener","this","margins","top","right","bottom","left","contentWindow","Error","setMessagePort","messagePort","onmessage","message","onMessageFromIframe","show","style","display","hide","setMargins","marginTop","marginLeft","marginBottom","marginRight","loadPage","url","src","setPlaceholder","size","visibility","width","height","event","data","kind","onContentSizeAvailable","onTap","x","y","onLinkActivated","URL","href","toString","outerHtml","_a","onIframeLoaded","ViewportStringBuilder","setInitialScale","scale","initialScale","setMinimumScale","minimumScale","setWidth","setHeight","build","components","push","join","GesturesDetector","document","addEventListener","onClick","defaultPrevented","selection","getSelection","type","nearestElement","target","HTMLElement","nearestInteractiveElement","HTMLAnchorElement","outerHTML","stopPropagation","preventDefault","element","indexOf","nodeName","toLowerCase","hasAttribute","getAttribute","parentElement","SingleAreaManager","metaViewport","fit","insets","source","ports","page","tapEvent","clientX","visualViewport","offsetLeft","clientY","offsetTop","_","pageListener","boundingRect","getBoundingClientRect","setViewport","viewport","layout","setFit","loadResource","safeDrawingSize","content","container","widthRatio","heightRatio","Math","min","fitContain","fitWidth","fitHeight","computeScale","BridgeGesturesAdapter","gesturesApi","nativeApi","JSON","stringify","getElementById","querySelector","singleArea","gestures","manager","viewporttWidth","viewportHeight","insetTop","insetRight","insetBottom","insetLeft","initialization","onScriptsLoaded","onDocumentLoaded"],"sourceRoot":""} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadMe.md b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadMe.md new file mode 100644 index 0000000000..b9d6ef6ee4 --- /dev/null +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadMe.md @@ -0,0 +1,112 @@ +# Dealing with Languages/scripts + +You’ll find default stylesheets at the root of this folder, and languages/script-specific ones in their dedicated folder. + +This is a temporary solution to a complex issue (i18n), which is aligned with our current implementation so that we can start testing those specific styles as soon as possible. + +## Right to Left + +If the publication has: + +- a `page-progression-direction` with the value set to `rtl`; +- and language is either Arabic (`ar`), Farsi (`fa`) or Hebrew (`he`). + +Then stylesheets in the `rtl` folder should be used. + +It is also important the `dir` attribute and `xml:lang` be appended to the `html` element of each document if needed. + +Finally, page progression is impacted: + +- previous page is `right`; +- next page is `left`. + +### User settings + +Disabled user settings: + +- `hyphens`; +- `word-spacing`; +- `letter-spacing`. + +Added user settings: + +- `font-variant-ligatures` (mapped to `--USER__ligatures` CSS variable). + +## CJK + +Chinese, Japanese, Korean, and Mongolian can be either written `horizontal-tb` or `vertical-*`. Consequently, there are stylesheets for horizontal and vertical writing modes. + +### Horizontal + +If the publication has: + +- a `page-progression-direction` with the value set to `ltr` – or no attribute –; +- and (at least one) language item is either Chinese (`zh`), Japanese (`ja`), or Korean (`ko`). + +Then stylesheets in the `cjk/horizontal` subfolder should be used. + +It is also important the `xml:lang` be appended to the `html` element of each document if needed. + +#### User settings + +Disabled user settings: + +- `text-align`; +- `hyphens`; +- paragraphs’ indent; +- `word-spacing`; +- `letter-spacing`. + +### Vertical + +If the publication has: + +- a `page-progression-direction` with the value set to `rtl`; +- and (at least one) language item is either Chinese (`zh`), Japanese (`ja`), or Korean (`ko`). + +Then stylesheets in the `cjk/vertical` subfolder should be used. + +It is also important the `xml:lang` be appended to the `html` element of each document if needed. You MUST NOT append a `dir` attribute. + +Please note the `vertical-rl` writing mode will be enforced in this case. + +Finally, page progression is impacted: + +- previous page (`right`) goes up; +- next page (`left`) goes down. + +This means that taps/swipes should behave as usual in horizontal writing i.e. `x-axis` but the app programmatically handles the progression on the `y-axis`. You might therefore want to disable page-transition animations in this case. + +This is consistent with the Readium 1 implementation so the same logic can apply. + +#### User settings + +Disabled user settings: + +- `column-count` (number of columns); +- `text-align`; +- `hyphens`; +- paragraphs’ indent; +- `word-spacing`; +- `letter-spacing`. + +### EBPAJ Polyfill + +The EBPAJ template only references fonts from MS Windows so we must reference fonts from other platforms and override authors’ stylesheets. What we do in this polyfill is keeping their default value and providing fallbacks. + +You might want to load this polyfill (at the end, after `ReadiumCSS-after-cjk(-*)?.css`) only if you find one of the following metadata items in the OPF package: + +- version 1: `ebpaj-guide-1.0` +- version 1.1: `1.1` + +Since we must use `@font-face` to align with their specific implementation (we have to go through 9–11 `local` sources in the worst-case scenario), expect a “rendering debt” though. Do not hesitate to report performance issues for this polyfill. + +### Mongolian + +This is currently an edge case as we still have to see whether we want to support it and how we can support it. Indeed, the situation is the following: + +- Traditional is written `vertical-lr` so we can’t use `page-progression-direction` as an hint, and we must check if the language item (`mn`) is enough: + - if `mn-Mong` is set, then `vertical-lr` must be used; + - if `mn-Cyrl` is set, then the publication is in cyrillic and it is `horizontal-tb`. +- We don’t currently support the `mn` language, and we can’t rely on system fonts to do so, we’ll have to embed one. + diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadiumCSS-after.css b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadiumCSS-after.css new file mode 100644 index 0000000000..042ad48e55 --- /dev/null +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadiumCSS-after.css @@ -0,0 +1,7 @@ +/* + * Readium CSS (v. 1.0.0-beta.3) + * Developers: Jiminy Panoz + * Copyright (c) 2017. Readium Foundation. All rights reserved. + * Use of this source code is governed by a BSD-style license which is detailed in the + * LICENSE file present in the project repository where this source code is maintained. +*/@namespace url("http://www.w3.org/1999/xhtml");@namespace epub url("http://www.idpf.org/2007/ops");@namespace m url("http://www.w3.org/1998/Math/MathML/");@namespace svg url("http://www.w3.org/2000/svg");:root{--RS__colWidth:45em;--RS__colCount:1;--RS__colGap:0;--RS__maxLineLength:40rem;--RS__pageGutter:20px;--RS__viewportWidth:100%}@page{margin:0!important}:root{position:relative;-webkit-column-width:var(--RS__colWidth);-moz-column-width:var(--RS__colWidth);column-width:var(--RS__colWidth);-webkit-column-count:var(--RS__colCount);-moz-column-count:var(--RS__colCount);column-count:var(--RS__colCount);-webkit-column-gap:var(--RS__colGap);-moz-column-gap:var(--RS__colGap);column-gap:var(--RS__colGap);-moz-column-fill:auto;column-fill:auto;width:var(--RS__viewportWidth);height:100vh;max-width:var(--RS__viewportWidth);max-height:100vh;min-width:var(--RS__viewportWidth);min-height:100vh;padding:0!important;margin:0!important;font-size:100%!important;-webkit-text-size-adjust:100%;box-sizing:border-box;-webkit-perspective:1;-webkit-touch-callout:none}body{width:100%;max-width:var(--RS__maxLineLength)!important;padding:0 var(--RS__pageGutter)!important;margin:0 auto!important;box-sizing:border-box}@media screen and (min-width:35em){:root{--RS__pageGutter:30px}}@media screen and (min-width:45em){:root{--RS__pageGutter:40px}}@media screen and (min-width:75em){:root{--RS__pageGutter:50px}}@media screen and (min-width:60em),screen and (min-device-width:36em) and (max-device-width:47em) and (orientation:landscape){:root{--RS__colWidth:20em;--RS__colCount:2;--RS__maxLineLength:39.99rem}}:root[style*=readium-scroll-on]{-webkit-columns:auto auto!important;-moz-columns:auto auto!important;columns:auto auto!important;width:auto!important;height:auto!important;max-width:none!important;max-height:none!important;min-width:0!important;min-height:0!important}:root[style*=readium-scroll-on] body{--RS__maxLineLength:40rem!important}:root[style*=readium-night-on]{--RS__backgroundColor:#000000;--RS__textColor:#FEFEFE;--RS__linkColor:#63caff;--RS__visitedColor:#0099E5;--RS__selectionBackgroundColor:#b4d8fe;--RS__selectionTextColor:inherit}:root[style*=readium-night-on] :not(a){color:inherit!important;background-color:transparent!important;border-color:currentColor!important}:root[style*=readium-night-on] svg text{fill:currentColor!important;stroke:none!important}:root[style*=readium-night-on] a:link,:root[style*=readium-night-on] a:link *{color:var(--RS__linkColor)!important}:root[style*=readium-night-on] a:visited,:root[style*=readium-night-on] a:visited *{color:var(--RS__visitedColor)!important}:root[style*=readium-night-on] [epub\:type~=titlepage] img:only-child,:root[style*=readium-night-on] [epub|type~=titlepage] img:only-child,:root[style*=readium-night-on] img[class*=gaiji]{-webkit-filter:invert(100%);filter:invert(100%)}:root[style*=readium-night-on][style*=readium-darken-on] img{-webkit-filter:brightness(80%);filter:brightness(80%)}:root[style*=readium-night-on][style*=readium-invert-on] img{-webkit-filter:invert(100%);filter:invert(100%)}:root[style*=readium-night-on][style*=readium-darken-on][style*=readium-invert-on] img{-webkit-filter:brightness(80%) invert(100%);filter:brightness(80%) invert(100%)}:root[style*=readium-sepia-on]{--RS__backgroundColor:#faf4e8;--RS__textColor:#121212;--RS__linkColor:#0000EE;--RS__visitedColor:#551A8B;--RS__selectionBackgroundColor:#b4d8fe;--RS__selectionTextColor:inherit;--RS__maxLineLength:40.01rem}:root[style*=readium-sepia-on] :not(a){color:inherit!important;background-color:transparent!important}:root[style*=readium-sepia-on] a:link,:root[style*=readium-sepia-on] a:link *{color:var(--RS__linkColor)}:root[style*=readium-sepia-on] a:visited,:root[style*=readium-sepia-on] a:visited *{color:var(--RS__visitedColor)}:root[style*=readium-sepia-on] img,:root[style*=readium-sepia-on] svg{background-color:transparent!important;mix-blend-mode:multiply}@media screen and (-ms-high-contrast:active){:root{color:windowText!important;background-color:window!important}:root :not(#\#):not(#\#):not(#\#),:root :not(#\#):not(#\#):not(#\#) :not(#\#):not(#\#):not(#\#) :root :not(#\#):not(#\#):not(#\#) :not(#\#):not(#\#):not(#\#) :not(#\#):not(#\#):not(#\#){color:inherit!important;background-color:inherit!important}.readiumCSS-mo-active-default{color:highlightText!important;background-color:highlight!important}}@media screen and (-ms-high-contrast:white-on-black){:root[style*=readium-night-on] [epub\:type~=titlepage] img:only-child,:root[style*=readium-night-on] [epub|type~=titlepage] img:only-child,:root[style*=readium-night-on] img[class*=gaiji]{-webkit-filter:none!important;filter:none!important}:root[style*=readium-night-on][style*=readium-invert-on] img{-webkit-filter:none!important;filter:none!important}:root[style*=readium-night-on][style*=readium-darken-on][style*=readium-invert-on] img{-webkit-filter:brightness(80%);filter:brightness(80%)}}@media screen and (inverted-colors){:root[style*=readium-night-on] [epub\:type~=titlepage] img:only-child,:root[style*=readium-night-on] [epub|type~=titlepage] img:only-child,:root[style*=readium-night-on] img[class*=gaiji]{-webkit-filter:none!important;filter:none!important}:root[style*=readium-night-on][style*=readium-invert-on] img{-webkit-filter:none!important;filter:none!important}:root[style*=readium-night-on][style*=readium-darken-on][style*=readium-invert-on] img{-webkit-filter:brightness(80%);filter:brightness(80%)}}@media screen and (min-width:60em),screen and (min-device-width:36em) and (max-device-width:47em) and (orientation:landscape){:root[style*="--USER__colCount: 1"],:root[style*="--USER__colCount: 2"],:root[style*="--USER__colCount:1"],:root[style*="--USER__colCount:2"]{-webkit-column-count:var(--USER__colCount);-moz-column-count:var(--USER__colCount);column-count:var(--USER__colCount)}:root[style*="--USER__colCount: 1"],:root[style*="--USER__colCount:1"]{--RS__maxLineLength:40rem!important;--RS__colWidth:100vw}:root[style*="--USER__colCount: 2"],:root[style*="--USER__colCount:2"]{--RS__colWidth:auto}}:root[style*="--USER__pageMargins"] body{padding:0 calc(var(--RS__pageGutter) * var(--USER__pageMargins))!important}:root[style*="--USER__backgroundColor"]{background-color:var(--USER__backgroundColor)!important}:root[style*="--USER__backgroundColor"] *{background-color:transparent!important}:root[style*="--USER__textColor"]{color:var(--USER__textColor)!important}:root[style*="--USER__textColor"] :not(h1):not(h2):not(h3):not(h4):not(h5):not(h6):not(pre){color:inherit!important}:root[style*=readium-advanced-on][style*="--USER__textAlign"]{text-align:var(--USER__textAlign)}:root[style*=readium-advanced-on][style*="--USER__textAlign"] :not(blockquote):not(figcaption) p,:root[style*=readium-advanced-on][style*="--USER__textAlign"] body,:root[style*=readium-advanced-on][style*="--USER__textAlign"] li{text-align:inherit!important;-moz-text-align-last:auto!important;-epub-text-align-last:auto!important;text-align-last:auto!important}:root[style*=readium-advanced-on][dir=rtl][style*="--USER__textAlign: left"],:root[style*=readium-advanced-on][dir=rtl][style*="--USER__textAlign:left"],:root[style*=readium-advanced-on][style*="--USER__textAlign: left"] [dir=rtl],:root[style*=readium-advanced-on][style*="--USER__textAlign:left"] [dir=rtl]{text-align:right}:root[style*=readium-advanced-on][dir=rtl][style*="--USER__textAlign: start"],:root[style*=readium-advanced-on][dir=rtl][style*="--USER__textAlign:start"]{text-align:right}:root[style*=readium-advanced-on][style*="--USER__textAlign: justify"] body,:root[style*=readium-advanced-on][style*="--USER__textAlign:justify"] body{-webkit-hyphens:auto;-moz-hyphens:auto;-ms-hyphens:auto;-epub-hyphens:auto;hyphens:auto}:root[style*=readium-advanced-on][style*="--USER__textAlign: left"] body,:root[style*=readium-advanced-on][style*="--USER__textAlign: right"] body,:root[style*=readium-advanced-on][style*="--USER__textAlign:left"] body,:root[style*=readium-advanced-on][style*="--USER__textAlign:right"] body{-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;-epub-hyphens:none;hyphens:none}:root[style*=readium-advanced-on][style*="--USER__bodyHyphens"]{-webkit-hyphens:var(--USER__bodyHyphens)!important;-moz-hyphens:var(--USER__bodyHyphens)!important;-ms-hyphens:var(--USER__bodyHyphens)!important;-epub-hyphens:var(--USER__bodyHyphens)!important;hyphens:var(--USER__bodyHyphens)!important}:root[style*=readium-advanced-on][style*="--USER__bodyHyphens"] body,:root[style*=readium-advanced-on][style*="--USER__bodyHyphens"] dd,:root[style*=readium-advanced-on][style*="--USER__bodyHyphens"] div,:root[style*=readium-advanced-on][style*="--USER__bodyHyphens"] li,:root[style*=readium-advanced-on][style*="--USER__bodyHyphens"] p{-webkit-hyphens:inherit;-moz-hyphens:inherit;-ms-hyphens:inherit;-epub-hyphens:inherit;hyphens:inherit}:root[style*=readium-font-on][style*="--USER__fontFamily"]{font-family:var(--USER__fontFamily)!important}:root[style*=readium-font-on][style*="--USER__fontFamily"] body,:root[style*=readium-font-on][style*="--USER__fontFamily"] dd,:root[style*=readium-font-on][style*="--USER__fontFamily"] div,:root[style*=readium-font-on][style*="--USER__fontFamily"] dt,:root[style*=readium-font-on][style*="--USER__fontFamily"] li,:root[style*=readium-font-on][style*="--USER__fontFamily"] p{font-family:inherit!important}:root[style*=readium-font-on][style*="--USER__fontFamily"] b:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] b:not([xml\:lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] cite:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] cite:not([xml\:lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] em:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] em:not([xml\:lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] i:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] i:not([xml\:lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] span:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] span:not([xml\:lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] strong:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] strong:not([xml\:lang]){font-family:inherit!important}:root[style*=readium-font-on][style*=AccessibleDfA]{font-family:AccessibleDfA,Verdana,Tahoma,"Trebuchet MS",sans-serif!important;--RS__lineHeightCompensation:1.167}:root[style*=readium-font-on][style*="IA Writer Duospace"]{font-family:"IA Writer Duospace",Menlo,"DejaVu Sans Mono","Bitstream Vera Sans Mono",Courier,monospace!important;--RS__lineHeightCompensation:1.167}:root[style*=readium-font-on][style*=readium-a11y-on]{font-family:var(--USER__fontFamily)!important;--RS__lineHeightCompensation:1.167}:root[style*=readium-font-on][style*="IA Writer Duospace"],:root[style*=readium-font-on][style*=AccessibleDfA],:root[style*=readium-font-on][style*=readium-a11y-on]{font-style:normal!important;font-weight:400!important}:root[style*=readium-font-on][style*="IA Writer Duospace"] :not(code):not(var):not(kbd):not(samp),:root[style*=readium-font-on][style*=AccessibleDfA] :not(code):not(var):not(kbd):not(samp),:root[style*=readium-font-on][style*=readium-a11y-on] :not(code):not(var):not(kbd):not(samp){font-family:inherit!important;font-style:inherit!important;font-weight:inherit!important}:root[style*=readium-font-on][style*="IA Writer Duospace"] *,:root[style*=readium-font-on][style*=AccessibleDfA] *,:root[style*=readium-font-on][style*=readium-a11y-on] *{text-decoration:none!important;font-variant-caps:normal!important;font-variant-numeric:normal!important;font-variant-position:normal!important}:root[style*=readium-font-on][style*="IA Writer Duospace"] sub,:root[style*=readium-font-on][style*="IA Writer Duospace"] sup,:root[style*=readium-font-on][style*=AccessibleDfA] sub,:root[style*=readium-font-on][style*=AccessibleDfA] sup,:root[style*=readium-font-on][style*=readium-a11y-on] sub,:root[style*=readium-font-on][style*=readium-a11y-on] sup{font-size:1rem!important;vertical-align:baseline!important}:root[style*="--USER__fontSize"]{font-size:var(--USER__fontSize)!important}:root[style*=readium-advanced-on][style*="--USER__lineHeight"]{line-height:var(--USER__lineHeight)!important}:root[style*=readium-advanced-on][style*="--USER__lineHeight"] body,:root[style*=readium-advanced-on][style*="--USER__lineHeight"] div,:root[style*=readium-advanced-on][style*="--USER__lineHeight"] li,:root[style*=readium-advanced-on][style*="--USER__lineHeight"] p{line-height:inherit}:root[style*=readium-advanced-on][style*="--USER__paraSpacing"] p{margin-top:var(--USER__paraSpacing)!important;margin-bottom:var(--USER__paraSpacing)!important}:root[style*=readium-advanced-on][style*="--USER__paraIndent"] p{text-indent:var(--USER__paraIndent)!important}:root[style*=readium-advanced-on][style*="--USER__paraIndent"] p *,:root[style*=readium-advanced-on][style*="--USER__paraIndent"] p:first-letter{text-indent:0!important}:root[style*=readium-advanced-on][style*="--USER__wordSpacing"] div,:root[style*=readium-advanced-on][style*="--USER__wordSpacing"] h1,:root[style*=readium-advanced-on][style*="--USER__wordSpacing"] h2,:root[style*=readium-advanced-on][style*="--USER__wordSpacing"] h3,:root[style*=readium-advanced-on][style*="--USER__wordSpacing"] h4,:root[style*=readium-advanced-on][style*="--USER__wordSpacing"] h5,:root[style*=readium-advanced-on][style*="--USER__wordSpacing"] h6,:root[style*=readium-advanced-on][style*="--USER__wordSpacing"] li,:root[style*=readium-advanced-on][style*="--USER__wordSpacing"] p{word-spacing:var(--USER__wordSpacing)}:root[style*=readium-advanced-on][style*="--USER__letterSpacing"] div,:root[style*=readium-advanced-on][style*="--USER__letterSpacing"] h1,:root[style*=readium-advanced-on][style*="--USER__letterSpacing"] h2,:root[style*=readium-advanced-on][style*="--USER__letterSpacing"] h3,:root[style*=readium-advanced-on][style*="--USER__letterSpacing"] h4,:root[style*=readium-advanced-on][style*="--USER__letterSpacing"] h5,:root[style*=readium-advanced-on][style*="--USER__letterSpacing"] h6,:root[style*=readium-advanced-on][style*="--USER__letterSpacing"] li,:root[style*=readium-advanced-on][style*="--USER__letterSpacing"] p{letter-spacing:var(--USER__letterSpacing);font-variant:none}:root[style*=readium-advanced-on]{--USER__typeScale:1.2}:root[style*=readium-advanced-on] dd,:root[style*=readium-advanced-on] div,:root[style*=readium-advanced-on] li,:root[style*=readium-advanced-on] p,:root[style*=readium-advanced-on] pre{font-size:1rem!important}:root[style*=readium-advanced-on] h1{font-size:1.75rem!important;font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale))!important}:root[style*=readium-advanced-on] h2{font-size:1.5rem!important;font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale))!important}:root[style*=readium-advanced-on] h3{font-size:1.25rem!important;font-size:calc(1rem * var(--USER__typeScale))!important}:root[style*=readium-advanced-on] h4,:root[style*=readium-advanced-on] h5,:root[style*=readium-advanced-on] h6{font-size:1rem!important}:root[style*=readium-advanced-on] small{font-size:smaller!important}:root[style*=readium-advanced-on] sub,:root[style*=readium-advanced-on] sup{font-size:67.5%!important}:root[style*=readium-advanced-on][style*="--USER__typeScale"] h1{font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale))!important}:root[style*=readium-advanced-on][style*="--USER__typeScale"] h2{font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale))!important}:root[style*=readium-advanced-on][style*="--USER__typeScale"] h3{font-size:calc(1rem * var(--USER__typeScale))!important} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadiumCSS-before.css b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadiumCSS-before.css new file mode 100644 index 0000000000..3a224ba632 --- /dev/null +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadiumCSS-before.css @@ -0,0 +1,7 @@ +/* + * Readium CSS (v. 1.0.0-beta.3) + * Developers: Jiminy Panoz + * Copyright (c) 2017. Readium Foundation. All rights reserved. + * Use of this source code is governed by a BSD-style license which is detailed in the + * LICENSE file present in the project repository where this source code is maintained. +*/@namespace url("http://www.w3.org/1999/xhtml");@namespace epub url("http://www.idpf.org/2007/ops");@namespace m url("http://www.w3.org/1998/Math/MathML/");@namespace svg url("http://www.w3.org/2000/svg");@-ms-viewport{width:device-width}@viewport{width:device-width;zoom:1}:root{--RS__oldStyleTf:"Iowan Old Style","Sitka Text",Palatino,"Book Antiqua",serif;--RS__modernTf:Athelas,Constantia,Georgia,serif;--RS__sansTf:-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;--RS__humanistTf:Seravek,Calibri,Roboto,Arial,sans-serif;--RS__monospaceTf:"Andale Mono",Consolas,monospace;--RS__baseFontFamily:var(--RS__oldStyleTf);--RS__lineHeightCompensation:1;--RS__baseLineHeight:calc((1em + (2ex - 1ch) - ((1rem - 16px) * 0.1667)) * var(--RS__lineHeightCompensation))}html{font-family:var(--RS__baseFontFamily);line-height:1.6;line-height:var(--RS__baseLineHeight);text-rendering:optimizeLegibility}h1,h2,h3{line-height:normal}:lang(ja),:lang(ko),:lang(zh){word-wrap:break-word;-webkit-line-break:strict;-epub-line-break:strict;line-break:strict}math{font-family:"Latin Modern Math","STIX Two Math","XITS Math","STIX Math","Libertinus Math","TeX Gyre Termes Math","TeX Gyre Bonum Math","TeX Gyre Schola","DejaVu Math TeX Gyre","TeX Gyre Pagella Math","Asana Math","Cambria Math","Lucida Bright Math","Minion Math",STIXGeneral,STIXSizeOneSym,Symbol,"Times New Roman",serif}:lang(am){--RS__baseFontFamily:Kefa,Nyala,Roboto,Noto,"Noto Sans Ethiopic",serif;--RS__lineHeightCompensation:1.167}:lang(ar){--RS__baseFontFamily:"Geeza Pro","Arabic Typesetting",Roboto,Noto,"Noto Naskh Arabic","Times New Roman",serif}:lang(bn){--RS__baseFontFamily:"Kohinoor Bangla","Bangla Sangam MN",Vrinda,Roboto,Noto,"Noto Sans Bengali",sans-serif;--RS__lineHeightCompensation:1.067}:lang(bo){--RS__baseFontFamily:Kailasa,"Microsoft Himalaya",Roboto,Noto,"Noto Sans Tibetan",sans-serif}:lang(chr){--RS__baseFontFamily:"Plantagenet Cherokee",Roboto,Noto,"Noto Sans Cherokee";--RS__lineHeightCompensation:1.167}:lang(fa){--RS__baseFontFamily:"Geeza Pro","Arabic Typesetting",Roboto,Noto,"Noto Naskh Arabic","Times New Roman",serif}:lang(gu){--RS__baseFontFamily:"Gujarati Sangam MN","Nirmala UI",Shruti,Roboto,Noto,"Noto Sans Gujarati",sans-serif;--RS__lineHeightCompensation:1.167}:lang(he){--RS__baseFontFamily:"New Peninim MT","Arial Hebrew",Gisha,"Times New Roman",Roboto,Noto,"Noto Sans Hebrew" sans-serif;--RS__lineHeightCompensation:1.1}:lang(hi){--RS__baseFontFamily:"Kohinoor Devanagari","Devanagari Sangam MN",Kokila,"Nirmala UI",Roboto,Noto,"Noto Sans Devanagari",sans-serif;--RS__lineHeightCompensation:1.1}:lang(hy){--RS__baseFontFamily:Mshtakan,Sylfaen,Roboto,Noto,"Noto Serif Armenian",serif}:lang(iu){--RS__baseFontFamily:"Euphemia UCAS",Euphemia,Roboto,Noto,"Noto Sans Canadian Aboriginal",sans-serif}:lang(ja){--RS__baseFontFamily:"游ゴシック体",YuGothic,"ヒラギノ丸ゴ","Hiragino Sans","Yu Gothic UI","Meiryo UI","MS Gothic",Roboto,Noto,"Noto Sans CJK JP",sans-serif;--RS__lineHeightCompensation:1.167;--RS__serif-ja:"MS P明朝","MS PMincho","Hiragino Mincho Pro","ヒラギノ明朝 Pro W3","游明朝","YuMincho","MS 明朝","MS Mincho","Hiragino Mincho ProN",serif;--RS__sans-serif-ja:"MS Pゴシック","MS PGothic","Hiragino Kaku Gothic Pro W3","ヒラギノ角ゴ Pro W3","Hiragino Sans GB","ヒラギノ角ゴシック W3","游ゴシック","YuGothic","MS ゴシック","MS Gothic","Hiragino Sans",sans-serif;--RS__serif-ja-v:"MS 明朝","MS Mincho","Hiragino Mincho Pro","ヒラギノ明朝 Pro W3","游明朝","YuMincho","MS P明朝","MS PMincho","Hiragino Mincho ProN",serif;--RS__sans-serif-ja-v:"MS ゴシック","MS Gothic","Hiragino Kaku Gothic Pro W3","ヒラギノ角ゴ Pro W3","Hiragino Sans GB","ヒラギノ角ゴシック W3","游ゴシック","YuGothic","MS Pゴシック","MS PGothic","Hiragino Sans",sans-serif}:lang(km){--RS__baseFontFamily:"Khmer Sangam MN","Leelawadee UI","Khmer UI",Roboto,Noto,"Noto Sans Khmer",sans-serif;--RS__lineHeightCompensation:1.067}:lang(kn){--RS__baseFontFamily:"Kannada Sangam MN","Nirmala UI",Tunga,Roboto,Noto,"Noto Sans Kannada",sans-serif;--RS__lineHeightCompensation:1.1}:lang(ko){--RS__baseFontFamily:"Nanum Gothic","Apple SD Gothic Neo","Malgun Gothic",Roboto,Noto,"Noto Sans CJK KR",sans-serif;--RS__lineHeightCompensation:1.167}:lang(lo){--RS__baseFontFamily:"Lao Sangam MN","Leelawadee UI","Lao UI",Roboto,Noto,"Noto Sans Lao",sans-serif}:lang(ml){--RS__baseFontFamily:"Malayalam Sangam MN","Nirmala UI",Kartika,Roboto,Noto,"Noto Sans Malayalam",sans-serif;--RS__lineHeightCompensation:1.067}:lang(or){--RS__baseFontFamily:"Oriya Sangam MN","Nirmala UI",Kalinga,Roboto,Noto,"Noto Sans Oriya",sans-serif;--RS__lineHeightCompensation:1.167}:lang(pa){--RS__baseFontFamily:"Gurmukhi MN","Nirmala UI",Kartika,Roboto,Noto,"Noto Sans Gurmukhi",sans-serif;--RS__lineHeightCompensation:1.1}:lang(si){--RS__baseFontFamily:"Sinhala Sangam MN","Nirmala UI","Iskoola Pota",Roboto,Noto,"Noto Sans Sinhala",sans-serif;--RS__lineHeightCompensation:1.167}:lang(ta){--RS__baseFontFamily:"Tamil Sangam MN","Nirmala UI",Latha,Roboto,Noto,"Noto Sans Tamil",sans-serif;--RS__lineHeightCompensation:1.067}:lang(te){--RS__baseFontFamily:"Kohinoor Telugu","Telugu Sangam MN","Nirmala UI",Gautami,Roboto,Noto,"Noto Sans Telugu",sans-serif}:lang(th){--RS__baseFontFamily:"Thonburi","Leelawadee UI","Cordia New",Roboto,Noto,"Noto Sans Thai",sans-serif;--RS__lineHeightCompensation:1.067}:lang(zh){--RS__baseFontFamily:"方体","PingFang SC","黑体","Heiti SC","Microsoft JhengHei UI","Microsoft JhengHei",Roboto,Noto,"Noto Sans CJK SC",sans-serif;--RS__lineHeightCompensation:1.167}:lang(zh-Hant),:lang(zh-TW){--RS__baseFontFamily:"方體","PingFang TC","黑體","Heiti TC","Microsoft JhengHei UI","Microsoft JhengHei",Roboto,Noto,"Noto Sans CJK TC",sans-serif;--RS__lineHeightCompensation:1.167}:lang(zh-HK){--RS__baseFontFamily:"方體","PingFang HK","方體","PingFang TC","黑體","Heiti TC","Microsoft JhengHei UI","Microsoft JhengHei",Roboto,Noto,"Noto Sans CJK TC",sans-serif;--RS__lineHeightCompensation:1.167}:root{--RS__backgroundColor:#FFFFFF;--RS__textColor:#121212;--RS__selectionBackgroundColor:#b4d8fe;--RS__selectionTextColor:inherit}:root{color:var(--RS__textColor)!important;background-color:var(--RS__backgroundColor)!important}::-moz-selection{color:var(--RS__selectionTextColor);background-color:var(--RS__selectionBackgroundColor)}::selection{color:var(--RS__selectionTextColor);background-color:var(--RS__selectionBackgroundColor)}@font-face{font-family:AccessibleDfA;font-style:normal;font-weight:400;src:local("AccessibleDfA"),url(fonts/AccessibleDfA.otf) format("opentype")}@font-face{font-family:"IA Writer Duospace";font-style:normal;font-weight:400;src:local("iAWriterDuospace-Regular"),url(fonts/iAWriterDuospace-Regular.ttf) format("truetype")}body{widows:2;orphans:2}figcaption,td,th{widows:1;orphans:1}caption,dt,h2,h3,h4,h5,h6,hr{-webkit-column-break-after:avoid;page-break-after:avoid;break-after:avoid}dt,figure,h1,h2,h3,h4,h5,h6,tr{-webkit-column-break-inside:avoid;page-break-inside:avoid;break-inside:avoid}body{-webkit-hyphenate-character:"\002D";-moz-hyphenate-character:"\002D";-ms-hyphenate-character:"\002D";hyphenate-character:"\002D";-webkit-hyphenate-limit-lines:3;-ms-hyphenate-limit-lines:3;hyphenate-limit-lines:3}address,caption,center,code,dt,figcaption,h1,h2,h3,h4,h5,h6,pre,var{-ms-hyphens:none;-moz-hyphens:none;-webkit-hyphens:none;-epub-hyphens:none;hyphens:none}body{font-variant-numeric:oldstyle-nums proportional-nums}:lang(ja) body,:lang(ko) body,:lang(zh) body{font-variant-numeric:lining-nums proportional-nums}dt,h1,h2,h3,h4,h5,h6{font-variant-numeric:lining-nums proportional-nums}table{font-variant-numeric:lining-nums tabular-nums}code,var{font-variant-ligatures:none;font-variant-numeric:lining-nums tabular-nums slashed-zero}rt{font-variant-east-asian:ruby}:lang(ar){font-variant-ligatures:common-ligatures}:lang(ko){font-kerning:normal}hr{color:inherit;border-color:currentColor}table,td,th{border-color:currentColor}blockquote,figure{margin:1em 5%}ol,ul{padding-left:5%}dd{margin-left:5%}pre{white-space:pre-wrap;-ms-tab-size:2;-moz-tab-size:2;-webkit-tab-size:2;tab-size:2}abbr[title],acronym[title]{text-decoration:dotted underline}nobr wbr{white-space:normal}ruby>rp,ruby>rt{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}:lang(ja),:lang(ja) cite,:lang(ja) dfn,:lang(ja) em,:lang(ja) i,:lang(ko),:lang(ko) cite,:lang(ko) dfn,:lang(ko) em,:lang(ko) i,:lang(zh),:lang(zh) cite,:lang(zh) dfn,:lang(zh) em,:lang(zh) i{font-style:normal}:lang(ja) a,:lang(ko) a,:lang(zh) a{text-decoration:none}:root{--RS__maxMediaWidth:100%;--RS__maxMediaHeight:95vh;--RS__boxSizingMedia:border-box;--RS__boxSizingTable:border-box}html{-webkit-line-box-contain:block glyphs replaced}:lang(ja){-webkit-line-box-contain:block inline replaced}a,h1,h2,h3,h4,h5,h6{word-wrap:break-word}div{max-width:var(--RS__maxMediaWidth)}audio,img,svg,video{object-fit:contain;width:auto;height:auto;max-width:var(--RS__maxMediaWidth);max-height:var(--RS__maxMediaHeight)!important;box-sizing:var(--RS__boxSizingMedia);-webkit-column-break-inside:avoid;page-break-inside:avoid;break-inside:avoid}table{max-width:var(--RS__maxMediaWidth);box-sizing:var(--RS__boxSizingTable)} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadiumCSS-default.css b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadiumCSS-default.css new file mode 100644 index 0000000000..b19b562c86 --- /dev/null +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadiumCSS-default.css @@ -0,0 +1,7 @@ +/* + * Readium CSS (v. 1.0.0-beta.3) + * Developers: Jiminy Panoz + * Copyright (c) 2017. Readium Foundation. All rights reserved. + * Use of this source code is governed by a BSD-style license which is detailed in the + * LICENSE file present in the project repository where this source code is maintained. +*/@namespace url("http://www.w3.org/1999/xhtml");@namespace epub url("http://www.idpf.org/2007/ops");@namespace m url("http://www.w3.org/1998/Math/MathML/");@namespace svg url("http://www.w3.org/2000/svg");:root{--RS__compFontFamily:var(--RS__baseFontFamily);--RS__codeFontFamily:var(--RS__monospaceTf);--RS__typeScale:1.125;--RS__baseFontSize:100%;--RS__flowSpacing:1.5rem;--RS__paraSpacing:0;--RS__paraIndent:1em;--RS__linkColor:#0000EE;--RS__visitedColor:#551A8B}body{font-size:var(--RS__baseFontSize)}h1,h2,h3,h4,h5,h6{font-family:var(--RS__compFontFamily)}aside,blockquote,figure,footer,form,hr,p,pre{margin-top:var(--RS__flowSpacing);margin-bottom:var(--RS__flowSpacing)}p{margin-top:var(--RS__paraSpacing);margin-bottom:var(--RS__paraSpacing);text-indent:var(--RS__paraIndent)}h1+p,h2+p,h3+p,h4+p,h5+p,h6+p,hr+p{text-indent:0}pre{font-family:var(--RS__codeFontFamily)}code,kbd,samp,tt{font-family:var(--RS__codeFontFamily)}sub,sup{position:relative;font-size:67.5%;line-height:1}sub{bottom:-.2ex}sup{bottom:0}:link{color:var(--RS__linkColor)}:visited{color:var(--RS__visitedColor)}h1{margin-top:calc(var(--RS__flowSpacing) * 2);margin-bottom:calc(var(--RS__flowSpacing) * 2);font-size:calc(((1em * var(--RS__typeScale)) * var(--RS__typeScale)) * var(--RS__typeScale))}h2{margin-top:calc(var(--RS__flowSpacing) * 2);margin-bottom:var(--RS__flowSpacing);font-size:calc((1em * var(--RS__typeScale)) * var(--RS__typeScale))}h3{margin-top:var(--RS__flowSpacing);margin-bottom:var(--RS__flowSpacing);font-size:calc(1em * var(--RS__typeScale))}h4{margin-top:var(--RS__flowSpacing);margin-bottom:var(--RS__flowSpacing);font-size:1em}h5{margin-top:var(--RS__flowSpacing);margin-bottom:var(--RS__flowSpacing);font-size:1em;font-variant:small-caps}h6{margin-top:var(--RS__flowSpacing);margin-bottom:0;font-size:1em;text-transform:lowercase;font-variant:small-caps}dl,ol,ul{margin-top:var(--RS__flowSpacing);margin-bottom:var(--RS__flowSpacing)}table{margin:var(--RS__flowSpacing) 0;border:1px solid currentColor;border-collapse:collapse;empty-cells:show}table>tr,tbody,tfoot,thead{vertical-align:top}th{text-align:left}td,th{padding:4px;border:1px solid currentColor} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadiumCSS-ebpaj_fonts_patch.css b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadiumCSS-ebpaj_fonts_patch.css new file mode 100644 index 0000000000..b73eb6744f --- /dev/null +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadiumCSS-ebpaj_fonts_patch.css @@ -0,0 +1,80 @@ +/* Readium CSS + EBPAJ Fonts Patch module + + A stylesheet improving EBPAJ @font-face declarations to cover all platforms + + Repo: https://github.com/readium/readium-css */ + +/* EBPAJ template only references fonts from MS Windows… + so we must reference fonts from other platforms + and override authors’ stylesheets. + What we do there is keeping their default value and providing fallbacks. + + /!\ /!\ /!\ /!\ /!\ + FYI, you might want to load this polyfill only if you find + one of the following metadata items in the OPF package: + - version 1: + ebpaj-guide-1.0 + - version 1.1: + 1.1 + */ + +/* 横組み用 (horizontal writing) */ + +@font-face { + font-family: "serif-ja"; + src: local("MS P明朝"), + local("MS PMincho"), + local("Hiragino Mincho Pro"), + local("ヒラギノ明朝 Pro W3"), + local("游明朝"), + local("YuMincho"), + local("MS 明朝"), + local("MS Mincho"), + local("Hiragino Mincho ProN"); +} + +@font-face { + font-family: "sans-serif-ja"; + src: local("MS Pゴシック"), + local("MS PGothic"), + local("Hiragino Kaku Gothic Pro W3"), + local("ヒラギノ角ゴ Pro W3"), + local("Hiragino Sans GB"), + local("ヒラギノ角ゴシック W3"), + local("游ゴシック"), + local("YuGothic"), + local("MS ゴシック"), + local("MS Gothic"), + local("Hiragino Sans"); +} + +/* 縦組み用 (vertical writing) */ + +@font-face { + font-family: "serif-ja-v"; + src: local("MS 明朝"), + local("MS Mincho"), + local("Hiragino Mincho Pro"), + local("ヒラギノ明朝 Pro W3"), + local("游明朝"), + local("YuMincho"), + local("MS P明朝"), + local("MS PMincho"), + local("Hiragino Mincho ProN"); +} + +@font-face { + font-family: "sans-serif-ja-v"; + src: local("MS ゴシック"), + local("MS Gothic"), + local("Hiragino Kaku Gothic Pro W3"), + local("ヒラギノ角ゴ Pro W3"), + local("Hiragino Sans GB"), + local("ヒラギノ角ゴシック W3"), + local("游ゴシック"), + local("YuGothic"), + local("MS Pゴシック"), + local("MS PGothic"), + local("Hiragino Sans"); +} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-horizontal/ReadiumCSS-after.css b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-horizontal/ReadiumCSS-after.css new file mode 100644 index 0000000000..fa397b4146 --- /dev/null +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-horizontal/ReadiumCSS-after.css @@ -0,0 +1,7 @@ +/* + * Readium CSS (v. 1.0.0-beta.3) + * Developers: Jiminy Panoz + * Copyright (c) 2017. Readium Foundation. All rights reserved. + * Use of this source code is governed by a BSD-style license which is detailed in the + * LICENSE file present in the project repository where this source code is maintained. +*/@namespace url("http://www.w3.org/1999/xhtml");@namespace epub url("http://www.idpf.org/2007/ops");@namespace m url("http://www.w3.org/1998/Math/MathML/");@namespace svg url("http://www.w3.org/2000/svg");:root{--RS__colWidth:45em;--RS__colCount:1;--RS__colGap:0;--RS__maxLineLength:40rem;--RS__pageGutter:20px;--RS__viewportWidth:100%}@page{margin:0!important}:root{position:relative;-webkit-column-width:var(--RS__colWidth);-moz-column-width:var(--RS__colWidth);column-width:var(--RS__colWidth);-webkit-column-count:var(--RS__colCount);-moz-column-count:var(--RS__colCount);column-count:var(--RS__colCount);-webkit-column-gap:var(--RS__colGap);-moz-column-gap:var(--RS__colGap);column-gap:var(--RS__colGap);-moz-column-fill:auto;column-fill:auto;width:var(--RS__viewportWidth);height:100vh;max-width:var(--RS__viewportWidth);max-height:100vh;min-width:var(--RS__viewportWidth);min-height:100vh;padding:0!important;margin:0!important;font-size:100%!important;-webkit-text-size-adjust:100%;box-sizing:border-box;-webkit-perspective:1;-webkit-touch-callout:none}body{width:100%;max-width:var(--RS__maxLineLength)!important;padding:0 var(--RS__pageGutter)!important;margin:0 auto!important;box-sizing:border-box}@media screen and (min-width:35em){:root{--RS__pageGutter:30px}}@media screen and (min-width:45em){:root{--RS__pageGutter:40px}}@media screen and (min-width:75em){:root{--RS__pageGutter:50px}}@media screen and (min-width:60em),screen and (min-device-width:36em) and (max-device-width:47em) and (orientation:landscape){:root{--RS__colWidth:20em;--RS__colCount:2;--RS__maxLineLength:39.99rem}}:root[style*=readium-scroll-on]{-webkit-columns:auto auto!important;-moz-columns:auto auto!important;columns:auto auto!important;width:auto!important;height:auto!important;max-width:none!important;max-height:none!important;min-width:0!important;min-height:0!important}:root[style*=readium-scroll-on] body{--RS__maxLineLength:40rem!important}:root[style*=readium-night-on]{--RS__backgroundColor:#000000;--RS__textColor:#FEFEFE;--RS__linkColor:#63caff;--RS__visitedColor:#0099E5;--RS__selectionBackgroundColor:#b4d8fe;--RS__selectionTextColor:inherit}:root[style*=readium-night-on] :not(a){color:inherit!important;background-color:transparent!important;border-color:currentColor!important}:root[style*=readium-night-on] svg text{fill:currentColor!important;stroke:none!important}:root[style*=readium-night-on] a:link,:root[style*=readium-night-on] a:link *{color:var(--RS__linkColor)!important}:root[style*=readium-night-on] a:visited,:root[style*=readium-night-on] a:visited *{color:var(--RS__visitedColor)!important}:root[style*=readium-night-on] [epub\:type~=titlepage] img:only-child,:root[style*=readium-night-on] [epub|type~=titlepage] img:only-child,:root[style*=readium-night-on] img[class*=gaiji]{-webkit-filter:invert(100%);filter:invert(100%)}:root[style*=readium-night-on][style*=readium-darken-on] img{-webkit-filter:brightness(80%);filter:brightness(80%)}:root[style*=readium-night-on][style*=readium-invert-on] img{-webkit-filter:invert(100%);filter:invert(100%)}:root[style*=readium-night-on][style*=readium-darken-on][style*=readium-invert-on] img{-webkit-filter:brightness(80%) invert(100%);filter:brightness(80%) invert(100%)}:root[style*=readium-sepia-on]{--RS__backgroundColor:#faf4e8;--RS__textColor:#121212;--RS__linkColor:#0000EE;--RS__visitedColor:#551A8B;--RS__selectionBackgroundColor:#b4d8fe;--RS__selectionTextColor:inherit;--RS__maxLineLength:40.01rem}:root[style*=readium-sepia-on] :not(a){color:inherit!important;background-color:transparent!important}:root[style*=readium-sepia-on] a:link,:root[style*=readium-sepia-on] a:link *{color:var(--RS__linkColor)}:root[style*=readium-sepia-on] a:visited,:root[style*=readium-sepia-on] a:visited *{color:var(--RS__visitedColor)}:root[style*=readium-sepia-on] img,:root[style*=readium-sepia-on] svg{background-color:transparent!important;mix-blend-mode:multiply}@media screen and (-ms-high-contrast:active){:root{color:windowText!important;background-color:window!important}:root :not(#\#):not(#\#):not(#\#),:root :not(#\#):not(#\#):not(#\#) :not(#\#):not(#\#):not(#\#) :root :not(#\#):not(#\#):not(#\#) :not(#\#):not(#\#):not(#\#) :not(#\#):not(#\#):not(#\#){color:inherit!important;background-color:inherit!important}.readiumCSS-mo-active-default{color:highlightText!important;background-color:highlight!important}}@media screen and (-ms-high-contrast:white-on-black){:root[style*=readium-night-on] [epub\:type~=titlepage] img:only-child,:root[style*=readium-night-on] [epub|type~=titlepage] img:only-child,:root[style*=readium-night-on] img[class*=gaiji]{-webkit-filter:none!important;filter:none!important}:root[style*=readium-night-on][style*=readium-invert-on] img{-webkit-filter:none!important;filter:none!important}:root[style*=readium-night-on][style*=readium-darken-on][style*=readium-invert-on] img{-webkit-filter:brightness(80%);filter:brightness(80%)}}@media screen and (inverted-colors){:root[style*=readium-night-on] [epub\:type~=titlepage] img:only-child,:root[style*=readium-night-on] [epub|type~=titlepage] img:only-child,:root[style*=readium-night-on] img[class*=gaiji]{-webkit-filter:none!important;filter:none!important}:root[style*=readium-night-on][style*=readium-invert-on] img{-webkit-filter:none!important;filter:none!important}:root[style*=readium-night-on][style*=readium-darken-on][style*=readium-invert-on] img{-webkit-filter:brightness(80%);filter:brightness(80%)}}@media screen and (min-width:60em),screen and (min-device-width:36em) and (max-device-width:47em) and (orientation:landscape){:root[style*="--USER__colCount: 1"],:root[style*="--USER__colCount: 2"],:root[style*="--USER__colCount:1"],:root[style*="--USER__colCount:2"]{-webkit-column-count:var(--USER__colCount);-moz-column-count:var(--USER__colCount);column-count:var(--USER__colCount)}:root[style*="--USER__colCount: 1"],:root[style*="--USER__colCount:1"]{--RS__maxLineLength:40rem!important;--RS__colWidth:100vw}:root[style*="--USER__colCount: 2"],:root[style*="--USER__colCount:2"]{--RS__colWidth:auto}}:root[style*="--USER__pageMargins"] body{padding:0 calc(var(--RS__pageGutter) * var(--USER__pageMargins))!important}:root[style*="--USER__backgroundColor"]{background-color:var(--USER__backgroundColor)!important}:root[style*="--USER__backgroundColor"] *{background-color:transparent!important}:root[style*="--USER__textColor"]{color:var(--USER__textColor)!important}:root[style*="--USER__textColor"] :not(h1):not(h2):not(h3):not(h4):not(h5):not(h6):not(pre){color:inherit!important}:root[style*=readium-font-on][style*="--USER__fontFamily"]{font-family:var(--USER__fontFamily)!important}:root[style*=readium-font-on][style*="--USER__fontFamily"] body,:root[style*=readium-font-on][style*="--USER__fontFamily"] dd,:root[style*=readium-font-on][style*="--USER__fontFamily"] div,:root[style*=readium-font-on][style*="--USER__fontFamily"] dt,:root[style*=readium-font-on][style*="--USER__fontFamily"] li,:root[style*=readium-font-on][style*="--USER__fontFamily"] p{font-family:inherit!important}:root[style*=readium-font-on][style*="--USER__fontFamily"] b:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] b:not([xml\:lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] cite:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] cite:not([xml\:lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] em:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] em:not([xml\:lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] i:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] i:not([xml\:lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] span:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] span:not([xml\:lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] strong:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] strong:not([xml\:lang]){font-family:inherit!important}:root[style*="--USER__fontSize"]{font-size:var(--USER__fontSize)!important}:root[style*=readium-advanced-on][style*="--USER__lineHeight"]{line-height:var(--USER__lineHeight)!important}:root[style*=readium-advanced-on][style*="--USER__lineHeight"] body,:root[style*=readium-advanced-on][style*="--USER__lineHeight"] div,:root[style*=readium-advanced-on][style*="--USER__lineHeight"] li,:root[style*=readium-advanced-on][style*="--USER__lineHeight"] p{line-height:inherit}:root[style*=readium-advanced-on][style*="--USER__paraSpacing"] p{margin-top:var(--USER__paraSpacing)!important;margin-bottom:var(--USER__paraSpacing)!important}:root[style*=readium-advanced-on]{--USER__typeScale:1.2}:root[style*=readium-advanced-on] dd,:root[style*=readium-advanced-on] div,:root[style*=readium-advanced-on] li,:root[style*=readium-advanced-on] p,:root[style*=readium-advanced-on] pre{font-size:1rem!important}:root[style*=readium-advanced-on] h1{font-size:1.75rem!important;font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale))!important}:root[style*=readium-advanced-on] h2{font-size:1.5rem!important;font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale))!important}:root[style*=readium-advanced-on] h3{font-size:1.25rem!important;font-size:calc(1rem * var(--USER__typeScale))!important}:root[style*=readium-advanced-on] h4,:root[style*=readium-advanced-on] h5,:root[style*=readium-advanced-on] h6{font-size:1rem!important}:root[style*=readium-advanced-on] small{font-size:smaller!important}:root[style*=readium-advanced-on] sub,:root[style*=readium-advanced-on] sup{font-size:67.5%!important}:root[style*=readium-advanced-on][style*="--USER__typeScale"] h1{font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale))!important}:root[style*=readium-advanced-on][style*="--USER__typeScale"] h2{font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale))!important}:root[style*=readium-advanced-on][style*="--USER__typeScale"] h3{font-size:calc(1rem * var(--USER__typeScale))!important} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-horizontal/ReadiumCSS-before.css b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-horizontal/ReadiumCSS-before.css new file mode 100644 index 0000000000..faee9a5bca --- /dev/null +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-horizontal/ReadiumCSS-before.css @@ -0,0 +1,7 @@ +/* + * Readium CSS (v. 1.0.0-beta.3) + * Developers: Jiminy Panoz + * Copyright (c) 2017. Readium Foundation. All rights reserved. + * Use of this source code is governed by a BSD-style license which is detailed in the + * LICENSE file present in the project repository where this source code is maintained. +*/@namespace url("http://www.w3.org/1999/xhtml");@namespace epub url("http://www.idpf.org/2007/ops");@namespace m url("http://www.w3.org/1998/Math/MathML/");@namespace svg url("http://www.w3.org/2000/svg");@-ms-viewport{width:device-width}@viewport{width:device-width;zoom:1}:root{--RS__oldStyleTf:"Iowan Old Style","Sitka Text",Palatino,"Book Antiqua",serif;--RS__modernTf:Athelas,Constantia,Georgia,serif;--RS__sansTf:-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;--RS__humanistTf:Seravek,Calibri,Roboto,Arial,sans-serif;--RS__monospaceTf:"Andale Mono",Consolas,monospace;--RS__baseFontFamily:var(--RS__oldStyleTf);--RS__lineHeightCompensation:1;--RS__baseLineHeight:calc((1em + (2ex - 1ch) - ((1rem - 16px) * 0.1667)) * var(--RS__lineHeightCompensation))}html{font-family:var(--RS__baseFontFamily);line-height:1.6;line-height:var(--RS__baseLineHeight);text-rendering:optimizeLegibility}h1,h2,h3{line-height:normal}:lang(ja),:lang(ko),:lang(zh){word-wrap:break-word;-webkit-line-break:strict;-epub-line-break:strict;line-break:strict}math{font-family:"Latin Modern Math","STIX Two Math","XITS Math","STIX Math","Libertinus Math","TeX Gyre Termes Math","TeX Gyre Bonum Math","TeX Gyre Schola","DejaVu Math TeX Gyre","TeX Gyre Pagella Math","Asana Math","Cambria Math","Lucida Bright Math","Minion Math",STIXGeneral,STIXSizeOneSym,Symbol,"Times New Roman",serif}:lang(am){--RS__baseFontFamily:Kefa,Nyala,Roboto,Noto,"Noto Sans Ethiopic",serif;--RS__lineHeightCompensation:1.167}:lang(ar){--RS__baseFontFamily:"Geeza Pro","Arabic Typesetting",Roboto,Noto,"Noto Naskh Arabic","Times New Roman",serif}:lang(bn){--RS__baseFontFamily:"Kohinoor Bangla","Bangla Sangam MN",Vrinda,Roboto,Noto,"Noto Sans Bengali",sans-serif;--RS__lineHeightCompensation:1.067}:lang(bo){--RS__baseFontFamily:Kailasa,"Microsoft Himalaya",Roboto,Noto,"Noto Sans Tibetan",sans-serif}:lang(chr){--RS__baseFontFamily:"Plantagenet Cherokee",Roboto,Noto,"Noto Sans Cherokee";--RS__lineHeightCompensation:1.167}:lang(fa){--RS__baseFontFamily:"Geeza Pro","Arabic Typesetting",Roboto,Noto,"Noto Naskh Arabic","Times New Roman",serif}:lang(gu){--RS__baseFontFamily:"Gujarati Sangam MN","Nirmala UI",Shruti,Roboto,Noto,"Noto Sans Gujarati",sans-serif;--RS__lineHeightCompensation:1.167}:lang(he){--RS__baseFontFamily:"New Peninim MT","Arial Hebrew",Gisha,"Times New Roman",Roboto,Noto,"Noto Sans Hebrew" sans-serif;--RS__lineHeightCompensation:1.1}:lang(hi){--RS__baseFontFamily:"Kohinoor Devanagari","Devanagari Sangam MN",Kokila,"Nirmala UI",Roboto,Noto,"Noto Sans Devanagari",sans-serif;--RS__lineHeightCompensation:1.1}:lang(hy){--RS__baseFontFamily:Mshtakan,Sylfaen,Roboto,Noto,"Noto Serif Armenian",serif}:lang(iu){--RS__baseFontFamily:"Euphemia UCAS",Euphemia,Roboto,Noto,"Noto Sans Canadian Aboriginal",sans-serif}:lang(ja){--RS__baseFontFamily:"游ゴシック体",YuGothic,"ヒラギノ丸ゴ","Hiragino Sans","Yu Gothic UI","Meiryo UI","MS Gothic",Roboto,Noto,"Noto Sans CJK JP",sans-serif;--RS__lineHeightCompensation:1.167;--RS__serif-ja:"MS P明朝","MS PMincho","Hiragino Mincho Pro","ヒラギノ明朝 Pro W3","游明朝","YuMincho","MS 明朝","MS Mincho","Hiragino Mincho ProN",serif;--RS__sans-serif-ja:"MS Pゴシック","MS PGothic","Hiragino Kaku Gothic Pro W3","ヒラギノ角ゴ Pro W3","Hiragino Sans GB","ヒラギノ角ゴシック W3","游ゴシック","YuGothic","MS ゴシック","MS Gothic","Hiragino Sans",sans-serif;--RS__serif-ja-v:"MS 明朝","MS Mincho","Hiragino Mincho Pro","ヒラギノ明朝 Pro W3","游明朝","YuMincho","MS P明朝","MS PMincho","Hiragino Mincho ProN",serif;--RS__sans-serif-ja-v:"MS ゴシック","MS Gothic","Hiragino Kaku Gothic Pro W3","ヒラギノ角ゴ Pro W3","Hiragino Sans GB","ヒラギノ角ゴシック W3","游ゴシック","YuGothic","MS Pゴシック","MS PGothic","Hiragino Sans",sans-serif}:lang(km){--RS__baseFontFamily:"Khmer Sangam MN","Leelawadee UI","Khmer UI",Roboto,Noto,"Noto Sans Khmer",sans-serif;--RS__lineHeightCompensation:1.067}:lang(kn){--RS__baseFontFamily:"Kannada Sangam MN","Nirmala UI",Tunga,Roboto,Noto,"Noto Sans Kannada",sans-serif;--RS__lineHeightCompensation:1.1}:lang(ko){--RS__baseFontFamily:"Nanum Gothic","Apple SD Gothic Neo","Malgun Gothic",Roboto,Noto,"Noto Sans CJK KR",sans-serif;--RS__lineHeightCompensation:1.167}:lang(lo){--RS__baseFontFamily:"Lao Sangam MN","Leelawadee UI","Lao UI",Roboto,Noto,"Noto Sans Lao",sans-serif}:lang(ml){--RS__baseFontFamily:"Malayalam Sangam MN","Nirmala UI",Kartika,Roboto,Noto,"Noto Sans Malayalam",sans-serif;--RS__lineHeightCompensation:1.067}:lang(or){--RS__baseFontFamily:"Oriya Sangam MN","Nirmala UI",Kalinga,Roboto,Noto,"Noto Sans Oriya",sans-serif;--RS__lineHeightCompensation:1.167}:lang(pa){--RS__baseFontFamily:"Gurmukhi MN","Nirmala UI",Kartika,Roboto,Noto,"Noto Sans Gurmukhi",sans-serif;--RS__lineHeightCompensation:1.1}:lang(si){--RS__baseFontFamily:"Sinhala Sangam MN","Nirmala UI","Iskoola Pota",Roboto,Noto,"Noto Sans Sinhala",sans-serif;--RS__lineHeightCompensation:1.167}:lang(ta){--RS__baseFontFamily:"Tamil Sangam MN","Nirmala UI",Latha,Roboto,Noto,"Noto Sans Tamil",sans-serif;--RS__lineHeightCompensation:1.067}:lang(te){--RS__baseFontFamily:"Kohinoor Telugu","Telugu Sangam MN","Nirmala UI",Gautami,Roboto,Noto,"Noto Sans Telugu",sans-serif}:lang(th){--RS__baseFontFamily:"Thonburi","Leelawadee UI","Cordia New",Roboto,Noto,"Noto Sans Thai",sans-serif;--RS__lineHeightCompensation:1.067}:lang(zh){--RS__baseFontFamily:"方体","PingFang SC","黑体","Heiti SC","Microsoft JhengHei UI","Microsoft JhengHei",Roboto,Noto,"Noto Sans CJK SC",sans-serif;--RS__lineHeightCompensation:1.167}:lang(zh-Hant),:lang(zh-TW){--RS__baseFontFamily:"方體","PingFang TC","黑體","Heiti TC","Microsoft JhengHei UI","Microsoft JhengHei",Roboto,Noto,"Noto Sans CJK TC",sans-serif;--RS__lineHeightCompensation:1.167}:lang(zh-HK){--RS__baseFontFamily:"方體","PingFang HK","方體","PingFang TC","黑體","Heiti TC","Microsoft JhengHei UI","Microsoft JhengHei",Roboto,Noto,"Noto Sans CJK TC",sans-serif;--RS__lineHeightCompensation:1.167}:root{--RS__backgroundColor:#FFFFFF;--RS__textColor:#121212;--RS__selectionBackgroundColor:#b4d8fe;--RS__selectionTextColor:inherit}:root{color:var(--RS__textColor)!important;background-color:var(--RS__backgroundColor)!important}::-moz-selection{color:var(--RS__selectionTextColor);background-color:var(--RS__selectionBackgroundColor)}::selection{color:var(--RS__selectionTextColor);background-color:var(--RS__selectionBackgroundColor)}body{widows:2;orphans:2}figcaption,td,th{widows:1;orphans:1}caption,dt,h2,h3,h4,h5,h6,hr{-webkit-column-break-after:avoid;page-break-after:avoid;break-after:avoid}dt,figure,h1,h2,h3,h4,h5,h6,tr{-webkit-column-break-inside:avoid;page-break-inside:avoid;break-inside:avoid}body{-webkit-hyphenate-character:"\002D";-moz-hyphenate-character:"\002D";-ms-hyphenate-character:"\002D";hyphenate-character:"\002D";-webkit-hyphenate-limit-lines:3;-ms-hyphenate-limit-lines:3;hyphenate-limit-lines:3}address,caption,center,code,dt,figcaption,h1,h2,h3,h4,h5,h6,pre,var{-ms-hyphens:none;-moz-hyphens:none;-webkit-hyphens:none;-epub-hyphens:none;hyphens:none}body{font-variant-numeric:oldstyle-nums proportional-nums}:lang(ja) body,:lang(ko) body,:lang(zh) body{font-variant-numeric:lining-nums proportional-nums}dt,h1,h2,h3,h4,h5,h6{font-variant-numeric:lining-nums proportional-nums}table{font-variant-numeric:lining-nums tabular-nums}code,var{font-variant-ligatures:none;font-variant-numeric:lining-nums tabular-nums slashed-zero}rt{font-variant-east-asian:ruby}:lang(ar){font-variant-ligatures:common-ligatures}:lang(ko){font-kerning:normal}hr{color:inherit;border-color:currentColor}table,td,th{border-color:currentColor}blockquote,figure{margin:1em 5%}ol,ul{padding-left:5%}dd{margin-left:5%}pre{white-space:pre-wrap;-ms-tab-size:2;-moz-tab-size:2;-webkit-tab-size:2;tab-size:2}abbr[title],acronym[title]{text-decoration:dotted underline}nobr wbr{white-space:normal}ruby>rp,ruby>rt{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}:lang(ja),:lang(ja) cite,:lang(ja) dfn,:lang(ja) em,:lang(ja) i,:lang(ko),:lang(ko) cite,:lang(ko) dfn,:lang(ko) em,:lang(ko) i,:lang(zh),:lang(zh) cite,:lang(zh) dfn,:lang(zh) em,:lang(zh) i{font-style:normal}:lang(ja) a,:lang(ko) a,:lang(zh) a{text-decoration:none}:root{--RS__maxMediaWidth:100%;--RS__maxMediaHeight:95vh;--RS__boxSizingMedia:border-box;--RS__boxSizingTable:border-box}html{-webkit-line-box-contain:block glyphs replaced}:lang(ja){-webkit-line-box-contain:block inline replaced}a,h1,h2,h3,h4,h5,h6{word-wrap:break-word}div{max-width:var(--RS__maxMediaWidth)}audio,img,svg,video{object-fit:contain;width:auto;height:auto;max-width:var(--RS__maxMediaWidth);max-height:var(--RS__maxMediaHeight)!important;box-sizing:var(--RS__boxSizingMedia);-webkit-column-break-inside:avoid;page-break-inside:avoid;break-inside:avoid}table{max-width:var(--RS__maxMediaWidth);box-sizing:var(--RS__boxSizingTable)} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-horizontal/ReadiumCSS-default.css b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-horizontal/ReadiumCSS-default.css new file mode 100644 index 0000000000..e6984a4855 --- /dev/null +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-horizontal/ReadiumCSS-default.css @@ -0,0 +1,7 @@ +/* + * Readium CSS (v. 1.0.0-beta.3) + * Developers: Jiminy Panoz + * Copyright (c) 2017. Readium Foundation. All rights reserved. + * Use of this source code is governed by a BSD-style license which is detailed in the + * LICENSE file present in the project repository where this source code is maintained. +*/@namespace url("http://www.w3.org/1999/xhtml");@namespace epub url("http://www.idpf.org/2007/ops");@namespace m url("http://www.w3.org/1998/Math/MathML/");@namespace svg url("http://www.w3.org/2000/svg");:root{--RS__compFontFamily:var(--RS__baseFontFamily);--RS__codeFontFamily:var(--RS__monospaceTf);--RS__typeScale:1.125;--RS__baseFontSize:87.5%;--RS__flowSpacing:1.5rem;--RS__paraSpacing:0;--RS__paraIndent:1em;--RS__linkColor:#0000EE;--RS__visitedColor:#551A8B}:root:lang(zh){--RS__paraIndent:2em}:root{quotes:"\201c" "\201d" "\2018" "\2019"}body{font-size:var(--RS__baseFontSize);text-align:justify;text-justify:inter-character}h1,h2,h3,h4,h5,h6{font-family:var(--RS__baseFontFamily);text-align:left;text-align:start}aside,blockquote,figure,footer,form,hr,p,pre{margin-top:var(--RS__flowSpacing);margin-bottom:var(--RS__flowSpacing)}p{margin-top:var(--RS__paraSpacing);margin-bottom:var(--RS__paraSpacing);text-indent:var(--RS__paraIndent)}pre{font-family:var(--RS__codeFontFamily)}code,kbd,samp,tt{font-family:var(--RS__codeFontFamily)}sub,sup{position:relative;font-size:67.5%;line-height:1}sub{bottom:-.2ex}sup{bottom:0}em{-webkit-text-emphasis:dot;-epub-text-emphasis:dot;text-emphasis:dot}:link{color:var(--RS__linkColor)}:visited{color:var(--RS__visitedColor)}h1{margin-top:calc(var(--RS__flowSpacing) * 2);margin-bottom:calc(var(--RS__flowSpacing) * 2);font-size:calc(((1em * var(--RS__typeScale)) * var(--RS__typeScale)) * var(--RS__typeScale));text-align:center}h2{margin-top:calc(var(--RS__flowSpacing) * 2);margin-bottom:var(--RS__flowSpacing);font-size:calc((1em * var(--RS__typeScale)) * var(--RS__typeScale));text-align:center}h3{margin-top:var(--RS__flowSpacing);margin-bottom:var(--RS__flowSpacing);font-size:calc(1em * var(--RS__typeScale));text-align:center}h4{margin-top:var(--RS__flowSpacing);margin-bottom:var(--RS__flowSpacing);font-family:var(--RS__compFontFamily);font-size:1em}h5{margin-top:var(--RS__flowSpacing);margin-bottom:var(--RS__flowSpacing);font-family:var(--RS__compFontFamily);font-size:smaller}h6{margin-top:var(--RS__flowSpacing);margin-bottom:0;font-family:var(--RS__compFontFamily);font-size:smaller;font-weight:400}dl,ol,ul{margin-top:var(--RS__flowSpacing);margin-bottom:var(--RS__flowSpacing)}table{margin:var(--RS__flowSpacing) 0;border:1px solid currentColor;border-collapse:collapse;empty-cells:show}table>tr,tbody,tfoot,thead{vertical-align:top}th{text-align:left}td,th{padding:4px;border:1px solid currentColor} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-vertical/ReadiumCSS-after.css b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-vertical/ReadiumCSS-after.css new file mode 100644 index 0000000000..d68fd908be --- /dev/null +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-vertical/ReadiumCSS-after.css @@ -0,0 +1,7 @@ +/* + * Readium CSS (v. 1.0.0-beta.3) + * Developers: Jiminy Panoz + * Copyright (c) 2017. Readium Foundation. All rights reserved. + * Use of this source code is governed by a BSD-style license which is detailed in the + * LICENSE file present in the project repository where this source code is maintained. +*/@namespace url("http://www.w3.org/1999/xhtml");@namespace epub url("http://www.idpf.org/2007/ops");@namespace m url("http://www.w3.org/1998/Math/MathML/");@namespace svg url("http://www.w3.org/2000/svg");:root{--RS__colWidth:100vh;--RS__colCount:1;--RS__colGap:0;--RS__maxLineLength:40rem;--RS__pageGutter:20px}@page{margin:0!important}:root{position:relative;-webkit-column-width:var(--RS__colWidth);-moz-column-width:var(--RS__colWidth);column-width:var(--RS__colWidth);-webkit-column-count:var(--RS__colCount);-moz-column-count:var(--RS__colCount);column-count:var(--RS__colCount);-webkit-column-gap:var(--RS__colGap);-moz-column-gap:var(--RS__colGap);column-gap:var(--RS__colGap);-moz-column-fill:auto;column-fill:auto;width:100%;height:100vh;max-width:100%;max-height:100vh;min-width:100%;min-height:100vh;padding:0 var(--RS__pageGutter)!important;margin:0!important;font-size:100%!important;-webkit-text-size-adjust:100%;box-sizing:border-box;hanging-punctuation:last allow-end;-webkit-perspective:1;-webkit-touch-callout:none;-ms-writing-mode:tb-rl;-webkit-writing-mode:vertical-rl;writing-mode:vertical-rl}:root:lang(mn-Mong){-ms-writing-mode:tb;-webkit-writing-mode:vertical-lr;writing-mode:vertical-lr}body{width:100%;max-height:var(--RS__maxLineLength)!important;padding:var(--RS__pageGutter) 0!important;margin:auto 0!important;box-sizing:border-box}@media screen and (min-width:35em){:root{--RS__pageGutter:30px}}@media screen and (min-width:45em){:root{--RS__pageGutter:40px}}@media screen and (min-width:60em){:root{--RS__pageGutter:50px}}@media screen and (min-width:75em){:root{--RS__pageGutter:60px}}:root[style*=readium-scroll-on]{-webkit-columns:auto auto!important;-moz-columns:auto auto!important;columns:auto auto!important;width:auto!important;max-width:none!important;max-height:100vh!important;min-width:0!important}:root[style*=readium-scroll-on] body{--RS__maxLineLength:40.01rem!important}:root[style*=readium-night-on]{--RS__backgroundColor:#000000;--RS__textColor:#FEFEFE;--RS__linkColor:#63caff;--RS__visitedColor:#0099E5;--RS__selectionBackgroundColor:#b4d8fe;--RS__selectionTextColor:inherit}:root[style*=readium-night-on] :not(a){color:inherit!important;background-color:transparent!important;border-color:currentColor!important}:root[style*=readium-night-on] svg text{fill:currentColor!important;stroke:none!important}:root[style*=readium-night-on] a:link,:root[style*=readium-night-on] a:link *{color:var(--RS__linkColor)!important}:root[style*=readium-night-on] a:visited,:root[style*=readium-night-on] a:visited *{color:var(--RS__visitedColor)!important}:root[style*=readium-night-on] [epub\:type~=titlepage] img:only-child,:root[style*=readium-night-on] [epub|type~=titlepage] img:only-child,:root[style*=readium-night-on] img[class*=gaiji]{-webkit-filter:invert(100%);filter:invert(100%)}:root[style*=readium-night-on][style*=readium-darken-on] img{-webkit-filter:brightness(80%);filter:brightness(80%)}:root[style*=readium-night-on][style*=readium-invert-on] img{-webkit-filter:invert(100%);filter:invert(100%)}:root[style*=readium-night-on][style*=readium-darken-on][style*=readium-invert-on] img{-webkit-filter:brightness(80%) invert(100%);filter:brightness(80%) invert(100%)}:root[style*=readium-sepia-on]{--RS__backgroundColor:#faf4e8;--RS__textColor:#121212;--RS__linkColor:#0000EE;--RS__visitedColor:#551A8B;--RS__selectionBackgroundColor:#b4d8fe;--RS__selectionTextColor:inherit;--RS__maxLineLength:40.01rem}:root[style*=readium-sepia-on] :not(a){color:inherit!important;background-color:transparent!important}:root[style*=readium-sepia-on] a:link,:root[style*=readium-sepia-on] a:link *{color:var(--RS__linkColor)}:root[style*=readium-sepia-on] a:visited,:root[style*=readium-sepia-on] a:visited *{color:var(--RS__visitedColor)}:root[style*=readium-sepia-on] img,:root[style*=readium-sepia-on] svg{background-color:transparent!important;mix-blend-mode:multiply}@media screen and (-ms-high-contrast:active){:root{color:windowText!important;background-color:window!important}:root :not(#\#):not(#\#):not(#\#),:root :not(#\#):not(#\#):not(#\#) :not(#\#):not(#\#):not(#\#) :root :not(#\#):not(#\#):not(#\#) :not(#\#):not(#\#):not(#\#) :not(#\#):not(#\#):not(#\#){color:inherit!important;background-color:inherit!important}.readiumCSS-mo-active-default{color:highlightText!important;background-color:highlight!important}}@media screen and (-ms-high-contrast:white-on-black){:root[style*=readium-night-on] [epub\:type~=titlepage] img:only-child,:root[style*=readium-night-on] [epub|type~=titlepage] img:only-child,:root[style*=readium-night-on] img[class*=gaiji]{-webkit-filter:none!important;filter:none!important}:root[style*=readium-night-on][style*=readium-invert-on] img{-webkit-filter:none!important;filter:none!important}:root[style*=readium-night-on][style*=readium-darken-on][style*=readium-invert-on] img{-webkit-filter:brightness(80%);filter:brightness(80%)}}@media screen and (inverted-colors){:root[style*=readium-night-on] [epub\:type~=titlepage] img:only-child,:root[style*=readium-night-on] [epub|type~=titlepage] img:only-child,:root[style*=readium-night-on] img[class*=gaiji]{-webkit-filter:none!important;filter:none!important}:root[style*=readium-night-on][style*=readium-invert-on] img{-webkit-filter:none!important;filter:none!important}:root[style*=readium-night-on][style*=readium-darken-on][style*=readium-invert-on] img{-webkit-filter:brightness(80%);filter:brightness(80%)}}:root[style*="--USER__pageMargins"] body{padding:calc(var(--RS__pageGutter) * var(--USER__pageMargins)) 0!important}:root[style*="--USER__backgroundColor"]{background-color:var(--USER__backgroundColor)!important}:root[style*="--USER__backgroundColor"] *{background-color:transparent!important}:root[style*="--USER__textColor"]{color:var(--USER__textColor)!important}:root[style*="--USER__textColor"] :not(h1):not(h2):not(h3):not(h4):not(h5):not(h6):not(pre){color:inherit!important}:root[style*=readium-font-on][style*="--USER__fontFamily"]{font-family:var(--USER__fontFamily)!important}:root[style*=readium-font-on][style*="--USER__fontFamily"] body,:root[style*=readium-font-on][style*="--USER__fontFamily"] dd,:root[style*=readium-font-on][style*="--USER__fontFamily"] div,:root[style*=readium-font-on][style*="--USER__fontFamily"] dt,:root[style*=readium-font-on][style*="--USER__fontFamily"] li,:root[style*=readium-font-on][style*="--USER__fontFamily"] p{font-family:inherit!important}:root[style*=readium-font-on][style*="--USER__fontFamily"] b:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] b:not([xml\:lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] cite:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] cite:not([xml\:lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] em:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] em:not([xml\:lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] i:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] i:not([xml\:lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] span:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] span:not([xml\:lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] strong:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] strong:not([xml\:lang]){font-family:inherit!important}:root[style*="--USER__fontSize"]{font-size:var(--USER__fontSize)!important}:root[style*=readium-advanced-on][style*="--USER__lineHeight"]{line-height:var(--USER__lineHeight)!important}:root[style*=readium-advanced-on][style*="--USER__lineHeight"] body,:root[style*=readium-advanced-on][style*="--USER__lineHeight"] div,:root[style*=readium-advanced-on][style*="--USER__lineHeight"] li,:root[style*=readium-advanced-on][style*="--USER__lineHeight"] p{line-height:inherit}:root[style*=readium-advanced-on][style*="--USER__paraSpacing"] p{margin-right:var(--USER__paraSpacing)!important;margin-left:var(--USER__paraSpacing)!important}:root[style*=readium-advanced-on]{--USER__typeScale:1.2}:root[style*=readium-advanced-on] dd,:root[style*=readium-advanced-on] div,:root[style*=readium-advanced-on] li,:root[style*=readium-advanced-on] p,:root[style*=readium-advanced-on] pre{font-size:1rem!important}:root[style*=readium-advanced-on] h1{font-size:1.75rem!important;font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale))!important}:root[style*=readium-advanced-on] h2{font-size:1.5rem!important;font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale))!important}:root[style*=readium-advanced-on] h3{font-size:1.25rem!important;font-size:calc(1rem * var(--USER__typeScale))!important}:root[style*=readium-advanced-on] h4,:root[style*=readium-advanced-on] h5,:root[style*=readium-advanced-on] h6{font-size:1rem!important}:root[style*=readium-advanced-on] small{font-size:smaller!important}:root[style*=readium-advanced-on] sub,:root[style*=readium-advanced-on] sup{font-size:67.5%!important}:root[style*=readium-advanced-on][style*="--USER__typeScale"] h1{font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale))!important}:root[style*=readium-advanced-on][style*="--USER__typeScale"] h2{font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale))!important}:root[style*=readium-advanced-on][style*="--USER__typeScale"] h3{font-size:calc(1rem * var(--USER__typeScale))!important} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-vertical/ReadiumCSS-before.css b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-vertical/ReadiumCSS-before.css new file mode 100644 index 0000000000..a57efed01a --- /dev/null +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-vertical/ReadiumCSS-before.css @@ -0,0 +1,7 @@ +/* + * Readium CSS (v. 1.0.0-beta.3) + * Developers: Jiminy Panoz + * Copyright (c) 2017. Readium Foundation. All rights reserved. + * Use of this source code is governed by a BSD-style license which is detailed in the + * LICENSE file present in the project repository where this source code is maintained. +*/@namespace url("http://www.w3.org/1999/xhtml");@namespace epub url("http://www.idpf.org/2007/ops");@namespace m url("http://www.w3.org/1998/Math/MathML/");@namespace svg url("http://www.w3.org/2000/svg");@-ms-viewport{width:device-width}@viewport{width:device-width;zoom:1}:root{--RS__oldStyleTf:"Iowan Old Style","Sitka Text",Palatino,"Book Antiqua",serif;--RS__modernTf:Athelas,Constantia,Georgia,serif;--RS__sansTf:-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;--RS__humanistTf:Seravek,Calibri,Roboto,Arial,sans-serif;--RS__monospaceTf:"Andale Mono",Consolas,monospace;--RS__baseFontFamily:var(--RS__oldStyleTf);--RS__lineHeightCompensation:1;--RS__baseLineHeight:calc((1em + (2ex - 1ch) - ((1rem - 16px) * 0.1667)) * var(--RS__lineHeightCompensation))}html{font-family:var(--RS__baseFontFamily);line-height:1.6;line-height:var(--RS__baseLineHeight);text-rendering:optimizeLegibility}h1,h2,h3{line-height:normal}:lang(ja),:lang(ko),:lang(zh){word-wrap:break-word;-webkit-line-break:strict;-epub-line-break:strict;line-break:strict}math{font-family:"Latin Modern Math","STIX Two Math","XITS Math","STIX Math","Libertinus Math","TeX Gyre Termes Math","TeX Gyre Bonum Math","TeX Gyre Schola","DejaVu Math TeX Gyre","TeX Gyre Pagella Math","Asana Math","Cambria Math","Lucida Bright Math","Minion Math",STIXGeneral,STIXSizeOneSym,Symbol,"Times New Roman",serif}:lang(am){--RS__baseFontFamily:Kefa,Nyala,Roboto,Noto,"Noto Sans Ethiopic",serif;--RS__lineHeightCompensation:1.167}:lang(ar){--RS__baseFontFamily:"Geeza Pro","Arabic Typesetting",Roboto,Noto,"Noto Naskh Arabic","Times New Roman",serif}:lang(bn){--RS__baseFontFamily:"Kohinoor Bangla","Bangla Sangam MN",Vrinda,Roboto,Noto,"Noto Sans Bengali",sans-serif;--RS__lineHeightCompensation:1.067}:lang(bo){--RS__baseFontFamily:Kailasa,"Microsoft Himalaya",Roboto,Noto,"Noto Sans Tibetan",sans-serif}:lang(chr){--RS__baseFontFamily:"Plantagenet Cherokee",Roboto,Noto,"Noto Sans Cherokee";--RS__lineHeightCompensation:1.167}:lang(fa){--RS__baseFontFamily:"Geeza Pro","Arabic Typesetting",Roboto,Noto,"Noto Naskh Arabic","Times New Roman",serif}:lang(gu){--RS__baseFontFamily:"Gujarati Sangam MN","Nirmala UI",Shruti,Roboto,Noto,"Noto Sans Gujarati",sans-serif;--RS__lineHeightCompensation:1.167}:lang(he){--RS__baseFontFamily:"New Peninim MT","Arial Hebrew",Gisha,"Times New Roman",Roboto,Noto,"Noto Sans Hebrew" sans-serif;--RS__lineHeightCompensation:1.1}:lang(hi){--RS__baseFontFamily:"Kohinoor Devanagari","Devanagari Sangam MN",Kokila,"Nirmala UI",Roboto,Noto,"Noto Sans Devanagari",sans-serif;--RS__lineHeightCompensation:1.1}:lang(hy){--RS__baseFontFamily:Mshtakan,Sylfaen,Roboto,Noto,"Noto Serif Armenian",serif}:lang(iu){--RS__baseFontFamily:"Euphemia UCAS",Euphemia,Roboto,Noto,"Noto Sans Canadian Aboriginal",sans-serif}:lang(ja){--RS__baseFontFamily:"游ゴシック体",YuGothic,"ヒラギノ丸ゴ","Hiragino Sans","Yu Gothic UI","Meiryo UI","MS Gothic",Roboto,Noto,"Noto Sans CJK JP",sans-serif;--RS__lineHeightCompensation:1.167;--RS__serif-ja:"MS P明朝","MS PMincho","Hiragino Mincho Pro","ヒラギノ明朝 Pro W3","游明朝","YuMincho","MS 明朝","MS Mincho","Hiragino Mincho ProN",serif;--RS__sans-serif-ja:"MS Pゴシック","MS PGothic","Hiragino Kaku Gothic Pro W3","ヒラギノ角ゴ Pro W3","Hiragino Sans GB","ヒラギノ角ゴシック W3","游ゴシック","YuGothic","MS ゴシック","MS Gothic","Hiragino Sans",sans-serif;--RS__serif-ja-v:"MS 明朝","MS Mincho","Hiragino Mincho Pro","ヒラギノ明朝 Pro W3","游明朝","YuMincho","MS P明朝","MS PMincho","Hiragino Mincho ProN",serif;--RS__sans-serif-ja-v:"MS ゴシック","MS Gothic","Hiragino Kaku Gothic Pro W3","ヒラギノ角ゴ Pro W3","Hiragino Sans GB","ヒラギノ角ゴシック W3","游ゴシック","YuGothic","MS Pゴシック","MS PGothic","Hiragino Sans",sans-serif}:lang(km){--RS__baseFontFamily:"Khmer Sangam MN","Leelawadee UI","Khmer UI",Roboto,Noto,"Noto Sans Khmer",sans-serif;--RS__lineHeightCompensation:1.067}:lang(kn){--RS__baseFontFamily:"Kannada Sangam MN","Nirmala UI",Tunga,Roboto,Noto,"Noto Sans Kannada",sans-serif;--RS__lineHeightCompensation:1.1}:lang(ko){--RS__baseFontFamily:"Nanum Gothic","Apple SD Gothic Neo","Malgun Gothic",Roboto,Noto,"Noto Sans CJK KR",sans-serif;--RS__lineHeightCompensation:1.167}:lang(lo){--RS__baseFontFamily:"Lao Sangam MN","Leelawadee UI","Lao UI",Roboto,Noto,"Noto Sans Lao",sans-serif}:lang(ml){--RS__baseFontFamily:"Malayalam Sangam MN","Nirmala UI",Kartika,Roboto,Noto,"Noto Sans Malayalam",sans-serif;--RS__lineHeightCompensation:1.067}:lang(or){--RS__baseFontFamily:"Oriya Sangam MN","Nirmala UI",Kalinga,Roboto,Noto,"Noto Sans Oriya",sans-serif;--RS__lineHeightCompensation:1.167}:lang(pa){--RS__baseFontFamily:"Gurmukhi MN","Nirmala UI",Kartika,Roboto,Noto,"Noto Sans Gurmukhi",sans-serif;--RS__lineHeightCompensation:1.1}:lang(si){--RS__baseFontFamily:"Sinhala Sangam MN","Nirmala UI","Iskoola Pota",Roboto,Noto,"Noto Sans Sinhala",sans-serif;--RS__lineHeightCompensation:1.167}:lang(ta){--RS__baseFontFamily:"Tamil Sangam MN","Nirmala UI",Latha,Roboto,Noto,"Noto Sans Tamil",sans-serif;--RS__lineHeightCompensation:1.067}:lang(te){--RS__baseFontFamily:"Kohinoor Telugu","Telugu Sangam MN","Nirmala UI",Gautami,Roboto,Noto,"Noto Sans Telugu",sans-serif}:lang(th){--RS__baseFontFamily:"Thonburi","Leelawadee UI","Cordia New",Roboto,Noto,"Noto Sans Thai",sans-serif;--RS__lineHeightCompensation:1.067}:lang(zh){--RS__baseFontFamily:"方体","PingFang SC","黑体","Heiti SC","Microsoft JhengHei UI","Microsoft JhengHei",Roboto,Noto,"Noto Sans CJK SC",sans-serif;--RS__lineHeightCompensation:1.167}:lang(zh-Hant),:lang(zh-TW){--RS__baseFontFamily:"方體","PingFang TC","黑體","Heiti TC","Microsoft JhengHei UI","Microsoft JhengHei",Roboto,Noto,"Noto Sans CJK TC",sans-serif;--RS__lineHeightCompensation:1.167}:lang(zh-HK){--RS__baseFontFamily:"方體","PingFang HK","方體","PingFang TC","黑體","Heiti TC","Microsoft JhengHei UI","Microsoft JhengHei",Roboto,Noto,"Noto Sans CJK TC",sans-serif;--RS__lineHeightCompensation:1.167}:root{--RS__backgroundColor:#FFFFFF;--RS__textColor:#121212;--RS__selectionBackgroundColor:#b4d8fe;--RS__selectionTextColor:inherit}:root{color:var(--RS__textColor)!important;background-color:var(--RS__backgroundColor)!important}::-moz-selection{color:var(--RS__selectionTextColor);background-color:var(--RS__selectionBackgroundColor)}::selection{color:var(--RS__selectionTextColor);background-color:var(--RS__selectionBackgroundColor)}body{widows:2;orphans:2}figcaption,td,th{widows:1;orphans:1}caption,dt,h2,h3,h4,h5,h6,hr{-webkit-column-break-after:avoid;page-break-after:avoid;break-after:avoid}dt,figure,h1,h2,h3,h4,h5,h6,tr{-webkit-column-break-inside:avoid;page-break-inside:avoid;break-inside:avoid}body{-webkit-hyphenate-character:"\002D";-moz-hyphenate-character:"\002D";-ms-hyphenate-character:"\002D";hyphenate-character:"\002D";-webkit-hyphenate-limit-lines:3;-ms-hyphenate-limit-lines:3;hyphenate-limit-lines:3}address,caption,center,code,dt,figcaption,h1,h2,h3,h4,h5,h6,pre,var{-ms-hyphens:none;-moz-hyphens:none;-webkit-hyphens:none;-epub-hyphens:none;hyphens:none}body{font-variant-numeric:oldstyle-nums proportional-nums}:lang(ja) body,:lang(ko) body,:lang(zh) body{font-variant-numeric:lining-nums proportional-nums}dt,h1,h2,h3,h4,h5,h6{font-variant-numeric:lining-nums proportional-nums}table{font-variant-numeric:lining-nums tabular-nums}code,var{font-variant-ligatures:none;font-variant-numeric:lining-nums tabular-nums slashed-zero}rt{font-variant-east-asian:ruby}:lang(ar){font-variant-ligatures:common-ligatures}:lang(ko){font-kerning:normal}hr{color:inherit;border-color:currentColor}table,td,th{border-color:currentColor}blockquote,figure{margin:1em 5%}ol,ul{padding-left:5%}dd{margin-left:5%}pre{white-space:pre-wrap;-ms-tab-size:2;-moz-tab-size:2;-webkit-tab-size:2;tab-size:2}abbr[title],acronym[title]{text-decoration:dotted underline}nobr wbr{white-space:normal}ruby>rp,ruby>rt{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}:lang(ja),:lang(ja) cite,:lang(ja) dfn,:lang(ja) em,:lang(ja) i,:lang(ko),:lang(ko) cite,:lang(ko) dfn,:lang(ko) em,:lang(ko) i,:lang(zh),:lang(zh) cite,:lang(zh) dfn,:lang(zh) em,:lang(zh) i{font-style:normal}:lang(ja) a,:lang(ko) a,:lang(zh) a{text-decoration:none}:root{--RS__maxMediaWidth:100%;--RS__maxMediaHeight:100vw;--RS__boxSizingMedia:border-box;--RS__boxSizingTable:border-box}html{-webkit-line-box-contain:block glyphs replaced}:lang(ja){-webkit-line-box-contain:block inline replaced}a,h1,h2,h3,h4,h5,h6{word-wrap:break-word}div{max-width:var(--RS__maxMediaHeight)}audio,img,svg,video{object-fit:contain;width:auto;height:auto;max-width:var(--RS__maxMediaHeight);max-height:var(--RS__maxMediaWidth)!important;box-sizing:var(--RS__boxSizingMedia);-webkit-column-break-inside:avoid;page-break-inside:avoid;break-inside:avoid}table{max-height:var(--RS__maxMediaWidth);box-sizing:var(--RS__boxSizingTable)} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-vertical/ReadiumCSS-default.css b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-vertical/ReadiumCSS-default.css new file mode 100644 index 0000000000..0a12c3d1fe --- /dev/null +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-vertical/ReadiumCSS-default.css @@ -0,0 +1,7 @@ +/* + * Readium CSS (v. 1.0.0-beta.3) + * Developers: Jiminy Panoz + * Copyright (c) 2017. Readium Foundation. All rights reserved. + * Use of this source code is governed by a BSD-style license which is detailed in the + * LICENSE file present in the project repository where this source code is maintained. +*/@namespace url("http://www.w3.org/1999/xhtml");@namespace epub url("http://www.idpf.org/2007/ops");@namespace m url("http://www.w3.org/1998/Math/MathML/");@namespace svg url("http://www.w3.org/2000/svg");:root{--RS__compFontFamily:var(--RS__baseFontFamily);--RS__codeFontFamily:var(--RS__monospaceTf);--RS__typeScale:1.125;--RS__baseFontSize:87.5%;--RS__flowSpacing:1.5rem;--RS__paraSpacing:0;--RS__paraIndent:1em;--RS__linkColor:#0000EE;--RS__visitedColor:#551A8B}:root:lang(zh){--RS__paraIndent:2em}:lang("mn-Mong"){--RS__baseFontSize:100%}body{font-size:var(--RS__baseFontSize);text-align:justify;text-justify:inter-character}h1,h2,h3,h4,h5,h6{font-family:var(--RS__baseFontFamily);text-align:left;text-align:start}aside,blockquote,figure,footer,form,hr,p,pre{margin-right:var(--RS__flowSpacing);margin-left:var(--RS__flowSpacing)}p{margin-right:var(--RS__paraSpacing);margin-left:var(--RS__paraSpacing);text-indent:var(--RS__paraIndent)}pre{font-family:var(--RS__codeFontFamily)}code,kbd,samp,tt{font-family:var(--RS__codeFontFamily)}sub,sup{position:relative;font-size:67.5%;line-height:1}sub{left:-.2ex}sup{right:0}em{-webkit-text-emphasis:sesame;-epub-text-emphasis:sesame;text-emphasis:sesame}:link{color:var(--RS__linkColor)}:visited{color:var(--RS__visitedColor)}h1{margin-right:calc(var(--RS__flowSpacing) * 2);margin-left:calc(var(--RS__flowSpacing) * 2);font-size:calc(((1em * var(--RS__typeScale)) * var(--RS__typeScale)) * var(--RS__typeScale));text-indent:2rem}h2{margin-right:calc(var(--RS__flowSpacing) * 2);margin-left:var(--RS__flowSpacing);font-size:calc((1em * var(--RS__typeScale)) * var(--RS__typeScale));text-indent:3rem}h3{margin-right:var(--RS__flowSpacing);margin-left:var(--RS__flowSpacing);font-size:calc(1em * var(--RS__typeScale));text-indent:4rem}h4{margin-right:var(--RS__flowSpacing);margin-left:var(--RS__flowSpacing);font-family:var(--RS__compFontFamily);font-size:1em;text-indent:4rem}h5{margin-right:var(--RS__flowSpacing);margin-left:var(--RS__flowSpacing);font-family:var(--RS__compFontFamily);font-size:smaller;text-indent:4rem}h6{margin-right:var(--RS__flowSpacing);margin-left:0;font-family:var(--RS__compFontFamily);font-size:smaller;font-weight:400;text-indent:4rem}dl,ol,ul{margin-right:var(--RS__flowSpacing);margin-left:var(--RS__flowSpacing)}table{margin:0 var(--RS__flowSpacing);border:1px solid currentColor;border-collapse:collapse;empty-cells:show}table>tr,tbody,tfoot,thead{vertical-align:top}th{text-align:left}td,th{padding:4px;border:1px solid currentColor} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/fonts/AccessibleDfA.otf b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/fonts/AccessibleDfA.otf new file mode 100755 index 0000000000000000000000000000000000000000..69c02218a5ab163c634edcc34b14e8a735513f82 GIT binary patch literal 145384 zcmeFa2Y40L);GS-^hxi%ob+DK%$yXlkaC79AWgvnAqgZB5=fybSU^R z|DYmc{zIECVa!!b{K(pIHRHRjy_I&e@);Aq8&lIZo<*?~D(_0l3~8vZsmpu(>{!}= zm9~-w$_RD`Tu9eT#HTlmYo9##nimffPlaUMHLhmzc>S3HbjX!WUrKY$xcaC&GhbmW zFM%=X-0>}K?Wa6!GL=vFz}(E`oEp1$rS;gkBZANV$?ei8gRxzUE-!cJyCa)NozQ+i z?vBf?y|!s=~DSkB5r5j zHPiVPlNb};VNSa+`8{^E_=+o3dY64E-@%fklWd%JGaIIy$Hs}f**3{?rAsy&DsN*i zDc`UU#0BgkX)60d9Le61R2g07D!p*( zki7ELJK_pUZH3mGKR$mwU2jq}i-d&SnkLAvQ`J&C2CqHbx%L zHVbF7DPrKMC!~Yyd7*)AQ{Q3t$!@krj%DNJGPYihptjn>?w9J>7;4nfatK=??PMNh zHR~m9WTx~qE0PwlP&#kDxWYA+=q6<@ZL6s-GT9Gw&&z15p>4K2pSAOIqS!h)%H`I} zU4hc2>`uC`Rdmf;H0qpl4@yJXV&dN>`nt0TKe29dD%(QGZWInuUq-p!k%qd`=-MfC z?SpjP+Rkk*xVy`kBT@6njce;M*)YoM;qlp!R%9 zT}d>6ZIafp3#ILBp0pQKyox<3&Z7HR%|gUMY>2dvT~6)%wDd8JN7|@AnmhNeb=ryc zFQwy;oViKQuydr}=^CQ)cU0e48oN$AB(PaZJg8H5>0-8t)4NzRZwtB~PUF}%C70^_ zA#39GpUawf8^y94IgMnuJJh-Nzf#3RbM=y{*x8bso})SJH7e(Mr%dSx+aY{HW6z=Kr+#**G?3bs zs94HYOGi!(5DZs0ryuE>r=4q@PZuwbKlK=LNQY5>O6@HBuT;B*O;$gmzWA2P+{kX| zI^W?XgWBO0wqA;67t0Gc?Qxn%{wR4Zs}r}en;j}20VVztK5m@;bH>oWLA5%zg8F@^ zyo1J=)6X>4NY7Ntk*wce=tW8kyQAwq{}pxm_+K4&j*$-e^B?Wv z>ACoak4pOH%uK2Se@^6??6IzKeCF}4ePQpZ6J7iNC(_g7ymNea-6OThpPsd@{4Uzn z#$EcOE5D0&wRsmWPr-Qa;vITs+wk&Mk}h_1>LTWM=6Qd&FOeSlyL@>ws}eVoZkob| z((_gJcjx@C%%kU~n^T_fBpdqglq>aM3;vz+{#TqM?`3EIJLO1jc5T;rQrI8+;@f}U z#$D(BJ5)T#RyyYi5iCyliZ#)8pTkRiT|Be@LB5Z4C{=z(VldzK23Cr0oVG$#H z{lEU9c3{HDQ^%xWRz>x?k+#MEsuXD$yXvpU#VM>8mGh?PX3r@-r4HH}{(8>e@xmU~ zEY|)pR)zQ2gI(tdSFzs05T-D8^0dyxu@hvvQGdL}CK1M7Kz%ey8u;h_AiHyXS2_Q? zsj&3V?JlgQzMwp+8{Nh~|B#*PjH7>f&Og8UKS%zjT0maICj3vy`j4Fdw7`E_;QzfA zaD24?TWc+iWhpB8H7dg~dwU+4a&Gc9!xM@}()Pl3(*7 z%Xg?ekSUIT?d*4b&MZTUB0KL0>(_P6p;9YrRECm`(4TqE%>O@eziWP_>)vQSatF=P zoc2MT`Ia+z=R9YA6}mb2RoB|sU41Q-$|eR z>($B@wnN>)o>of!OleM&`+r^Zuh;!6-kE>-XUEAu7-rx|5KFYPb8i2PyMQYHn;KD`|I+b|C;~*Do^8`&!7Ew>;HH23;*4+{&U@b zTHrq|@PAJW(7cWxZHs7fVo?BN`(@`{g!4{qD$Uc(_+yjDGJj|8=JXcD7SMGY=sncw zcMeXgsJj?{V;PXo<~zKQ$y&%hYEg!>7KcCc(=~79psngo}S-PcF?

!C0KHonOXtp~cd3Rl*L5LL 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%0A_=a#T64x>QXKCd^D! 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 literal 0 HcmV?d00001 diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/fonts/LICENSE-AccessibleDfa b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/fonts/LICENSE-AccessibleDfa new file mode 100755 index 0000000000..bf56c05169 --- /dev/null +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/fonts/LICENSE-AccessibleDfa @@ -0,0 +1,95 @@ +Copyright (c) Orange 2015, www.orange.com +with Reserved Font Name Accessible-Dfa. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. + diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/fonts/LICENSE-IaWriterDuospace.md b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/fonts/LICENSE-IaWriterDuospace.md new file mode 100755 index 0000000000..3261f95cf6 --- /dev/null +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/fonts/LICENSE-IaWriterDuospace.md @@ -0,0 +1,110 @@ +# IBM Plex Typeface + +Copyright © 2017 IBM Corp. with Reserved Font Name "Plex" + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. + + +# IBM Type Code + +Copyright 2017 IBM +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/fonts/iAWriterDuospace-Regular.ttf b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/fonts/iAWriterDuospace-Regular.ttf new file mode 100755 index 0000000000000000000000000000000000000000..7e75aa351cf4ce6a8f31d1b8126491e0d12b4c74 GIT binary patch literal 81636 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

(*R-QJxnMdh<8^9 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,ruby>rt{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}:lang(ja),:lang(ja) cite,:lang(ja) dfn,:lang(ja) em,:lang(ja) i,:lang(ko),:lang(ko) cite,:lang(ko) dfn,:lang(ko) em,:lang(ko) i,:lang(zh),:lang(zh) cite,:lang(zh) dfn,:lang(zh) em,:lang(zh) i{font-style:normal}:lang(ja) a,:lang(ko) a,:lang(zh) a{text-decoration:none}:root{--RS__maxMediaWidth:100%;--RS__maxMediaHeight:95vh;--RS__boxSizingMedia:border-box;--RS__boxSizingTable:border-box}html{-webkit-line-box-contain:block glyphs replaced}:lang(ja){-webkit-line-box-contain:block inline replaced}a,h1,h2,h3,h4,h5,h6{word-wrap:break-word}div{max-width:var(--RS__maxMediaWidth)}audio,img,svg,video{object-fit:contain;width:auto;height:auto;max-width:var(--RS__maxMediaWidth);max-height:var(--RS__maxMediaHeight)!important;box-sizing:var(--RS__boxSizingMedia);-webkit-column-break-inside:avoid;page-break-inside:avoid;break-inside:avoid}table{max-width:var(--RS__maxMediaWidth);box-sizing:var(--RS__boxSizingTable)} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/rtl/ReadiumCSS-default.css b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/rtl/ReadiumCSS-default.css new file mode 100644 index 0000000000..44530f93cb --- /dev/null +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/rtl/ReadiumCSS-default.css @@ -0,0 +1,7 @@ +/* + * Readium CSS (v. 1.0.0-beta.3) + * Developers: Jiminy Panoz + * Copyright (c) 2017. Readium Foundation. All rights reserved. + * Use of this source code is governed by a BSD-style license which is detailed in the + * LICENSE file present in the project repository where this source code is maintained. +*/@namespace url("http://www.w3.org/1999/xhtml");@namespace epub url("http://www.idpf.org/2007/ops");@namespace m url("http://www.w3.org/1998/Math/MathML/");@namespace svg url("http://www.w3.org/2000/svg");:root{--RS__compFontFamily:var(--RS__baseFontFamily);--RS__codeFontFamily:var(--RS__monospaceTf);--RS__typeScale:1.125;--RS__baseFontSize:100%;--RS__flowSpacing:1.5rem;--RS__paraSpacing:0;--RS__paraIndent:1em;--RS__linkColor:#0000EE;--RS__visitedColor:#551A8B}body{font-size:var(--RS__baseFontSize);text-align:justify}h1,h2,h3,h4,h5,h6{font-family:var(--RS__compFontFamily);text-align:right}aside,blockquote,figure,footer,form,hr,p,pre{margin-top:var(--RS__flowSpacing);margin-bottom:var(--RS__flowSpacing)}p{margin-top:var(--RS__paraSpacing);margin-bottom:var(--RS__paraSpacing);text-indent:var(--RS__paraIndent)}h1+p,h2+p,h3+p,h4+p,h5+p,h6+p,hr+p{text-indent:0}pre{font-family:var(--RS__codeFontFamily)}code,kbd,samp,tt{font-family:var(--RS__codeFontFamily)}sub,sup{position:relative;font-size:67.5%;line-height:1}sub{bottom:-.2ex}sup{bottom:0}:link{color:var(--RS__linkColor)}:visited{color:var(--RS__visitedColor)}h1{margin-top:calc(var(--RS__flowSpacing) * 2);margin-bottom:calc(var(--RS__flowSpacing) * 2);font-size:calc(((1em * var(--RS__typeScale)) * var(--RS__typeScale)) * var(--RS__typeScale))}h2{margin-top:calc(var(--RS__flowSpacing) * 2);margin-bottom:var(--RS__flowSpacing);font-size:calc((1em * var(--RS__typeScale)) * var(--RS__typeScale))}h3{margin-top:var(--RS__flowSpacing);margin-bottom:var(--RS__flowSpacing);font-size:calc(1em * var(--RS__typeScale))}h4{margin-top:var(--RS__flowSpacing);margin-bottom:var(--RS__flowSpacing);font-size:1em}h5{margin-top:var(--RS__flowSpacing);margin-bottom:var(--RS__flowSpacing);font-size:smaller}h6{margin-top:var(--RS__flowSpacing);margin-bottom:0;font-size:smaller;font-weight:400}dl,ol,ul{margin-top:var(--RS__flowSpacing);margin-bottom:var(--RS__flowSpacing)}table{margin:var(--RS__flowSpacing) 0;border:1px solid currentColor;border-collapse:collapse;empty-cells:show}table>tr,tbody,tfoot,thead{vertical-align:top}th{text-align:initial}td,th{padding:4px;border:1px solid currentColor} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/reflowable-injectable-script.js b/readium/navigators/web/src/main/assets/readium/navigators/web/reflowable-injectable-script.js new file mode 100644 index 0000000000..fc276e0e28 --- /dev/null +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/reflowable-injectable-script.js @@ -0,0 +1,2 @@ +!function(){"use strict";const t=new class{constructor(t){this.nativeApi=t}onTap(t){this.nativeApi.onTap(JSON.stringify(t))}onLinkActivated(t,e){this.nativeApi.onLinkActivated(t,e)}}(window.gestures),e={onTap:e=>{const n={x:e.clientX*visualViewport.scale,y:e.clientY*visualViewport.scale};t.onTap(n)},onLinkActivated:(e,n)=>{t.onLinkActivated(e,n)}};new class{constructor(t,e){this.window=t,this.listener=e,document.addEventListener("click",(t=>{this.onClick(t)}),!1)}onClick(t){if(t.defaultPrevented)return;const e=this.window.getSelection();if(e&&"Range"==e.type)return;let n;n=t.target instanceof HTMLElement?this.nearestInteractiveElement(t.target):null,n?n instanceof HTMLAnchorElement&&this.listener.onLinkActivated(n.href,n.outerHTML):this.listener.onTap(t),t.stopPropagation(),t.preventDefault()}nearestInteractiveElement(t){return null==t?null:-1!=["a","audio","button","canvas","details","input","label","option","select","submit","textarea","video"].indexOf(t.nodeName.toLowerCase())||t.hasAttribute("contenteditable")&&"false"!=t.getAttribute("contenteditable").toLowerCase()?t:t.parentElement?this.nearestInteractiveElement(t.parentElement):null}}(window,e),Window.prototype.readiumcss=new class{constructor(t){this.document=t}setProperties(t){for(const[e,n]of t)this.setProperty(e,n)}setProperty(t,e){null===e||""===e?this.removeProperty(t):document.documentElement.style.setProperty(t,e,"important")}removeProperty(t){document.documentElement.style.removeProperty(t)}}(window.document),window.initialization.onScriptsLoaded(),window.addEventListener("load",(t=>{window.initialization.onDocumentLoaded()}))}(); +//# sourceMappingURL=reflowable-injectable-script.js.map \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/reflowable-injectable-script.js.map b/readium/navigators/web/src/main/assets/readium/navigators/web/reflowable-injectable-script.js.map new file mode 100644 index 0000000000..bef877ff64 --- /dev/null +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/reflowable-injectable-script.js.map @@ -0,0 +1 @@ +{"version":3,"file":"reflowable-injectable-script.js","mappings":"yBAWA,MAAMA,EAAiB,ICXhB,MACH,WAAAC,CAAYC,GACRC,KAAKC,UAAYF,CACrB,CACA,KAAAG,CAAMC,GACFH,KAAKC,UAAUC,MAAME,KAAKC,UAAUF,GACxC,CACA,eAAAG,CAAgBC,EAAMC,GAClBR,KAAKC,UAAUK,gBAAgBC,EAAMC,EACzC,GDE6CC,OAAOC,UAClDC,EAAmB,CACrBT,MAAQC,IACJ,MAAMS,EAAW,CACbC,EAAGV,EAAMW,QAAUC,eAAeC,MAClCC,EAAGd,EAAMe,QAAUH,eAAeC,OAEtCnB,EAAeK,MAAMU,EAAS,EAElCN,gBAAiB,CAACC,EAAMC,KACpBX,EAAeS,gBAAgBC,EAAMC,EAAU,GAGvD,IExBO,MACH,WAAAV,CAAYW,EAAQU,GAChBnB,KAAKS,OAASA,EACdT,KAAKmB,SAAWA,EAChBC,SAASC,iBAAiB,SAAUlB,IAChCH,KAAKsB,QAAQnB,EAAM,IACpB,EACP,CACA,OAAAmB,CAAQnB,GACJ,GAAIA,EAAMoB,iBACN,OAEJ,MAAMC,EAAYxB,KAAKS,OAAOgB,eAC9B,GAAID,GAA+B,SAAlBA,EAAUE,KAIvB,OAEJ,IAAIC,EAEAA,EADAxB,EAAMyB,kBAAkBC,YACP7B,KAAK8B,0BAA0B3B,EAAMyB,QAGrC,KAEjBD,EACIA,aAA0BI,mBAC1B/B,KAAKmB,SAASb,gBAAgBqB,EAAepB,KAAMoB,EAAeK,WAItEhC,KAAKmB,SAASjB,MAAMC,GAExBA,EAAM8B,kBACN9B,EAAM+B,gBACV,CAEA,yBAAAJ,CAA0BK,GACtB,OAAe,MAAXA,EACO,MAgBqD,GAdxC,CACpB,IACA,QACA,SACA,SACA,UACA,QACA,QACA,SACA,SACA,SACA,WACA,SAEgBC,QAAQD,EAAQE,SAASC,gBAIzCH,EAAQI,aAAa,oBACoC,SAAzDJ,EAAQK,aAAa,mBAAmBF,cAJjCH,EAQPA,EAAQM,cACDzC,KAAK8B,0BAA0BK,EAAQM,eAE3C,IACX,GF7CiBhC,OAAQE,GAC7B+B,OAAOC,UAAUC,WAAa,IGzBvB,MACH,WAAA9C,CAAYsB,GACRpB,KAAKoB,SAAWA,CACpB,CACA,aAAAyB,CAAcC,GACV,IAAK,MAAOC,EAAKC,KAAUF,EACvB9C,KAAKiD,YAAYF,EAAKC,EAE9B,CAEA,WAAAC,CAAYF,EAAKC,GACC,OAAVA,GAA4B,KAAVA,EAClBhD,KAAKkD,eAAeH,GAGP3B,SAAS+B,gBAGjBC,MAAMH,YAAYF,EAAKC,EAAO,YAE3C,CAEA,cAAAE,CAAeH,GACE3B,SAAS+B,gBACjBC,MAAMF,eAAeH,EAC9B,GHAwCtC,OAAOW,UACnDX,OAAO4C,eAAeC,kBAEtB7C,OAAOY,iBAAiB,QAASlB,IAC7BM,OAAO4C,eAAeE,kBAAkB,G","sources":["webpack://readium-js/./src/index-reflowable-injectable.ts","webpack://readium-js/./src/bridge/all-gestures-bridge.ts","webpack://readium-js/./src/common/gestures.ts","webpack://readium-js/./src/bridge/reflowable-css-bridge.ts"],"sourcesContent":["//\n// Copyright 2024 Readium Foundation. All rights reserved.\n// Use of this source code is governed by the BSD-style license\n// available in the top-level LICENSE file of the project.\n//\n/**\n * Script loaded by reflowable resources.\n */\nimport { BridgeGesturesAdapter, } from \"./bridge/all-gestures-bridge\";\nimport { CssBridge } from \"./bridge/reflowable-css-bridge\";\nimport { GesturesDetector } from \"./common/gestures\";\nconst bridgeListener = new BridgeGesturesAdapter(window.gestures);\nconst gesturesListener = {\n onTap: (event) => {\n const tapEvent = {\n x: event.clientX * visualViewport.scale,\n y: event.clientY * visualViewport.scale,\n };\n bridgeListener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n bridgeListener.onLinkActivated(href, outerHtml);\n },\n};\nnew GesturesDetector(window, gesturesListener);\nWindow.prototype.readiumcss = new CssBridge(window.document);\nwindow.initialization.onScriptsLoaded();\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nwindow.addEventListener(\"load\", (event) => {\n window.initialization.onDocumentLoaded();\n});\n","export class BridgeGesturesAdapter {\n constructor(gesturesApi) {\n this.nativeApi = gesturesApi;\n }\n onTap(event) {\n this.nativeApi.onTap(JSON.stringify(event));\n }\n onLinkActivated(href, outerHtml) {\n this.nativeApi.onLinkActivated(href, outerHtml);\n }\n}\n","export class GesturesDetector {\n constructor(window, listener) {\n this.window = window;\n this.listener = listener;\n document.addEventListener(\"click\", (event) => {\n this.onClick(event);\n }, false);\n }\n onClick(event) {\n if (event.defaultPrevented) {\n return;\n }\n const selection = this.window.getSelection();\n if (selection && selection.type == \"Range\") {\n // There's an on-going selection, the tap will dismiss it so we don't forward it.\n // selection.type might be None (collapsed) or Caret with a collapsed range\n // when there is not true selection.\n return;\n }\n let nearestElement;\n if (event.target instanceof HTMLElement) {\n nearestElement = this.nearestInteractiveElement(event.target);\n }\n else {\n nearestElement = null;\n }\n if (nearestElement) {\n if (nearestElement instanceof HTMLAnchorElement) {\n this.listener.onLinkActivated(nearestElement.href, nearestElement.outerHTML);\n }\n }\n else {\n this.listener.onTap(event);\n }\n event.stopPropagation();\n event.preventDefault();\n }\n // See. https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling\n nearestInteractiveElement(element) {\n if (element == null) {\n return null;\n }\n const interactiveTags = [\n \"a\",\n \"audio\",\n \"button\",\n \"canvas\",\n \"details\",\n \"input\",\n \"label\",\n \"option\",\n \"select\",\n \"submit\",\n \"textarea\",\n \"video\",\n ];\n if (interactiveTags.indexOf(element.nodeName.toLowerCase()) != -1) {\n return element;\n }\n // Checks whether the element is editable by the user.\n if (element.hasAttribute(\"contenteditable\") &&\n element.getAttribute(\"contenteditable\").toLowerCase() != \"false\") {\n return element;\n }\n // Checks parents recursively because the touch might be for example on an inside a .\n if (element.parentElement) {\n return this.nearestInteractiveElement(element.parentElement);\n }\n return null;\n }\n}\n","export class CssBridge {\n constructor(document) {\n this.document = document;\n }\n setProperties(properties) {\n for (const [key, value] of properties) {\n this.setProperty(key, value);\n }\n }\n // For setting user setting.\n setProperty(key, value) {\n if (value === null || value === \"\") {\n this.removeProperty(key);\n }\n else {\n const root = document.documentElement;\n // The `!important` annotation is added with `setProperty()` because if it's part of the\n // `value`, it will be ignored by the Web View.\n root.style.setProperty(key, value, \"important\");\n }\n }\n // For removing user setting.\n removeProperty(key) {\n const root = document.documentElement;\n root.style.removeProperty(key);\n }\n}\n"],"names":["bridgeListener","constructor","gesturesApi","this","nativeApi","onTap","event","JSON","stringify","onLinkActivated","href","outerHtml","window","gestures","gesturesListener","tapEvent","x","clientX","visualViewport","scale","y","clientY","listener","document","addEventListener","onClick","defaultPrevented","selection","getSelection","type","nearestElement","target","HTMLElement","nearestInteractiveElement","HTMLAnchorElement","outerHTML","stopPropagation","preventDefault","element","indexOf","nodeName","toLowerCase","hasAttribute","getAttribute","parentElement","Window","prototype","readiumcss","setProperties","properties","key","value","setProperty","removeProperty","documentElement","style","initialization","onScriptsLoaded","onDocumentLoaded"],"sourceRoot":""} \ No newline at end of file diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt index 01ceebfde8..dd7deb730c 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt @@ -6,6 +6,7 @@ package org.readium.navigator.web +import android.annotation.SuppressLint import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.displayCutout @@ -30,14 +31,14 @@ import org.readium.navigator.common.NullInputListener import org.readium.navigator.common.TapContext import org.readium.navigator.common.defaultHyperlinkListener import org.readium.navigator.common.defaultInputListener +import org.readium.navigator.web.fixed.DoubleSpreadState +import org.readium.navigator.web.fixed.DoubleViewportSpread +import org.readium.navigator.web.fixed.SingleSpreadState +import org.readium.navigator.web.fixed.SingleViewportSpread import org.readium.navigator.web.layout.DoubleViewportSpread import org.readium.navigator.web.layout.SingleViewportSpread import org.readium.navigator.web.location.FixedWebLocation import org.readium.navigator.web.pager.NavigatorPager -import org.readium.navigator.web.spread.DoubleSpreadState -import org.readium.navigator.web.spread.DoubleViewportSpread -import org.readium.navigator.web.spread.SingleSpreadState -import org.readium.navigator.web.spread.SingleViewportSpread import org.readium.navigator.web.util.AbsolutePaddingValues import org.readium.navigator.web.util.DisplayArea import org.readium.navigator.web.util.WebViewServer @@ -47,6 +48,7 @@ import org.readium.r2.shared.util.AbsoluteUrl import org.readium.r2.shared.util.RelativeUrl import org.readium.r2.shared.util.Url +@SuppressLint("UnusedBoxWithConstraintsScope") @ExperimentalReadiumApi @Composable public fun FixedWebRendition( @@ -115,7 +117,8 @@ public fun FixedWebRendition( } }, state = spreadState, - backgroundColor = backgroundColor + backgroundColor = backgroundColor, + reverseScrollDirection = !reverseLayout ) } is DoubleViewportSpread -> { @@ -138,7 +141,8 @@ public fun FixedWebRendition( } }, state = spreadState, - backgroundColor = backgroundColor + backgroundColor = backgroundColor, + reverseScrollDirection = !reverseLayout ) } } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionState.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionState.kt index 869ad41e66..9453fa8813 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionState.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionState.kt @@ -29,6 +29,8 @@ import org.readium.navigator.web.preferences.FixedWebSettings import org.readium.navigator.web.util.HyperlinkProcessor import org.readium.navigator.web.util.WebViewClient import org.readium.navigator.web.util.WebViewServer +import org.readium.navigator.web.util.WebViewServer.Companion.assetsBaseHref +import org.readium.navigator.web.util.injectHtml import org.readium.r2.navigator.SimpleOverflow import org.readium.r2.navigator.preferences.Axis import org.readium.r2.navigator.preferences.Fit @@ -68,15 +70,23 @@ public class FixedWebRenditionState internal constructor( internal val hyperlinkProcessor = HyperlinkProcessor(container) + private val htmlInjector: (Resource, MediaType) -> Resource = { resource, mediaType -> + resource.injectHtml( + charset = mediaType.charset, + injectableScript = RelativeUrl("readium/navigators/web/fixed-injectable-script.js")!!, + assetsBaseHref = assetsBaseHref, + disableSelection = isRestricted + ) + } + private val webViewServer = WebViewServer( application = application, container = container, mediaTypes = resourceMediaTypes, errorPage = RelativeUrl("readium/navigators/web/error.xhtml")!!, - injectableScript = RelativeUrl("readium/navigators/web/fixed-injectable-script.js")!!, + htmlInjector = htmlInjector, servedAssets = listOf("readium/.*"), - disableSelection = isRestricted, onResourceLoadFailed = { _, _ -> } ) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebNavigatorFactory.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebNavigatorFactory.kt new file mode 100644 index 0000000000..61d9d15f30 --- /dev/null +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebNavigatorFactory.kt @@ -0,0 +1,119 @@ +/* + * Copyright 2024 Readium Foundation. All rights reserved. + * Use of this source code is governed by the BSD-style license + * available in the top-level LICENSE file of the project. + */ + +package org.readium.navigator.web + +import android.app.Application +import org.readium.navigator.web.layout.ReadingOrder +import org.readium.navigator.web.layout.ReadingOrderItem +import org.readium.navigator.web.location.ReflowableWebGoLocation +import org.readium.navigator.web.location.ReflowableWebLocatorAdapter +import org.readium.navigator.web.preferences.ReflowableWebDefaults +import org.readium.navigator.web.preferences.ReflowableWebPreferences +import org.readium.navigator.web.preferences.ReflowableWebPreferencesEditor +import org.readium.navigator.web.preferences.ReflowableWebSettings +import org.readium.r2.shared.ExperimentalReadiumApi +import org.readium.r2.shared.InternalReadiumApi +import org.readium.r2.shared.publication.Link +import org.readium.r2.shared.publication.Publication +import org.readium.r2.shared.publication.epub.EpubLayout +import org.readium.r2.shared.publication.presentation.page +import org.readium.r2.shared.publication.presentation.presentation +import org.readium.r2.shared.publication.services.ContentProtectionService +import org.readium.r2.shared.util.Try + +@OptIn(InternalReadiumApi::class) +@ExperimentalReadiumApi +/** + * Creates components to render a reflowable publication. + * + * These components are meant to work together. DO not mix components from different + * factory instances. + */ +public class ReflowableWebNavigatorFactory private constructor( + private val application: Application, + private val publication: Publication, + private val defaults: ReflowableWebDefaults, +) { + + public companion object { + + public operator fun invoke( + application: Application, + publication: Publication, + ): ReflowableWebNavigatorFactory? { + if (!publication.conformsTo(Publication.Profile.EPUB) || + publication.metadata.presentation.layout != EpubLayout.REFLOWABLE + ) { + return null + } + + if (publication.readingOrder.isEmpty()) { + return null + } + + return ReflowableWebNavigatorFactory( + application, + publication, + ReflowableWebDefaults() + ) + } + } + + public sealed class Error( + override val message: String, + override val cause: org.readium.r2.shared.util.Error?, + ) : org.readium.r2.shared.util.Error { + + public class Initialization( + cause: org.readium.r2.shared.util.Error, + ) : Error("Could not initialize the navigator.", cause) + } + + public suspend fun createRenditionState( + initialSettings: ReflowableWebSettings, + initialLocation: ReflowableWebGoLocation? = null, + readingOrder: List = publication.readingOrder, + ): Try { + val readingOrderItems = readingOrder.map { + ReadingOrderItem( + href = it.url(), + page = it.properties.page + ) + } + + val resourceMediaTypes = (publication.readingOrder + publication.resources) + .mapNotNull { link -> link.mediaType?.let { link.url() to it } } + .associate { it } + + val state = + ReflowableWebRenditionState( + application = application, + readingOrder = ReadingOrder(readingOrderItems), + resourceMediaTypes = resourceMediaTypes, + isRestricted = publication.findService(ContentProtectionService::class)?.isRestricted == true, + initialSettings = initialSettings, + initialLocation = initialLocation ?: ReflowableWebGoLocation( + readingOrderItems[0].href + ), + container = publication.container + ) + + return Try.success(state) + } + + public fun createPreferencesEditor( + initialPreferences: ReflowableWebPreferences, + ): ReflowableWebPreferencesEditor = + ReflowableWebPreferencesEditor( + initialPreferences, + publication.metadata, + defaults + ) + + public fun createLocatorAdapter(): ReflowableWebLocatorAdapter = + ReflowableWebLocatorAdapter(publication) +} diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt new file mode 100644 index 0000000000..313229d4c5 --- /dev/null +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt @@ -0,0 +1,142 @@ +/* + * Copyright 2024 Readium Foundation. All rights reserved. + * Use of this source code is governed by the BSD-style license + * available in the top-level LICENSE file of the project. + */ + +package org.readium.navigator.web + +import android.annotation.SuppressLint +import androidx.compose.foundation.layout.BoxWithConstraints +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.displayCutout +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.rememberUpdatedState +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.unit.DpSize +import androidx.compose.ui.unit.LayoutDirection +import kotlinx.coroutines.launch +import org.readium.navigator.common.HyperlinkListener +import org.readium.navigator.common.HyperlinkLocation +import org.readium.navigator.common.InputListener +import org.readium.navigator.common.NullHyperlinkListener +import org.readium.navigator.common.NullInputListener +import org.readium.navigator.common.TapContext +import org.readium.navigator.common.defaultHyperlinkListener +import org.readium.navigator.common.defaultInputListener +import org.readium.navigator.web.location.ReflowableWebLocation +import org.readium.navigator.web.pager.NavigatorPager +import org.readium.navigator.web.reflowable.ReflowableResource +import org.readium.navigator.web.util.AbsolutePaddingValues +import org.readium.navigator.web.util.DisplayArea +import org.readium.navigator.web.util.WebViewServer +import org.readium.r2.navigator.preferences.ReadingProgression +import org.readium.r2.shared.ExperimentalReadiumApi +import org.readium.r2.shared.util.AbsoluteUrl +import org.readium.r2.shared.util.RelativeUrl +import org.readium.r2.shared.util.Url + +@SuppressLint("UnusedBoxWithConstraintsScope") +@ExperimentalReadiumApi +@Composable +public fun ReflowableWebRendition( + state: ReflowableWebRenditionState, + modifier: Modifier = Modifier, + windowInsets: WindowInsets = WindowInsets.displayCutout, + backgroundColor: Color = MaterialTheme.colorScheme.background, + inputListener: InputListener = state.controller + ?.let { defaultInputListener(controller = it) } + ?: NullInputListener(), + hyperlinkListener: HyperlinkListener = + state.controller + ?.let { defaultHyperlinkListener(controller = it) } + ?: NullHyperlinkListener(), +) { + BoxWithConstraints( + modifier = Modifier.fillMaxSize(), + propagateMinConstraints = true + ) { + val viewportSize = DpSize(maxWidth, maxHeight) + + val safeDrawingPadding = windowInsets.asAbsolutePaddingValues() + val displayArea = rememberUpdatedState(DisplayArea(viewportSize, safeDrawingPadding)) + + val readingProgression = + state.layoutDelegate.settings.value.readingProgression + + val reverseLayout = + LocalLayoutDirection.current.toReadingProgression() != readingProgression + + val itemIndex = state.pagerState.currentPage + val itemHref = state.readingOrder.items[itemIndex].href + state.updateLocation(ReflowableWebLocation(itemHref)) + + val coroutineScope = rememberCoroutineScope() + + NavigatorPager( + modifier = modifier, + state = state.pagerState, + beyondViewportPageCount = 2, + reverseLayout = reverseLayout + ) { index -> + ReflowableResource( + href = state.readingOrder.items[index].href, + publicationBaseUrl = WebViewServer.publicationBaseHref, + webViewClient = state.webViewClient, + displayArea = displayArea.value, + reverseLayout = reverseLayout, + rsProperties = state.readiumCss.value.rsProperties, + userProperties = state.readiumCss.value.userProperties, + onTap = { inputListener.onTap(it, TapContext(viewportSize)) }, + onLinkActivated = { url, outerHtml -> + coroutineScope.launch { + onLinkActivated(url, outerHtml, state, hyperlinkListener) + } + }, + backgroundColor = backgroundColor + ) + } + } +} + +@Composable +private fun WindowInsets.asAbsolutePaddingValues(): AbsolutePaddingValues { + val density = LocalDensity.current + val layoutDirection = LocalLayoutDirection.current + val top = with(density) { getTop(density).toDp() } + val right = with(density) { getRight(density, layoutDirection).toDp() } + val bottom = with(density) { getBottom(density).toDp() } + val left = with(density) { getLeft(density, layoutDirection).toDp() } + return AbsolutePaddingValues(top = top, right = right, bottom = bottom, left = left) +} + +private fun LayoutDirection.toReadingProgression(): ReadingProgression = + when (this) { + LayoutDirection.Ltr -> ReadingProgression.LTR + LayoutDirection.Rtl -> ReadingProgression.RTL + } + +@OptIn(ExperimentalReadiumApi::class) +private suspend fun onLinkActivated( + url: Url, + outerHtml: String, + state: ReflowableWebRenditionState, + listener: HyperlinkListener, +) { + val location = HyperlinkLocation(url.removeFragment()) + val isReadingOrder = state.readingOrder.indexOfHref(url.removeFragment()) != null + val context = state.computeHyperlinkContext(url, outerHtml) + when { + isReadingOrder -> listener.onReadingOrderLinkActivated(location, context) + else -> when (url) { + is RelativeUrl -> listener.onNonLinearLinkActivated(location, context) + is AbsoluteUrl -> listener.onExternalLinkActivated(url, context) + } + } +} diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt new file mode 100644 index 0000000000..f5aeea07bf --- /dev/null +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt @@ -0,0 +1,212 @@ +/* + * Copyright 2024 Readium Foundation. All rights reserved. + * Use of this source code is governed by the BSD-style license + * available in the top-level LICENSE file of the project. + */ + +package org.readium.navigator.web + +import android.app.Application +import androidx.compose.foundation.pager.PagerState +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.Stable +import androidx.compose.runtime.State +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.mutableStateOf +import org.readium.navigator.common.HyperlinkLocation +import org.readium.navigator.common.LinkContext +import org.readium.navigator.common.NavigationController +import org.readium.navigator.common.Overflow +import org.readium.navigator.common.OverflowController +import org.readium.navigator.common.RenditionState +import org.readium.navigator.common.SettingsController +import org.readium.navigator.web.css.ReadiumCss +import org.readium.navigator.web.layout.ReadingOrder +import org.readium.navigator.web.location.ReflowableWebGoLocation +import org.readium.navigator.web.location.ReflowableWebLocation +import org.readium.navigator.web.preferences.ReflowableWebSettings +import org.readium.navigator.web.util.HyperlinkProcessor +import org.readium.navigator.web.util.WebViewClient +import org.readium.navigator.web.util.WebViewServer +import org.readium.navigator.web.util.WebViewServer.Companion.assetsBaseHref +import org.readium.navigator.web.util.injectHtmlReflowable +import org.readium.r2.navigator.SimpleOverflow +import org.readium.r2.navigator.preferences.Axis +import org.readium.r2.shared.ExperimentalReadiumApi +import org.readium.r2.shared.InternalReadiumApi +import org.readium.r2.shared.util.RelativeUrl +import org.readium.r2.shared.util.Url +import org.readium.r2.shared.util.data.Container +import org.readium.r2.shared.util.mediatype.MediaType +import org.readium.r2.shared.util.resource.Resource + +@ExperimentalReadiumApi +@Stable +public class ReflowableWebRenditionState internal constructor( + application: Application, + internal val readingOrder: ReadingOrder, + container: Container, + resourceMediaTypes: Map, + isRestricted: Boolean, + initialSettings: ReflowableWebSettings, + initialLocation: ReflowableWebGoLocation, +) : RenditionState { + + private val navigatorState: MutableState = + mutableStateOf(null) + + override val controller: ReflowableWebRenditionController? get() = + navigatorState.value + + internal val layoutDelegate: ReflowableLayoutDelegate = + ReflowableLayoutDelegate( + initialSettings + ) + + internal val hyperlinkProcessor = + HyperlinkProcessor(container) + + internal val readiumCss: MutableState = + mutableStateOf( + ReadiumCss( + assetsBaseHref = assetsBaseHref, + readiumCssAssets = RelativeUrl("readium/navigators/web/readium-css/")!! + ) + ) + + private val htmlInjector: (Resource, MediaType) -> Resource = { resource, mediaType -> + resource.injectHtmlReflowable( + charset = mediaType.charset, + readiumCss = readiumCss.value, + injectableScript = RelativeUrl("readium/navigators/web/reflowable-injectable-script.js")!!, + assetsBaseHref = assetsBaseHref, + disableSelection = isRestricted + ) + } + + private val webViewServer = + WebViewServer( + application = application, + container = container, + mediaTypes = resourceMediaTypes, + errorPage = RelativeUrl("readium/navigators/web/error.xhtml")!!, + htmlInjector = htmlInjector, + servedAssets = listOf("readium/.*"), + onResourceLoadFailed = { _, _ -> } + ) + + internal val webViewClient: WebViewClient = + WebViewClient(webViewServer) + + internal val pagerState: PagerState = + PagerState( + currentPage = readingOrder.indexOfHref(initialLocation.href) ?: 0, + pageCount = { readingOrder.items.size } + ) + + internal suspend fun computeHyperlinkContext(originUrl: Url, outerHtml: String): LinkContext? = + hyperlinkProcessor.computeLinkContext(originUrl, outerHtml) + + private lateinit var navigationDelegate: ReflowableNavigationDelegate + + internal fun updateLocation(location: ReflowableWebLocation) { + initControllerIfNeeded(location) + navigationDelegate.updateLocation(location) + } + + private fun initControllerIfNeeded(location: ReflowableWebLocation) { + if (controller != null) { + return + } + + navigationDelegate = + ReflowableNavigationDelegate( + readingOrder, + pagerState, + layoutDelegate.settings, + location + ) + navigatorState.value = + ReflowableWebRenditionController( + navigationDelegate, + layoutDelegate + ) + } +} + +@ExperimentalReadiumApi +@Stable +public class ReflowableWebRenditionController internal constructor( + private val navigationDelegate: ReflowableNavigationDelegate, + layoutDelegate: ReflowableLayoutDelegate, +) : NavigationController by navigationDelegate, + OverflowController by navigationDelegate, + SettingsController by layoutDelegate + +@OptIn(ExperimentalReadiumApi::class) +internal class ReflowableLayoutDelegate( + initialSettings: ReflowableWebSettings, +) : SettingsController { + + override val settings: MutableState = + mutableStateOf(initialSettings) +} + +@OptIn(ExperimentalReadiumApi::class, InternalReadiumApi::class) +internal class ReflowableNavigationDelegate( + private val readingOrder: ReadingOrder, + private val pagerState: PagerState, + private val settings: State, + initialLocation: ReflowableWebLocation, +) : NavigationController, OverflowController { + + private val locationMutable: MutableState = + mutableStateOf(initialLocation) + + internal fun updateLocation(location: ReflowableWebLocation) { + locationMutable.value = location + } + + override val location: State = + locationMutable + + override suspend fun goTo(location: HyperlinkLocation) { + goTo(ReflowableWebGoLocation(location.href)) + } + + override suspend fun goTo(location: ReflowableWebGoLocation) { + val resourceIndex = readingOrder.indexOfHref(location.href) ?: return + pagerState.scrollToPage(resourceIndex) + } + + override suspend fun goTo(location: ReflowableWebLocation) { + goTo(ReflowableWebGoLocation(location.href)) + } + + override val overflow: State = + derivedStateOf { + SimpleOverflow( + settings.value.readingProgression, + false, + Axis.HORIZONTAL + ) + } + + override val canMoveForward: Boolean + get() = pagerState.currentPage < readingOrder.items.size - 1 + + override val canMoveBackward: Boolean + get() = pagerState.currentPage > 0 + + override suspend fun moveForward() { + if (canMoveForward) { + pagerState.scrollToPage(pagerState.currentPage + 1) + } + } + + override suspend fun moveBackward() { + if (canMoveBackward) { + pagerState.scrollToPage(pagerState.currentPage - 1) + } + } +} diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/FontFamilyDeclaration.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/FontFamilyDeclaration.kt new file mode 100644 index 0000000000..2bcb702818 --- /dev/null +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/FontFamilyDeclaration.kt @@ -0,0 +1,207 @@ +/* + * Copyright 2022 Readium Foundation. All rights reserved. + * Use of this source code is governed by the BSD-style license + * available in the top-level LICENSE file of the project. + */ + +package org.readium.navigator.web.css + +import org.readium.r2.shared.ExperimentalReadiumApi +import org.readium.r2.shared.util.Either +import org.readium.r2.shared.util.Url + +/** + * Build a declaration for [fontFamily] using [builderAction]. + * + * @param alternates Specifies a list of alternative font families used as fallbacks when symbols + * are missing from [fontFamily]. + */ +@ExperimentalReadiumApi +internal fun buildFontFamilyDeclaration( + fontFamily: String, + alternates: List, + builderAction: (MutableFontFamilyDeclaration).() -> Unit, +) = + MutableFontFamilyDeclaration(fontFamily, alternates).apply(builderAction).toFontFamilyDeclaration() + +/** + * A font family declaration. + * + * @param alternates Specifies a list of alternative font families used as fallbacks when symbols + * are missing from [fontFamily]. + */ +@ExperimentalReadiumApi +internal data class FontFamilyDeclaration( + val fontFamily: String, + val alternates: List, + val fontFaces: List, +) + +/** + * An immutable font face declaration. + */ +@ExperimentalReadiumApi +internal data class FontFaceDeclaration( + val fontFamily: String, + val sources: List, + var fontStyle: FontStyle? = null, + var fontWeight: Either>? = null, +) { + + fun links(urlNormalizer: (Url) -> Url): List = + sources + .filter { it.preload } + .map { + """""" + } + + fun toCss(urlNormalizer: (Url) -> Url): String { + val descriptors = buildMap { + set("font-family", """"$fontFamily"""") + + val urls = sources.map { urlNormalizer(it.href) } + val src = urls.joinToString(", ") { """url("$it")""" } + set("src", src) + + fontStyle?.let { set("font-style", it.name.lowercase()) } + + fontWeight?.let { + when (it) { + is Either.Left -> + set("font-weight", it.value.value) + is Either.Right -> + set("font-weight", "${it.value.start} ${it.value.endInclusive}") + } + } + } + + val descriptorList = descriptors + .map { entry -> "${entry.key}: ${entry.value};" } + .joinToString(" ") + + return "@font-face { $descriptorList }" + } +} + +/** + * Represents an individual font file. + * + * @param preload Indicates whether this source will be declared for preloading in the HTML using + * ``. + */ +internal data class FontFaceSource( + val href: Url, + val preload: Boolean = false, +) + +/** + * A mutable font family declaration. + */ +@ExperimentalReadiumApi +@ConsistentCopyVisibility +public data class MutableFontFamilyDeclaration internal constructor( + private val fontFamily: String, + private val alternates: List, + private val fontFaces: MutableList = mutableListOf(), +) { + + public fun addFontFace(builderAction: MutableFontFaceDeclaration.() -> Unit) { + val fontFace = MutableFontFaceDeclaration(fontFamily).apply(builderAction) + fontFaces.add(fontFace.toFontFaceDeclaration()) + } + + internal fun toFontFamilyDeclaration(): FontFamilyDeclaration { + check(fontFaces.isNotEmpty()) + return FontFamilyDeclaration(fontFamily, alternates, fontFaces) + } +} + +/** + * A mutable font face declaration. + */ +@ExperimentalReadiumApi +@ConsistentCopyVisibility +public data class MutableFontFaceDeclaration internal constructor( + private val fontFamily: String, + private val sources: MutableList = mutableListOf(), + private var fontStyle: FontStyle? = null, + private var fontWeight: Either>? = null, +) { + + /** + * Add a source for the font face. + * + * @param path Path to the font file. + * @param preload Indicates whether this source will be declared for preloading in the HTML + * using ``. + */ + public fun addSource(path: String, preload: Boolean = false) { + val url = requireNotNull(Url.fromDecodedPath(path)) { + "Invalid font path: $path" + } + addSource(url, preload = preload) + } + + /** + * Add a source for the font face. + * + * @param preload Indicates whether this source will be declared for preloading in the HTML + * using ``. + */ + public fun addSource(href: Url, preload: Boolean = false) { + this.sources.add(FontFaceSource(href = href, preload = preload)) + } + + /** + * Set the font style of the font face. + */ + public fun setFontStyle(fontStyle: FontStyle) { + this.fontStyle = fontStyle + } + + /** + * Set the font weight of the font face. + */ + public fun setFontWeight(fontWeight: FontWeight) { + this.fontWeight = Either(fontWeight) + } + + /** + * Set the font weight range of a variable font face. + */ + public fun setFontWeight(range: ClosedRange) { + require(range.start >= 1) + require(range.endInclusive <= 1000) + this.fontWeight = Either(range) + } + + internal fun toFontFaceDeclaration() = + FontFaceDeclaration(fontFamily, sources, fontStyle, fontWeight) +} + +/** + * Styles that a font can be styled with. + */ +@ExperimentalReadiumApi +public enum class FontStyle { + NORMAL, + ITALIC, +} + +/** + * Weight (or boldness) of a font. + * + * See https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-weight#common_weight_name_mapping + */ +@ExperimentalReadiumApi +public enum class FontWeight(public val value: Int) { + THIN(100), + EXTRA_LIGHT(200), + LIGHT(300), + NORMAL(400), + MEDIUM(500), + SEMI_BOLD(600), + BOLD(700), + EXTRA_BOLD(800), + BLACK(900), +} diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/Layout.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/Layout.kt new file mode 100644 index 0000000000..9aa9044f5e --- /dev/null +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/Layout.kt @@ -0,0 +1,70 @@ +/* + * Copyright 2022 Readium Foundation. All rights reserved. + * Use of this source code is governed by the BSD-style license + * available in the top-level LICENSE file of the project. + */ + +package org.readium.navigator.web.css + +import org.readium.navigator.web.util.isCjk +import org.readium.r2.navigator.epub.EpubSettings +import org.readium.r2.navigator.preferences.ReadingProgression +import org.readium.r2.shared.util.Language +import org.readium.r2.shared.util.RelativeUrl + +/** + * Readium CSS layout variant to use. + * + * See https://github.com/readium/readium-css/tree/master/css/dist + */ +internal data class Layout( + val language: Language? = null, + val stylesheets: Stylesheets = Stylesheets.Default, + val readingProgression: ReadingProgression = ReadingProgression.LTR, +) { + /** + * Readium CSS stylesheet variants. + */ + enum class Stylesheets(val folder: RelativeUrl?, val htmlDir: HtmlDir) { + /** Left to right */ + Default(null, HtmlDir.Ltr), + + /** Right to left */ + Rtl(RelativeUrl("rtl/")!!, HtmlDir.Rtl), + + /** + * Asian language, laid out vertically. + * + * The HTML `dir` attribute must not be modified with vertical CJK: + * https://github.com/readium/readium-css/tree/master/css/dist#vertical + */ + CjkVertical(RelativeUrl("cjk-vertical/")!!, HtmlDir.Unspecified), + + /** Asian language, laid out horizontally */ + CjkHorizontal(RelativeUrl("cjk-horizontal/")!!, HtmlDir.Ltr), + } + + enum class HtmlDir { + Unspecified, + Ltr, + Rtl, + } + + companion object { + + internal fun from(settingsValues: EpubSettings): Layout { + val stylesheets = when { + settingsValues.verticalText -> Stylesheets.CjkVertical + settingsValues.language?.isCjk == true -> Stylesheets.CjkHorizontal + settingsValues.readingProgression == ReadingProgression.RTL -> Stylesheets.Rtl + else -> Stylesheets.Default + } + + return Layout( + language = settingsValues.language, + readingProgression = settingsValues.readingProgression, + stylesheets = stylesheets + ) + } + } +} diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/Properties.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/Properties.kt new file mode 100644 index 0000000000..25925be6e7 --- /dev/null +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/Properties.kt @@ -0,0 +1,590 @@ +/* + * Copyright 2022 Readium Foundation. All rights reserved. + * Use of this source code is governed by the BSD-style license + * available in the top-level LICENSE file of the project. + */ + +@file:OptIn(ExperimentalReadiumApi::class) + +package org.readium.navigator.web.css + +import androidx.annotation.ColorInt +import java.text.NumberFormat +import java.util.* +import org.readium.r2.shared.ExperimentalReadiumApi +import org.readium.r2.shared.util.Either + +/** + * Holds a set of Readium CSS properties applied together. + */ +@ExperimentalReadiumApi +public interface Properties : Cssable { + public fun toCssProperties(): Map + + override fun toCss(): String? { + val props = toCssProperties() + .filterValues { it != null } + + if (props.isEmpty()) { + return "" + } + + return props + .map { (key, value) -> "$key: $value !important;" } + .joinToString("\n") + "\n" + } +} + +/** + * User settings properties. + * + * See https://readium.org/readium-css/docs/CSS19-api.html#user-settings + * + * @param view User view: paged or scrolled. + * @param colCount The number of columns (column-count) the user wants displayed (one-page view + * or two-page spread). To reset, change the value to auto. + * @param pageMargins A factor applied to horizontal margins (padding-left and padding-right) + * the user wants to set. Recommended values: a range from 0.5 to 2. Increments are left to + * implementers’ judgment. To reset, change the value to 1. + * @param appearance This flag applies a reading mode (sepia or night). + * @param darkenImages This will only apply in night mode to darken images and impact img. + * Requires: appearance = Appearance.Night + * @param invertImages This will only apply in night mode to invert images and impact img. + * Requires: appearance = Appearance.Night + * @param textColor The color for textual contents. It impacts all elements but headings and pre + * in the DOM. To reset, remove the CSS variable. + * @param backgroundColor The background-color for the whole screen. To reset, remove the CSS + * variable. + * @param fontOverride This flag is required to change the font-family user setting. + * @param fontFamily The typeface (font-family) the user wants to read with. It impacts body, p, + * li, div, dt, dd and phrasing elements which don’t have a lang or xml:lang attribute. To reset, + * remove the required flag. Requires: fontOverride + * @param fontSize Increasing and decreasing the root font-size. It will serve as a reference + * for the cascade. To reset, remove the required flag. + * @param advancedSettings This flag is required to apply the font-size and/or advanced user + * settings. + * @param typeScale The type scale the user wants to use for the publication. It impacts + * headings, p, li, div, pre, dd, small, sub, and sup. Recommended values: a range from 75% to + * 250%. Increments are left to implementers’ judgment. Requires: advancedSettings + * @param textAlign The alignment (text-align) the user prefers. It impacts body, li, and p + * which are not children of blockquote and figcaption. Requires: advancedSettings + * @param lineHeight Increasing and decreasing leading (line-height). It impacts body, p, li and + * div. Recommended values: a range from 1 to 2. Increments are left to implementers’ judgment. + * Requires: advancedSettings + * @param paraSpacing The vertical margins (margin-top and margin-bottom) for paragraphs. + * Recommended values: a range from 0 to 2rem. Increments are left to implementers’ + * judgment. Requires: advancedSettings = true + * @param paraIndent The text-indent for paragraphs. Recommended values: a range from 0 to 3rem. + * Increments are left to implementers’ judgment. Requires: advancedSettings + * @param wordSpacing Increasing space between words (word-spacing, related to a11y). + * Recommended values: a range from 0 to 1rem. Increments are left to implementers’ judgment. + * Requires: advancedSettings + * @param letterSpacing Increasing space between letters (letter-spacing, related to a11y). + * Recommended values: a range from 0 to 0.5rem. Increments are left to implementers’ + * judgment. Requires: advancedSettings + * @param bodyHyphens Enabling and disabling hyphenation. It impacts body, p, li, div and dd. + * Requires: advancedSettings + * @param ligatures Enabling and disabling ligatures in Arabic (related to a11y). + * Requires: advancedSettings + * @param a11yNormalize It impacts font style, weight and variant, text decoration, super and + * subscripts. Requires: fontOverride + */ +@ExperimentalReadiumApi +public data class UserProperties( + // View mode + val view: View? = null, + + // Pagination + val colCount: ColCount? = null, + val pageMargins: Double? = null, + + // Appearance + val appearance: Appearance? = null, + val darkenImages: Boolean? = null, + val invertImages: Boolean? = null, + + // Colors + val textColor: Color? = null, + val backgroundColor: Color? = null, + + // Typography + val fontOverride: Boolean? = null, + val fontFamily: List? = null, + val fontSize: Length? = null, + + // Advanced settings + val advancedSettings: Boolean? = null, + val typeScale: Double? = null, + val textAlign: TextAlign? = null, + val lineHeight: Either? = null, // line-height supports unitless numbers + val paraSpacing: Length? = null, + val paraIndent: Length.Rem? = null, + val wordSpacing: Length.Rem? = null, + val letterSpacing: Length.Rem? = null, + val bodyHyphens: Hyphens? = null, + val ligatures: Ligatures? = null, + + // Accessibility + val a11yNormalize: Boolean? = null, + + val overrides: Map = emptyMap(), +) : Properties { + + override fun toCssProperties(): Map = buildMap { + // View mode + putCss("--USER__view", view) + + // Pagination + putCss("--USER__colCount", colCount) + putCss("--USER__pageMargins", pageMargins) + + // Appearance + putCss("--USER__appearance", appearance) + putCss("--USER__darkenImages", flag("darken", darkenImages)) + putCss("--USER__invertImages", flag("invert", invertImages)) + + // Colors + putCss("--USER__textColor", textColor) + putCss("--USER__backgroundColor", backgroundColor) + + // Typography + putCss("--USER__fontOverride", flag("font", fontOverride)) + putCss("--USER__fontFamily", fontFamily) + putCss("--USER__fontSize", fontSize) + + // Advanced settings + putCss("--USER__advancedSettings", flag("advanced", advancedSettings)) + putCss("--USER__typeScale", typeScale) + putCss("--USER__textAlign", textAlign) + lineHeight + ?.onLeft { putCss("--USER__lineHeight", it) } + ?.onRight { putCss("--USER__lineHeight", it) } + ?: run { put("--USER__lineHeight", null) } + putCss("--USER__paraSpacing", paraSpacing) + putCss("--USER__paraIndent", paraIndent) + putCss("--USER__wordSpacing", wordSpacing) + putCss("--USER__letterSpacing", letterSpacing) + putCss("--USER__bodyHyphens", bodyHyphens) + putCss("--USER__ligatures", ligatures) + + // Accessibility + putCss("--USER__a11yNormalize", flag("a11y", a11yNormalize)) + + for ((key, value) in overrides) { + put(key, value) + } + } +} + +/** + * Reading System properties. + * + * See https://readium.org/readium-css/docs/CSS19-api.html#reading-system-styles + * + * @param colWidth The optimal column’s width. It serves as a floor in our design. + * @param colCount The optimal number of columns (depending on the columns’ width). + * @param colGap The gap between columns. You must account for this gap when scrolling. + * @param pageGutter The horizontal page margins. + * @param flowSpacing The default vertical margins for HTML5 flow content e.g. pre, figure, + * blockquote, etc. + * @param paraSpacing The default vertical margins for paragraphs. + * @param paraIndent The default text-indent for paragraphs. + * @param maxLineLength The optimal line-length. It must be set in rem in order to take :root’s + * font-size as a reference, whichever the body’s font-size might be. + * @param maxMediaWidth The max-width for media elements i.e. img, svg, audio and video. + * @param maxMediaHeight The max-height for media elements i.e. img, svg, audio and video. + * @param boxSizingMedia The box model (box-sizing) you want to use for media elements. + * @param boxSizingTable The box model (box-sizing) you want to use for tables. + * @param textColor The default color for body copy’s text. + * @param backgroundColor The default background-color for pages. + * @param selectionTextColor The color for selected text. + * @param selectionBackgroundColor The background-color for selected text. + * @param linkColor The default color for hyperlinks. + * @param visitedColor The default color for visited hyperlinks. + * @param primaryColor An optional primary accentuation color you could use for headings or any + * other element of your choice. + * @param secondaryColor An optional secondary accentuation color you could use for any element + * of your choice. + * @param typeScale The scale to be used for computing all elements’ font-size. Since those font + * sizes are computed dynamically, you can set a smaller type scale when the user sets one + * of the largest font sizes. + * @param baseFontFamily The default typeface for body copy in case the ebook doesn’t have one + * declared. Please note some languages have a specific font-stack (japanese, hindi, etc.) + * @param baseLineHeight The default line-height for body copy in case the ebook doesn’t have + * one declared. + * @param oldStyleTf An old style serif font-stack relying on pre-installed fonts. + * @param modernTf A modern serif font-stack relying on pre-installed fonts. + * @param sansTf A neutral sans-serif font-stack relying on pre-installed fonts. + * @param humanistTf A humanist sans-serif font-stack relying on pre-installed fonts. + * @param monospaceTf A monospace font-stack relying on pre-installed fonts. + * @param serifJa A Mincho font-stack whose fonts with proportional latin characters are + * prioritized for horizontal writing. + * @param sansSerifJa A Gothic font-stack whose fonts with proportional latin characters are + * prioritized for horizontal writing. + * @param serifJaV A Mincho font-stack whose fonts with fixed-width latin characters are + * prioritized for vertical writing. + * @param sansSerifJaV A Gothic font-stack whose fonts with fixed-width latin characters are + * prioritized for vertical writing. + * @param compFontFamily The typeface for headings. + * The value can be another variable e.g. var(-RS__humanistTf). + * @param codeFontFamily The typeface for code snippets. + * The value can be another variable e.g. var(-RS__monospaceTf). + */ +@ExperimentalReadiumApi +public data class RsProperties( + // Pagination + val colWidth: Length? = null, + val colCount: ColCount? = null, + val colGap: Length.Absolute? = null, + val pageGutter: Length.Absolute? = null, + + // Vertical rhythm + val flowSpacing: Length? = null, + val paraSpacing: Length? = null, + val paraIndent: Length? = null, + + // Safeguards + val maxLineLength: Length.Rem? = null, + val maxMediaWidth: Length? = null, + val maxMediaHeight: Length? = null, + val boxSizingMedia: BoxSizing? = null, + val boxSizingTable: BoxSizing? = null, + + // Colors + val textColor: Color? = null, + val backgroundColor: Color? = null, + val selectionTextColor: Color? = null, + val selectionBackgroundColor: Color? = null, + val linkColor: Color? = null, + val visitedColor: Color? = null, + val primaryColor: Color? = null, + val secondaryColor: Color? = null, + + // Typography + val typeScale: Double? = null, + val baseFontFamily: List? = null, + val baseLineHeight: Either? = null, // line-height supports unitless numbers + + // Default font-stacks + val oldStyleTf: List? = null, + val modernTf: List? = null, + val sansTf: List? = null, + val humanistTf: List? = null, + val monospaceTf: List? = null, + + // Default font-stacks for Japanese publications + val serifJa: List? = null, + val sansSerifJa: List? = null, + val serifJaV: List? = null, + val sansSerifJaV: List? = null, + + // Default styles for unstyled publications + val compFontFamily: List? = null, + val codeFontFamily: List? = null, + + val overrides: Map = emptyMap(), +) : Properties { + + override fun toCssProperties(): Map = buildMap { + // Pagination + putCss("--RS__colWidth", colWidth) + putCss("--RS__colCount", colCount) + putCss("--RS__colGap", colGap) + putCss("--RS__pageGutter", pageGutter) + + // Vertical rhythm + putCss("--RS__flowSpacing", flowSpacing) + putCss("--RS__paraSpacing", paraSpacing) + putCss("--RS__paraIndent", paraIndent) + + // Safeguards + putCss("--RS__maxLineLength", maxLineLength) + putCss("--RS__maxMediaWidth", maxMediaWidth) + putCss("--RS__maxMediaHeight", maxMediaHeight) + putCss("--RS__boxSizingMedia", boxSizingMedia) + putCss("--RS__boxSizingTable", boxSizingTable) + + // Colors + putCss("--RS__textColor", textColor) + putCss("--RS__backgroundColor", backgroundColor) + putCss("--RS__selectionTextColor", selectionTextColor) + putCss("--RS__selectionBackgroundColor", selectionBackgroundColor) + putCss("--RS__linkColor", linkColor) + putCss("--RS__visitedColor", visitedColor) + putCss("--RS__primaryColor", primaryColor) + putCss("--RS__secondaryColor", secondaryColor) + + // Typography + putCss("--RS__typeScale", typeScale) + putCss("--RS__baseFontFamily", baseFontFamily) + baseLineHeight + ?.onLeft { putCss("--RS__baseLineHeight", it) } + ?.onRight { putCss("--RS__baseLineHeight", it) } + ?: run { put("--RS__baseLineHeight", null) } + + // Default font-stacks + putCss("--RS__oldStyleTf", oldStyleTf) + putCss("--RS__modernTf", modernTf) + putCss("--RS__sansTf", sansTf) + putCss("--RS__humanistTf", humanistTf) + putCss("--RS__monospaceTf", monospaceTf) + + // Default font-stacks for Japanese publications + putCss("--RS__serif-ja", serifJa) + putCss("--RS__sans-serif-ja", sansSerifJa) + putCss("--RS__serif-ja-v", serifJaV) + putCss("--RS__sans-serif-ja-v", sansSerifJaV) + + // Default styles for unstyled publications + putCss("--RS__compFontFamily", compFontFamily) + putCss("--RS__codeFontFamily", codeFontFamily) + + for ((key, value) in overrides) { + put(key, value) + } + } +} + +/** User view. */ +@ExperimentalReadiumApi +public enum class View(private val css: String) : Cssable { + PAGED("readium-paged-on"), + SCROLL("readium-scroll-on"), + ; + + override fun toCss(): String = css +} + +/** Reading mode. */ +@ExperimentalReadiumApi +public enum class Appearance(private val css: String?) : Cssable { + NIGHT("readium-night-on"), + SEPIA("readium-sepia-on"), + ; + + override fun toCss(): String? = css +} + +/** CSS color. */ +@ExperimentalReadiumApi +public interface Color : Cssable { + + public data class Rgb(val red: kotlin.Int, val green: kotlin.Int, val blue: kotlin.Int) : Color { + init { + require(red in 0..255) + require(green in 0..255) + require(blue in 0..255) + } + + override fun toCss(): String = "rgb($red, $green, $blue)" + } + + @JvmInline + public value class Hex(public val color: String) : Color { + init { + require(Regex("^#(?:[0-9a-fA-F]{3}){1,2}$").matches(color)) + } + + override fun toCss(): String = color + } + + @JvmInline + public value class Int(@ColorInt public val color: kotlin.Int) : Color { + override fun toCss(): String = + String.format("#%06X", 0xFFFFFF and color) + } +} + +/** CSS length dimension. */ +@ExperimentalReadiumApi +public interface Length : Cssable { + + /** Absolute CSS length. */ + public interface Absolute : Length + + /** Centimeters */ + @JvmInline + public value class Cm(public val value: Double) : Absolute { + override fun toCss(): String = value.toCss("cm") + } + + /** Millimeters */ + @JvmInline + public value class Mm(public val value: Double) : Absolute { + override fun toCss(): String = value.toCss("mm") + } + + /** Inches */ + @JvmInline + public value class In(public val value: Double) : Absolute { + override fun toCss(): String = value.toCss("in") + } + + /** Pixels */ + @JvmInline + public value class Px(public val value: Double) : Absolute { + override fun toCss(): String = value.toCss("px") + } + + /** Points */ + @JvmInline + public value class Pt(public val value: Double) : Absolute { + override fun toCss(): String = value.toCss("pt") + } + + /** Picas */ + @JvmInline + public value class Pc(public val value: Double) : Absolute { + override fun toCss(): String = value.toCss("pc") + } + + /** Relative CSS length. */ + public interface Relative : Length + + /** Relative to the font-size of the element. */ + @JvmInline + public value class Em(public val value: Double) : Relative { + override fun toCss(): String = value.toCss("em") + } + + /** Relative to the width of the "0" (zero). */ + @JvmInline + public value class Ch(public val value: Double) : Relative { + override fun toCss(): String = value.toCss("ch") + } + + /** Relative to font-size of the root element. */ + @JvmInline + public value class Rem(public val value: Double) : Relative { + override fun toCss(): String = value.toCss("rem") + } + + /** Relative to 1% of the width of the viewport. */ + @JvmInline + public value class Vw(public val value: Double) : Relative { + override fun toCss(): String = value.toCss("vw") + } + + /** Relative to 1% of the height of the viewport. */ + @JvmInline + public value class Vh(public val value: Double) : Relative { + override fun toCss(): String = value.toCss("vh") + } + + /** Relative to 1% of viewport's smaller dimension. */ + @JvmInline + public value class VMin(public val value: Double) : Relative { + override fun toCss(): String = value.toCss("vmin") + } + + /** Relative to 1% of viewport's larger dimension. */ + @JvmInline + public value class VMax(public val value: Double) : Relative { + override fun toCss(): String = value.toCss("vmax") + } + + /** Relative to the parent element. */ + @JvmInline + public value class Percent(public val value: Double) : Relative { + override fun toCss(): String = (value * 100).toCss("%") + } +} + +/** Number of CSS columns. */ +@ExperimentalReadiumApi +public enum class ColCount(private val css: String) : Cssable { + AUTO("auto"), + ONE("1"), + TWO("2"), + ; + + override fun toCss(): String? = css +} + +/** CSS text alignment. */ +@ExperimentalReadiumApi +public enum class TextAlign(private val css: String) : Cssable { + START("start"), + LEFT("left"), + RIGHT("right"), + JUSTIFY("justify"), + ; + + override fun toCss(): String? = css +} + +/** CSS hyphenation. */ +@ExperimentalReadiumApi +public enum class Hyphens(private val css: String) : Cssable { + NONE("none"), + AUTO("auto"), + ; + + override fun toCss(): String? = css +} + +/** CSS ligatures. */ +@ExperimentalReadiumApi +public enum class Ligatures(private val css: String) : Cssable { + NONE("none"), + COMMON("common-ligatures"), + ; + + override fun toCss(): String? = css +} + +/** CSS box sizing. */ +@ExperimentalReadiumApi +public enum class BoxSizing(private val css: String) : Cssable { + CONTENT_BOX("content-box"), + BORDER_BOX("border-box"), + ; + + override fun toCss(): String? = css +} + +@ExperimentalReadiumApi +public fun interface Cssable { + public fun toCss(): String? +} + +private fun MutableMap.putCss(name: String, value: Cssable?) { + put(name, value?.toCss()) +} + +private fun MutableMap.putCss(name: String, double: Double?) { + put(name, double?.toString()) +} + +private fun MutableMap.putCss(name: String, string: String?) { + put(name, string?.toCss()) +} + +private fun MutableMap.putCss(name: String, strings: List?) { + val value = strings?.joinToString(", ") { it.toCss() } + put(name, value) +} + +/** Readium CSS boolean flag. */ +private fun flag(name: String, value: Boolean?) = Cssable { + if (value == true) { + "readium-$name-on" + } else { + null + } +} + +/** +* Converts a [String] to a CSS literal. +*/ +private fun String.toCss(): String = + '"' + replace("\"", "\\\"") + '"' + +/** + * Converts a [Double] to a string literal with the given [unit]. + */ +private fun Double.toCss(unit: String): String = + NumberFormat.getNumberInstance(Locale.ROOT).run { + maximumFractionDigits = 2 + format(this@toCss) + } + unit diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCss.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCss.kt new file mode 100644 index 0000000000..da79008eca --- /dev/null +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCss.kt @@ -0,0 +1,268 @@ +/* + * Copyright 2022 Readium Foundation. All rights reserved. + * Use of this source code is governed by the BSD-style license + * available in the top-level LICENSE file of the project. + */ + +package org.readium.navigator.web.css + +import android.net.Uri +import org.jsoup.Jsoup +import org.jsoup.nodes.Document +import org.jsoup.nodes.Element +import org.readium.r2.navigator.preferences.FontFamily +import org.readium.r2.navigator.preferences.ReadingProgression +import org.readium.r2.shared.ExperimentalReadiumApi +import org.readium.r2.shared.util.AbsoluteUrl +import org.readium.r2.shared.util.RelativeUrl +import org.readium.r2.shared.util.Url + +@ExperimentalReadiumApi +internal data class ReadiumCss( + val layout: Layout = Layout(language = null, Layout.Stylesheets.Default, ReadingProgression.LTR), + val rsProperties: RsProperties = RsProperties(), + val userProperties: UserProperties = UserProperties(), + val fontFamilyDeclarations: List = emptyList(), + val googleFonts: List = emptyList(), + val assetsBaseHref: AbsoluteUrl, + val readiumCssAssets: RelativeUrl, +) { + + /** + * Injects Readium CSS in the given [html] resource. + * + * https://github.com/readium/readium-css/blob/develop/docs/CSS06-stylesheets_order.md + */ + // FIXME: Replace existing attributes instead of adding new ones + @Throws + internal fun injectHtml(html: String): String { + val document = Jsoup.parse(html) + val content = StringBuilder(html) + injectStyles(content) + injectCssProperties(content) + injectDir(content) + injectLang(content, document) + return content.toString() + } + + /** + * Inject the Readium CSS stylesheets and font face declarations. + */ + private fun injectStyles(content: StringBuilder) { + val hasStyles = content.hasStyles() + + val headBeforeIndex = content.indexForOpeningTag("head") + content.insert( + headBeforeIndex, + "\n" + buildList { + addAll(fontsInjectableLinks) + + add(stylesheetLink(beforeCss)) + + // Fix Readium CSS issue with the positioning of

, S : Settings, E : PreferencesEditor> UserPreferen fit = editor.fit, spreads = editor.spreads ) + is ReflowableWebPreferencesEditor -> + ReflowableUserPreferences( + backgroundColor = editor.backgroundColor, + columnCount = editor.columnCount, + fontFamily = editor.fontFamily, + fontSize = editor.fontSize, + fontWeight = editor.fontWeight, + hyphens = editor.hyphens, + imageFilter = editor.imageFilter, + language = editor.language, + letterSpacing = editor.letterSpacing, + ligatures = editor.ligatures, + lineHeight = editor.lineHeight, + paragraphIndent = editor.paragraphIndent, + paragraphSpacing = editor.paragraphSpacing, + publisherStyles = editor.publisherStyles, + readingProgression = editor.readingProgression, + scroll = editor.scroll, + textAlign = editor.textAlign, + textColor = editor.textColor, + textNormalization = editor.textNormalization, + theme = editor.theme, + verticalText = editor.verticalText, + wordSpacing = editor.wordSpacing + ) } } } @@ -157,6 +190,261 @@ private fun FixedLayoutUserPreferences( } } +/** + * User settings for a publication with adjustable fonts and dimensions, such as + * a reflowable EPUB, HTML document or PDF with reflow mode enabled. + */ +@Composable +private fun ReflowableUserPreferences( + backgroundColor: Preference? = null, + columnCount: EnumPreference? = null, + fontFamily: Preference? = null, + fontSize: RangePreference? = null, + fontWeight: RangePreference? = null, + hyphens: Preference? = null, + imageFilter: EnumPreference? = null, + language: Preference? = null, + letterSpacing: RangePreference? = null, + ligatures: Preference? = null, + lineHeight: RangePreference? = null, + pageMargins: RangePreference? = null, + paragraphIndent: RangePreference? = null, + paragraphSpacing: RangePreference? = null, + publisherStyles: Preference? = null, + readingProgression: EnumPreference? = null, + scroll: Preference? = null, + textAlign: EnumPreference? = null, + textColor: Preference? = null, + textNormalization: Preference? = null, + theme: EnumPreference? = null, + typeScale: RangePreference? = null, + verticalText: Preference? = null, + wordSpacing: RangePreference? = null, +) { + if (language != null || readingProgression != null || verticalText != null) { + if (language != null) { + LanguageItem( + preference = language, + ) + } + + if (readingProgression != null) { + ButtonGroupItem( + title = "Reading progression", + preference = readingProgression, + formatValue = { it.name } + ) + } + + if (verticalText != null) { + SwitchItem( + title = "Vertical text", + preference = verticalText, + ) + } + + Divider() + } + + if (scroll != null || columnCount != null || pageMargins != null) { + if (scroll != null) { + SwitchItem( + title = "Scroll", + preference = scroll + ) + } + + if (columnCount != null) { + ButtonGroupItem( + title = "Columns", + preference = columnCount, + formatValue = Int::toString + ) + } + + if (pageMargins != null) { + StepperItem( + title = "Page margins", + preference = pageMargins + ) + } + + Divider() + } + + if (theme != null || textColor != null || imageFilter != null) { + if (theme != null) { + ButtonGroupItem( + title = "Theme", + preference = theme + ) { value -> + when (value) { + Theme.LIGHT -> "Light" + Theme.DARK -> "Dark" + Theme.SEPIA -> "Sepia" + } + } + } + + if (imageFilter != null) { + ButtonGroupItem( + title = "Image filter", + preference = imageFilter + ) { value -> + when (value) { + ImageFilter.DARKEN -> "Darken" + ImageFilter.INVERT -> "Invert" + null -> "None" + } + } + } + + if (textColor != null) { + ColorItem( + title = "Text color", + preference = textColor + ) + } + + if (backgroundColor != null) { + ColorItem( + title = "Background color", + preference = backgroundColor + ) + } + + Divider() + } + + if (fontFamily != null || fontSize != null || textNormalization != null) { + if (fontFamily != null) { + MenuItem( + title = "Typeface", + preference = fontFamily + .withSupportedValues( + null, + // FontFamily.LITERATA, + FontFamily.SANS_SERIF, + FontFamily.IA_WRITER_DUOSPACE, + FontFamily.ACCESSIBLE_DFA, + FontFamily.OPEN_DYSLEXIC + ) + ) { value -> + when (value) { + null -> "Original" + FontFamily.SANS_SERIF -> "Sans Serif" + else -> value.name + } + } + } + + if (fontSize != null) { + StepperItem( + title = "Font size", + preference = fontSize + ) + } + + if (fontWeight != null) { + StepperItem( + title = "Font weight", + preference = fontWeight + ) + } + + if (textNormalization != null) { + SwitchItem( + title = "Text normalization", + preference = textNormalization + ) + } + + Divider() + } + + if (publisherStyles != null) { + SwitchItem( + title = "Publisher styles", + preference = publisherStyles + ) + + if (!(publisherStyles.value ?: publisherStyles.effectiveValue)) { + if (textAlign != null) { + ButtonGroupItem( + title = "Alignment", + preference = textAlign + ) { value -> + when (value) { + ReadiumTextAlign.CENTER -> "Center" + ReadiumTextAlign.JUSTIFY -> "Justify" + ReadiumTextAlign.START -> "Start" + ReadiumTextAlign.END -> "End" + ReadiumTextAlign.LEFT -> "Left" + ReadiumTextAlign.RIGHT -> "Right" + null -> "Default" + } + } + } + + if (typeScale != null) { + StepperItem( + title = "Type scale", + preference = typeScale + ) + } + + if (lineHeight != null) { + StepperItem( + title = "Line height", + preference = lineHeight + ) + } + + if (paragraphIndent != null) { + StepperItem( + title = "Paragraph indent", + preference = paragraphIndent + ) + } + + if (paragraphSpacing != null) { + StepperItem( + title = "Paragraph spacing", + preference = paragraphSpacing + ) + } + + if (wordSpacing != null) { + StepperItem( + title = "Word spacing", + preference = wordSpacing + ) + } + + if (letterSpacing != null) { + StepperItem( + title = "Letter spacing", + preference = letterSpacing + ) + } + + if (hyphens != null) { + SwitchItem( + title = "Hyphens", + preference = hyphens + ) + } + + if (ligatures != null) { + SwitchItem( + title = "Ligatures", + preference = ligatures + ) + } + } + } +} + @Composable private fun Divider() { HorizontalDivider(modifier = Modifier.padding(vertical = 16.dp)) diff --git a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/util/ColorPicker.kt b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/util/ColorPicker.kt new file mode 100644 index 0000000000..35fa10403a --- /dev/null +++ b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/util/ColorPicker.kt @@ -0,0 +1,73 @@ +/* + * Copyright 2024 Readium Foundation. All rights reserved. + * Use of this source code is governed by the BSD-style license + * available in the top-level LICENSE file of the project. + */ + +package org.readium.navigator.demo.util + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp + +@Composable +fun ColorPicker(onPick: (Int) -> Unit) { + val colors = listOf( + // Gray + listOf("#ffffff", "#bfbfbf", "#808080", "#404040", "#000000"), + // Sepia + listOf("#FAF4E8", "#CDBEAE", "#A08774", "#73513A", "#461A00"), + // Brown + listOf("#d7ccc8", "#a1887f", "#795548", "#5d4037", "#3e2723"), + // Red + listOf("#ffcdd2", "#e57373", "#f44336", "#d32f2f", "#b71c1c"), + // Purple + listOf("#e1bee7", "#ba68c8", "#9c27b0", "#7b1fa2", "#4a148c"), + // Blue + listOf("#bbdefb", "#64b5f6", "#2196f3", "#1976d2", "#0d47a1"), + // Green + listOf("#c8e6c9", "#81c784", "#4caf50", "#388e3c", "#1b5e20"), + // Yellow + listOf("#fff9c4", "#fff176", "#ffeb3b", "#fbc02d", "#f57f17"), + // Orange + listOf("#ffe0b2", "#ffb74d", "#ff9800", "#f57c00", "#e65100") + ) + + Column { + for (row in colors) { + Row( + modifier = Modifier + .fillMaxWidth() + ) { + for (color in row) { + ColorBox(color, onClick = onPick) + } + } + } + } +} + +@Composable +private fun RowScope.ColorBox(colorHex: String, onClick: (Int) -> Unit) { + val color = remember(colorHex) { android.graphics.Color.parseColor(colorHex) } + + Box( + modifier = Modifier + .clickable { onClick(color) } + .weight(1f) + .size(40.dp) + .background(Color(color)) + ) +} + +@Preview(showBackground = true) +@Composable +fun PreviewColorPicker() { + ColorPicker {} +} diff --git a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/util/DropdownMenuButton.kt b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/util/DropdownMenuButton.kt new file mode 100644 index 0000000000..bbf3b7dd12 --- /dev/null +++ b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/util/DropdownMenuButton.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2024 Readium Foundation. All rights reserved. + * Use of this source code is governed by the BSD-style license + * available in the top-level LICENSE file of the project. + */ + +package org.readium.navigator.demo.util + +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.RowScope +import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.OutlinedButton +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue + +@Composable +fun DropdownMenuButton( + text: @Composable RowScope.() -> Unit, + content: @Composable ColumnScope.(dismiss: () -> Unit) -> Unit, +) { + var isExpanded by remember { mutableStateOf(false) } + fun dismiss() { + isExpanded = false + } + + OutlinedButton( + onClick = { isExpanded = true } + ) { + text() + DropdownMenu( + expanded = isExpanded, + onDismissRequest = { isExpanded = false } + ) { + content(::dismiss) + } + } +} diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt index f5aeea07bf..01c38fcd0c 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt @@ -25,6 +25,7 @@ import org.readium.navigator.web.layout.ReadingOrder import org.readium.navigator.web.location.ReflowableWebGoLocation import org.readium.navigator.web.location.ReflowableWebLocation import org.readium.navigator.web.preferences.ReflowableWebSettings +import org.readium.navigator.web.preferences.update import org.readium.navigator.web.util.HyperlinkProcessor import org.readium.navigator.web.util.WebViewClient import org.readium.navigator.web.util.WebViewServer @@ -66,13 +67,16 @@ public class ReflowableWebRenditionState internal constructor( internal val hyperlinkProcessor = HyperlinkProcessor(container) - internal val readiumCss: MutableState = - mutableStateOf( + internal val readiumCss: State = + derivedStateOf { ReadiumCss( assetsBaseHref = assetsBaseHref, readiumCssAssets = RelativeUrl("readium/navigators/web/readium-css/")!! + ).update( + settings = layoutDelegate.settings.value, + useReadiumCssFontSize = true ) - ) + } private val htmlInjector: (Resource, MediaType) -> Resource = { resource, mediaType -> resource.injectHtmlReflowable( diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/Layout.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/Layout.kt index 9aa9044f5e..36b86cda64 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/Layout.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/Layout.kt @@ -6,9 +6,10 @@ package org.readium.navigator.web.css +import org.readium.navigator.web.preferences.ReflowableWebSettings import org.readium.navigator.web.util.isCjk -import org.readium.r2.navigator.epub.EpubSettings import org.readium.r2.navigator.preferences.ReadingProgression +import org.readium.r2.shared.ExperimentalReadiumApi import org.readium.r2.shared.util.Language import org.readium.r2.shared.util.RelativeUrl @@ -52,7 +53,8 @@ internal data class Layout( companion object { - internal fun from(settingsValues: EpubSettings): Layout { + @OptIn(ExperimentalReadiumApi::class) + internal fun from(settingsValues: ReflowableWebSettings): Layout { val stylesheets = when { settingsValues.verticalText -> Stylesheets.CjkVertical settingsValues.language?.isCjk == true -> Stylesheets.CjkHorizontal diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/Properties.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/Properties.kt index 25925be6e7..6c66bc1068 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/Properties.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/Properties.kt @@ -43,9 +43,6 @@ public interface Properties : Cssable { * @param view User view: paged or scrolled. * @param colCount The number of columns (column-count) the user wants displayed (one-page view * or two-page spread). To reset, change the value to auto. - * @param pageMargins A factor applied to horizontal margins (padding-left and padding-right) - * the user wants to set. Recommended values: a range from 0.5 to 2. Increments are left to - * implementers’ judgment. To reset, change the value to 1. * @param appearance This flag applies a reading mode (sepia or night). * @param darkenImages This will only apply in night mode to darken images and impact img. * Requires: appearance = Appearance.Night @@ -61,11 +58,9 @@ public interface Properties : Cssable { * remove the required flag. Requires: fontOverride * @param fontSize Increasing and decreasing the root font-size. It will serve as a reference * for the cascade. To reset, remove the required flag. + * @param lineLength Increasing and decreasing the line length. * @param advancedSettings This flag is required to apply the font-size and/or advanced user * settings. - * @param typeScale The type scale the user wants to use for the publication. It impacts - * headings, p, li, div, pre, dd, small, sub, and sup. Recommended values: a range from 75% to - * 250%. Increments are left to implementers’ judgment. Requires: advancedSettings * @param textAlign The alignment (text-align) the user prefers. It impacts body, li, and p * which are not children of blockquote and figcaption. Requires: advancedSettings * @param lineHeight Increasing and decreasing leading (line-height). It impacts body, p, li and @@ -95,8 +90,7 @@ public data class UserProperties( val view: View? = null, // Pagination - val colCount: ColCount? = null, - val pageMargins: Double? = null, + val colCount: Int? = null, // Appearance val appearance: Appearance? = null, @@ -111,10 +105,10 @@ public data class UserProperties( val fontOverride: Boolean? = null, val fontFamily: List? = null, val fontSize: Length? = null, + val lineLength: Length? = null, // Advanced settings val advancedSettings: Boolean? = null, - val typeScale: Double? = null, val textAlign: TextAlign? = null, val lineHeight: Either? = null, // line-height supports unitless numbers val paraSpacing: Length? = null, @@ -136,7 +130,6 @@ public data class UserProperties( // Pagination putCss("--USER__colCount", colCount) - putCss("--USER__pageMargins", pageMargins) // Appearance putCss("--USER__appearance", appearance) @@ -151,10 +144,10 @@ public data class UserProperties( putCss("--USER__fontOverride", flag("font", fontOverride)) putCss("--USER__fontFamily", fontFamily) putCss("--USER__fontSize", fontSize) + putCss("--USER__lineLength", lineLength) // Advanced settings putCss("--USER__advancedSettings", flag("advanced", advancedSettings)) - putCss("--USER__typeScale", typeScale) putCss("--USER__textAlign", textAlign) lineHeight ?.onLeft { putCss("--USER__lineHeight", it) } @@ -190,7 +183,7 @@ public data class UserProperties( * @param paraSpacing The default vertical margins for paragraphs. * @param paraIndent The default text-indent for paragraphs. * @param maxLineLength The optimal line-length. It must be set in rem in order to take :root’s - * font-size as a reference, whichever the body’s font-size might be. + * font-size as a reference, whichever the body’s font-size might be. * @param maxMediaWidth The max-width for media elements i.e. img, svg, audio and video. * @param maxMediaHeight The max-height for media elements i.e. img, svg, audio and video. * @param boxSizingMedia The box model (box-sizing) you want to use for media elements. @@ -205,9 +198,6 @@ public data class UserProperties( * other element of your choice. * @param secondaryColor An optional secondary accentuation color you could use for any element * of your choice. - * @param typeScale The scale to be used for computing all elements’ font-size. Since those font - * sizes are computed dynamically, you can set a smaller type scale when the user sets one - * of the largest font sizes. * @param baseFontFamily The default typeface for body copy in case the ebook doesn’t have one * declared. Please note some languages have a specific font-stack (japanese, hindi, etc.) * @param baseLineHeight The default line-height for body copy in case the ebook doesn’t have @@ -234,7 +224,7 @@ public data class UserProperties( public data class RsProperties( // Pagination val colWidth: Length? = null, - val colCount: ColCount? = null, + val colCount: Int? = null, val colGap: Length.Absolute? = null, val pageGutter: Length.Absolute? = null, @@ -261,7 +251,6 @@ public data class RsProperties( val secondaryColor: Color? = null, // Typography - val typeScale: Double? = null, val baseFontFamily: List? = null, val baseLineHeight: Either? = null, // line-height supports unitless numbers @@ -315,7 +304,6 @@ public data class RsProperties( putCss("--RS__secondaryColor", secondaryColor) // Typography - putCss("--RS__typeScale", typeScale) putCss("--RS__baseFontFamily", baseFontFamily) baseLineHeight ?.onLeft { putCss("--RS__baseLineHeight", it) } @@ -552,16 +540,21 @@ private fun MutableMap.putCss(name: String, value: Cssable?) { put(name, value?.toCss()) } -private fun MutableMap.putCss(name: String, double: Double?) { - put(name, double?.toString()) +private fun MutableMap.putCss(name: String, value: Double?) { + put(name, value?.toString()) } -private fun MutableMap.putCss(name: String, string: String?) { - put(name, string?.toCss()) +private fun MutableMap.putCss(name: String, value: Int?) { + put(name, value?.toString()) } -private fun MutableMap.putCss(name: String, strings: List?) { - val value = strings?.joinToString(", ") { it.toCss() } +@Suppress("unused") +private fun MutableMap.putCss(name: String, value: String?) { + put(name, value?.toCss()) +} + +private fun MutableMap.putCss(name: String, values: List?) { + val value = values?.joinToString(", ") { it.toCss() } put(name, value) } @@ -578,7 +571,7 @@ private fun flag(name: String, value: Boolean?) = Cssable { * Converts a [String] to a CSS literal. */ private fun String.toCss(): String = - '"' + replace("\"", "\\\"") + '"' + "\\\"" + replace("\"", "\\\"") + "\\\"" /** * Converts a [Double] to a string literal with the given [unit]. diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebDefaults.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebDefaults.kt index 97af681dc0..415d75f866 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebDefaults.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebDefaults.kt @@ -6,13 +6,38 @@ package org.readium.navigator.web.preferences -import org.readium.r2.navigator.preferences.Fit +import org.readium.r2.navigator.preferences.ImageFilter import org.readium.r2.navigator.preferences.ReadingProgression +import org.readium.r2.navigator.preferences.Spread +import org.readium.r2.navigator.preferences.TextAlign import org.readium.r2.shared.ExperimentalReadiumApi +import org.readium.r2.shared.util.Language +/** + * Default values for the Reflowable Web navigator. + * + * These values will be used when no publication metadata or user preference takes precedence. + * + * @see ReflowableWebPreferences + */ @ExperimentalReadiumApi public data class ReflowableWebDefaults( - val fit: Fit? = null, + val columnCount: Int? = null, + val fontSize: Double? = null, + val fontWeight: Double? = null, + val hyphens: Boolean? = null, + val imageFilter: ImageFilter? = null, + val language: Language? = null, + val letterSpacing: Double? = null, + val ligatures: Boolean? = null, + val lineHeight: Double? = null, + val paragraphIndent: Double? = null, + val paragraphSpacing: Double? = null, + val publisherStyles: Boolean? = null, val readingProgression: ReadingProgression? = null, - val spreads: Boolean? = null, + val scroll: Boolean? = null, + val spread: Spread? = null, + val textAlign: TextAlign? = null, + val textNormalization: Boolean? = null, + val wordSpacing: Double? = null, ) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferences.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferences.kt index 5c72e21acf..ecb3648cd1 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferences.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferences.kt @@ -7,27 +7,106 @@ package org.readium.navigator.web.preferences import kotlinx.serialization.Serializable -import org.readium.r2.navigator.preferences.Configurable -import org.readium.r2.navigator.preferences.Fit -import org.readium.r2.navigator.preferences.ReadingProgression +import org.readium.navigator.common.Preferences +import org.readium.r2.navigator.preferences.* import org.readium.r2.shared.ExperimentalReadiumApi +import org.readium.r2.shared.util.Language +/** + * Preferences for the Reflowable Web navigator. + * + * @param backgroundColor Default page background color. + * @param columnCount Number of reflowable columns to display. + * @param fontFamily Default typeface for the text. + * @param fontSize Base text font size. + * @param fontWeight Default boldness for the text. + * @param hyphens Enable hyphenation. + * @param imageFilter Filter applied to images in dark theme. + * @param language Language of the publication content. + * @param letterSpacing Space between letters. + * @param ligatures Enable ligatures in Arabic. + * @param lineHeight Leading line height. + * @param paragraphIndent Text indentation for paragraphs. + * @param paragraphSpacing Vertical margins for paragraphs. + * @param publisherStyles Indicates whether the original publisher styles should be observed. + * Many settings require this to be off. + * @param readingProgression Direction of the reading progression across resources. + * @param scroll Indicates if the overflow of resources should be handled using scrolling + * instead of synthetic pagination. + * @param spread Indicates if the fixed-layout publication should be rendered with a + * synthetic spread (dual-page). + * @param textAlign Page text alignment. + * @param textColor Default page text color. + * @param textNormalization Normalize text styles to increase accessibility. + * @param theme Reader theme. + * @param verticalText Indicates whether the text should be laid out vertically. This is used + * for example with CJK languages. This setting is automatically derived from the language if + * no preference is given. + * @param wordSpacing Space between words. + */ @Serializable @ExperimentalReadiumApi public data class ReflowableWebPreferences( - val fit: Fit? = null, + val backgroundColor: Color? = null, + val columnCount: Int? = null, + val fontFamily: FontFamily? = null, + val fontSize: Double? = null, + val fontWeight: Double? = null, + val hyphens: Boolean? = null, + val imageFilter: ImageFilter? = null, + val language: Language? = null, + val letterSpacing: Double? = null, + val ligatures: Boolean? = null, + val lineHeight: Double? = null, + val paragraphIndent: Double? = null, + val paragraphSpacing: Double? = null, + val publisherStyles: Boolean? = null, val readingProgression: ReadingProgression? = null, - val spreads: Boolean? = null, -) : Configurable.Preferences { + val scroll: Boolean? = null, + val spread: Spread? = null, + val textAlign: TextAlign? = null, + val textColor: Color? = null, + val textNormalization: Boolean? = null, + val theme: Theme? = null, + val verticalText: Boolean? = null, + val wordSpacing: Double? = null, +) : Preferences { init { - require(fit in listOf(null, Fit.CONTAIN, Fit.WIDTH, Fit.HEIGHT)) + require(columnCount == null || columnCount > 1) + require(fontSize == null || fontSize >= 0) + require(fontWeight == null || fontWeight in 0.0..2.5) + require(letterSpacing == null || letterSpacing >= 0) + require(paragraphSpacing == null || paragraphSpacing >= 0) + require(spread in listOf(null, Spread.NEVER, Spread.ALWAYS)) + require(wordSpacing == null || wordSpacing >= 0) } + @OptIn(ExperimentalReadiumApi::class) override operator fun plus(other: ReflowableWebPreferences): ReflowableWebPreferences = ReflowableWebPreferences( - fit = other.fit ?: fit, + backgroundColor = other.backgroundColor ?: backgroundColor, + columnCount = other.columnCount ?: columnCount, + fontFamily = other.fontFamily ?: fontFamily, + fontWeight = other.fontWeight ?: fontWeight, + fontSize = other.fontSize ?: fontSize, + hyphens = other.hyphens ?: hyphens, + imageFilter = other.imageFilter ?: imageFilter, + language = other.language ?: language, + letterSpacing = other.letterSpacing ?: letterSpacing, + ligatures = other.ligatures ?: ligatures, + lineHeight = other.lineHeight ?: lineHeight, + paragraphIndent = other.paragraphIndent ?: paragraphIndent, + paragraphSpacing = other.paragraphSpacing ?: paragraphSpacing, + publisherStyles = other.publisherStyles ?: publisherStyles, readingProgression = other.readingProgression ?: readingProgression, - spreads = other.spreads ?: spreads + scroll = other.scroll ?: scroll, + spread = other.spread ?: spread, + textAlign = other.textAlign ?: textAlign, + textColor = other.textColor ?: textColor, + textNormalization = other.textNormalization ?: textNormalization, + theme = other.theme ?: theme, + verticalText = other.verticalText ?: verticalText, + wordSpacing = other.wordSpacing ?: wordSpacing ) } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesEditor.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesEditor.kt index 23782af7b0..595d52c8e4 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesEditor.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesEditor.kt @@ -11,25 +11,35 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import org.readium.navigator.common.PreferencesEditor +import org.readium.navigator.web.css.Layout +import org.readium.r2.navigator.extensions.format +import org.readium.r2.navigator.preferences.Color +import org.readium.r2.navigator.preferences.DoubleIncrement import org.readium.r2.navigator.preferences.EnumPreference import org.readium.r2.navigator.preferences.EnumPreferenceDelegate -import org.readium.r2.navigator.preferences.Fit +import org.readium.r2.navigator.preferences.FontFamily +import org.readium.r2.navigator.preferences.ImageFilter import org.readium.r2.navigator.preferences.Preference import org.readium.r2.navigator.preferences.PreferenceDelegate +import org.readium.r2.navigator.preferences.RangePreference +import org.readium.r2.navigator.preferences.RangePreferenceDelegate import org.readium.r2.navigator.preferences.ReadingProgression +import org.readium.r2.navigator.preferences.TextAlign +import org.readium.r2.navigator.preferences.Theme import org.readium.r2.shared.ExperimentalReadiumApi import org.readium.r2.shared.InternalReadiumApi import org.readium.r2.shared.publication.Metadata +import org.readium.r2.shared.util.Language /** - * Interactive editor of [FixedWebPreferences]. + * Interactive editor of [ReflowableWebPreferences]. * * This can be used as a view model for a user preferences screen. Every data you can get * from the editor is observable so if you use it in a composable function, * it will be recomposed on every change. * - * @see FixedWebPreferences - * @see FixedWebSettings + * @see ReflowableWebPreferences + * @see ReflowableWebSettings */ @ExperimentalReadiumApi @OptIn(InternalReadiumApi::class) @@ -43,6 +53,7 @@ public class ReflowableWebPreferencesEditor internal constructor( private data class State( val preferences: ReflowableWebPreferences, val settings: ReflowableWebSettings, + val layout: Layout, ) private val settingsResolver: ReflowableWebSettingsResolver = @@ -56,19 +67,258 @@ public class ReflowableWebPreferencesEditor internal constructor( override val settings: ReflowableWebSettings get() = state.settings + /** + * Reset all preferences. + */ + @OptIn(ExperimentalReadiumApi::class) override fun clear() { updateValues { ReflowableWebPreferences() } } - public val fit: EnumPreference = + /** + * Default background color. + * + * For fixed-layout publications, it applies to the navigator background but not the publication + * pages. + * + * When unset, the current [theme] background color is effective. + */ + public val backgroundColor: Preference = + PreferenceDelegate( + getValue = { preferences.backgroundColor }, + getEffectiveValue = { + state.settings.backgroundColor ?: Color( + (theme.value ?: theme.effectiveValue).backgroundColor + ) + }, + getIsEffective = { preferences.backgroundColor != null }, + updateValue = { value -> updateValues { it.copy(backgroundColor = value) } } + ) + + /** + * Number of reflowable columns to display (one-page view or two-page spread). + * + * Only effective when: + * - the publication is reflowable + * - [scroll] is off + */ + @ExperimentalReadiumApi + public val columnCount: EnumPreference = EnumPreferenceDelegate( - getValue = { preferences.fit }, - getEffectiveValue = { state.settings.fit }, + getValue = { preferences.columnCount }, + getEffectiveValue = { state.settings.columnCount }, + getIsEffective = { true }, + updateValue = { value -> updateValues { it.copy(columnCount = value) } }, + supportedValues = listOf(1, 2) + ) + + /** + * Default typeface for the text. + * + * Only effective with reflowable publications. + */ + public val fontFamily: Preference = + PreferenceDelegate( + getValue = { preferences.fontFamily }, + getEffectiveValue = { state.settings.fontFamily }, + getIsEffective = { true }, + updateValue = { value -> updateValues { it.copy(fontFamily = value) } } + ) + + /** + * Base text font size as a percentage. Default to 100%. + * + * Note that allowing a font size that is too large could break the pagination. + * + * Only effective with reflowable publications. + */ + public val fontSize: RangePreference = + RangePreferenceDelegate( + getValue = { preferences.fontSize }, + getEffectiveValue = { state.settings.fontSize }, + getIsEffective = { true }, + updateValue = { value -> updateValues { it.copy(fontSize = value) } }, + supportedRange = 0.1..5.0, + progressionStrategy = DoubleIncrement(0.1), + valueFormatter = percentFormatter() + ) + + /** + * Default boldness for the text as a percentage. + * + * If you want to change the boldness of all text, including headers, you can use this with + * [textNormalization]. + * + * Only effective with reflowable publications. + */ + public val fontWeight: RangePreference = + RangePreferenceDelegate( + getValue = { preferences.fontWeight }, + getEffectiveValue = { state.settings.fontWeight ?: 1.0 }, + getIsEffective = { preferences.fontWeight != null }, + updateValue = { value -> updateValues { it.copy(fontWeight = value) } }, + valueFormatter = percentFormatter(), + supportedRange = 0.0..2.5, + progressionStrategy = DoubleIncrement(0.25) + ) + + /** + * Enable hyphenation for latin languages. + * + * Only effective when: + * - the publication is reflowable + * - [publisherStyles] is off + * - the layout is LTR + */ + public val hyphens: Preference = + PreferenceDelegate( + getValue = { preferences.hyphens }, + getEffectiveValue = { + state.settings.hyphens + ?: (state.settings.textAlign == TextAlign.JUSTIFY) + }, + getIsEffective = ::isHyphensEffective, + updateValue = { value -> updateValues { it.copy(hyphens = value) } } + ) + + /** + * Filter applied to images in dark theme. + * + * Only effective when: + * - the publication is reflowable + * - the [theme] is set to [Theme.DARK] + */ + public val imageFilter: EnumPreference = + EnumPreferenceDelegate( + getValue = { preferences.imageFilter }, + getEffectiveValue = { state.settings.imageFilter }, + getIsEffective = { state.settings.theme == Theme.DARK }, + updateValue = { value -> updateValues { it.copy(imageFilter = value) } }, + supportedValues = listOf(ImageFilter.DARKEN, ImageFilter.INVERT) + ) + + /** + * Language of the publication content. + * + * This has an impact on the resolved layout (e.g. LTR, RTL). + */ + public val language: Preference = + PreferenceDelegate( + getValue = { preferences.language }, + getEffectiveValue = { state.settings.language }, + getIsEffective = { true }, + updateValue = { value -> updateValues { it.copy(language = value) } } + ) + + /** + * Space between letters. + * + * Only effective when: + * - the publication is reflowable + * - [publisherStyles] is off + * - the layout is LTR + */ + public val letterSpacing: RangePreference = + RangePreferenceDelegate( + getValue = { preferences.letterSpacing }, + getEffectiveValue = { state.settings.letterSpacing ?: 0.0 }, + getIsEffective = ::isLetterSpacingEffective, + updateValue = { value -> updateValues { it.copy(letterSpacing = value) } }, + supportedRange = 0.0..1.0, + progressionStrategy = DoubleIncrement(0.1), + valueFormatter = percentFormatter() + ) + + /** + * Enable ligatures in Arabic. + * + * Only effective when: + * - the publication is reflowable + * - [publisherStyles] is off + * - the layout is RTL + */ + public val ligatures: Preference = + PreferenceDelegate( + getValue = { preferences.ligatures }, + getEffectiveValue = { state.settings.ligatures ?: false }, + getIsEffective = ::isLigaturesEffective, + updateValue = { value -> updateValues { it.copy(ligatures = value) } } + ) + + /** + * Leading line height. + * + * Only effective when: + * - the publication is reflowable + * - [publisherStyles] is off + */ + public val lineHeight: RangePreference = + RangePreferenceDelegate( + getValue = { preferences.lineHeight }, + getEffectiveValue = { state.settings.lineHeight ?: 1.2 }, + getIsEffective = { !state.settings.publisherStyles && preferences.lineHeight != null }, + updateValue = { value -> updateValues { it.copy(lineHeight = value) } }, + supportedRange = 1.0..2.0, + progressionStrategy = DoubleIncrement(0.1), + valueFormatter = { it.format(5) } + ) + + /** + * Text indentation for paragraphs. + * + * Only effective when: + * - the publication is reflowable + * - [publisherStyles] is off + * - the layout is LTR or RTL + */ + public val paragraphIndent: RangePreference = + RangePreferenceDelegate( + getValue = { preferences.paragraphIndent }, + getEffectiveValue = { state.settings.paragraphIndent ?: 0.0 }, + getIsEffective = ::isParagraphIndentEffective, + updateValue = { value -> updateValues { it.copy(paragraphIndent = value) } }, + supportedRange = 0.0..3.0, + progressionStrategy = DoubleIncrement(0.2), + valueFormatter = percentFormatter() + ) + + /** + * Vertical margins for paragraphs. + * + * Only effective when: + * - the publication is reflowable + * - [publisherStyles] is off + */ + public val paragraphSpacing: RangePreference = + RangePreferenceDelegate( + getValue = { preferences.paragraphSpacing }, + getEffectiveValue = { state.settings.paragraphSpacing ?: 0.0 }, + getIsEffective = { !state.settings.publisherStyles && preferences.paragraphSpacing != null }, + updateValue = { value -> updateValues { it.copy(paragraphSpacing = value) } }, + supportedRange = 0.0..2.0, + progressionStrategy = DoubleIncrement(0.1), + valueFormatter = percentFormatter() + ) + + /** + * Indicates whether the original publisher styles should be observed. Many advanced settings + * require this to be off. + * + * Only effective with reflowable publications. + */ + public val publisherStyles: Preference = + PreferenceDelegate( + getValue = { preferences.publisherStyles }, + getEffectiveValue = { state.settings.publisherStyles }, getIsEffective = { true }, - updateValue = { value -> updateValues { it.copy(fit = value) } }, - supportedValues = listOf(Fit.CONTAIN, Fit.WIDTH, Fit.HEIGHT) + updateValue = { value -> updateValues { it.copy(publisherStyles = value) } } ) + /** + * Direction of the reading progression across resources. + * + * This can be changed to influence directly the layout (e.g. LTR or RTL). + */ public val readingProgression: EnumPreference = EnumPreferenceDelegate( getValue = { preferences.readingProgression }, @@ -78,21 +328,165 @@ public class ReflowableWebPreferencesEditor internal constructor( supportedValues = listOf(ReadingProgression.LTR, ReadingProgression.RTL) ) - public val spreads: Preference = + /** + * Indicates if the overflow of resources should be handled using scrolling instead of synthetic + * pagination. + * + * Only effective with reflowable publications. + */ + public val scroll: Preference = PreferenceDelegate( - getValue = { preferences.spreads }, - getEffectiveValue = { state.settings.spreads }, + getValue = { preferences.scroll }, + getEffectiveValue = { state.settings.scroll }, + getIsEffective = { !state.settings.verticalText }, + updateValue = { value -> updateValues { it.copy(scroll = value) } } + ) + + /** + * Page text alignment. + * + * Only effective when: + * - the publication is reflowable + * - [publisherStyles] is off + * - the layout is LTR or RTL + */ + public val textAlign: EnumPreference = + EnumPreferenceDelegate( + getValue = { preferences.textAlign }, + getEffectiveValue = { state.settings.textAlign }, + getIsEffective = ::isTextAlignEffective, + updateValue = { value -> updateValues { it.copy(textAlign = value) } }, + supportedValues = listOf( + TextAlign.START, + TextAlign.LEFT, + TextAlign.RIGHT, + TextAlign.JUSTIFY + ) + ) + + /** + * Default page text color. + * + * When unset, the current [theme] text color is effective. + * Only effective with reflowable publications. + */ + public val textColor: Preference = + PreferenceDelegate( + getValue = { preferences.textColor }, + getEffectiveValue = { + state.settings.textColor ?: Color( + (theme.value ?: theme.effectiveValue).contentColor + ) + }, + getIsEffective = { preferences.textColor != null }, + updateValue = { value -> updateValues { it.copy(textColor = value) } } + ) + + /** + * Normalize text styles to increase accessibility. + * + * Only effective with reflowable publications. + */ + public val textNormalization: Preference = + PreferenceDelegate( + getValue = { preferences.textNormalization }, + getEffectiveValue = { state.settings.textNormalization }, + getIsEffective = { true }, + updateValue = { value -> updateValues { it.copy(textNormalization = value) } } + ) + + /** + * Reader theme (light, dark, sepia). + * + * Only effective with reflowable publications. + */ + public val theme: EnumPreference = + EnumPreferenceDelegate( + getValue = { preferences.theme }, + getEffectiveValue = { state.settings.theme }, getIsEffective = { true }, - updateValue = { value -> updateValues { it.copy(spreads = value) } } + updateValue = { value -> updateValues { it.copy(theme = value) } }, + supportedValues = listOf(Theme.LIGHT, Theme.DARK, Theme.SEPIA) ) - private fun updateValues( - updater: (ReflowableWebPreferences) -> ReflowableWebPreferences, - ) { + /** + * Indicates whether the text should be laid out vertically. This is used for example with CJK + * languages. This setting is automatically derived from the language if no preference is given. + * + * Only effective with reflowable publications. + */ + public val verticalText: Preference = + PreferenceDelegate( + getValue = { preferences.verticalText }, + getEffectiveValue = { state.settings.verticalText }, + getIsEffective = { true }, + updateValue = { value -> updateValues { it.copy(verticalText = value) } } + ) + + /** + * Space between words. + * + * Only effective when: + * - the publication is reflowable + * - the layout is LTR + */ + public val wordSpacing: RangePreference = + RangePreferenceDelegate( + getValue = { preferences.wordSpacing }, + getEffectiveValue = { state.settings.wordSpacing ?: 0.0 }, + getIsEffective = ::isWordSpacingEffective, + updateValue = { value -> updateValues { it.copy(wordSpacing = value) } }, + supportedRange = 0.0..1.0, + progressionStrategy = DoubleIncrement(0.1), + valueFormatter = percentFormatter() + ) + + private fun percentFormatter(): (Double) -> String = + { it.format(maximumFractionDigits = 0, percent = true) } + + private fun updateValues(updater: (ReflowableWebPreferences) -> ReflowableWebPreferences) { val newPreferences = updater(preferences) state = newPreferences.toState() } - private fun ReflowableWebPreferences.toState() = - State(preferences = this, settings = settingsResolver.settings(this)) + private fun ReflowableWebPreferences.toState(): State { + val settings = settingsResolver.settings(this) + val layout = Layout.from(settings) + + return State( + preferences = this, + settings = settings, + layout = layout + ) + } + + private fun isHyphensEffective() = + state.layout.stylesheets == Layout.Stylesheets.Default && + !state.settings.publisherStyles && + (preferences.hyphens != null || state.settings.textAlign == TextAlign.JUSTIFY) + + private fun isLetterSpacingEffective() = + state.layout.stylesheets == Layout.Stylesheets.Default && + !state.settings.publisherStyles && + preferences.letterSpacing != null + + private fun isLigaturesEffective() = + state.layout.stylesheets == Layout.Stylesheets.Rtl && + !state.settings.publisherStyles && + preferences.ligatures != null + + private fun isParagraphIndentEffective() = + state.layout.stylesheets in listOf(Layout.Stylesheets.Default, Layout.Stylesheets.Rtl) && + !state.settings.publisherStyles && + preferences.paragraphIndent != null + + private fun isTextAlignEffective() = + state.layout.stylesheets in listOf(Layout.Stylesheets.Default, Layout.Stylesheets.Rtl) && + !state.settings.publisherStyles && + preferences.textAlign != null + + private fun isWordSpacingEffective(): Boolean = + state.layout.stylesheets == Layout.Stylesheets.Default && + !state.settings.publisherStyles && + preferences.wordSpacing != null } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesFilters.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesFilters.kt index dcb5e86a2f..b25014a2f9 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesFilters.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesFilters.kt @@ -17,22 +17,22 @@ public object ReflowableWebSharedPreferencesFilter : PreferencesFilter { override fun filter(preferences: ReflowableWebPreferences): ReflowableWebPreferences = ReflowableWebPreferences( - fit = preferences.fit, readingProgression = preferences.readingProgression, - spreads = preferences.spreads + language = preferences.language, + verticalText = preferences.verticalText ) } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettings.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettings.kt index 08a616e744..3da736b5a3 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettings.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettings.kt @@ -6,14 +6,125 @@ package org.readium.navigator.web.preferences +import org.readium.navigator.web.css.Appearance +import org.readium.navigator.web.css.Color as CssColor +import org.readium.navigator.web.css.FontWeight +import org.readium.navigator.web.css.Hyphens +import org.readium.navigator.web.css.Layout +import org.readium.navigator.web.css.Length +import org.readium.navigator.web.css.Ligatures +import org.readium.navigator.web.css.ReadiumCss +import org.readium.navigator.web.css.TextAlign as CssTextAlign +import org.readium.navigator.web.css.View +import org.readium.r2.navigator.preferences.Color import org.readium.r2.navigator.preferences.Configurable -import org.readium.r2.navigator.preferences.Fit +import org.readium.r2.navigator.preferences.FontFamily +import org.readium.r2.navigator.preferences.ImageFilter import org.readium.r2.navigator.preferences.ReadingProgression +import org.readium.r2.navigator.preferences.Spread +import org.readium.r2.navigator.preferences.TextAlign +import org.readium.r2.navigator.preferences.Theme import org.readium.r2.shared.ExperimentalReadiumApi +import org.readium.r2.shared.util.Either +import org.readium.r2.shared.util.Either.Companion.invoke +import org.readium.r2.shared.util.Language @ExperimentalReadiumApi public data class ReflowableWebSettings( - val fit: Fit, + val backgroundColor: Color?, + val columnCount: Int, + val fontFamily: FontFamily?, + val fontSize: Double, + val fontWeight: Double?, + val hyphens: Boolean?, + val imageFilter: ImageFilter?, + val language: Language?, + val letterSpacing: Double?, + val ligatures: Boolean?, + val lineHeight: Double?, + val paragraphIndent: Double?, + val paragraphSpacing: Double?, + val publisherStyles: Boolean, val readingProgression: ReadingProgression, - val spreads: Boolean, + val scroll: Boolean, + val spread: Spread, + val textAlign: TextAlign?, + val textColor: Color?, + val textNormalization: Boolean, + val theme: Theme, + val verticalText: Boolean, + val wordSpacing: Double?, ) : Configurable.Settings + +@OptIn(ExperimentalReadiumApi::class) +internal fun ReadiumCss.update(settings: ReflowableWebSettings, useReadiumCssFontSize: Boolean): ReadiumCss { + fun resolveFontStack(fontFamily: String): List = buildList { + add(fontFamily) + + val alternates = fontFamilyDeclarations + .firstOrNull { it.fontFamily == fontFamily } + ?.alternates + ?: emptyList() + + addAll(alternates.flatMap(::resolveFontStack)) + } + + fun FontFamily.toCss(): List = + resolveFontStack(name) + + fun Color.toCss(): CssColor = + CssColor.Int(int) + + return with(settings) { + copy( + layout = Layout.from(settings), + userProperties = userProperties.copy( + view = when (scroll) { + false -> View.PAGED + true -> View.SCROLL + }, + colCount = columnCount, + appearance = when (theme) { + Theme.LIGHT -> null + Theme.DARK -> Appearance.NIGHT + Theme.SEPIA -> Appearance.SEPIA + }, + darkenImages = imageFilter == ImageFilter.DARKEN, + invertImages = imageFilter == ImageFilter.INVERT, + textColor = textColor?.toCss(), + backgroundColor = backgroundColor?.toCss(), + fontOverride = (fontFamily != null || textNormalization), + fontFamily = fontFamily?.toCss(), + fontSize = if (useReadiumCssFontSize) { + Length.Percent(fontSize) + } else { + null + }, + advancedSettings = !publisherStyles, + textAlign = when (textAlign) { + TextAlign.JUSTIFY -> CssTextAlign.JUSTIFY + TextAlign.LEFT -> CssTextAlign.LEFT + TextAlign.RIGHT -> CssTextAlign.RIGHT + TextAlign.START, TextAlign.CENTER, TextAlign.END -> CssTextAlign.START + null -> null + }, + lineHeight = lineHeight?.let { Either(it) }, + paraSpacing = paragraphSpacing?.let { Length.Rem(it) }, + paraIndent = paragraphIndent?.let { Length.Rem(it) }, + wordSpacing = wordSpacing?.let { Length.Rem(it) }, + letterSpacing = letterSpacing?.let { Length.Rem(it / 2) }, + bodyHyphens = hyphens?.let { if (it) Hyphens.AUTO else Hyphens.NONE }, + ligatures = ligatures?.let { if (it) Ligatures.COMMON else Ligatures.NONE }, + a11yNormalize = textNormalization, + overrides = mapOf( + "font-weight" to + if (fontWeight != null) { + (FontWeight.NORMAL.value * fontWeight).toInt().coerceIn(1, 1000).toString() + } else { + "" + } + ) + ) + ) + } +} diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettingsResolver.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettingsResolver.kt index 43792c8e83..314e5a759f 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettingsResolver.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettingsResolver.kt @@ -6,11 +6,15 @@ package org.readium.navigator.web.preferences -import org.readium.r2.navigator.preferences.Fit +import org.readium.navigator.web.util.isCjk +import org.readium.navigator.web.util.isRtl import org.readium.r2.navigator.preferences.ReadingProgression +import org.readium.r2.navigator.preferences.Spread +import org.readium.r2.navigator.preferences.Theme import org.readium.r2.shared.ExperimentalReadiumApi import org.readium.r2.shared.publication.Metadata import org.readium.r2.shared.publication.ReadingProgression as PublicationReadingProgression +import org.readium.r2.shared.util.Language @ExperimentalReadiumApi internal class ReflowableWebSettingsResolver( @@ -19,23 +23,99 @@ internal class ReflowableWebSettingsResolver( ) { fun settings(preferences: ReflowableWebPreferences): ReflowableWebSettings { - val readingProgression: ReadingProgression = - preferences.readingProgression - ?: when (metadata.readingProgression) { - PublicationReadingProgression.LTR -> ReadingProgression.LTR - PublicationReadingProgression.RTL -> ReadingProgression.RTL - else -> null - } ?: defaults.readingProgression - ?: ReadingProgression.LTR + val (language, readingProgression) = resolveReadingProgression(metadata, preferences) + + val verticalPref = preferences.verticalText + val verticalText = resolveVerticalText(verticalPref, language, readingProgression) + + val theme = preferences.theme ?: Theme.LIGHT - val fit = preferences.fit ?: defaults.fit ?: Fit.CONTAIN + var scroll = preferences.scroll ?: defaults.scroll ?: false - val spreads = preferences.spreads ?: defaults.spreads ?: false + // / We disable pagination with vertical text, because CSS columns don't support it properly. + // / See https://github.com/readium/swift-toolkit/discussions/370 + if (verticalText) { + scroll = true + } return ReflowableWebSettings( - fit = fit, + backgroundColor = preferences.backgroundColor, + columnCount = preferences.columnCount ?: defaults.columnCount ?: 1, + fontFamily = preferences.fontFamily, + fontSize = preferences.fontSize ?: defaults.fontSize ?: 1.0, + fontWeight = preferences.fontWeight ?: defaults.fontWeight, + hyphens = preferences.hyphens ?: defaults.hyphens, + imageFilter = preferences.imageFilter ?: defaults.imageFilter, + language = language, + letterSpacing = preferences.letterSpacing ?: defaults.letterSpacing, + ligatures = preferences.ligatures ?: defaults.ligatures, + lineHeight = preferences.lineHeight ?: defaults.lineHeight, + paragraphIndent = preferences.paragraphIndent ?: defaults.paragraphIndent, + paragraphSpacing = preferences.paragraphSpacing ?: defaults.paragraphSpacing, + publisherStyles = preferences.publisherStyles ?: defaults.publisherStyles ?: true, readingProgression = readingProgression, - spreads = spreads + scroll = scroll, + spread = preferences.spread ?: defaults.spread ?: Spread.NEVER, + textAlign = preferences.textAlign ?: defaults.textAlign, + textColor = preferences.textColor, + textNormalization = preferences.textNormalization ?: defaults.textNormalization ?: false, + theme = theme, + verticalText = verticalText, + wordSpacing = preferences.wordSpacing ?: defaults.wordSpacing ) } + + private fun resolveReadingProgression( + metadata: Metadata, + preferences: ReflowableWebPreferences, + ): Pair { + val rpPref = preferences.readingProgression + val langPref = preferences.language + val metadataLanguage = metadata.language + val metadataReadingProgression = metadata.readingProgression + + // Compute language according to the following rule: + // preference value > metadata value > default value > null + val language = langPref + ?: metadataLanguage + ?: defaults.language + + // Compute readingProgression according to the following rule: + // preference value > value inferred from language preference > metadata value + // value inferred from metadata languages > default value > + // value inferred from default language > LTR + val readingProgression = when { + rpPref != null -> + rpPref + langPref != null -> + if (langPref.isRtl) ReadingProgression.RTL else ReadingProgression.LTR + metadataReadingProgression != null -> + when (metadataReadingProgression) { + PublicationReadingProgression.RTL -> ReadingProgression.RTL + PublicationReadingProgression.LTR -> ReadingProgression.LTR + } + metadataLanguage != null -> + if (metadataLanguage.isRtl) ReadingProgression.RTL else ReadingProgression.LTR + defaults.readingProgression != null -> + defaults.readingProgression + defaults.language != null -> + if (defaults.language.isRtl) ReadingProgression.RTL else ReadingProgression.LTR + else -> + ReadingProgression.LTR + } + + return Pair(language, readingProgression) + } + + // Compute verticalText according to the following rule: + // preference value > value computed from resolved language > false + private fun resolveVerticalText( + verticalPreference: Boolean?, + language: Language?, + readingProgression: ReadingProgression, + ) = when { + verticalPreference != null -> verticalPreference + language != null -> language.isCjk && readingProgression == ReadingProgression.RTL + else -> false + } } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt index ce57630073..086070ea1a 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt @@ -61,8 +61,8 @@ internal fun ReflowableResource( publicationBaseUrl: AbsoluteUrl, webViewClient: WebViewClient, displayArea: DisplayArea, - userProperties: UserProperties, reverseLayout: Boolean, + userProperties: UserProperties, rsProperties: RsProperties, onTap: (TapEvent) -> Unit, onLinkActivated: (Url, String) -> Unit, diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/util/Language.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/util/Language.kt index 881188e6e9..d42ea6c589 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/util/Language.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/util/Language.kt @@ -4,8 +4,6 @@ * available in the top-level LICENSE file of the project. */ -@file:Suppress("unused") - package org.readium.navigator.web.util import org.readium.r2.shared.util.Language From 7d6c6fd60f85861b9735a37845ede3883bab0423 Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Tue, 10 Dec 2024 18:32:30 +0100 Subject: [PATCH 03/88] Upgrade to Readium CSS2 and fix snapping bug --- Makefile | 3 +- .../demo/preferences/UserPreferences.kt | 1 + readium/navigators/web/scripts/package.json | 3 +- readium/navigators/web/scripts/pnpm-lock.yaml | 7 + .../scripts/public/fixed-double-index.html | 2 +- .../scripts/public/fixed-single-index.html | 2 +- .../navigators/web/scripts/webpack.config.js | 5 +- .../{ => generated}/fixed-double-index.html | 2 +- .../{ => generated}/fixed-double-script.js | 0 .../fixed-double-script.js.map | 0 .../fixed-injectable-script.js | 0 .../fixed-injectable-script.js.map | 0 .../{ => generated}/fixed-single-index.html | 2 +- .../{ => generated}/fixed-single-script.js | 0 .../fixed-single-script.js.map | 0 .../web/{ => generated}/readium-css/ReadMe.md | 18 +- .../readium-css/ReadiumCSS-after.css | 542 ++++++++++++++++++ .../readium-css/ReadiumCSS-before.css | 425 ++++++++++++++ .../readium-css/ReadiumCSS-default.css | 152 +++++ .../ReadiumCSS-ebpaj_fonts_patch.css | 79 +++ .../readium-css/android-fonts-patch/ReadMe.md | 22 + .../android-fonts-patch.css | 136 +++++ .../sans-serif/GNU General Public License.txt | 340 +++++++++++ .../sans-serif/NimbusSans-Bold.woff | Bin 0 -> 87656 bytes .../sans-serif/NimbusSans-BoldItalic.woff | Bin 0 -> 92752 bytes .../sans-serif/NimbusSans-Italic.woff | Bin 0 -> 97380 bytes .../sans-serif/NimbusSans.woff | Bin 0 -> 90032 bytes .../serif/GNU General Public License.txt | 340 +++++++++++ .../serif/NimbusRoman-Bold.woff | Bin 0 -> 109832 bytes .../serif/NimbusRoman-BoldItalic.woff | Bin 0 -> 116532 bytes .../serif/NimbusRoman-Italic.woff | Bin 0 -> 115832 bytes .../serif/NimbusRoman.woff | Bin 0 -> 106680 bytes .../cjk-horizontal/ReadiumCSS-after.css | 428 ++++++++++++++ .../cjk-horizontal/ReadiumCSS-before.css | 397 +++++++++++++ .../cjk-horizontal/ReadiumCSS-default.css | 170 ++++++ .../cjk-vertical/ReadiumCSS-after.css | 415 ++++++++++++++ .../cjk-vertical/ReadiumCSS-before.css | 397 +++++++++++++ .../cjk-vertical/ReadiumCSS-default.css | 173 ++++++ .../fonts/AccessibleDfA-Bold.woff2 | Bin 0 -> 66864 bytes .../fonts/AccessibleDfA-Italic.woff2 | Bin 0 -> 73504 bytes .../fonts/AccessibleDfA-Regular.woff | Bin 0 -> 89336 bytes .../fonts/AccessibleDfA-Regular.woff2 | Bin 0 -> 65592 bytes .../readium-css/fonts/LICENSE-AccessibleDfa | 0 .../fonts/LICENSE-IaWriterDuospace.md | 0 .../fonts/iAWriterDuospace-Regular.ttf | Bin .../readium-css/rtl/ReadiumCSS-after.css | 452 +++++++++++++++ .../readium-css/rtl/ReadiumCSS-before.css | 397 +++++++++++++ .../readium-css/rtl/ReadiumCSS-default.css | 152 +++++ .../reflowable-injectable-script.js | 0 .../reflowable-injectable-script.js.map | 0 .../web/prepaginated-double-index.html | 48 -- .../web/prepaginated-single-index.html | 39 -- .../web/readium-css/ReadiumCSS-after.css | 7 - .../web/readium-css/ReadiumCSS-before.css | 7 - .../web/readium-css/ReadiumCSS-default.css | 7 - .../ReadiumCSS-ebpaj_fonts_patch.css | 80 --- .../cjk-horizontal/ReadiumCSS-after.css | 7 - .../cjk-horizontal/ReadiumCSS-before.css | 7 - .../cjk-horizontal/ReadiumCSS-default.css | 7 - .../cjk-vertical/ReadiumCSS-after.css | 7 - .../cjk-vertical/ReadiumCSS-before.css | 7 - .../cjk-vertical/ReadiumCSS-default.css | 7 - .../web/readium-css/fonts/AccessibleDfA.otf | Bin 145384 -> 0 bytes .../web/readium-css/rtl/ReadiumCSS-after.css | 7 - .../web/readium-css/rtl/ReadiumCSS-before.css | 7 - .../readium-css/rtl/ReadiumCSS-default.css | 7 - .../navigator/web/FixedWebRenditionState.kt | 2 +- .../web/ReflowableWebRenditionState.kt | 7 +- .../readium/navigator/web/css/Properties.kt | 2 +- .../web/preferences/ReflowableWebDefaults.kt | 1 + .../preferences/ReflowableWebPreferences.kt | 4 + .../ReflowableWebPreferencesEditor.kt | 17 + .../web/preferences/ReflowableWebSettings.kt | 4 + .../ReflowableWebSettingsResolver.kt | 1 + .../navigator/web/util/HtmlInjector.kt | 4 +- .../navigator/web/webapi/FixedDoubleApi.kt | 2 +- .../navigator/web/webapi/FixedSingleApi.kt | 2 +- .../navigator/web/webview/RelaxedWebView.kt | 2 +- 78 files changed, 5088 insertions(+), 273 deletions(-) rename readium/navigators/web/src/main/assets/readium/navigators/web/{ => generated}/fixed-double-index.html (91%) rename readium/navigators/web/src/main/assets/readium/navigators/web/{ => generated}/fixed-double-script.js (100%) rename readium/navigators/web/src/main/assets/readium/navigators/web/{ => generated}/fixed-double-script.js.map (100%) rename readium/navigators/web/src/main/assets/readium/navigators/web/{ => generated}/fixed-injectable-script.js (100%) rename readium/navigators/web/src/main/assets/readium/navigators/web/{ => generated}/fixed-injectable-script.js.map (100%) rename readium/navigators/web/src/main/assets/readium/navigators/web/{ => generated}/fixed-single-index.html (85%) rename readium/navigators/web/src/main/assets/readium/navigators/web/{ => generated}/fixed-single-script.js (100%) rename readium/navigators/web/src/main/assets/readium/navigators/web/{ => generated}/fixed-single-script.js.map (100%) rename readium/navigators/web/src/main/assets/readium/navigators/web/{ => generated}/readium-css/ReadMe.md (92%) create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-after.css create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-before.css create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-default.css create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-ebpaj_fonts_patch.css create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/ReadMe.md create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/android-fonts-patch.css create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/sans-serif/GNU General Public License.txt create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/sans-serif/NimbusSans-Bold.woff create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/sans-serif/NimbusSans-BoldItalic.woff create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/sans-serif/NimbusSans-Italic.woff create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/sans-serif/NimbusSans.woff create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/serif/GNU General Public License.txt create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/serif/NimbusRoman-Bold.woff create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/serif/NimbusRoman-BoldItalic.woff create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/serif/NimbusRoman-Italic.woff create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/serif/NimbusRoman.woff create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-horizontal/ReadiumCSS-after.css create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-horizontal/ReadiumCSS-before.css create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-horizontal/ReadiumCSS-default.css create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-vertical/ReadiumCSS-after.css create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-vertical/ReadiumCSS-before.css create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-vertical/ReadiumCSS-default.css create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/fonts/AccessibleDfA-Bold.woff2 create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/fonts/AccessibleDfA-Italic.woff2 create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/fonts/AccessibleDfA-Regular.woff create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/fonts/AccessibleDfA-Regular.woff2 rename readium/navigators/web/src/main/assets/readium/navigators/web/{ => generated}/readium-css/fonts/LICENSE-AccessibleDfa (100%) mode change 100755 => 100644 rename readium/navigators/web/src/main/assets/readium/navigators/web/{ => generated}/readium-css/fonts/LICENSE-IaWriterDuospace.md (100%) mode change 100755 => 100644 rename readium/navigators/web/src/main/assets/readium/navigators/web/{ => generated}/readium-css/fonts/iAWriterDuospace-Regular.ttf (100%) mode change 100755 => 100644 create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/rtl/ReadiumCSS-after.css create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/rtl/ReadiumCSS-before.css create mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/rtl/ReadiumCSS-default.css rename readium/navigators/web/src/main/assets/readium/navigators/web/{ => generated}/reflowable-injectable-script.js (100%) rename readium/navigators/web/src/main/assets/readium/navigators/web/{ => generated}/reflowable-injectable-script.js.map (100%) delete mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/prepaginated-double-index.html delete mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/prepaginated-single-index.html delete mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadiumCSS-after.css delete mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadiumCSS-before.css delete mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadiumCSS-default.css delete mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadiumCSS-ebpaj_fonts_patch.css delete mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-horizontal/ReadiumCSS-after.css delete mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-horizontal/ReadiumCSS-before.css delete mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-horizontal/ReadiumCSS-default.css delete mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-vertical/ReadiumCSS-after.css delete mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-vertical/ReadiumCSS-before.css delete mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-vertical/ReadiumCSS-default.css delete mode 100755 readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/fonts/AccessibleDfA.otf delete mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/rtl/ReadiumCSS-after.css delete mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/rtl/ReadiumCSS-before.css delete mode 100644 readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/rtl/ReadiumCSS-default.css diff --git a/Makefile b/Makefile index 03abb520de..5d5db709cf 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,8 @@ scripts-new: pnpm run format; \ pnpm run lint; \ pnpm run bundle; \ - mv dist/* ../src/main/assets/readium/navigators/web/ + rm -r ../src/main/assets/readium/navigators/web/generated/*; \ + mv dist/* ../src/main/assets/readium/navigators/web/generated/ .PHONY: scripts scripts: scripts-legacy scripts-new diff --git a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/preferences/UserPreferences.kt b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/preferences/UserPreferences.kt index 57ea7529ac..506671b1f1 100644 --- a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/preferences/UserPreferences.kt +++ b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/preferences/UserPreferences.kt @@ -104,6 +104,7 @@ fun

, S : Settings, E : PreferencesEditor> UserPreferen letterSpacing = editor.letterSpacing, ligatures = editor.ligatures, lineHeight = editor.lineHeight, + pageMargins = editor.pageMargins, paragraphIndent = editor.paragraphIndent, paragraphSpacing = editor.paragraphSpacing, publisherStyles = editor.publisherStyles, diff --git a/readium/navigators/web/scripts/package.json b/readium/navigators/web/scripts/package.json index b9670beee1..80ad0d93dc 100644 --- a/readium/navigators/web/scripts/package.json +++ b/readium/navigators/web/scripts/package.json @@ -26,7 +26,8 @@ "prettier": "2.3.1", "vite": "^5.4.1", "webpack": "^5.88.2", - "webpack-cli": "^5.1.4" + "webpack-cli": "^5.1.4", + "@readium/css": "2.0.0-alpha.5" }, "dependencies": { "approx-string-match": "^1.1.0", diff --git a/readium/navigators/web/scripts/pnpm-lock.yaml b/readium/navigators/web/scripts/pnpm-lock.yaml index 3ba6fb5827..14a0c197b7 100644 --- a/readium/navigators/web/scripts/pnpm-lock.yaml +++ b/readium/navigators/web/scripts/pnpm-lock.yaml @@ -31,6 +31,9 @@ devDependencies: '@babel/preset-env': specifier: ^7.22.20 version: 7.22.20(@babel/core@7.23.0) + '@readium/css': + specifier: 2.0.0-alpha.5 + version: 2.0.0-alpha.5 '@typescript-eslint/eslint-plugin': specifier: ^8.3.0 version: 8.3.0(@typescript-eslint/parser@8.3.0)(eslint@8.57.0)(typescript@5.5.4) @@ -1550,6 +1553,10 @@ packages: fastq: 1.17.1 dev: true + /@readium/css@2.0.0-alpha.5: + resolution: {integrity: sha512-m3wC4z8lO0ny9k+SuCUpuAWDF4rF3FnfSvYXMUfQb4yYUGi5YEMzVIFPiexs3gDUU2JtpVPGXDAVZmTmRbSjPQ==} + dev: true + /@rollup/rollup-android-arm-eabi@4.20.0: resolution: {integrity: sha512-TSpWzflCc4VGAUJZlPpgAJE1+V60MePDQnBd7PPkpuEmOy8i87aL6tinFGKBFKuEDikYpig72QzdT3QPYIi+oA==} cpu: [arm] diff --git a/readium/navigators/web/scripts/public/fixed-double-index.html b/readium/navigators/web/scripts/public/fixed-double-index.html index 0a15204dda..8ee3bb9a60 100644 --- a/readium/navigators/web/scripts/public/fixed-double-index.html +++ b/readium/navigators/web/scripts/public/fixed-double-index.html @@ -52,6 +52,6 @@ - + diff --git a/readium/navigators/web/scripts/public/fixed-single-index.html b/readium/navigators/web/scripts/public/fixed-single-index.html index 4c8982b165..20ab2af950 100644 --- a/readium/navigators/web/scripts/public/fixed-single-index.html +++ b/readium/navigators/web/scripts/public/fixed-single-index.html @@ -34,6 +34,6 @@ - + diff --git a/readium/navigators/web/scripts/webpack.config.js b/readium/navigators/web/scripts/webpack.config.js index 67619f3fb8..36c7f6a0e8 100644 --- a/readium/navigators/web/scripts/webpack.config.js +++ b/readium/navigators/web/scripts/webpack.config.js @@ -35,7 +35,10 @@ module.exports = { }, plugins: [ new CopyPlugin({ - patterns: [{ from: "public" }], + patterns: [ + { from: "public" }, + { from: "node_modules/@readium/css/css/dist", to: "readium-css" }, + ], }), ], } diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/fixed-double-index.html b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-double-index.html similarity index 91% rename from readium/navigators/web/src/main/assets/readium/navigators/web/fixed-double-index.html rename to readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-double-index.html index 0a15204dda..8ee3bb9a60 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/fixed-double-index.html +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-double-index.html @@ -52,6 +52,6 @@ - + diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/fixed-double-script.js b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-double-script.js similarity index 100% rename from readium/navigators/web/src/main/assets/readium/navigators/web/fixed-double-script.js rename to readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-double-script.js diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/fixed-double-script.js.map b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-double-script.js.map similarity index 100% rename from readium/navigators/web/src/main/assets/readium/navigators/web/fixed-double-script.js.map rename to readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-double-script.js.map diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/fixed-injectable-script.js b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-injectable-script.js similarity index 100% rename from readium/navigators/web/src/main/assets/readium/navigators/web/fixed-injectable-script.js rename to readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-injectable-script.js diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/fixed-injectable-script.js.map b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-injectable-script.js.map similarity index 100% rename from readium/navigators/web/src/main/assets/readium/navigators/web/fixed-injectable-script.js.map rename to readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-injectable-script.js.map diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/fixed-single-index.html b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-single-index.html similarity index 85% rename from readium/navigators/web/src/main/assets/readium/navigators/web/fixed-single-index.html rename to readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-single-index.html index 4c8982b165..20ab2af950 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/fixed-single-index.html +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-single-index.html @@ -34,6 +34,6 @@ - + diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/fixed-single-script.js b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-single-script.js similarity index 100% rename from readium/navigators/web/src/main/assets/readium/navigators/web/fixed-single-script.js rename to readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-single-script.js diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/fixed-single-script.js.map b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-single-script.js.map similarity index 100% rename from readium/navigators/web/src/main/assets/readium/navigators/web/fixed-single-script.js.map rename to readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-single-script.js.map diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadMe.md b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadMe.md similarity index 92% rename from readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadMe.md rename to readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadMe.md index b9d6ef6ee4..518fe6289e 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadMe.md +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadMe.md @@ -25,7 +25,6 @@ Finally, page progression is impacted: Disabled user settings: - `hyphens`; -- `word-spacing`; - `letter-spacing`. Added user settings: @@ -54,8 +53,11 @@ Disabled user settings: - `text-align`; - `hyphens`; - paragraphs’ indent; -- `word-spacing`; -- `letter-spacing`. +- `word-spacing`. + +Added user settings: + +- hiding/disabling ruby (mapped to `--USER__noRuby: readium-noRuby-on` flag). ### Vertical @@ -87,8 +89,11 @@ Disabled user settings: - `text-align`; - `hyphens`; - paragraphs’ indent; -- `word-spacing`; -- `letter-spacing`. +- `word-spacing`. + +Added user settings: + +- hiding/disabling ruby (mapped to `--USER__noRuby: readium-noRuby-on` flag). ### EBPAJ Polyfill @@ -110,3 +115,6 @@ This is currently an edge case as we still have to see whether we want to suppor - if `mn-Cyrl` is set, then the publication is in cyrillic and it is `horizontal-tb`. - We don’t currently support the `mn` language, and we can’t rely on system fonts to do so, we’ll have to embed one. +## Android Fonts Patch + +See [the specific ReadMe](android-fonts-patch/ReadMe.md) for further information. \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-after.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-after.css new file mode 100644 index 0000000000..5b9090a12c --- /dev/null +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-after.css @@ -0,0 +1,542 @@ +/* + * Readium CSS (v. 2.0.0-alpha.5) + * Developers: Jiminy Panoz + * Copyright (c) 2017. Readium Foundation. All rights reserved. + * Use of this source code is governed by a BSD-style license which is detailed in the + * LICENSE file present in the project repository where this source code is maintained. +*/ + +@namespace url("http://www.w3.org/1999/xhtml"); + +@namespace epub url("http://www.idpf.org/2007/ops"); + +@namespace m url("http://www.w3.org/1998/Math/MathML"); + +@namespace svg url("http://www.w3.org/2000/svg"); + +:root{ + --RS__colWidth:100vw; + --RS__colCount:1; + --RS__colGap:0; + --RS__defaultLineLength:40rem; + --RS__pageGutter:0; + --RS__viewportWidth:100%; +} + +@page{ + margin:0 !important; +} + +:root{ + position:relative; + + -webkit-column-width:var(--RS__colWidth); + -moz-column-width:var(--RS__colWidth); + column-width:var(--RS__colWidth); + -webkit-column-count:var(--RS__colCount); + -moz-column-count:var(--RS__colCount); + column-count:var(--RS__colCount); + + -webkit-column-gap:var(--RS__colGap); + -moz-column-gap:var(--RS__colGap); + column-gap:var(--RS__colGap); + -moz-column-fill:auto; + column-fill:auto; + width:var(--RS__viewportWidth); + height:100vh; + max-width:var(--RS__viewportWidth); + max-height:100vh; + min-width:var(--RS__viewportWidth); + min-height:100vh; + padding:0 !important; + margin:0 !important; + font-size:100% !important; + + -webkit-text-size-adjust:100%; + box-sizing:border-box; + -webkit-touch-callout:none; +} + +body{ + width:100%; + max-width:var(--RS__defaultLineLength) !important; + padding:0 var(--RS__pageGutter) !important; + margin:0 auto !important; + overflow:hidden; + box-sizing:border-box; +} + +@supports (overflow: clip){ + + :root{ + overflow:clip; + } + + body{ + overflow:clip; + overflow-clip-margin:content-box; + } +} + +:root[style*="readium-scroll-on"]{ + -webkit-columns:auto auto !important; + -moz-columns:auto auto !important; + columns:auto auto !important; + width:auto !important; + height:auto !important; + max-width:none !important; + max-height:none !important; + min-width:0 !important; + min-height:0 !important; +} + +:root[style*="readium-scroll-on"] body{ + overflow:auto; + --RS__defaultLineLength:40rem !important; +} + +@supports (overflow: clip){ + + :root[style*="readium-scroll-on"]{ + overflow:auto; + } + + :root[style*="readium-scroll-on"] body{ + overflow:clip; + } +} + +:root[style*="readium-night-on"]{ + --RS__backgroundColor:#000000; + --RS__textColor:#FEFEFE; + + --RS__linkColor:#63caff; + --RS__visitedColor:#0099E5; + --RS__selectionBackgroundColor:#b4d8fe; + --RS__selectionTextColor:inherit; +} + +:root[style*="readium-night-on"] *:not(a){ + color:inherit !important; + background-color:transparent !important; + border-color:currentcolor !important; +} + +:root[style*="readium-night-on"] svg text{ + fill:currentcolor !important; + stroke:none !important; +} + +:root[style*="readium-night-on"] a:link, +:root[style*="readium-night-on"] a:link *{ + color:var(--RS__linkColor) !important; +} + +:root[style*="readium-night-on"] a:visited, +:root[style*="readium-night-on"] a:visited *{ + color:var(--RS__visitedColor) !important; +} + +:root[style*="readium-night-on"] img[class*="gaiji"], +:root[style*="readium-night-on"] *[epub\:type~="titlepage"] img:only-child, +:root[style*="readium-night-on"] *[epub|type~="titlepage"] img:only-child{ + -webkit-filter:invert(100%); + filter:invert(100%); +} + +:root[style*="readium-night-on"][style*="readium-darken-on"] img{ + -webkit-filter:brightness(80%); + filter:brightness(80%); +} + +:root[style*="readium-night-on"][style*="readium-invert-on"] img{ + -webkit-filter:invert(100%); + filter:invert(100%); +} + +:root[style*="readium-night-on"][style*="readium-darken-on"][style*="readium-invert-on"] img{ + -webkit-filter:brightness(80%) invert(100%); + filter:brightness(80%) invert(100%); +} + +:root[style*="readium-sepia-on"]{ + --RS__backgroundColor:#faf4e8; + --RS__textColor:#121212; + + --RS__linkColor:#0000EE; + --RS__visitedColor:#551A8B; + --RS__selectionBackgroundColor:#b4d8fe; + --RS__selectionTextColor:inherit; + + --RS__defaultLineLength:40.01rem; +} + +:root[style*="readium-sepia-on"] *:not(a){ + color:inherit !important; + background-color:transparent !important; +} + +:root[style*="readium-sepia-on"] a:link, +:root[style*="readium-sepia-on"] a:link *{ + color:var(--RS__linkColor); +} + +:root[style*="readium-sepia-on"] a:visited, +:root[style*="readium-sepia-on"] a:visited *{ + color:var(--RS__visitedColor); +} + +:root[style*="readium-sepia-on"] svg, +:root[style*="readium-sepia-on"] img{ + background-color:transparent !important; + mix-blend-mode:multiply; +} + +@media screen and (-ms-high-contrast: active){ + + :root{ + color:windowText !important; + background-color:window !important; + } + + :root :not(#\#):not(#\#):not(#\#), + :root :not(#\#):not(#\#):not(#\#) :not(#\#):not(#\#):not(#\#) + :root :not(#\#):not(#\#):not(#\#) :not(#\#):not(#\#):not(#\#) :not(#\#):not(#\#):not(#\#){ + color:inherit !important; + background-color:inherit !important; + } + + .readiumCSS-mo-active-default{ + color:highlightText !important; + background-color:highlight !important; + } +} + +@media screen and (-ms-high-contrast: white-on-black){ + + :root[style*="readium-night-on"] img[class*="gaiji"], + :root[style*="readium-night-on"] *[epub\:type~="titlepage"] img:only-child, + :root[style*="readium-night-on"] *[epub|type~="titlepage"] img:only-child{ + -webkit-filter:none !important; + filter:none !important; + } + + :root[style*="readium-night-on"][style*="readium-invert-on"] img{ + -webkit-filter:none !important; + filter:none !important; + } + + :root[style*="readium-night-on"][style*="readium-darken-on"][style*="readium-invert-on"] img{ + -webkit-filter:brightness(80%); + filter:brightness(80%); + } +} + +@media screen and (inverted-colors){ + + :root[style*="readium-night-on"] img[class*="gaiji"], + :root[style*="readium-night-on"] *[epub\:type~="titlepage"] img:only-child, + :root[style*="readium-night-on"] *[epub|type~="titlepage"] img:only-child{ + -webkit-filter:none !important; + filter:none !important; + } + + :root[style*="readium-night-on"][style*="readium-invert-on"] img{ + -webkit-filter:none !important; + filter:none !important; + } + + :root[style*="readium-night-on"][style*="readium-darken-on"][style*="readium-invert-on"] img{ + -webkit-filter:brightness(80%); + filter:brightness(80%); + } +} + +@media screen and (monochrome){ +} + +@media screen and (prefers-reduced-motion){ +} + +:root[style*="--USER__colCount"]{ + -webkit-column-count:var(--USER__colCount); + -moz-column-count:var(--USER__colCount); + column-count:var(--USER__colCount); + + --RS__colWidth:auto; +} + +:root[style*="--USER__colCount: 0"], +:root[style*="--USER__colCount:0"]{ + -webkit-column-count:1; + -moz-column-count:1; + column-count:1; +} + +:root[style*="--USER__colCount: 0"], +:root[style*="--USER__colCount:0"], +:root[style*="--USER__colCount: 1"], +:root[style*="--USER__colCount:1"]{ + --RS__colWidth:100vw; +} + +:root[style*="--USER__lineLength"] body{ + max-width:var(--USER__lineLength) !important; + } + +:root[style*="--USER__backgroundColor"]{ + background-color:var(--USER__backgroundColor) !important; +} + +:root[style*="--USER__backgroundColor"] *{ + background-color:transparent !important; +} + +:root[style*="--USER__textColor"]{ + color:var(--USER__textColor) !important; +} + +:root[style*="--USER__textColor"] *:not(h1):not(h2):not(h3):not(h4):not(h5):not(h6):not(pre){ + color:inherit !important; +} + +:root[style*="readium-advanced-on"][style*="--USER__textAlign"]{ + text-align:var(--USER__textAlign); +} + +:root[style*="readium-advanced-on"][style*="--USER__textAlign"] body, +:root[style*="readium-advanced-on"][style*="--USER__textAlign"] *:not(blockquote):not(figcaption) p, +:root[style*="readium-advanced-on"][style*="--USER__textAlign"] li{ + text-align:var(--USER__textAlign) !important; + -moz-text-align-last:auto !important; + -epub-text-align-last:auto !important; + text-align-last:auto !important; +} + +:root[style*="readium-advanced-on"][style*="--USER__textAlign: justify"] body, +:root[style*="readium-advanced-on"][style*="--USER__textAlign:justify"] body{ + -webkit-hyphens:auto; + -moz-hyphens:auto; + -ms-hyphens:auto; + -epub-hyphens:auto; + hyphens:auto; +} + +:root[style*="readium-advanced-on"][style*="--USER__textAlign: left"] body, +:root[style*="readium-advanced-on"][style*="--USER__textAlign:left"] body, +:root[style*="readium-advanced-on"][style*="--USER__textAlign: right"] body, +:root[style*="readium-advanced-on"][style*="--USER__textAlign:right"] body{ + -webkit-hyphens:none; + -moz-hyphens:none; + -ms-hyphens:none; + -epub-hyphens:none; + hyphens:none; +} + +:root[style*="readium-advanced-on"][style*="--USER__bodyHyphens"]{ + -webkit-hyphens:var(--USER__bodyHyphens) !important; + -moz-hyphens:var(--USER__bodyHyphens) !important; + -ms-hyphens:var(--USER__bodyHyphens) !important; + -epub-hyphens:var(--USER__bodyHyphens) !important; + hyphens:var(--USER__bodyHyphens) !important; +} + +:root[style*="readium-advanced-on"][style*="--USER__bodyHyphens"] body, +:root[style*="readium-advanced-on"][style*="--USER__bodyHyphens"] p, +:root[style*="readium-advanced-on"][style*="--USER__bodyHyphens"] li, +:root[style*="readium-advanced-on"][style*="--USER__bodyHyphens"] div, +:root[style*="readium-advanced-on"][style*="--USER__bodyHyphens"] dd{ + -webkit-hyphens:inherit; + -moz-hyphens:inherit; + -ms-hyphens:inherit; + -epub-hyphens:inherit; + hyphens:inherit; +} + +:root[style*="readium-font-on"][style*="--USER__fontFamily"]{ + font-family:var(--USER__fontFamily) !important; +} + +:root[style*="readium-font-on"][style*="--USER__fontFamily"] *:not(code):not(var):not(kbd):not(samp){ + font-family:inherit !important; +} + +:root[style*="readium-font-on"][style*="AccessibleDfA"]{ + font-family:AccessibleDfA, Verdana, Tahoma, "Trebuchet MS", sans-serif !important; + --RS__lineHeightCompensation:1.167; +} + +:root[style*="readium-font-on"][style*="IA Writer Duospace"]{ + font-family:"IA Writer Duospace", Menlo, "DejaVu Sans Mono", "Bitstream Vera Sans Mono", Courier, monospace !important; + --RS__lineHeightCompensation:1.167; +} + +:root[style*="readium-font-on"][style*="readium-a11y-on"]{ + font-family:var(--USER__fontFamily) !important; + --RS__lineHeightCompensation:1.167; +} + +:root[style*="readium-font-on"][style*="AccessibleDfA"],:root[style*="readium-font-on"][style*="IA Writer Duospace"], +:root[style*="readium-font-on"][style*="readium-a11y-on"]{ + font-style:normal !important; + font-weight:normal !important; +} + +:root[style*="readium-font-on"][style*="AccessibleDfA"] *:not(code):not(var):not(kbd):not(samp),:root[style*="readium-font-on"][style*="IA Writer Duospace"] *:not(code):not(var):not(kbd):not(samp), +:root[style*="readium-font-on"][style*="readium-a11y-on"] *:not(code):not(var):not(kbd):not(samp){ + font-family:inherit !important; + font-style:inherit !important; + font-weight:inherit !important; +} + +:root[style*="readium-font-on"][style*="AccessibleDfA"] *,:root[style*="readium-font-on"][style*="IA Writer Duospace"] *, +:root[style*="readium-font-on"][style*="readium-a11y-on"] *{ + text-decoration:none !important; + font-variant-caps:normal !important; + font-variant-numeric:normal !important; + font-variant-position:normal !important; +} + +:root[style*="readium-font-on"][style*="AccessibleDfA"] sup,:root[style*="readium-font-on"][style*="IA Writer Duospace"] sup, +:root[style*="readium-font-on"][style*="readium-a11y-on"] sup, +:root[style*="readium-font-on"][style*="AccessibleDfA"] sub, +:root[style*="readium-font-on"][style*="IA Writer Duospace"] sub, +:root[style*="readium-font-on"][style*="readium-a11y-on"] sub{ + font-size:1rem !important; + vertical-align:baseline !important; +} + +:root[style*="--USER__fontSize"]{ + zoom:var(--USER__fontSize) !important; +} + +@supports not (zoom: 1){ + + :root[style*="--USER__fontSize"]{ + font-size:var(--USER__fontSize) !important; + } +} + +:root[style*="readium-advanced-on"][style*="--USER__lineHeight"]{ + line-height:var(--USER__lineHeight) !important; +} + +:root[style*="readium-advanced-on"][style*="--USER__lineHeight"] body, +:root[style*="readium-advanced-on"][style*="--USER__lineHeight"] p, +:root[style*="readium-advanced-on"][style*="--USER__lineHeight"] li, +:root[style*="readium-advanced-on"][style*="--USER__lineHeight"] div{ + line-height:inherit; +} + +:root[style*="readium-advanced-on"][style*="--USER__paraSpacing"] p{ + margin-top:var(--USER__paraSpacing) !important; + margin-bottom:var(--USER__paraSpacing) !important; +} + +:root[style*="readium-advanced-on"][style*="--USER__paraIndent"] p{ + text-indent:var(--USER__paraIndent) !important; +} + +:root[style*="readium-advanced-on"][style*="--USER__paraIndent"] p *, +:root[style*="readium-advanced-on"][style*="--USER__paraIndent"] p:first-letter{ + text-indent:0 !important; +} + +:root[style*="readium-advanced-on"][style*="--USER__wordSpacing"] h1, +:root[style*="readium-advanced-on"][style*="--USER__wordSpacing"] h2, +:root[style*="readium-advanced-on"][style*="--USER__wordSpacing"] h3, +:root[style*="readium-advanced-on"][style*="--USER__wordSpacing"] h4, +:root[style*="readium-advanced-on"][style*="--USER__wordSpacing"] h5, +:root[style*="readium-advanced-on"][style*="--USER__wordSpacing"] h6, +:root[style*="readium-advanced-on"][style*="--USER__wordSpacing"] p, +:root[style*="readium-advanced-on"][style*="--USER__wordSpacing"] li, +:root[style*="readium-advanced-on"][style*="--USER__wordSpacing"] div{ + word-spacing:var(--USER__wordSpacing); +} + +:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] h1, +:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] h2, +:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] h3, +:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] h4, +:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] h5, +:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] h6, +:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] p, +:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] li, +:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] div{ + letter-spacing:var(--USER__letterSpacing); + font-variant:none; +} + +:root[style*="readium-font-on"][style*="--USER__fontWeight"] body{ + font-weight:var(--USER__fontWeight) !important; +} + +:root[style*="readium-font-on"][style*="--USER__fontWeight"] b, +:root[style*="readium-font-on"][style*="--USER__fontWeight"] strong{ + font-weight:bolder; +} + +:root[style*="readium-font-on"][style*="--USER__fontWidth"] body{ + font-stretch:var(--USER__fontWidth) !important; +} + +:root[style*="readium-font-on"][style*="--USER__fontOpticalSizing"] body{ + font-optical-sizing:var(--USER__fontOpticalSizing) !important; +} + +@supports not (zoom: 1){ + + :root[style*="readium-advanced-on"]{ + --USER__typeScale:1.2; + } + + :root[style*="readium-advanced-on"] p, + :root[style*="readium-advanced-on"] li, + :root[style*="readium-advanced-on"] div, + :root[style*="readium-advanced-on"] pre, + :root[style*="readium-advanced-on"] dd{ + font-size:1rem !important; + } + + :root[style*="readium-advanced-on"] h1{ + font-size:1.75rem !important; + font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important; + } + + :root[style*="readium-advanced-on"] h2{ + font-size:1.5rem !important; + font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important; + } + + :root[style*="readium-advanced-on"] h3{ + font-size:1.25rem !important; + font-size:calc(1rem * var(--USER__typeScale)) !important; + } + + :root[style*="readium-advanced-on"] h4, + :root[style*="readium-advanced-on"] h5, + :root[style*="readium-advanced-on"] h6{ + font-size:1rem !important; + } + + :root[style*="readium-advanced-on"] small{ + font-size:smaller !important; + } + + :root[style*="readium-advanced-on"] sub, + :root[style*="readium-advanced-on"] sup{ + font-size:67.5% !important; + } + + :root[style*="readium-advanced-on"][style*="--USER__typeScale"] h1{ + font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important; + } + + :root[style*="readium-advanced-on"][style*="--USER__typeScale"] h2{ + font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important; + } + + :root[style*="readium-advanced-on"][style*="--USER__typeScale"] h3{ + font-size:calc(1rem * var(--USER__typeScale)) !important; + } +} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-before.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-before.css new file mode 100644 index 0000000000..2c16fe32fd --- /dev/null +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-before.css @@ -0,0 +1,425 @@ +/* + * Readium CSS (v. 2.0.0-alpha.5) + * Developers: Jiminy Panoz + * Copyright (c) 2017. Readium Foundation. All rights reserved. + * Use of this source code is governed by a BSD-style license which is detailed in the + * LICENSE file present in the project repository where this source code is maintained. +*/ + +@namespace url("http://www.w3.org/1999/xhtml"); + +@namespace epub url("http://www.idpf.org/2007/ops"); + +@namespace m url("http://www.w3.org/1998/Math/MathML"); + +@namespace svg url("http://www.w3.org/2000/svg"); + +@-ms-viewport{ + width:device-width; +} + +@viewport{ + width:device-width; + zoom:1; +} + +:root{ + --RS__oldStyleTf:"Iowan Old Style", sitka, "Sitka Text", palatino, "Book Antiqua", "URW Palladio L", p052, serif; + --RS__modernTf:athelas, constantia, charter, "Bitstream Charter", cambria, "Georgia Pro", georgia, serif; + --RS__sansTf:-ui-sans-serif, -apple-system, system-ui, blinkmacsystemfont, "Segoe UI Variable", "Segoe UI", inter, roboto, "Helvetica Neue", "Arial Nova", "Liberation Sans", arial, sans-serif; + --RS__humanistTf:seravek, calibri, "Gill Sans Nova", roboto, ubuntu, "DejaVu Sans", source-sans-pro, sans-serif; + --RS__monospaceTf:ui-monospace, "Andale Mono", "Cascadia Code", "Source Code Pro", menlo, consolas, "DejaVu Sans Mono", monospace; + --RS__baseFontFamily:var(--RS__oldStyleTf); + --RS__lineHeightCompensation:1; + --RS__baseLineHeight:calc((1em + (2ex - 1ch) - ((1rem - 16px) * 0.1667)) * var(--RS__lineHeightCompensation)); +} + +html{ + font-family:var(--RS__baseFontFamily); + line-height:1.6; + line-height:var(--RS__baseLineHeight); + text-rendering:optimizelegibility; +} + +h1, h2, h3{ + line-height:normal; +} + +:lang(ja), +:lang(zh), +:lang(ko){ + word-wrap:break-word; + -webkit-line-break:strict; + -epub-line-break:strict; + line-break:strict; +} + +math{ + font-family:"Latin Modern Math", "STIX Two Math", "XITS Math", "STIX Math", "Libertinus Math", "TeX Gyre Termes Math", "TeX Gyre Bonum Math", "TeX Gyre Schola", "DejaVu Math TeX Gyre", "TeX Gyre Pagella Math", "Asana Math", "Cambria Math", "Lucida Bright Math", "Minion Math", STIXGeneral, STIXSizeOneSym, Symbol, "Times New Roman", serif; +} + +:lang(am){ + --RS__baseFontFamily:kefa, nyala, roboto, noto, "Noto Sans Ethiopic", serif; + --RS__lineHeightCompensation:1.167; +} + +:lang(ar){ + --RS__baseFontFamily:"Geeza Pro", "Arabic Typesetting", roboto, noto, "Noto Naskh Arabic", "Times New Roman", serif; +} + +:lang(bn){ + --RS__baseFontFamily:"Kohinoor Bangla", "Bangla Sangam MN", vrinda, roboto, noto, "Noto Sans Bengali", sans-serif; + --RS__lineHeightCompensation:1.067; +} + +:lang(bo){ + --RS__baseFontFamily:kailasa, "Microsoft Himalaya", roboto, noto, "Noto Sans Tibetan", sans-serif; +} + +:lang(chr){ + --RS__baseFontFamily:"Plantagenet Cherokee", roboto, noto, "Noto Sans Cherokee"; + --RS__lineHeightCompensation:1.167; +} + +:lang(fa){ + --RS__baseFontFamily:"Geeza Pro", "Arabic Typesetting", roboto, noto, "Noto Naskh Arabic", "Times New Roman", serif; +} + +:lang(gu){ + --RS__baseFontFamily:"Gujarati Sangam MN", "Nirmala UI", shruti, roboto, noto, "Noto Sans Gujarati", sans-serif; + --RS__lineHeightCompensation:1.167; +} + +:lang(he){ + --RS__baseFontFamily:"New Peninim MT", "Arial Hebrew", gisha, "Times New Roman", roboto, noto, "Noto Sans Hebrew" sans-serif; + --RS__lineHeightCompensation:1.1; +} + +:lang(hi){ + --RS__baseFontFamily:"Kohinoor Devanagari", "Devanagari Sangam MN", kokila, "Nirmala UI", roboto, noto, "Noto Sans Devanagari", sans-serif; + + --RS__lineHeightCompensation:1.1; +} + +:lang(hy){ + --RS__baseFontFamily:mshtakan, sylfaen, roboto, noto, "Noto Serif Armenian", serif; +} + +:lang(iu){ + --RS__baseFontFamily:"Euphemia UCAS", euphemia, roboto, noto, "Noto Sans Canadian Aboriginal", sans-serif; +} + +:lang(ja){ + --RS__baseFontFamily:yugothic, "Hiragino Maru Gothic ProN", "Hiragino Sans", "Yu Gothic UI", "Meiryo UI", "MS Gothic", roboto, noto, "Noto Sans CJK JP", sans-serif; + --RS__lineHeightCompensation:1.167; + --RS__serif-ja:"Hiragino Mincho ProN", "Hiragino Mincho Pro", "YuMincho", "BIZ UDPMincho", "Yu Mincho", "MS P明朝", "MS PMincho", serif; + --RS__sans-serif-ja:"Hiragino Sans", "Hiragino Kaku Gothic ProN", "Hiragino Kaku Gothic Pro", "ヒラギノ角ゴ W3", "YuGothic", "Yu Gothic Medium", "BIZ UDPGothic", "Yu Gothic", "MS Pゴシック", "MS PGothic", sans-serif; + --RS__serif-ja-v:"Hiragino Mincho ProN", "Hiragino Mincho Pro", "YuMincho", "BIZ UDMincho", "Yu Mincho", "MS明朝", "MS Mincho", serif; + --RS__sans-serif-ja-v:"Hiragino Sans", "Hiragino Kaku Gothic ProN", "Hiragino Kaku Gothic Pro", "ヒラギノ角ゴ W3", "YuGothic", "Yu Gothic Medium", "BIZ UDGothic", "Yu Gothic", "MSゴシック", "MS Gothic", sans-serif; +} + +:lang(km){ + --RS__baseFontFamily:"Khmer Sangam MN", "Leelawadee UI", "Khmer UI", roboto, noto, "Noto Sans Khmer", sans-serif; + --RS__lineHeightCompensation:1.067; +} + +:lang(kn){ + --RS__baseFontFamily:"Kannada Sangam MN", "Nirmala UI", tunga, roboto, noto, "Noto Sans Kannada", sans-serif; + --RS__lineHeightCompensation:1.1; +} + +:lang(ko){ + --RS__baseFontFamily:"Nanum Gothic", "Apple SD Gothic Neo", "Malgun Gothic", roboto, noto, "Noto Sans CJK KR", sans-serif; + --RS__lineHeightCompensation:1.167; +} + +:lang(lo){ + --RS__baseFontFamily:"Lao Sangam MN", "Leelawadee UI", "Lao UI", roboto, noto, "Noto Sans Lao", sans-serif; +} + +:lang(ml){ + --RS__baseFontFamily:"Malayalam Sangam MN", "Nirmala UI", kartika, roboto, noto, "Noto Sans Malayalam", sans-serif; + --RS__lineHeightCompensation:1.067; +} + +:lang(or){ + --RS__baseFontFamily:"Oriya Sangam MN", "Nirmala UI", kalinga, roboto, noto, "Noto Sans Oriya", sans-serif; + --RS__lineHeightCompensation:1.167; +} + +:lang(pa){ + --RS__baseFontFamily:"Gurmukhi MN", "Nirmala UI", kartika, roboto, noto, "Noto Sans Gurmukhi", sans-serif; + --RS__lineHeightCompensation:1.1; +} + +:lang(si){ + --RS__baseFontFamily:"Sinhala Sangam MN", "Nirmala UI", "Iskoola Pota", roboto, noto, "Noto Sans Sinhala", sans-serif; + --RS__lineHeightCompensation:1.167; +} + +:lang(ta){ + --RS__baseFontFamily:"Tamil Sangam MN", "Nirmala UI", latha, roboto, noto, "Noto Sans Tamil", sans-serif; + --RS__lineHeightCompensation:1.067; +} + +:lang(te){ + --RS__baseFontFamily:"Kohinoor Telugu", "Telugu Sangam MN", "Nirmala UI", gautami, roboto, noto, "Noto Sans Telugu", sans-serif; +} + +:lang(th){ + --RS__baseFontFamily:"Thonburi", "Leelawadee UI", "Cordia New", roboto, noto, "Noto Sans Thai", sans-serif; + --RS__lineHeightCompensation:1.067; +} + +:lang(zh){ + --RS__baseFontFamily:"方体", "PingFang SC", "黑体", "Heiti SC", "Microsoft JhengHei UI", "Microsoft JhengHei", roboto, noto, "Noto Sans CJK SC", sans-serif; + --RS__lineHeightCompensation:1.167; +} + +:lang(zh-Hant), +:lang(zh-TW){ + --RS__baseFontFamily:"方體", "PingFang TC", "黑體", "Heiti TC", "Microsoft JhengHei UI", "Microsoft JhengHei", roboto, noto, "Noto Sans CJK TC", sans-serif; + --RS__lineHeightCompensation:1.167; +} + +:lang(zh-HK){ + --RS__baseFontFamily:"方體", "PingFang HK", "方體", "PingFang TC", "黑體", "Heiti TC", "Microsoft JhengHei UI", "Microsoft JhengHei", roboto, noto, "Noto Sans CJK TC", sans-serif; + --RS__lineHeightCompensation:1.167; +} + +:root{ + --RS__backgroundColor:#FFFFFF; + --RS__textColor:#121212; + --RS__selectionBackgroundColor:#b4d8fe; + --RS__selectionTextColor:inherit; +} + +:root{ + color:var(--RS__textColor) !important; + background-color:var(--RS__backgroundColor) !important; +} + +::-moz-selection{ + color:var(--RS__selectionTextColor); + background-color:var(--RS__selectionBackgroundColor); +} + +::selection{ + color:var(--RS__selectionTextColor); + background-color:var(--RS__selectionBackgroundColor); +} + +@font-face{ + font-family:AccessibleDfA; + font-style:normal; + font-weight:normal; + src:local("AccessibleDfA"), url("fonts/AccessibleDfA-Regular.woff2") format("woff2"), url("fonts/AccessibleDfA-Regular.woff") format("woff"); +} + +@font-face{ + font-family:AccessibleDfA; + font-style:normal; + font-weight:bold; + src:local("AccessibleDfA"), url("fonts/AccessibleDfA-Bold.woff2") format("woff2"); +} + +@font-face{ + font-family:AccessibleDfA; + font-style:italic; + font-weight:normal; + src:local("AccessibleDfA"), url("fonts/AccessibleDfA-Italic.woff2") format("woff2"); +} + +@font-face{ + font-family:"IA Writer Duospace"; + font-style:normal; + font-weight:normal; + src:local("iAWriterDuospace-Regular"), url("fonts/iAWriterDuospace-Regular.ttf") format("truetype"); +} + +body{ + widows:2; + orphans:2; +} + +figcaption, th, td{ + widows:1; + orphans:1; +} + +h2, h3, h4, h5, h6, dt, +hr, caption{ + -webkit-column-break-after:avoid; + page-break-after:avoid; + break-after:avoid; +} + +h1, h2, h3, h4, h5, h6, dt, +figure, tr{ + -webkit-column-break-inside:avoid; + page-break-inside:avoid; + break-inside:avoid; +} + +body{ + -webkit-hyphenate-character:"\002D"; + -moz-hyphenate-character:"\002D"; + -ms-hyphenate-character:"\002D"; + hyphenate-character:"\002D"; + -webkit-hyphenate-limit-lines:3; + -ms-hyphenate-limit-lines:3; + hyphenate-limit-lines:3; +} + +h1, h2, h3, h4, h5, h6, dt, +figcaption, pre, caption, address, +center, code, var{ + -ms-hyphens:none; + -moz-hyphens:none; + -webkit-hyphens:none; + -epub-hyphens:none; + hyphens:none; +} + +body{ + font-variant-numeric:oldstyle-nums proportional-nums; +} + +:lang(ja) body, +:lang(zh) body, +:lang(ko) body{ + font-variant-numeric:lining-nums proportional-nums; +} + +h1, h2, h3, h4, h5, h6, dt{ + font-variant-numeric:lining-nums proportional-nums; +} + +table{ + font-variant-numeric:lining-nums tabular-nums; +} + +code, var{ + font-variant-ligatures:none; + font-variant-numeric:lining-nums tabular-nums slashed-zero; +} + +rt{ + font-variant-east-asian:ruby; +} + +:lang(ar){ + font-variant-ligatures:common-ligatures; +} + +:lang(ko){ + font-kerning:normal; +} + +hr{ + color:inherit; + border-color:currentcolor; +} + +table, th, td{ + border-color:currentcolor; +} + +figure, blockquote{ + margin:1em 5%; +} + +ul, ol{ + padding-left:5%; +} + +dd{ + margin-left:5%; +} + +pre{ + white-space:pre-wrap; + -ms-tab-size:2; + -moz-tab-size:2; + -webkit-tab-size:2; + tab-size:2; +} + +abbr[title], acronym[title]{ + text-decoration:dotted underline; +} + +nobr wbr{ + white-space:normal; +} + +ruby > rt, ruby > rp{ + -webkit-user-select:none; + -moz-user-select:none; + -ms-user-select:none; + user-select:none; +} + +*:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)), +*:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)), +*:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)), +:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)) cite, +:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)) dfn, +:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)) em, +:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)) i, +:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)) cite, +:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)) dfn, +:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)) em, +:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)) i, +:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)) cite, +:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)) dfn, +:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)) em, +:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)) i{ + font-style:normal; +} + +:lang(ja) a, +:lang(zh) a, +:lang(ko) a{ + text-decoration:none; +} + +:root{ + --RS__maxMediaWidth:100%; + --RS__maxMediaHeight:95vh; + --RS__boxSizingMedia:border-box; + --RS__boxSizingTable:border-box; +} + +a, a span, span a, h1, h2, h3, h4, h5, h6{ + word-wrap:break-word; +} + +div{ + max-width:var(--RS__maxMediaWidth); +} + +img, svg|svg, video{ + object-fit:contain; + + width:auto; + height:auto; + max-width:var(--RS__maxMediaWidth); + max-height:var(--RS__maxMediaHeight) !important; + box-sizing:var(--RS__boxSizingMedia); + -webkit-column-break-inside:avoid; + page-break-inside:avoid; + break-inside:avoid; +} + +audio{ + max-width:100%; + -webkit-column-break-inside:avoid; + page-break-inside:avoid; + break-inside:avoid; + } + +table{ + max-width:var(--RS__maxMediaWidth); + box-sizing:var(--RS__boxSizingTable); +} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-default.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-default.css new file mode 100644 index 0000000000..e9918d4424 --- /dev/null +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-default.css @@ -0,0 +1,152 @@ +/* + * Readium CSS (v. 2.0.0-alpha.5) + * Developers: Jiminy Panoz + * Copyright (c) 2017. Readium Foundation. All rights reserved. + * Use of this source code is governed by a BSD-style license which is detailed in the + * LICENSE file present in the project repository where this source code is maintained. +*/ + +@namespace url("http://www.w3.org/1999/xhtml"); + +@namespace epub url("http://www.idpf.org/2007/ops"); + +@namespace m url("http://www.w3.org/1998/Math/MathML"); + +@namespace svg url("http://www.w3.org/2000/svg"); + +:root{ + --RS__compFontFamily:var(--RS__baseFontFamily); + --RS__codeFontFamily:var(--RS__monospaceTf); + + --RS__typeScale:1.125; + --RS__baseFontSize:100%; + + --RS__flowSpacing:1.5rem; + --RS__paraSpacing:0; + --RS__paraIndent:1em; + + --RS__linkColor:#0000EE; + --RS__visitedColor:#551A8B; + + --RS__primaryColor:; + --RS__secondaryColor:; +} + +body{ + font-size:var(--RS__baseFontSize); +} + +h1, h2, h3, h4, h5, h6{ + font-family:var(--RS__compFontFamily); +} + +blockquote, figure, p, pre, +aside, footer, form, hr{ + margin-top:var(--RS__flowSpacing); + margin-bottom:var(--RS__flowSpacing); +} + +p{ + margin-top:var(--RS__paraSpacing); + margin-bottom:var(--RS__paraSpacing); + text-indent:var(--RS__paraIndent); +} + +h1 + p, h2 + p, h3 + p, h4 + p, h5 + p, h6 + p, +hr + p{ + text-indent:0; +} + +pre{ + font-family:var(--RS__codeFontFamily); +} + +code, kbd, samp, tt{ + font-family:var(--RS__codeFontFamily); +} + +sub, sup{ + position:relative; + font-size:67.5%; + line-height:1; +} + +sub{ + bottom:-0.2ex; +} + +sup{ + bottom:0; +} + +:link{ + color:var(--RS__linkColor); +} + +:visited{ + color:var(--RS__visitedColor); +} + +h1{ + margin-top:calc(var(--RS__flowSpacing) * 2); + margin-bottom:calc(var(--RS__flowSpacing) * 2); + font-size:calc(((1em * var(--RS__typeScale)) * var(--RS__typeScale)) * var(--RS__typeScale)); +} + +h2{ + margin-top:calc(var(--RS__flowSpacing) * 2); + margin-bottom:var(--RS__flowSpacing); + font-size:calc((1em * var(--RS__typeScale)) * var(--RS__typeScale)); +} + +h3{ + margin-top:var(--RS__flowSpacing); + margin-bottom:var(--RS__flowSpacing); + font-size:calc(1em * var(--RS__typeScale)); +} + +h4{ + margin-top:var(--RS__flowSpacing); + margin-bottom:var(--RS__flowSpacing); + font-size:1em; +} + +h5{ + margin-top:var(--RS__flowSpacing); + margin-bottom:var(--RS__flowSpacing); + font-size:1em; + font-variant:small-caps; +} + +h6{ + margin-top:var(--RS__flowSpacing); + margin-bottom:0; + font-size:1em; + text-transform:lowercase; + font-variant:small-caps; +} + +dl, ol, ul{ + margin-top:var(--RS__flowSpacing); + margin-bottom:var(--RS__flowSpacing); +} + +table{ + margin:var(--RS__flowSpacing) 0; + border:1px solid currentcolor; + border-collapse:collapse; + empty-cells:show; +} + +thead, tbody, tfoot, table > tr{ + vertical-align:top; +} + +th{ + text-align:left; +} + +th, td{ + padding:4px; + border:1px solid currentcolor; +} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-ebpaj_fonts_patch.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-ebpaj_fonts_patch.css new file mode 100644 index 0000000000..ee7623c415 --- /dev/null +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-ebpaj_fonts_patch.css @@ -0,0 +1,79 @@ +/* Readium CSS + EBPAJ Fonts Patch module + + A stylesheet improving EBPAJ @font-face declarations to cover all platforms + + Repo: https://github.com/readium/readium-css */ + +/* EBPAJ template only references fonts from MS Windows… + so we must reference fonts from other platforms + and override authors’ stylesheets. + What we do there is keeping their default value and providing fallbacks. + + /!\ /!\ /!\ /!\ /!\ + FYI, you might want to load this polyfill only if you find + one of the following metadata items in the OPF package: + - version 1: + ebpaj-guide-1.0 + - version 1.1: + 1.1 +*/ + +/* + Hiragino PostScript Font name lists: + https://www.screen.co.jp/ga_product/sento/support/QA/ss_psname.html +*/ + +/* 横組み用 (horizontal writing) */ + +@font-face { + font-family: "serif-ja"; + src: local("MS P明朝"), /* for IE */ + local("MS PMincho"), /* MS P明朝 */ + local("HiraMinProN-W3"), local("Hiragino Mincho ProN"), /* ヒラギノ明朝 ProN W3 */ + local("HiraMinPro-W3"), local("Hiragino Mincho Pro"), /* ヒラギノ明朝 Pro W3 */ + local("YuMin-Medium"), local("YuMincho"), /* 游明朝体(macOS) */ + local("Yu Mincho"), /* 游明朝(Windows) */ + local("BIZ UDPMincho"); /* BIZ UDP明朝 */ +} + +@font-face { + font-family: "sans-serif-ja"; + src: local("MS Pゴシック"), /* for IE */ + local("MS PGothic"), /* MS Pゴシック */ + local("HiraginoSans-W3"), local("Hiragino Sans"), /* ヒラギノ角ゴシック */ + local("HiraKakuProN-W3"), local("Hiragino Kaku Gothic ProN"), /* ヒラギノ角ゴ ProN W3 */ + local("HiraKakuPro-W3"), local("Hiragino Kaku Gothic Pro"), /* ヒラギノ角ゴ Pro W3 */ + local("ヒラギノ角ゴ W3"), /* for old Safari */ + local("HiraginoKaku-W3-90msp-RKSJ-H"), /* ヒラギノ角ゴ W3(TrueType) */ + local("YuGothic-Medium"), local("YuGothic"), /* 游ゴシック体(macOS) */ + local("Yu Gothic Medium"), local("Yu Gothic"), /* 游ゴシック(Windows) "Yu Gothic" is a fallback. */ + local("BIZ UDPGothic"); /* BIZ UDPゴシック */ +} + +/* 縦組み用 (vertical writing) */ + +@font-face { + font-family: "serif-ja-v"; + src: local("MS 明朝"), /* for IE */ + local("MS Mincho"), /* MS 明朝 */ + local("HiraMinProN-W3"), local("Hiragino Mincho ProN"), /* ヒラギノ明朝 ProN W3 */ + local("HiraMinPro-W3"), local("Hiragino Mincho Pro"), /* ヒラギノ明朝 Pro W3 */ + local("YuMin-Medium"), local("YuMincho"), /* 游明朝体(macOS) */ + local("Yu Mincho"), /* 游明朝(Windows) */ + local("BIZ UDMincho"); /* BIZ UD明朝 */ +} + +@font-face { + font-family: "sans-serif-ja-v"; + src: local("MS ゴシック"), /* for IE */ + local("MS Gothic"), /* MS ゴシック */ + local("HiraginoSans-W3"), local("Hiragino Sans"), /* ヒラギノ角ゴシック */ + local("HiraKakuProN-W3"), local("Hiragino Kaku Gothic ProN"), /* ヒラギノ角ゴ ProN W3 */ + local("HiraKakuPro-W3"), local("Hiragino Kaku Gothic Pro"), /* ヒラギノ角ゴ Pro W3 */ + local("ヒラギノ角ゴ W3"), /* for old Safari */ + local("HiraKakuDS-W3-83pv-RKSJ-H"), /* ヒラギノ角ゴ W3(TrueType) */ + local("YuGothic-Medium"), local("YuGothic"), /* 游ゴシック体(macOS) */ + local("Yu Gothic Medium"), local("Yu Gothic"), /* 游ゴシック(Windows) "Yu Gothic" is a fallback. */ + local("BIZ UDGothic"); /* BIZ UDゴシック */ +} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/ReadMe.md b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/ReadMe.md new file mode 100644 index 0000000000..7c3c6474d0 --- /dev/null +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/ReadMe.md @@ -0,0 +1,22 @@ +# Android Fonts Patch + +This patch is intended to fix a Fixed-Layout issue on Android, and only on this platform. **It doesn’t apply to reflowable EPUBs or any other platform.** + +See https://github.com/readium/readium-css/issues/149 + +## What it does + +It declares open source fonts alternatives (Nimbus Roman and Nimbus Sans) as the font-families that generic font-family `serif` and `sans-serif` are usually resolving to on other platforms: + +- `Nimbus Roman` as `Times` and `Times New Roman`; +- `Nimbus Sans` as `Helvetica` and `Arial`. + +Indeed, these fonts are fully metric compatible while Droid Serif and Roboto are not, which creates issues with text that is absolutely positioned in Fixed-Layout e.g. overlapping or overflowing text, etc. + +Unfortunately, it is not possible to assign these fonts to generic font-family `serif` and `sans-serif`, we have to target the font-family names they are resolving to. + +## When to load it? + +You want to target Fixed-Layout EPUBs on Android devices, in which there is text (not a manga or a *bande dessinée* made of images) but no font embedded in the package. Ideally, you would check whether `Times`, `Times New Roman`, `Arial` or `Helvetica` can be found in stylesheets (`.css`). + +Logic is up to implementers. \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/android-fonts-patch.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/android-fonts-patch.css new file mode 100644 index 0000000000..37e71aa959 --- /dev/null +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/android-fonts-patch.css @@ -0,0 +1,136 @@ +/* Readium CSS + Android Fonts Patch module + + A stylesheet aligning Android generic serif and sans-serif fonts on other platforms + + Repo: https://github.com/readium/readium-css */ + +/* Android resolves sans-serif to Roboto, and serif to Droid Serif + This created issues for FXL EPUBs relying on Times (New Roman), + Helvetica or Arial while not embedding the font files in the package. + + See https://github.com/readium/readium-css/issues/149 + + Unfortunately it is no possible to target generic family using @font-face, + we have to target specific font-family names e.g. Times, Arial, etc. + + This stylesheet/patch should be loaded only for this case i.e. + a Fixed-Layout EPUB with text but no embedded font on an Android device. + The logic for checking these conditions are up to implementers. +*/ + +/* Serif (Times + Times New Roman) */ + +@font-face { + font-family: Times; + src: url(serif/NimbusRoman.woff) format("woff"); + font-weight: normal; + font-style: normal; +} + +@font-face { + font-family: "Times New Roman"; + src: url(serif/NimbusRoman.woff) format("woff"); + font-weight: normal; + font-style: normal; +} + +@font-face { + font-family: Times; + src: url(serif/NimbusRoman-Italic.woff) format("woff"); + font-weight: normal; + font-style: italic; +} + +@font-face { + font-family: "Times New Roman"; + src: url(serif/NimbusRoman-Italic.woff) format("woff"); + font-weight: normal; + font-style: italic; +} + +@font-face { + font-family: Times; + src: url(serif/NimbusRoman-Bold.woff) format("woff"); + font-weight: bold; + font-style: normal; +} + +@font-face { + font-family: "Times New Roman"; + src: url(serif/NimbusRoman-Bold.woff) format("woff"); + font-weight: bold; + font-style: normal; +} + +@font-face { + font-family: Times; + src: url(serif/NimbusRoman-BoldItalic.woff) format("woff"); + font-weight: bold; + font-style: italic; +} + +@font-face { + font-family: "Times New Roman"; + src: url(serif/NimbusRoman-BoldItalic.woff) format("woff"); + font-weight: bold; + font-style: italic; +} + +/* Sans-serif (Helvetica + Arial) */ + +@font-face { + font-family: Helvetica; + src: url(sans-serif/NimbusSans.woff) format("woff"); + font-weight: normal; + font-style: normal; +} + +@font-face { + font-family: Arial; + src: url(sans-serif/NimbusSans.woff) format("woff"); + font-weight: normal; + font-style: normal; +} + +@font-face { + font-family: Helvetica; + src: url(sans-serif/NimbusSans-Italic.woff) format("woff"); + font-weight: normal; + font-style: italic; +} + +@font-face { + font-family: Arial; + src: url(sans-serif/NimbusSans-Italic.woff) format("woff"); + font-weight: normal; + font-style: italic; +} + +@font-face { + font-family: Helvetica; + src: url(sans-serif/NimbusSans-Bold.woff) format("woff"); + font-weight: bold; + font-style: normal; +} + +@font-face { + font-family: Arial; + src: url(sans-serif/NimbusSans-Bold.woff) format("woff"); + font-weight: bold; + font-style: normal; +} + +@font-face { + font-family: Helvetica; + src: url(sans-serif/NimbusSans-BoldItalic.woff) format("woff"); + font-weight: bold; + font-style: italic; +} + +@font-face { + font-family: Arial; + src: url(sans-serif/NimbusSans-BoldItalic.woff) format("woff"); + font-weight: bold; + font-style: italic; +} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/sans-serif/GNU General Public License.txt b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/sans-serif/GNU General Public License.txt new file mode 100644 index 0000000000..6db9098689 --- /dev/null +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/sans-serif/GNU General Public License.txt @@ -0,0 +1,340 @@ +GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/sans-serif/NimbusSans-Bold.woff b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/sans-serif/NimbusSans-Bold.woff new file mode 100644 index 0000000000000000000000000000000000000000..4d37568319808b1ca3cefac2d3ea9ed7dc12cb24 GIT binary patch literal 87656 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 HAK3r^Ju#5e literal 0 HcmV?d00001 diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/sans-serif/NimbusSans-BoldItalic.woff b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/sans-serif/NimbusSans-BoldItalic.woff new file mode 100644 index 0000000000000000000000000000000000000000..3b8e384307959d11e25a3644ecc00e7c6e35f271 GIT binary patch literal 92752 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 literal 0 HcmV?d00001 diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/sans-serif/NimbusSans-Italic.woff b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/sans-serif/NimbusSans-Italic.woff new file mode 100644 index 0000000000000000000000000000000000000000..a28e6f078a6fc4c9bc933a8f540ddbce4b9b980b GIT binary patch literal 97380 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 ac_R}?CvY(6cZP|7a|Hv})Fo*J1N&d>zP~sC literal 0 HcmV?d00001 diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/sans-serif/NimbusSans.woff b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/sans-serif/NimbusSans.woff new file mode 100644 index 0000000000000000000000000000000000000000..c7b438f567837b3ca38652caffa44bef32b2287c GIT binary patch literal 90032 zcmZ6y19UGx)HYh%w%wlE#;>+*+xDq#^R%b7ZJ*kcUB_^gK`=eO;!{hx2uT)$Hae%1U4>$M| zrv3p9ga|Z_xPrX$4|f9uMEMN_Bm{%vCmJlStSbDY^1}gj|HM&o5>v3tD>E?vnAHAo zaz8L|8=WjNwl#DB0;2s1f^h)>L5Mx^E{++yxex&XG4TG7f_>-s( z^nCaodv;GhdvZ;4^@vFj2e)XD=Axz^B%@mouH*@He4^h5-|Tq*NuF6Qfu8oC&|(&q zdAA(K`J!O(%HQ;O{&Z8dA>?x_?&0ZN7j4G!6xW8((4NLxq~Hb)82}2 zq3chy9Bb}0s*Ce-S-4dcB`89S@hx3(t~|aLC%n14&Ad#xe5?p-@t%IrJN{f0u(^9J znyzEAkA1{`4!O?0&7%CcO@Qn1e{z=7;kZ2)|0K};uox=*Ok(H5c+prj*5{=sK=l52 zLQSPC=1sU8T&3*x*u(uk7sz-_5`YX3@C{@E@n>7Lc3L}7PI@nXk=5iavWnD?C%5pP z=>dnAZ<2X5)hMQr@%1~4QugoTWNor3CtaajG2dJM@FnpOyUFUihUmfcp?MK@5WO)N zO^(kXrWN)>uje@s9OWS14t)#m#?c~p6Fo`$6J!|Guhg#=rVEot_@(z!cJuE>Ak-h< zkLP2%|8gFsxGLSvY3;g1H*X1-iOdbS?@$M$VwM z*+Xw7bc5NX7uzt$k>JGQYU=7?1FbpYh}j@P+~j8=|4`k~Em=ZQRK0UN)w5A`F=>2K$c$`_9P@%@?+M6zhv^o01_o2X!4=pkr- zDYS?Z)EWwMvQNjp1#kiV9S^5}Nj3bQ!WwjAMwR5MG8l!T;a<{%ySE;DG(unzfJN%W zg<6e#?mR7DVpWb~m`iv|frgz2Do<_+?ANQp)tAFXJ#1SaYr&6RKD z`D(fNh5E15yvRmH#E2WkT#I<4PVP}&{Y4v1s!qBwn(f5$sYq%ITogkRDH(C8>Zmk=ZK zRtbu@L{TtO6fhP8CK!B{HjK%1a^_kxP+ANl(Smda3}2W}9 zogvqp+D&`n^y!37$U)Oa)-PT|2R69k2*n#FY(lyIu-!dEp&SMul^U#(=k6Cf-WuXj z=)(?1RpR0bnwQ4#)f+bP#ctRLw8r%UXz8b3mAw?Q1(XQsQD(C4Fhg*EnUD3YLyu*IO zOh;YQR0eqJpmXwE2f&LatB4hbHy3F8Dp@xnkGGu=y^2KY!aE$%GSHOn#iV>Fu?3^y z87rLHt3q?|iL_TQRp64u5>~sdsCr>LE?E5DLhNAmG)Ss}r7!^1{JNk)xe2#OqXU&v zLxsn&2rH=f_Xr@wTh4G2K}CvU%SnT{fhCVdvQqB)BBYp(84s8kc2@406M%MJfF^5d zpD4CY@}D-iNmC2{7%^NN@7WVTR?x{4g`H0yvanCEp?q-paJSb*g`hD54$tgLkQgP- z`z&X$7!CM#38Qi4^hW5}qTxV0LH*-Q=YPwcUHL|)|yjtRj zh=U>`=Hs6HU_Wemphg*`*c1w33bVQ{shHKFA}XeOc$C;#7)R?!8I{8NjRqQ?Ex0GX zo>f3eP`*8gFZ}AMxSAXhDIuh*Kq;+gxzH;7KRpGvpjyb_$vsQgh|(IcMf8_-7=P_u zd)g1%ke;fW7W6Onphn5;-ENX$@o1xmY>^{T6BR}pY*ioq$<}|_(+dc%;a0;P@He(8 zOywxj?Z3E%iwz_ZQ{nbbiRiG=fDbf?EJSYH$nuVn{T<7p2(ul$yQVK6?JBYJVLbZ} ziArtr34k7fN+AXLfX;vw5ChhL*MQ>@qF{EZDbG@bn}YJ=*04Z+V~a^+CVD5VT~}Xo zbH8UC&bUIpDn@fM|000ZeQXcH)-|wXdvk?fqLqioE+8GUGjb%%yT^LRmN&Wv^1KK; zoFpuFr>C-4V>#dOeI-ubDb0d|rXC z3o&3==y#E_2hw9^ykmI|Cpwh7P`lQkMM;%;7wvIG??)$j@N5-ogmb(fpzTwx` zppDa%ts$#iLP^&*j3vUDU3&AJ=L{`?=tAnS_D&nPmkh||n@E^x~!Q|$uSFfh$YM?a915pE#dS@!}i#IH)bO6!+R*Gt8xNDAx*9!a%n=A<#y72A>`G*|Gx(tP>FZ0!fs*B3PI zQ`<8}4@`GU5Y&8D<&w_T1Qw@A)R4?ogg?-{SW?behd;mq-f-@YaAy5t(n~4V&Ld!P zM<36&BpcOR)nDX{05#m|8*16Tkua5|zt_1@PscTO)0}O=kvkHXRXfdy?0;dHCHSr~ zCc+l;{of(zA!V6Yn0p(<$Hb878TB#ox9ma4$b%1D<-&MU^Q*?e9?VA%qav z1!U`elVHu)@g=@w_B|_h=8f^qde~r~7?=KTXroMJ3S&x3&oZY;MUQE>O6gN4W!eMR zA2O&5Ac2@_->Jm(yBIXdi#U;0`Tc3&3CVX&dd|5|#_T8EoxA(>KmGSgU}Pg|qRc?$ zwk^|9b9HwVLA>igneWxaRTYE|-mT_Lt#Te?Hp2Mb=I_M79H&Msr4@>YtWncaj%@wu zJf4ROQXE3&g}&()0beuD?|{Ds6!1|Uak@ZE$hO^yVf7IR+oZ|g5tgVX%=Ikcr? z6Yg*opXA7<2#pRbYvY>~0o^i&3Vo7PN|gDCO1}ukcqq^aMkINBy5YE?g+8M*1Ew!J zjF90p>RM+4H;kFK;=UQ9Tc$QA#VVvU6=0hj%B%TXYkI$5i@LwK;w2F1OvuC0T_-FH zD{=(MJ%X#3;;P+A@+iwtnFBVUl*%ff+n7^tE2aKg(NX9}9s+OeV^iSVAhV$+(kDm^2;BuwML}Urg#$${t z(vj>!VqsJ?1VE7(K5Du(g66#z9OGj>CdVZHSF+4{oSM=7Gm5Dj){a7hThGUH0i2pVT zKu1>~M$vHf7m3v6{iO@3=edKlldz{j?q+j-RBvQd?2E$a*fb@k#y!9VQsVy+VW-ov zf3AJSfcO6!X@r+XSWak23L_VhKXd}}&TpNG{pbg$OK$HiKYR!T@vuL462)UPql4Ah^6Tx)rNI+$v+5IaI@wW0n$ z;~b9j;f^tq5-C2JTR9u!hfc7kUAk6f0FB zn_4TjL7Utwwj6v*WT67*c0j7Eq1VQ$_!UxA*hrw`;0p+wLhlB34Ce+=aKXFcoAQ%} zgBe=;khEWnd**WJN}BR4f^7(9GS>k7HF?pcE=8vLDaWqg=ZhCopBj(ODiz+o732)G zD-p>v&S;5A=m$oKo4SbSRUBN0L8*>b%o4eM%SpG7&M$AKJ~?pZygpfB@`ZwFi0!-| z?gYWJFZ5W+iYfqqpJVtrs`zRMOK!h$qGw*gY~oy{uvKx>ARo*&ZG=0AkHe6j#9MXd zFR5Yuu@_owfAakrjgOSLp1WIh{;z){|9n1N!ThU+^~p7|BZf|2DnR^A4LqT{|MjbT z8|H%vknfk6d^AE37VT$Y8XR)^dBW;n6qS=Vn2(o~A1W^vlv$kK)viJFWW0>+RjU}E zM&&Md|0cbxa0CP~GH5&ya;&=W!!TP9GM`PSrzw%^T*#hpZLb8ng(Ck+<97_T&CndPA)=7O=3^*f?K zVWi(DBsgbbJ-5lCb=lo@IcJr$=Eh*SN&Ku6qJP#2$%?r~#7`mVJ~Ehw8-L^zidhC+ zf1`y(Ltml(MgPI#g$e2@D@GJo=h^&U&x!etu2-EH%4(F}iff7fVQ>iz8a*&g3KS0F zLvRH?$b!ke>`@5Ob}msI=Nee~!pJjpmnyFDS??VBI$+*a#!h7I?~oJ|V$Wn5ijN>H zk;Pd*$Jaq2$f{|ekxb?5!E8sir?Jl;2_XAeEl6LFATQyTP~9Q>y^ zbZU)wm=Uk-l&N!?&b&YlmfIsOz2yu(uucAFjQdT|?g|4HSlD+J!bZ_Hbzb|cna^EL zWyy|+FwS}tsAxSi%KBXO%|7!WBT_Z{-*qHx!NDdU=fFY6rIKD<4@1{plW+lrf>+s6 zDa(9ID0F&aU9uu;ckgd>%df_SGA{i9!gJGKTA8zRWn2rNDLR1QUudTWwnGD2SrvJY zLxcntRStQoD)~)_RiGA^L!kz&>t%Cpb!d{@-D#)cOy@hFDeaiUbc`6XPl(3mc*t0h zm|YW7kI}0Y>!*^JS8~&0V(#&?U1o9WmQS7od(4WSlP>;zCO1gvu2>6x`EF-h3wJ2( z!h-tnPKfS+#^3FWm)eL5X+hlm7iDRg_^0{j*%+teo42V`UDb>0V{Zl1XpozHjH>gR^HwWp@TJCI#cW?32;(g&L1ys)Zr&WRSCE2FwW)%V!- zbJ^1YBuKu>lX6Q!6EFK+Zk;9aJDIn7NLZO=xLd{MT4UDST(yzU6`tQLVh}$3L!E3I zkF0qteT^9QXPX~hyvZT>xTO%Q8x09k4#U~ooIC%7Vm*3QS#+BERV!Az^n=dX7fm!v z*J|q!adV7VOV@=q?3fv%G}oqL%GI4m7E_858?n?HCaOygw-&<;o&Vhay+T`7W~-mj zjO{LzcQ$U#1LLT&uoRRI;wcYH$2K?VxGRdu*gS~3V!+ARq;PLY?V0@N6>v*Wdv4fO z0K?F(6GoTstVP8fzXb<@@7w-W$+mUjc5Sy7EzV$ERxN^<5t&ab1am#=k#q@rqXXZm z6^wj5daRAkiZ1}I&M=6GX2Y2e_Uh4*MzCE<4wE>!{jp+w|0iDe2D0>I zWQ+KpsJR_e;nrZz=EZ0A%&eX+ntkDGaN}r@i{}xls4xTat3{F4tu$&UX)X7Koa2e# z+O3Ad`0GADwld535mW->s}c{YY=}>(MT!8Uf&o@nN1Mgd6d} zGD>UYGe|WY*Ium4N_n^m_(aly?@xgL+fC%E@j!Eb)8*APw~%FMWIvNFtmG_a1#_p% z<{8yNVc(Z(mTol?>Si-j^89P(S}>BI+6J;DiLR+bjrJz@sDmZCA$prB5{r;2(y$`9 z?HH>l+G!rVC8!NwzokQs4Yk8>K>@KHv+JF}*lip9%C)iglA}xbAuGwZi`zngt`OsI zhO%``IV6Vf#wcr)^Yx$g@Xq-Oo&nDB7krVtH~$0vR|cUaE-~stJT6RZ^k}JvfSINv z82fv&TVzyKV?kyFZ=ch(k)J6?BN&NoIaiJai#+fHYCuBLmyOzrbMd`B5&t8#MNL^} zpF{;?$+PhU3+81YdkZ8^{7Up70U0~7qJXkR?^f!&9B^iB6YTl}v=3@Co1ymqiY6m% z&`jLgD&Y0Z+A3%?S+noiQmqy76NF*N_2EPof(yZ6gAq8#iut!l%tQna+?il#uCCNMIFo z|0U2(La|x`nPGp$!6QcBzcKty!1y|7_&UKJfNJBow!kZH?aP7z`ZR{waXV!pr;bd( zVxKE$HJ=iu(Lhlyw*r`E} z!*Aby=qG5(8UNrfc>&V}c`Wf#P-k6l#JPgbUzK=VZZ>FDp1w*8*xiCa@wH30#i z9nYPYZ?q|7%eS!uUwN`2`LCMWZ~PU)Ui_Qys5;0-uk>!JTn`z>lIsEC%#zH)tDKTZ@bjV%b@D6h+hLdF4J-RZr%UY zVAe!6x0LAC`r{e?HMU#barjNth0UYq=IB(DY?T52CS6eaF>sXIk^s-eX>~Csg_xU| zmpZEx{gP$%DZ%#i!<|60^^Apb>5lZ6SC{pSsule8_4cn;cNi~ogWT2_ubs#P<*?VO zMcPyTvHdT3=7{Gx3A|@g{N=KqMaRwa($4Fu7|W}ip}4BJLK)K~)r`o9XBU^V@Ci48 z{T_iNm(3fpV!l2WfR6s&mC4l-&jHqz+@G3=-7C5)xnYFQjSVBWU@uHgWLfc9m*iDb z4d;kbfw;ISR8YRb06%7L;Jn)RKcJc=)6}>9VkX(Uxz5p1IyH0W82j~5X5z+}O8l07 zkALI?_f%rX%E_F~oUi~L5A*a$hXGV0+4);>`Tay1Qn40jw3Us0 zM0K+@A8d)zm8>|jq%~@1F12TK;Vby{Yk$fRWqq$$dNFQPgBXx~A`avTus-`dFc6ml z<_WVYdo!S>0Nk6Le`sGAX`>-KQ0+Gl`%A8}U6vc*$JS-!E4(!~8)6?S+SM07PlLVn z@K1jyU7!1?$A`7ATTC+RE%^SuA||9n+#eh8xKo(c zv6z}=*n6jWSdYQ$~C>vD{i3C6T*4DER4(J3Es#8aXV8=yR@ukANn(RW1bg#8Y$QR5zHH{f#<+Z zHEau~ynH;hv*+Bi0TShx1nxM;+iJqRN6|K~Cjt@X!@T)tFefPgBkDTl&587x=ly{j zE>?^20K#w_-_RyvT%q9(CyG|O?&!q+#%wUhQ@ypopAOuV7j@6FJdoiGbClg9=q)+) zukSnR^i?)lcFN1QVBNg(^ZADynmzkmsq>^0riqmh0hY;Y_$Jk9B}Y9a`#y0BpTGTo z$NTrsSQ|2DJaKAH(8)pNJM*Oybl+NX;nQ_ydjMAAPeNCA%N`Mdx6wfDAA+@J3Ow!w zpSB4!&a$k4@vavpM6B{^ zjIVkHuu;Spz4ujN_B9z>Y*1ivI-;*Sbe%t=k0RBesVnHDv!D@4 zf(tdy2xz(hc>#BQ(2#25&kbMMYqD@+-{P?E-2>KUIL7&)4E&Y3K^w%3k<60)9X?fA z^hT1RjlluvtIzl;gMMG7wfF*KBdAz8BV#7I6Dm71H~2b5m{^RzjYLIo)RPjHLQ>eX zo#PT~XZ%G@e54Zw7i4R!)tiHg^mv5%d-%VfpKHa`O)*<+NjK{4pYsVv^V<&;ObHJD zWbt%tJ}pPgI$VLznVGO#$Hfz0(1jpw=rL~gqN8p@hM$V)yaou#x_nj#ai5t^G04zi zW6M5|-LNx1;HVT^BX>=Dhyit^3Vx20+iXhu9fpq)MJL(cwP$fbmO6*cd=vQb(dZ3K z7qjmf6JEfIIkP;;vRmgSb!fNJV#(%Ma7S*geINJv#Dq5*J%bm_MnZb`)!g5?+EDd{ z%8_*;@YpvT5%$uqDTj^C7M{>3*q^@q?eH93c@)v(y*@o6sAk<5K%(~_DM4wRbNv^G zjd{va@gny;?r(rziClL_Q<$1^sk>g zb|jl~Bb_SKopHH2{G;MG_nWg?ke6E3wG3Tr^_8o>@3^lkvHJOt2OVuH`Wad(USDF6 zMy<4#;W2H&EqC^I?>m0yR=*N%%15&ovPsPt4~@u{DvnSfl!#PSR$ki;i@Kk%dp=jW zfg1YT30i`ll}GuIavo}vet#GGfz$-y3qy?`XWmo~$c*vNFXv`zH#9+@{62#ddda-Ko$ZpX-;{!?1BT^l7 z9!X$Emslmy+%FpTk*o+hRblapcj^kzh&mGy21c<;*M#4qH&cspoUk!E0yk@BYzWCv zGs`tMLuH|4YRJpLpSTdRFZqbQ#`95oTLyoCjOkzI0>t&|ZLN}mkY2v6TWS=*An`|C;G7#v2C~4lJRm$?pGnSAtbkS#>a`Jefv8$ z1!q4{>&7qSaQXEMB4f4h{FfRPZk=Nm&b;Wx1~J9e9<*pzW_XCKgF2!+xr2IC3j0fi zh!xAyQ{O(D2VG*`ZpF0cH~I7SK_+~x{lI>U$~uq7SS%%;PtEKp9JOe_qyu`uIaI4t z#5zT74!Ab;N~HlU_&PaR*TqykzJwM$yY0SWC2e21l7nybU-|I5sA%~fI?ZF^vtpp$yGx&lTe|lS`g2RvZC7=nQ@~*87%-HkVQb2I`>KyU zX+^71gH_2PG#hxNt+584*`aZ*K(2CtVwQ~ZhtPP8^5%s)omNA=eCL*#c99S+>~W_P z2o}`fmyj~98ls_XTow!EW}LOab7zOWj`7=Y4h*h@Q`ITXMlca5Lh+w`k0M^W!~~2ofT^wFvqnJ*?*U zfV|!3#{s{Z#b1Maa*fsmc7h!Y5ye4xqK)2?X8TFX)*20|GhUWE@d)Z6-top`26RFk z{P^MTl!^TD4@w06fDhV;dLZu1;>`m(2@b*@R~b^OK@MJt1fcHliArGE*j|k9_EGg1 z3T~By4T`dy6Wr&~G{s za=Ug`p<`_xI+oHU9)v6s`U&ne*ue7 zFZshQ$@jV@U{#T{TZN}ow7<=bFVOO&L-ujoIF+Sh7fo;)PW@wGepe3a3CXyepffzO zbkBWe>e$SY#&4Ia|5`VAV4v6u^o8V$eCojTI~`WjUCwINLflrNznhMA6V>O{YR>7K$>zYilAB*OhP%0m}&{T@R_0>y~+EDNui!kGLM9si|z-+luz+758?Yz#+ls!a& zjW+ABb`?r}dTP<|fIM)sQFF=D8;rx(R|rX%@5^Z^4cFapO;aE0-Z!k(Ouq)x&g;lz z%UbNa+MCq1#&?0!n}hj%?&BV$R}|#g62CU|=`K{dGS7D*#u@<7b<|F@|WSw9oYDKH`xq*@+aRD%* zM6n*iIz#0nbgc~OuvgHxN9kc-s#}-%SgKT)1^6O1xNM~ih-N&6jx~6>=d$G&4(VoS z&aaBcrY_%(|MD>_^qpDiFq~j5s>r?SvWUn1R;`o^6g;Tv1h zjbBnPQ%t{d;%4K*BiD|PyD2BIMM`mMrgf^erom))*R2~pgu?LTnx^Y(aH^^7&NEuA4e-EpmGJjZlbLDa6eMeC z&?1=wM6QsfMoyBbnnaqC{I;(jazbWMQ(#ex1SCx1S9s`7x(gVaIDArHX$@qTyz(mp zBATLIjs9p%U(rZUpyQ6N+Z@=duoZ+a!|}2nC%eWuQ<0x8orr( z3Jb;B{hTYO)2c{9s!hr~{Wk5sX!{<)DwHdCd6u262^-%E9vvIk9=}Bjnp6)8%n3>3 z{>a-z#;e-o{yqQZJ;8g7zacn`n2MOt7x6oa&*D1z?!|~Wo>{T^+TOJ!GiBD97K51l z&a&yh+JO8jp_Tsj4}uH0BobqMmhV;azqnxh{)0?zG~sVFLF{&vVQ%FxRte^cqg}Ym z)ytbU%_?sv7f$C2Eh|3Z{9j^4iXVa> zr#Znw{yE`;&6Hd0&(L=)b9AyTU0ITOwjE$Q)8jth1IqGk=<&_q>O6Vf7y0Oq9ywNv z4y@gGq4ibmDqJNvM{Pd!sYFlch24?c zekSqWSYaB(u^ICSpE{MeW}S~Un5zS?_5N8z#lQK{ zhJU{7)f;l#OahI`U}Y73QW@2m(Ju`~yw=78y^$&KQ$H|-rS^U(FdnAyY?HABrzBoDkJUXz~y|^3MYRm*m?x z5H_8NNjhAbBI3m^fu8iVY`%`D51?QF z@X|^jaJ_CHjNGAm3Vpe2(ld<7n}&Q4-qrsV`-kJHy7X__q{}AWKQU&GrYBMMPXEw# zmBfBjKzfO4Oiq67z*Z8HtS9MP`Dv_Y6!t;7X*%g&WvQmA zC3NrKh=X7XjX&rAOy%le`WcaYC9RT4@bRKVT;gH&b}mSog_(*J&h{|y08s4@K_By8 zU8(d4*PELiY2!gaNd5b;8G1G`qa8;vSiq+i+Ai;4Z!Xht2*>3Vat&ERO36z*8Y$q8 zy1J6)J!CytJYzXVvcwKk9O0kmrv~Y$-<}>9?;ICtg&oF1T*7oz)0y}nW~I1tRJFKg zA^COWsr})L+l^!sC+%W?i(UA_R8cd3eJ7&s%`&NHT9tw9b#8wHMZpnf|95`T*uadd zk25eZB`{<${g4h6bbtL?=nW0ahqSQgnw$VL`#Prns&HvyJuP(kr!xG=Mt{0O(duSQbX`HDOq5NOs-u4~?zX>erv zN!EZf?T0F_psyT1>FPXk@W$rfrXHPP=RtznvZK z>nZP>txg8S-9J7+<{M++aeJg5c!cAWx2$@-Q66kH#~rVVl#USG@W+h6LI8PWs^6mN zP?$lYjp67K1%OJ-6r+X}nlnI<1v+8G_+I3Tk`Jj}IM1H>?M%vvl$)%>VF!$EO?xDv zLd~+8A*T)Phfx2hdb4nco+a(VNlbIUElhhr>YP@4)K!uAiKN$7$&4J|1O4Y>-Iilq zAb7pPuuVvU4QrIYlwn5I%nJidn^=|nZgG`hYo0vuXvs{T_zPO-3QS!b`rWIr-fc37 zGr}ii$OI)!(_Ss-Env63YUWB=!lOXpKDPI& z>%iMmyB(WGSS9`vOvQwjRhK2YW{6sDifNHH^%5s-cSDhLHsvttWyBraJ=`ta9VhQ6 zpJA?oJmJ0jef4Wn*+hj|mS^7ti+Ki@S!#x*S^E5>i*tR3$#7O*x$>sk@&dJL8GAWQ zlTeka^@7!7vsTf+MJLtb)H03UDH51x$FPj3|XjL94%GrW&NwFI#PY7W&&A07&lyT$v_5 z1BKD4za*b=lC#>{{YJ52$|q?aRR=&!qh{}#YV%?2c#;<^46OK_$S0XHqewEe+~x{I z($AvF@OK|cCpwp*$SW-=6CrR7qp`=VgQDdaxsf{@(M0Jhi~8~CFr~f zRjfT{(t3u3y4Eb;%KX*r)I8d~MnvoN@ZhHjKFEfeF#DldbmD&^VG{nnjuS8GAc%?g zh{S^N90f#7m3Q5HXxfvb+@6)ZE3w0ID9c)_o$ z+gbxm)xUXWd?{cnvrEW3Qu#MD@JFm^Qx(e8--ucVE?6>MtkouzSCz5fs!WXoZrtIz z{ax27t&kBt_7>ojzN0cr! z!$Gu$-24RbNiVEwdosJe+me&3tIJ^IVZ za2mb5zDc>191sYmKlQeZC5kI^yK2ahPSHJ|v5wy{=u4;zd&?sIUISnY3PfCfHfc@BX1t$HC8)y`NHH1AH4Z z$JsRe;R<5u0-y6Ll_Vt7~Tha5K$<)=1AR%(rc73*zjb)3E zxO&j|quv-Dt#sjFW?A)3nEq@c ztkTNBw?gLN@wmwx-q^nYO@`h}EwG7itj&f-!Q?#pdfLeaEBP%hz*1O`?9EIj}P8DH% zWlN-NSBBXjO5FaE{4u357B|p2ddsd$khf5HU2>&Y2su|Co@_W~$YaDCr+`!WB-t_l}_8xha@5BD?wl!M6k!W);^24$kkDXq2#{c3SZE?1 zs8KVh@NjGlA!KxHzz|l5PE^u2?tttwfj@yK}k_R$3~4eQKPmD2WGq!T{DY^*+-$ zGb-}H0gH&S&h8DZk%n10BnW(!QwA6?u@L1+BhE=22Q;@d1baREl11}Mb}Lf_Z$({% zy(KQq(JsqGg1(|OtV?hHstrp+y!~%>2$h35>_*-JLqI4p_yCmIAAi<_KB&jO8z+_z zME+7T!kvg4q+LVRNs1)u=y}(1MjpBwVV+O^cYvNJp^j65yeGl7i|hwPR?Y17L5?E_ zgJa<~i_ursKv}5w2ITBjT7q#Uy>b%0xw~lp;o#`i~b_vL- z4h^%P;+ScHnqfm?JvL@4kf^~wTq4F;Lhs}lNjSN(`RV-LA3daFcwvpwKC19PG^CSrj;PGyHRlE$!#XNOD- z!pI4_$7Sv$7CdA z?3uo|82w!kkAIl&PEJ2QXKd07SJ{F?1dE}egBl!SP`L=brj^cTpjxs|XgF0Cu{!3u?($lG?B>K~mTwxDd0idNa`WiZZ~@!$dK6SC?nY_ZxA2I%kvJYv|u> z3T-OOwyjN9V}h^!NXK!rjlesBPp6U1;U?`%%CQ@J=QqC`cZ;d$eB@z@v3lpNG{pVd zD!xCbx7&O3b2D8HUYF79XdNxm?&&HA!;NCVK3H;K_6e}MgqjUjR4ZqospsJ69tE(2 z)Jr({APO+3O^Q5LS_a%)O}HW>9^|KE_@UJYXdBArwCBW)F%%lzixqaLIny1V0u#GhMRI)?DGU$Li&u*Ey}PlxQ1zoK zk9?E;3US;cK5jkUY;T5k&3Xfa)rT_Dw`fb+-Z&Lo0+#25-P()dy2%wW(}so&bF4TG zb|hk6P)(jbWg(qcw2OycoUoUWlpVNrZsSj*;Z!k{J zqTuktAre>PHsfqu-YjLYP)X$3T-^ry&9=Ch7yM2Dyf5UhX?czte}4Y?r=IWEKbJi& zI_MW-N1PAnzxQ-ziTi{g_$*j}P2f?Z?I`yFA_I)G)(EnCe<_rb$|WbIC!+?*T|?uP zs_k-`n(fR678k~S#*YV5pY7@S919xTzV8g@vdy>y4I=afrA=KxK0s0WC*;4_dIdKyseO0lfjvql_zF}qq$w+c=S!j*q3&5^1v z8C5RuuaC<1tM4jes^PO`(R!D;cz>I8z+xVv#!@N*#{d-x+ZJ|Q6IXr3swJr z+dO?1Sh{hQ3FPUG8aWdNb+`>reUOKa{Vg$!au|nF`*2EHziECWXRbX%qUbLc<)q`{ zYHOAH2HN}i-=nakQ+^gvcha)pi8co^UU)?`tBOZ6gZ{R$(xeh&*wOYg1d=tj*V_>` zzz;5vV3j^22T=&3a87?BKW`x9LcX89!1oY0TZSY!)RcVDG~a^ znVbejDKXDDoH~d#aQ9|RKZ|8{Y0AtTn~8ac>-V--L5OpQxck1Q*9VPgf0!kP;4P9( zeTBiXqv}Dt<<(i~WWWBWSu8s=2TU4sXR^c)LCE4v(F!moy($xoDmH;*c_|^5%L@BQ z8uz(8c~8wKS@Z$NV$g=i<_2r*nt;7>b}@a-70o_OmP?hzST8OX?YOEar(eQCLDnYq z{>dy=@MsX+DuI=RzDWvCLBI{dlB`X7?wpF1hj(1u&04L&fo4Gi!J2{@O*=Mi?4ei$ zGDK`-0uI`Wu9-A29|Pjhv}trXjkc>JIrBTlfYdCY2{Rqeu#*DJx;1~Pd(Ci~_w7yl zU0toRh5R(O{wev8^KF9fIl_E;tAp(2W|#8&?O|mV7J=Tk(MIqV^qzpu!*+K~eUK1g zg0Q<=D)Sm>r;sS!9>VL@0&J;u$Py9o)7)&~VI21cM?}9M;LFQycYvWmIIzKlkW2E3 z8+2(syK|Sy*{ieZ1DvxN#q7u&f~g~1rUXwVj~@OybSR3$(U{xiVy2en&IKf(PpzUT zD=YO?CN8wf2FbG_XnAelDY`=6ULaq+jU4|RsB9nFlh2DJq&uGK0VNJUD1<9%OL z+FvzqiPKYic*yaYH*|c`xE+z!5BDb&V0K*#P8rwt`G~7|qBSNp$&k81jhdSwjI*lk zrNxqRgvElWlnvY+qsjM?Q3uvV6s`Q7X~Mw@Ilmu}vstB5yC4D$He8>44qYpVA71;? zdhoZk@ul&>L|Z966^W1+Dt-Wrm?AP>#i%gjj_Tbw%ML4*d+>#TXYX`0*@$=C5m z+<4SG2E0p-_SeJ6-UK{ku5QEISXf*3+Rz@`?J$4cuU<;_4-%kU-3;|fkUcN9K&`*}9pAJ|Jl3`qczY(3 zgcltqigu_>I}5N(Cc5va9(-G6Z1I3ZOxUhQHXbC`4^4)*6{$oxj1q=ZO6l-QuX0jzcSpza0M-Um5lhOE3Yim}m zs-7*zJ$}#HCmvh3b`PR4jNyO}6W}8bczKr>FM~luoqcdz0Zw4ZG!=m^Gqp#c+uXn` ztW%b-rrbyc>Pia?1!m$H85UFVtxq2Pw#d znz=_J)({RJ{6x)Lzu=(rKdvm!FB({UZpG7AnE2Kwchzq=fQQangyXQjau{ab`w*Lt zO#Samr^GJ_3v)|eynp+%jT;+aQ2zktYvyubpc*t^i7Sy<2Z<;ZlyPdquIx~bWH=G) z4o&rd5s4NeLJrWHXRPo|;?eA9eyU2w_ZM2Opzj z3PtM_caAt~>~!kD2+(r@v4i-DK&yOS8CeXpBb7b*UGy0R$lK-EdSn~m8-{rE!e5UPOiK)f=z9`%-9;lv46y+xO^WS z2P_j1 znbIXyZ6jW^+iSMDooTS+jDT=v|FMetJ4&|Rb^n?d{_)A_Z>kngE5gU{t_9=nSyHn0 z_E~kipZ@lT50BJ5Q9E|(An__N4ub}ZS2d5p9E#B$=!`40*vVjB3}%H`kbP{a6hzF_ zW2_;u6QPzw09bB1;iJjGNBxPME+{i#olZL$X|)A9g|D)~{L*QWZcPVmy_>DJ_r| z9$>Am25AJW84DdCzwMc!z?|Mo5$u9ZyH^91!o^P zgV*1;@(*{P6~EYh_czm;A0IaO(%x-YyXSEB-Dek6Hw-SyzdW>Z0p&puuCSV0U?u3$ z(4#ucF-oZ0Lj42ynu&-)B@t)p8d_+0dA-+DK&2~KtJUhYdN2&bi06Q2Z{+7DMOD>49cwzbUl!}U!>E+@Ud|}NW{;)>O=38oKKYM+0pXW9n zS+Sa}=oVMB;_jljZojU)Z~2N%L@rIcd4Zn|Yr~2rc#JX-G{gcWQk$%9Wf_3wIYm)r zR$nj%EK_cV8=941(-f|Ez*9YZo&EmrvpFJl+{dVw>v9$~YX10p)W zw;T{{2aqz3eJ~E462po@ELk2bSB)gg61xpjcm|qseR}}9gaAl~bmaYX36Thv{Pq)| z%UYOs$dZxYjL|sYuO{FxJ6cJ6DM48?8PKtYV>N4tha-SnTdnv(RNm64tS9>7h9;_n z2LsB}3V!49ba!KJsN@jYk=>k{WJy2NFpN<+b;MAhCSSRMQ;jN#&efQ$G@bqi%;^A|) z{(5cOQ{rLqo6WzDC>ep-cha9B_-=%erc$~W%c2T|2#pAG)b{7yqDuLke8NnmPwC>J zB$gHr2@?Vv!k3M!Z9~V8v*^SL3C(RQnGL^WNHL0Y@U4Ny%X+HfZyvG+Q9fgoZ9jG7 zjgS#Hyg_6hbO3$XZeCz(;lE~O{M}%2k=8rwr*xb>7Dz5^#{^@)jraTjBZ~IPg0g>h_o`N(MM!a80cOQPhJ@zFG)O&`Dg1C zK*PE;hk8) zUkKY%*dLX)(r_Vssi5hG7weXJ8P*;PD7n*|15DOhQDJ z5Yf!W;S#)g(~4KculI`od9C&czWuM?idS*+cVFWa@e}@Aak%*KG4Yj|dltTjlV7-w zXS{Vle4*__@gOe8At0|DOs|D4KztE(cgH*31-&S@B80&*K=Y9ZrHSY_a<>Mv!ZPy-*W9@&91`P z2R7f>tl)Jc#j6=5q2VrLlGS1+lp;H>r9imb6(J)#?iA4;r`$w@42!0_A2VcmW~AE4 z65%zeZgY_sizZ8$21n)sUTqSJ^HTY%Q!X9+8^!I5xa7kYTyo^1_*(Nm@#Am56F#yO*KX*8KKV7(m(FA08|H8vVL?iObS^%$u}dprY@KGI@K zapnQ;?bL=!B}7<#g89?cujZ~9Rbj(yQtp=-%w6}07JP13!|>vVLphQP4~8; zGHu~mNp2fT+DVM$iCGAo1Qrwt?g^0~RVAk>)t+qZO{fTyMOY`o-ckOz* zs%)qDKjQw~S>5qbwtUuiuaEB8cl{s42Js4xyYV{kL{tcu@Ze+jFB(0~UY&mO{;4nb zTinur+sqA9Ru?5L>^F9)ecDhQ_TJa`);VvNF)bU=6{jgfG(Pl%_*|BC-BzJKD*dHar>1L<}BQ}HLP`HYMD_4>Y%!>?ZP(A?m+<57!Arup?*TRo z<~?850eWv8;7=ek6myc6dCBC_0YsgVSHM61#|z>C@$dz)t_4TovU7M8Hn(u^{py5w z4&+`VU($Q|9I8w6UeXDy>b=2|?s301SkeQE<{=q6RFlFh=|4I%D--r_u~wXUoe2|- z*YR3h_ZcI$G0gn7ZH&lVYHManB_4@^_m)z7y!T52OX$=^Oqz_W%o)-fqfWHF`ET5e z8$V-8N%!pLwshtaeFxcJXrwx>++`q0!=(a{Y=~n1lXw&?FxJP=HY@hE`#Iy$dVp%m znHFp%!4#{Ld%Crrt^0KgTi5zB-_rE!+5-o;4U%nLFAfL)j;sT_D~ayO%5Rf7zK|K} z&F&V^qhKO1=;B4Oo^N^ZzfU}<*@%4hJbOxE$PUruWy6_)C#K*p7K$-s?~@nl*s{gp zxXC>>_2QI9S;%^i&Flmt(`hwkU%ZG{i^Crjrat)d3S!4I``DR$6RZd8pM)6$T@fTA zg-hx5$!M0ytp6tg4WuqL4CcXyaACtQKR57Atv8sNZM(_*E{eOjy`l(%PNn^HyvIy? zBY~{FzdA&5=1hsFvbfjqW&UfjM@{<(Cw<_0c(%m1tr@Jo@KYOR^~|If(>%?G|DuD?u6(m4ScCt__LNkYJdR z*wA)o2-e8q8?wP%G9+{4DBbwytDk)RHOJz^wL_RyOO~%NG_gtcCEvgOe$Py^c)k0i z&G#>#KV$oyDe*JvOl2cSmOZ!qe7PkeGB~GC*07Nirj4jcU;WUQwoPf7KfDnhZVsPN zSut*^t&resKHw~y#y_Ibz0JW4!*j|)PNW_I$(o}QxtPdi-_)BN8mr|=2F-MDNX7A{ zn|fr&0Mi`<0;qP&!K5;VMTCb%8>3ChwlED%88nhT9O{!NrCMw_NeGj72{v@6_wuwD-O}zJ?|9t6I&`! zZ#CeeQA5X4-gm-0Z^(4~LvskLqN7!yQcHtn8>P6tBQ8xhUUs^@A=!zvJrPo|WQUI9 z8A?g&o~s^{fF{fVNyLPKgeKdJT1nPBL!=Oq$xGZ!i5DMe zdcI-f{wIn1(J;LV_XSTKVdv9KM%$Io#rr?|$187MqjRkwdtE@&2o#65x?|ULlWh&z zlwx>Pt?aWGmnmUsX@8Q;GpQXgCV7g}-E9QAr=tLINZ>i4#sl0wyD=%;mSnU`*^O4P zMoH))Pa>;KRo+ThI~UXX6%!Sov7zEZNmJr~j$IR5vEkE)uRAkZzhTBbwXW^}{^X9D ztlLU19ef*SGvT=3!|Ufy*!I$kL_U(8t1$iwcrojahF}kYVFB`V;4W%UvlBG}LpF0{ zg{Z7jnpNW$5=pBRo|E5|3?~JYr>hh&ACAI%*+}$4OE{S9x&vh$bXPCZ0<(+5OxWSZ zEn7A$%g#v+U&iHZZXL%yy}5aDoxXvYdw|leL>$0g2HGW}OdQ*sXa>)ZOhZq%;Teu3 z>aL-2c`X(MWnpSG(!z9GhlO-nAvDcZZbabGWFC{Yff`tU%Ug12R7+{3fyJz$S%%(? zRZU!(pbZ2b32WS~cmUP#z(Y!N4|o;)A%35sQN)OJ3MHVeH{cdDY{$?Il?`xTI=o?A23mU-{d~vmX;a+X9?%4P;3;sy@n)e3Vkf z;!<1a#U!jDrzYjd;aJrJNy5|YbR~aS{c%;*OJ-ut6SG$q_@Du8M&i1`#EiBrjb)E6 zdi-ePp#J05KLJ)?+nH(Qdp5SVFxMCK&VGA;+aXEkgLws}atqy0o8!Bm*@y0D7L@hdY;R{`!5l@mAQFE9Dws_{-Y61ap|>~ zK^m~oh!rAjTe2)Sk)%HLk+z_S_dZ2oo_Lb&$C9iF6_f{{$`u?E5@HN7hTCj(ufr?_ z;ZmKH708gbH160I6CY_B(XX+Q%lYN|c?*SYOkugOkPZ*#w+v>(QJ-OsOQ+RvSkCU3 zTs;Lb1!W9Y3y^N)SH%Q&Cjb`67PoW)zzsk(dyo{(3FG?{Gf1EA`mwX@a)V^Qs%Nho8fDn%SiQASQ7U@B3h0|$s4 zI3T$oW*htkn@FpRC26~Ki9~u9io8zT|JkzVw#Vkw-k)9e;GBp5*feWW?T)6}$?%QK zd3b8&@X_Ok?B3RTg}GL}=*gvRlbCBY3&>BTtoP3WKW4Pwz25cmdN1(1-a}}zDv3m4 zDsVkdtR1!sBqwM_K@`n%t#qF@pixV}JVWvE5z{xb zA6Yo&e%@7WAG=SAGzg_&Y*e79><~_6vVp8irnj_|2po~#-a1chO zu%L+G2n~-6*g!*^#Fj;pi5KZHeweJUL{Yr<`AwMd=Uevg-_r2(KCWE+K>SktS-gOI z;!qIyz4m+}-u?Hh$KUx>l6UjP0bDlBgV=eWy9_Kf1Hc#{Ua?*>SqZ1AOmW3tFB2rU zP$plThO)LqKYu{huJ)EgJu5KnS)Qr!ZJ>Y=`$OaL0%TChcr0WkE$C}LCQ-H^sNaAH z!=>p@J9#&_iJ6%o6rI)2@ zv)N=*&ZQ9{0(Pqa3aMdF>3t(3GXC@w1H$9a%V!BMaDV!9+eMNO4SrP8jEG%wgvYOtJ-_~p?|#k${ALu95bdY|MsZVlm-x@M_%cZ-|hB^!}144 zr1sdfX6K7dFrv7d7Z@!+7Fp0HV$oov0}3-92ZZD6$xa6XDql3NjNZHeOJx=u2hP{ms%^v^6 zy=+077PQt=FmE!>aAJ$YI0ZDQeZ1Povh~Cesa2-;gwLvcL)c8otK!BtaRSbM1Kfh$ z>`c-W+Vg-g_&LIF476iW-@1myIihz5_snnPoUN~u@e~1$4#0SHXl}EBRr|l5uy}!2SX^OXpV+u$d2u9{ zlWunU9vcfBIA=Gv)ib+WA7<9IJqtEwYwJV1S!O5ceylj0af0b>MOm)y(NQ{9iYOy? zvL}8%*&RQ(qC{(kRgRyBU<+}3Bg`a$!$A&-<{5KSNFrvcF(o&TamEjIj;MNybq)-pb+Tbq=qzZ?0b}RF*gCKR`_Wi=4kA%T>NfJ2XKC09 zY#Wl@3^w8z+5F(~2wM`d6NnCxLi$v95OrZoQVx$KV0xHw|DB6x+)?>XSl^I-i9!6G znng4E_4+L_D$6-7R%A-V6-U7xi`I zgr^uIZOKU~Mw&otvC_l<5|$*^L8KH!15Z(tO7_ypf+W_F8Glk1zVPmE-#NvqU&T6 z4r9OKYQY0ZMYCLq;PHfTfc(f{9q3Q3Ktcd)sU?)bB^r?Iw|h(vlIlUM4r-OiJ~N5n zNyjqa@fbNfgheB&T)}a%HfwBZTxzC`Cz&cV9fX{ZC0kIbd65J^d662Djp}t=<{!)M ztXMg(V%DN*0|v}rys&ESvWgW;7B~yU<5lbJzG(8oI~O?f z?_9Q^a`v3@_|Y|0V^^;pJ$?<9QIW8!C-6<+aX)_4j5S*21cnvpt06nN8Z?u~@&u}N zSgY;hZU0;0GmW<1FSv3%HeG@t+_Byp5b#v#PQIguAt}Q|Aegbcc7x0?kwO z0JAs5{dj`7|ERbZPk}F|IPnF1H=h53Sk1K5?wKX-#xrN_sbwy;&1D{JOP6GzN55#u zNn7`!Y|826OfM)4lK&_9AT)`MXdI$*THh0|wY~>^j1z})L3CZ-j`Cc+2lVUP(}V?v zC{a(Yo^txi6G_f<+HDE(QIU3%-HL66SUI3BrIl#hega9@gHI)Tr`oBf;69!c2hIsy zC3Y%e*yhGLDIO~?&gF8^Oo*smcmKU@h zx0^wnj=14EjfNIpAaY2j84(|spO@1!EhR2HK07(tWKRk+D7sbh(Zc9%kR-_kdd`Q0 z@3EA;&j_45MT<-1NTNUI=+z&7XSi|Oq9;}?-CUYDqu1#9;oHo%xaz}y`uJ+|rl-Xd zPvE2rt5#hUKidDOca9JJU{b!cJ0iuC&c3uGaPlRC(Z1> z1q&B1W9_5({HhD$-}mej|9)ZRn!jM{6;j8B0j~oAlv&eZeW-ikR zIAT!>>V-cjJCq6QF)RXeLK??tIX%xXT9$bKSwuF`&#{i8}|4OFYEc+UgqlK+Xn0$LBrShZCj~VpT8o3p=gA1vhB%M zas;89*%WNh3UqZC^wLQpIVnM^aFLfQr6kB1365T1hdX+uIt3*eA(z?Gc7~})Omg(r zRWF*hcx1*z=)gZk-Lu=lO`Z%?7oy0ZMX!o0EtARKE?jt@%D9y@#dT1TvokFv*% z%Na0t;hW<2p4)3f%!Xb$J$jW(Yy1ql%do)-lFbp|EWw&S|EqT(9GdS<^ z<+(jBmDVU`a$bMphMg^mSpM1)6>JGZ~((lQ<2zIh#6*-9A7h)?-iVOOY24! zwH?B5{?57xoLi1`16$I8ZbLJuB&i~Kk6|?Lk>oV$SfpEHAkqXAX#%o@!{oq-Ue0s$ z5hqDjgbE9sy)(O89Z8PF_?Rf@J~Gw{ib_txQDr`2-^@pnd}{7gvM^a&@YCD>(8HB) zWw0rBUp!MZNcxvj2vYcW3A z75RcuJ|D!)<{!Jod?99b+j;)6ty?ADnZ|}O=lRu04?4XM?IkO4aGun~F@+f-f+D0k zI3zGnyY;Gt<0*Kv`<|oC^=q16s;gMIXxPYw3;5MX?^)M;45On<7nF}!vaq6j0X@%m z^DAyJ*NO}%6xGUEMp|{55U@r#491N{BTPhskWX?8?EWDHK~t#!YJ_1`u81ITzJo%8 zLPLVxhePx}1xBRvfJ%`Oe4sUv9kqr0e+wxz(q^Z~!YCZLd=otn+k@<8dzW-5@sxA` zkqY1AP+U@Yno-bqBk$^ueX20fqkCj`Lc`RzZ4>6~xNF7qvYhe=i?Eh^WY_v<-m1IJ zWoBNxYv*Ibi;AZX7}MRJJZ8@$TNmx0F(7$xUpk%;CY`B+@uZ*^kA};27eYLB7Z$iH zBDjYLQjsP;m$~aMjNm*c_IwK|bkdBZ0r=K;Kwjk?O4RUVJITY4YM2c1@IeED5x_Evi z$%K<)0~^FbZXEdGF=(+Xh-@$FNp3Z#L~FZAM}6tm<`kOwRwe~wlnpv~LZW6Is+Az+ zr@jxA97tN;%WN~6Z0cM$;%iXzR*7{IeZq|!m@~GLU3qc-kjBPkGdApPoM4<$XQ~+6 z=oIt#AC<^wYyBvie=R=5Wzihr3|E?5Bw!6W3%HIXukaH|!d)NAuO?(vRo|hBDe#vb zO(VyuxvZu22kJ-Nm0La*>)+&C>i;`XcGw6<=&(`@O+P%?+v%wT*3)})TqT0-){WT0^g@iK;h z-(m*8g@^>3lNbx&xnSpe3G>RL$FAk}Pht!O(^_{E994krxQp73WS4TgWY{Hwie@p- z)@bP_7kIWzd70pC$@P@82`QW)n?x#jvT&2(e_HpBmo) z3*|#8`E;`N)4tM~v?*KP_Bjr2c<7P)H}BfDxqQNey%WX}gNBVc_Wb_lm!5g{*qn8X z7O$&Yu(aN7zdYt^zhDdR%u99h(hr6cPhGvrTom7e@0)xq7;+-ddGnG`Pw^fM%0327 zpd55ZG-fqnU|KSzh}ZL^3LnxCf@oO1rjl$nuv&(#4l*!W9TxOjVJ3(={Y0eK=!Zo` zMa4wLkUE7%6ImBPxL|N}C9lLyJP;jrrGkouR8YZ4CMSD!S?jcATt9Iw-ZyE}rnTbF zZUVD2f62J9f=O(6G&1}2Fwc~ zd?j!k7bI{sVWCV=FxH0z>1VdYXX`f=}SB4B8I2M zameBERqkpDbQhGJg5(Scn-84lJg^7KPvHcIR3$;SOdX2MBD`#LIxLLi<&hiiDA~4* z7EUXNRJKi{5zkgr7&%o{Cxl^Z9 zcpgQ^o`6<);W8vKtwRT^?9@MIEET5UpHbT?Swrcl*Xf_(5V zC{cWy9JzP&@+HWLW$};1_Zd4VA;)}|al&nhJ&LQ+oZj=~eryS|#*|ji3y!vdT$biq zF7uQLE%BPI6$Zl!8d$CZ4<4G|d0M4;281Ltj0+7Vt0B}BYBGj-uL(>=J7p^W+L|-_R={-kjj1D6w_ngfHhh|0xht=R;bZ+NU=`f>3q6H0-dyRv60qp zR>`XlFdzR`me2HlESojElziEpxh1*1eHhaZ*=0j!jdR+QozCQx-XMn~LFw$K z=N-&wt~62NBJetpr+Ta-8-u7?i#??n1OZRfC^NOU0|k$pq+(9>G@&It!otGLVP=!O zSrBF*y9H!&p5hGFC?dv=w|#W*FU$B5nDcEp zl3!CwYjgC+{ahB1{U|yrm}S@?@E6(A7_3ur`TD{7*9yFL4bo}^t!5RNK`et7fJ2~T z=PBN4f8yclCc{K@MPB&_Wrs}AN1>lSbW)hRYn>3x_V1_@W>u%X_??Nm0}Y{rMpvWi zNtHDr)oDWgQUCB{yD5vfKZFo`V8qy$XJXti%NBwg~2B8rx*9I*K@ zr8G$SwEdf$ zs8dxK;jYNK*L&RV^#9FnoK>duGmg5Qza*tT&J7N;;P>om|`Z;J|pAoCZ zy8(JKq2))zu*O}XB%O{$i>1NnI!3o&SU&>~N62LK8hSfqORCrl->;o~tM18t8`R^! zO0_U6kH4Ja+l*FAL+>7>Gq4(>MrmCYeTQRD^$+Z4@bO_`gj*y@=fg9>zSB^))YS9% z2iaaz&*Ffrn@FWzgkJ#Ukv+WO?!0S|cJ(B!ub%Tt>Q_JUxym5G5e#BO;?2in=}}Oc z@Q+_`^XxYGRw%!_#GM_*LfOpc5}a#p8XKv zTPg4z3%YpZQLQSoFp|E3!{imb_q0_{=*xNKG^ymPhwOWFCtwC$h>s0vHsgA%< zcG!G8n(nbmBbn=_f4W?^DF{WQ@v`L$y=yfL;xIjArtmJud1_wAsX=IQzo~9WS`Z>Q zI5;{u+GtNowi25+CWG9zAQyB>$7Ulf=|rkP0LwNvG%y2j48Bc#UHrW5_z67ib8Co#>Nn1{qg;!~u)6Vu%G15U+pIA+^U(X>h0W1w|bz!uh_cr?$u(n=z+#-*cy zI%4?g_*%WsQGY)mQnI4nU5%w1Lh-Rtk>o;&kRXFzuFPWas?5UrvwiuD%dH|Q*YfJJ z_}y{2;|JKXB9?;Dn~>ugozdI7h6`TX5}KqKz0}61^;}?Wgi%j+wlt$85X~er0^_`p+*_rUm{X(X8^xfnz}OKoRWZHOn?@hqE(TI=E@)%4sz=a_`% zA5B!94^5)eAi)M6bQzg|#t&IlK=Nc&u+&W>lTEVvPPbE{%06f(bbaAX>Xde6(nYeI zljb~%&N&CIlGVHSl0&fM40Im)_H#~Y4=Yby)r3qvflNIoJF|OQY6{&@S0f;(Q+j(6 z&{VE#$M}d}5p3^D}=43!iyXtbx|Y1gx29y9nQmS-3+k>XU!BZiY+s7me?`_XRxzpiY?+r`PVF* zF+;or(=G%Y{wNUtIv%B#_dkRShE5a#8QmHACX62DBd{Vt#W5y}8pq-9nI;Oy&o`pKvNJmhq(_|=~4;^Til)`T~+ z^(M$#>-SuMj85{^`uJ#0@9^FC7*8BDPC*qGjqf?EI$lpjb z>ZnB}ePdOE)gKz$%U$;%^(JYQ(yd9pD3s)?4;HO&zFq$$u?XAY@r*mZCylk7;<1}z zmBr~aTK78lGtOxBbKikRSS&`PrJIG^HKfp8@0afKO7|J{V99oDH|8B~JCf8JDgoMS z!ICWXsW=ot48(d;V7s32G3wn9yvpmmWHg#c^}8rf9U>aujXcqI^56IfZv3omKcTm} zA`!LlrCM^|QhU~dM!WC6@Kk}7l6usG@bg%9(-afmVpb~3xoev_EK-h-T+d9ZDR%-l ze)!W@FOiaR_wIaXgSZ&ii>vvT8(+Tr>URh3U$t^GIm>(V61Nb>myPDT^ifzq$*P#M zjqD(j$^`05EEtB?0`XKcw~>5!o}`Dkp=p8V>F!2Ys)PqG>Cr38Zcet+(^yXTO$790 zZf>4Z;+f_tNhSK71(*VXGGsEsHyzxwdi@iPdHr|%<(>aswZ39?5z2blK`ter7!_3GKb9_EHmTi0vh2hYykk`bM4&s{zGQ}Msrz0ci0p*}7Kn1R;* z;lHM}fBNA>-|9ahG;L3#<+K`d2??p+vp`Nb4p<6EsutnZhF{ZJBa)2R-M5juj*w4l zcgjVooWu+cR(;3ChkE#dl2$GiGGUOLF5gnR6rrzOVTHh#9@?-nZL$cv-U@Nj z$ogs5s59!MQlvw(PRY~54`e6w2`TFDrjY*kP)O0(x4L|qrTw~Fqtj{eELHbzTD?YT zH4JP0ts#dS7eRW!O%T11P&3(pJEvC9c1=B)_tS@)W<8X40DyE_68&%AftqyAzzsUA z#8%}BA68Z}c;IaVTvmmS!M|^%`3c9|Dpli_#y=95H_nwTZB<&ci@?9TH4^V^2}_Cw zM=yvvdYnw>W3sGtp`ZLwI?JQUG#c&1AiaU@SfkmfMr*Ih{I+&eH%)0lK>!*QVzqy| zX8Qx}grZS}h57k~u0mH)f3<20{#~j~u}yDveO@BFv$saNZIWRt(@fA(nhiuFa7f3i zQxA$oudNBf%F62B0p(J>R;S$5O#{Du_+6a7WsV zN4Wau59~Y8P0Zg>IFa?g@qDYa{g-EF+F9!CeQQMi$E>m;vt~&f*EXlqmeO02$AfQP z5KeOCC>ISvL(w@`NDAh_sMhE~Eg?m7=76W5XE{Bw!nGQtB?QzUy{6iLS(cwnkXT$s z>`AG>kmo#Vk3bCp7$CJIxaIDFrIhn&AdmzAa!*-}swuP_<9?l%7P~Q(4Y_^r0GB=7 zW;bP~B+0jz$iXf*&2oK61`;zdQWl#QrC6R1^~_SWJb`IS`r+tZZ{%8n7N1}K_^Yqg zem`e0UU}ED75XODYR^5k7;7ixy*7U*sh=m;)%&2Wviqd_?_WM|^2*vCx%-)M`|Ilt z;K2vq9#@`ZSw5?2+xha$a6^xxtlv2h3)#{|BLPV;{TKF`VM-@2{4_G_Uwzj zxBUBd(p(9=y1Vh(@RxS{^H82KIVrq*S9bi#b$Cv>*kYtlbxkHNCMJGZ<;JB2Q>rt} zgNCGKyBwLZwkX$KLuSm8i)$K4)y)SUr&Txg-^d&MQQb$mGo-g!@&>m)Dc9WGvS7t$ z@1FP@=HB>JTGO;9CHN_%CZ!eqsK{-_5%eiIDf@u|YE))YxgDUXT&vQj2SK4)mfAn; zLYYg4KX{2YwSg;Mf=?MAA8(Dfn&rxu#HZ}I@+H}+?Y#Qs_ou;A3{V1-`9}5$y>b0- z3D>>c9-Z&3srlIfsuBy#M<}Lo%gzgo zR@1D-z&KX%^S2bo$>`^!Nx&vbyv^b9&u#_R)L97Jv_oWPsol1&u(dz6M-1{L)FfPag>B-zmNtC*%E?%-eP(Dw3p~1o5)J1EAbSB}pI&;}P4- zi(Gy5Rk;v4gEqjo9C;qw-S?f)%8qN0bRSK-X?O$pnT5XunF2Y!txBo!Glzf~G_#+j z88n{p0}Xy4IXfVCNdC+dUimZ8999pJ_nt#qdkA+bO@X@hYx_(ai4@-1Ikd!p_cS`r z#hLxA;pAI&PwlIhXY)E;(kv2SKB;`8oQt!s>`cyg0%X%KWJ@PL0EE>V?I zQ&s5mTsP~to=I^h^-QWZbCqAu~$DF0aa|-D$Er)`POqX!yxGa!|3X z!)mH2v<32M5vaoIt@WQ4u!a9hta1d$J9D2l4N$o?!w+ajwOnB_rIFk$_(#j*5!>Eh zRad_`|6ZkDnPto3cgOag@vRS=DQDGCV0X5RPa8KTJIt7(Y;RXVz=s-oguS+Xec38k zOk^Y}F&h~j86DM4U1(MpxX>(Xwqbw8X5W2_Xpg`ZXPLgr-5S35Ipb#T8ksNgiMovQ%w6tkqH0mc&{r2>4JN7+p~WU2(C#2e{n_Vl`t z{zY+^*&Yy{83I*-u5u+1RAzQhwcC=c39-@M2n`C1P_y4uF@N|Su$1J7IVZaJ4-7YMDrwj`QqG0rJ#hdfNk8^?l_T*;yFbP zqNO!v17X+}BTK@V_!yFq*iIgHfMr%TZ~Wo)EQ#fJghoM5Nr4&61SAe-Ps_HQoI@K= zk2k>jm259^gkGbZDaxnf%P#=A{9EI>{JRqyjot$;U8YX%0%yjzw6ri8TegUe@bd@d zjHmtPNv?p_b&o+dwA>YK0_??E447kBy%v-)TWZF*M5nrD(5>K=3^k9zW+J)#44UqS zk%}!V8lF5HBe!CRxz?OwPqWinr0p@LL;j(Bj9c`TM_p~F&*GOnO*+)Z@tFRNA; zZ=43yIKN@p>tfW{x-I+LPT{Xc{$b00E^_-rpNKz*=hrsmKfLuD9EN*t*dQKgyFBgh zC+`(EGpVybIk{2F*`~F9L06ekBzoPex-Td!ff0CSjRp$>y_Zv6>vxK;!jfPmUY#K| z@v8hQD=dxYEUXOcT^~5v7r?tz@D$RdoR;zq4-bzFk2F!Eh~(7xs~Jp_q`m3}i;+Z; z`&18B`-3Wc9Pz@34Wt?a(_Dkdsts8BIFp`NRX}CgDw~|X*ogBSv-Mjn+2-@yf7#?J zm)M$ zA=zJ-*;#)kL6G@zf-XoF4H`AQ(oyt8Dq0&7P%FPdbx_0veElMQc z>EQq72dQk4&-D-Pn;%@^CL@yX1%~m2$=8ONjp}>gd@g=y?DO2r3%~f@{GeIVc4PQx z@lEk3KX*T{GCdW3f7q9zgq0H{JBH@E@_|X}l`QLrsEP2IRF2szYu1ah5#9`JCS;a! zX8n`~SNPXIsdJ?uO*>M*>#|e$<|kye-C|zlQd$pA;fKYPAEM9#FMhCr{G~b?X&FHqs9JywC9#HISjrh%Z3L`u zbzKL&nlo5Ogj^gI7`}&ZJ&>Yhp$A7!)~?X+*>a>J(&SSZz`SvA@qG-R-C|{BDo=GF#6OLl@BhIz=1*$z+_Y8L> zbe0Y6f19gpX;9VkHBY{NqUVw$HA4u?>YDi56psDe>vG$;sr@J!!YlLpR;F7vx!E-& zCy%o0w&AOHZf$?jEko{d=Vxo`>7ME$i5NZPq6ECAKER!@QexZ`+PsFj`C?ATuk3TvXONClCG{7_nLV$b-Gesx!yxUKD~_~~=C^Ob@WVgiju3Z4QJ zUy98$CXC+RcIbt<*m+E zoAuV4y*qfbs%eeRs_*Rmke3JqCvAlgJtcFhf{1{a`fe6B74U zCmG)2a4b}XAgsx?i;q^d9e)~)ZM^gW$tajw)O)&{UqX5VJ0lKfN_rs@!1PDOJ7#@R z9>XIHW0pkUtM|;@MIG7D2zEgDGQyRyC1qAhCNwVO9aB*mcuhBh(Sqb5IF{Iw7;On} zNxFt(EvkuW>r~QqiSYSUJg;;&MQEQ6tb!q7dW;3yCrtav<`6dPL`g1@V)pds%fRji zY$R)G>oWbm0&GcJFMZi1N&Ei-+%Ji!N@{Mjz*5|#Q>N^%kp@}g`;ztvzcj171l;*y z(NmK}m^r4PlZKr`#`^$giDQ*kXUXkii}|Gk+O>1;PbU-mR-@9H5n8nR2K#9MB}!{h zqaxSp?TaO-iLQ)tbAdg7^>C0}Vm`S8iuka&sr&t5~C_B<_tFF$?AhITC7I_;}vEZX2mvZNYx{@ z$|s90{+4D^J8DsAH5n&4Jh*+RdCd1Gq&8#41z>^9!sbSa_;@L?1G9ybvDcTZ*-A!0 z)iYJ#Xxctt|FTIIs)Fr~;8DU$2P{ijdOWD${2!`?7$b%+LZ6S_x~Se>-<9aL0=q>0 zZx07-Hr)Tr~G;z_t?h0?k6CFqw0m<`b&t!&o*?$UyjJ0_%d=;V6lirTz;&K zMDZb#^x#Rz7LOX0k3~x$>_EjloH?wF1y%(lZZa~@c7O~CuENc4Y6*CM=j;|SyTU*c zb_{WssJP2i)Rdo}FTr2&T4D7?FI8~ibd*i8;YI4CoGPg1epQv5%|}yU^^e|{xdHo} z7Z#{2*tuS@Thx;$yRVhT!@xX1=ku~#UTYG#ZYRdJ82o6hzIV6MwSN2Mi^uscGsm6M z(SgLt6{#*dYV_*}hxSz=qlt8?s-zEQM%lrxLUK0g;B z0+dDHX_B8ZPSfqpT9AR0$C#9%Xpk1gI;+!Euz7ZX{Jp z$#oXMa9-{x4$EZ(=;OZ)jFtb2n8(LQL&6Vd;7bJw4N9osGamjvImdrrVn${6Kx4L1 zaiSvK=q0Xw_oF)2f4@iAh`=Mbk}NpZ?;Aw8%!K*Aj)>YNW#~xsiF*d0>h?<^#snDe zgYqFbo6vf$pjCtkVx4|2Ffz(tsN~}#XSAy5>$Yfz52)`_oyX>M{IyJltF$W(B$q_& z@qbACcV_4ATbBF{2Z#d0kE~mdS-SuAl@M*L%DO(S(Whdck^)Pgo~zAMXt%Mo0)-r; zc!k}{#;y-dkv4NiRF6GZDU>}l{O5>J8}}4KU4mG{5-I(N#1dEc))Z|9m?W1-tV@kX z27CgevwNNxn=)@7zMR5~DSH8S(aX?UWx5+%a>gcKjCGE0a9d5fS_VubAL7eugZsC2tLx_%|4Jn& z#-@ZWvfoKtkrxLyS1w1RF;wbG|Lssl@2C6zlr~RpnUY8EGj3Y+B0XfoHpTA0Jwgm$ zRaYx4R``!T@;w~xs^d|ew=0d(5LH4-uY`7q%EguQ`q=pZ?MX`xHQ`AuiCcpGNnr5@ z`)k-YTgWRU2UIl|LN9kI{%jLsQ?sJd;*!4ji{m9yWopOcaKy%WylfNB)Wk8#QgfvC zfGh)8w8Y7tBX@_z$O{ktYc9H;`wx(F_`riu$N%CNuuq)8{{J`z{-SqSC#HmhtWEZn z{*n@f|7e;Nm_aTUWAVfz$t$NMWM{TSTB)eLDC`Ub+xzppH@Wn_H7++XXGZ{qZ^OCpY|f(mhQGUA4CQa64KSgg3=alo5{GTWvir z3|gt-aS=vO4`22e$q!NUtgczvPAV;S)+6EJrQ@cVPPnSuOp>7zOH$;!U~mi>l&Ga7 z+FV<>qz%z%XfQ3Euj$da&c?-Xx^R4O>+xLeuM~s`N}by7G~9bCkD+1za&GW6uU~8M zeSdmdlipv?(pv5DZLVrN49P(m!S6{{=k?vxbCQBgQ<077_WXBA`S=m+KA2&g*KS?g> zdYLHy`?mSsyYvFfR$xIbYy#>P@H#$%9_KDaDxvlSToy)iXFlBbtR<6_#HHrBjpl-K zf@66!(CGv*uHjN2M64LZ`sf)aplm)1#{xEur3ibQLhz^oRQS0`-Wr%HQz9NiJY6)Y;vw-1e4<5lDavAAa5)7aQxglPJ7D$ zrYx)Jr(Sa>kaHpZ+M1u0X7gWeXD912Kw%_lxNVx zNAfL%#xVg8cf&toT~hLB6+?~hjP*|4{YpQZkz?Wnk&3d_>^24+0Y3=d6@v+{2QuWNh)RhO%n+U6%)GpC#k8KJ8T z8FCCEe?%bxP@zLJ0g)@hU~XVkU?e0YMsN{<$TjM4sd?xT)?$hFi13IdrOL5_>}1a+ zrRLNPEo! zqO5vUv+UG9(dw)M`B(4^3sf-x54K!A;Fr@N-vf3E5#+#8ncq^!)xu3c!qGY{c(N@X z$-m|*lIUMaJcXt*S=2{2RHqT>|bs3;Kw(A9v?1uGP&)p z%_!USc3Lr1bfPd!TO5dsC8HK5?yf}RE_4K-!($Z54uJ};1lXnxwfn|_d(MHebKD*T z9W)U|Ksr-bWyrjy=ykhRsbG#B7wQPnKPMruR${!KfLxv~JaQH#Q{DEcKUqI6+Ezvu z=8j0j-Dhp`k?tk=oRTXl%rM!*@I|PPpu@|V*u&xrgvCL?$AIo{8e?IwjIyAf`vucX zv4qN;iJYokfIxuulbJAQ4q}9GDSX!Nm?wtd-c*A4l-Vz>bvj!Vu^dW$iK02~+PU)z zc-#Y!%?sHQoIKfCwUd99X~+a&2WkvtHjSbGD#tSgQiik<8%;L}?jY;z4?{C%>0^e~ zi70#gaQ9-7)5&SZd3!o~Fq?*V-{qT^HVZ1&&r5G~ikyB8uCJfY=%cQTj<89%AygdA zNNP>Cb-9V`vZ47$3_KG`hiZQCUOSwa<^Zl6H5GZL%GZMqi`k?@=wQ=G=-bf7LA5-g z@mX#li;#n0G)7Qx855Z2R$Yr+$ygkmLGYp$UjR;=4{ExoUp~Qd!F?V1lw&ABrr48S zZP@Whj>0-}v9tBJOO18^wu3tL5FXvW%Qxf;Tin*~)R%Q0H2Uuts|s3T^2S`QxFLpc zC%zy~14jiJ7VDx+U77+*b36Q^XAIpDWk*t}UcxV~9~m#JxB!lGP-BV#GA z=7=D!hvy_M3k7f7AUKj`iH#8nmO9P$)+aB6dyXuBs_%u^lGHs7?V<=A)USuieA>Ft zE8y-f5b@+`eQu`-6^+}FN>2pmS%=w9+ciAlWHsO8wM4D?oR!3t?6*CLVLVx_4w+BpZJ0KCA^W(3u7du^6+uw&_o%hIm~haFTm? zd$hU66)Y-jK(sX#f5zG7H#-$TB6YH*|GT}S9;$5ZvuB}4_%v{efZciCL23bmUf0Ol zDbn{y&T8X4R6{W6RvN?u@e)3{$^dSBLxw6yo)JK?7^Gr1I5&~DcUAMNJQM< z|KK}Lg;i)^iDIt#WQS3sui*cJyv+1t3I8>z(ZA$QO3k!0&B{WQ3|!6m0!bO7P~_o_ zZPSDZVrTB1J&4|t(v^Rs#0(o~L(x+CmU56Yy-=`7kZ1XIfb+b?X&@)Y(1W=8)P3uC zUjMd^z^kRjb3sN581zJIA2=>&+Tj`E0s**7+w|2kIa69tPBM;O3~4aloKiOmUj)_l zXKU@lPwq((c!!tO09$|%xq*t$i_YA-`wwIT>qa;-xn_lI)T>!7irz$Giyo`?|Bi`~ zb=L-b35uyjp0D8G;Dm@2T$IkXy&ajlP++mj=>ktl#3R&ElzqWGuKkH~Z6qvysfs5D zZNMmgq%6dflxtEn6Rn@;9X3{pKcFOKnUlumTvyu$Hko97FAY|Z^UyxM9Hsn(Y~DPe zd}LD_>8zt&FJsHE->KG_9V?_2RgWS9k^J#^C07`n$_j-EEg1cr&X>n33@l&|j8*&X zzRUsOIsotHW@90*)G3Ko{f-0Somd6I%!~Wy?dgU?#OS zOg!|{AkU7L=zy7a(%hs&z_nq^%Tm5Wr;ZAlc?jB+R3IM>-v#^|A3zE+M2i( zKfHH}#mld7k{h^YN~7`B03X}U@ST?RrVl7BJPtWB^1S;VsZQCXa>&xc5z9 zH#AOnDUW9^JPe1Srm2NDVD{f8h^omDjAzWk+cr_uEC?V%1?Va{=@dgIGG7fBqY~Vs z?V6rm0+n22n=o_mH|FZ&IdWNwoDT?Qb#2F6|p?{&-Y9)p=0coHaA#~#LqNkalu?O`RHWBQeD8&$2 z2>oxfFsgxrwPF_iOAd}}wn&*K4oYaU@RPxj!YB8?ZXmT8C^k%N6jaGr$YR2sb*1S5 z^#(+lOIu|JrawI=-)QY@PWcmenn+IM10N*n%hr-g=#w3nTZvE+sitUWqoB5cVEz6T zR$yBuP(UH3RiI`v7pn^3wwar}%%F(H5v-lHnFt`9j5v?N$u@#t9-^^RSO`_xppHpM zcM{BqQdaF;2Vf${rv$tPQgZ)ZZ(AAmftDQb#*(}XfiVIGnQWVB5Bu7ndB`#R=u8^& zz$RnBqW+M9RGpf4mjdf3iq%{eFn1TGV9nNBBUs?Vw^*ibu1LC8|&hS&niD)gVC0B_F zUKajR)Y`d&M5-HmC1}Md;yG7!dZ#f0av02O#)^p7T$9)8wz!4Of~k_-n|i3AxRe$n ziX5JNP_qA)h$G#f0kk0Iu}m3g%7!Z$zghy;7U8uaO8x?gvx%f?5*Ju17{H|nfed4Z z1Y2*UO&{6U(nO3QD&9QQgNP{o!5L-+1yTKxjTWoaq0Ae@%t@wrBsf#dRV!R`6N+FL$I$Vyv|tgmS>U0F*qf}UfT)SsrKs9WC9z0oS5e-T&XM}B zEBoQe6-YK^&neWY57JnYq|LzghUe(r4}}bMnV;Htzx-$-y`K?xIyPHnbYTFq-!q0K zz>GOyQb7O|W=%+=k3s5OM$=)3GPnWR4{ws4)dYBOeIUfYQS?#^Y1IJ|h)t&T$P-1j z+Gk_11hl{)+BWV%*M~f;AIVT38Hwm4A!5*Z znu_GTN&HAx9Jk}?Fw7BW%%m|2kA0$m^bj7Y>7w(zm>!sQw^y~2QEZsQ*4~%)m3c_9 z*47VQKRe5%`OB;B@KINPN}1=}%A{@z&4=RJTs)6Hon?MZG)tt(3NvUrXh3QoOJvlY z3*WZKEmgXv0;u8e#cGnExd=j?$JX&^x}|p&WNHClW?Hqn#ub-x^@S*(xsoD%&@1%` zCDzeQPt~!iF);qE5S4#f!7r|4)`?wfTi?LyiC)KxTQ9Y2U(44c3Nt)xCws;9=+KA0 zpR`bLTo_}5A`fdDP~|(AW-B|9VV}Fr(PlL6r^D-KuRE(PV833j&V-c{rA2d)G_W(? zKVx!yjH--p)geAed~`drwAXf=6MciwkyTY_9Vw z7KQ~pHP6GHjAnpq3tbNekSHzh>ZFMNWyk=r2^ba7^Rk`xtIQvXhnl;yt}Is*g3B4L zYGLojB>WAqfO}nw{FraMrB27_HFHq0i-XHvV-615AW7?QQLK&B*)F?ZoZ`S5D85D^TIyFb}DFj2uCGgR9g;KFZWc6*>C{ z3Dhd1b1DqkJVPukL<0!FeFCCs^DD8ZD{A&j{Fe7Ci%KG#gI2n=3 zsHTR#ZkVv_YI!zeZT^TH-y7WuUTBo+Zt9c=37!&11TMx2qCWUwQ9=2f0CQu4Mmr*N=0=>6X{WLMpJ8td4*w7BSL(tKDVkOn6dO|nu& zVgONIU+m#O=cfX?he1nkcef%g_jYV&+`W^lJ%e^6(mzf-Ov=LN#ybHvZ0MiZJX}Sg z^bW%sZUC7nB}$ZY(C={#OOf-{3`T2Ia~r zv-VRVI+^Lz!=>kEr;zito7ddz6PiSTd3W`u>qpOE_g+cqXeC`_6WyrijxQfT9)W=8 zPaYwSp*O@^2hr(x>(%Uby+OG_EXA&C_j+`MkTt8fBG2P{!Kk~r`0$vj*q$b3st4TB zy70Fz@dET{D|q90c{3e8(YElGw~aG{B^uMU+!QllBReJ`2<@tra_sr!wF}Ggfu_^c z6OKP*k;Zchr30A?U*FdQOc$sZgN?y}ol&vv%H{4ZERRl?-?0lpy8ZJ@N#@E&;d$>* zXKNhZTajL<-`Jsnk3r6Y=T%I{r|?~g&F0PF_Ltrt-!{whAUFh`u5v4&j4Bp_E!Vem zpcF61v50pEy7dCXV9xX=h48;9zzjKd-8{C~y+Qb4%m&$2>}-T_Um4X-;OQB=1(1WV zdO4d0$CUPId8;H&CK7)5W}cD-Ib?)UZG3NxD?r1T0cCSJq>0iP5fwV5P+{pgnH}^b zTH|OA@;w!fKW3}$5}QF0cT$SWfiCvM{{;69=Z;5Nyq2H0YvcVGinfU09nqh zAtUGp5rbY1_5+kHG%f{qd32QUwu4sZ$5=x5*$JTV&R8!!t&Svi3W{J8Uf%UFqj-Kq z%)CvA#S2T&T~`aSOIC4-Dt??1=Bju3rmhWZSCfY}@VbdmmiEFN=4~$!*P>%rCZjdt z*1)Z)hq(u_GP6G{l%UT(`OQf0-)8P!V=N149&hBKv{;#!V*14&=Y&U*atCu8w>P-s zx%2chnRt@G;{|;P4|q`g8BR!KBGjOI(xB^TdDC0V7sjA(!Xpr7f&BZrg?fQ0whsDo zF;`WUtMh#n7y#_00QoVdoC<9#1**>q(T@lXyr}R7h)YL@R%-w>RO8UOQECKB3|l;& zC5W%LT?OMiwL!^#sa4oUdCah7zcC`)q~r>%)h{SIT;@2$Fw4{PB~fa?kVQF}78bVL z^G{iUszON#B!tZF$1lI!MteO?f{X_0bLF>V#jTGh-O+1L(B01WzNUHk)9)qyHRT07 zf|L=uuTkqHuid&^h&R_ypX}FZYfJ>WnAJaPf8##~&0BVOJ!<>}=QFDR=(RhVp6}(r zuuto;le!JZD67Ao#P&zn`+Yg+zDkti@Yjm#^b-D_zwdxd*&F4A5#7(bdxi~4Z>pL( z6^5F>mFMndy50Q{y6$}sxdf^Sjlc5(su42|cmh^`wE%%qCKt&iHlsixPr*8@sN|Sc z#hu|^Prr?&B$h-vR%e(}2rciJyjbrbSyuq;erUMBj!+6+g_=?bHO;99m z8F`)|?{K4@0}-F(9yYnOKzKaei>1t>Trs^URH*8vzb4kRzw=>NG6;$%)7_D>#n#fSVnEeH^O@O=Om3#(c)A*&+j2C_F)^A`U+CCM{96W@ImcISVC z#}~pseV|g@9eM)-^Bkjj(wa;X>KJb{yEC3k*Xh_*>Rgi9QID6W-q`fW9jlg#HMxbq z4?3Qvca6bSovUn+k8}3BLrmlOG^zaMbvvm%qW1x09^UN^+Imyn>G}LcLD1IOB!#c} z+g8x?`L?AC^^_|Qu~oNN%WU9${^M#9_-r)R=4mB;0u3;??RmGYF6b7S8 zpKlJ;i>Nh??ET*&xXv*`!|7VaEMIp$_V! z&IRmy>)@aIAnq@W8ByTl`);(UzlElz>a(KWqK7;hv%|Az?U;B3m`eXP`XNf9esdqH z&_=YyRV%OF2CT~p7VXw`4&Da5s*CJ_WKrzfwE1j(FGf)A1$H_R_slLQ$;pdk+pO^q z2OQj47Nc2?g;;G$f~G+x-(o}g4?IFnmmq0xxsDjokfv>m^$Pys3aS}(5=ddyg(`Y% z$|e0~WL%etqi*+9q_VWAd$VQ+8I6$5h~%M!_^r;BZ#Op+e+4Q=ZnOdbuO7kMb8KC= zrES*B#R4F!Im(@&o1n)oj$HKv`N&NFz-vbqeT*zP| zlui8T{HB2_U2qtu*ScAlIshZCqeYb`3rhTHPHbzzpc&X{he*QmN3QHpoMr{BOseU? zL^c{S&M0W=f92-B;|3>&JD5lupiwQ`oI{bEF{P!i~b% zg>M65BoKw))2&-Wo0ol*=!MCYn&`nXdBnNr0s>h>QxA4j`(WFtR|?UXN7;m?_<5x= z@sVr(nCB~sPPkkTQ!L3`lm5`8mX;)d!IqI?&u`$6WOD?)-h5O`l=5I&Mk@^O1l<@g zD@BO{)lS*Ob%WGG-Mv|tw=P(I|A5OB&ZKyDh!v8sz23Yu)g1ffeT-L_N$YN$9GmLf=TuZ$riSCF zFQGrV?>f@Fy3JgV=rDTbS6FRow$zfUsQ$ZY^vJZM2+PNs`hF;}fo=XT9Ybp~`OCto zQ^U+0cx|$xo}^f7xTopz*iys*F_o1@rhGihmYrJzHz!qGv2dx_5v)Kqym@d)!2SGK zPv&a=A5Z?l8`750xhxk;+fGG+z3L0t3{jrM{xz+##8wCCSTA*cox#QE~Hl)9|* zp2V8Y)iT3b_-WF}h8HZwKQS`ULx&w*aErH(DT*Dk27^vv!$JF<9;(vUuq^wSzFSAU<*Fk zdn&f;v1l5*LS(S(uE#5v4qNlz6}FE~?wB8Grf})>_`@Ul`jvgPb9GiOxt?o7jN$~IH6ErwvpDZEi^ z4HqfTM|IHJ^C^@9&OJgMC;6)PaRUgp)(m4d(bX6bEP5?XVF)ky`iyq&^Mg4jlB$<=JN?t z6?W7TZ0lnov>gLkLgom@xI1?AJu|KVGzDg`q*=C=jLsS82rQg0Px^ zO~d>OSc9P&7A1B@%++}eLCpOEn-0y0k7rm)Ro&5I_ul$MdGtH8{{!x>o1y%Cldib@ z#_3O^&uQYC=S&0AN1(0O`P^^$3GT4_K;A7zpDL}$=LuNIk*Q|l7DFbqmmnI$$z%-F zz-|K`M+EaA!HLH@HLB08W{K$}c3@|oG9)hxXUePt(Ix9*I1k(t0IVL-wguG-{rWWL zn<(wtyFFHr>J)QyZGT7t$uQv7p(B@O zfrH?(ZR+}z7qIpI2-Ypg?=4tsJzVboz{!Kusa^XSbih7ouTN9z<(uve?R!H6d@6d% zldw?c-GBV9)AVXqhm9#p*7Xo8Ymv`sT4Mn*dZVc=mWl4jeLZ54iQGaSUe{6L6}^u= z={4HtRoeI+oxk3|a-Czp;`h1nenS7z(p-F*9X_DaikBq4sh4CINbrFT(~d|z8Lu?` zrc9O(l~O;qs+MA~i*=o4l>ghHJvSJ&S*w;Y473xr29i6EWHYy_=(hwK)#IbUQC#3^9%laSnU=Y~7xvh@}O- zE9bBHfxr7c|2S8~lEIJnrwgAM2pD*3k?^L_h5&kr`TZPHK^n>7X1FJyjFbAd6+erR z!=iK-3ee8RllYE!5_=I*jhhF^2goSn=~fGql^|EEd>RFJ4*)pn6L#f8v?VI=_i$=KvT49Z&_N7bEs=m z2u((K)2uWP9$zg?Dl)7O@PAO;Zlnt9R=Vu`N$611aXz?_%nYn@y1B^2dDjBX|VmP3D7A7A<(Zp2-v~lBZcIp={P&C6bYFkz#}-;T_J0I8Swk zRcs5CLt?4asBNv9<0baUu~@mrk6)!IW4HtW&`Om2;RQeO6)W{3rrn9p(7L5gi-5YQ zQYlTXZ82hk7Tw|cz?-bo#?9NxQ3{m8F7yMD+FSZ35Lt#jFg@R?&y9zE%FxUV6n%e&A{jY+LNJ8qn2(cUWGSUBboJ`bF-*pio^C#BcG^&P}2Hg@2Uz7p`x}q}q z^ZBI6v5~_ZT4|o%uD$HnY#)q+*b~~q9tQxTR3gt z9WF)(u`W{5r_qGBE;ZH(Z+GEY`QOw3n$2uZq)-9FO8|}O zn&Ay1egUGyUvL~Y4TEYpahI;P=ste7b?XZ5rxt4?Jd!TqmJ4wIZaAse!VRWHeF&k9 zgvGriaGT^BxLH@GNgfZtaHXDBPiS%czbwDZ{a3HAzBu84U(rHb-J=@O{t2 zwP_#_FkJ`hjO24GNg3D!>=5z$DEHWu^*b2$_){SZ0v9_1O(hwnC-m*k-dHiEFH!XH zUH-&Dph^HR2R3Zf0Por zEk}xO7f)Wm#|cE+EN{#zWPvvb7oHSy7y>+a*|5OWV=={fBZ-*ilGW-bCjvEW#3h;m zVE$NUB6OlD7v}Q`ue$6fy89Z zK2c$D;WSF?5LJYcr5v7+ouQ7kDHy-(jFN4F;gR7L00&u3&th2cjy`A6r}h~pS99Im43St(mWrMNGBie-iwp1K3e1I#AO!(2G+74#;$ zo!;J2(SwSl@|C*ywe8hOgs#U|kGVc?^XVkF*k1E~OiMyZ{8v z{Q5usUr8OSHrt-Nx{WLJ|JJX;%04Qr4HBJ(X8nHq=+vC_49jxQ#+@giF8+}iU%O>F zj@8z1K9~#DF1@V5Xg0vub?M}lT%?G}Vp?HGNAUYtV;I{N44tr;dxV)-b!H$1&?d)q z0Jy1@aaH7o*2-OS7pH~ez#~YFJ3^Pq1t{Wl7`?(@n+BvzSZGOtlV&l;6i~8%=CZ3- z17U>z*O{Igo(^9$Dy@deBoPyRxq#!5*DA>XJPKh;8~ru#Ab1`h&^W8%@=}C2em=tu zq|X$!&+bMq2Fa@*GqjMOKG*zHnl6EN!2PdXAyf1IdbO={=v=qsJ{8(D!uy!g#(!#_4=bItxn)IUAY?&}6qoP$~^V6H-lo#b7lll~NehRQ=pkYhGIHX**p zo^y%33XfVql5s~0{MkxGhWJc%#-W+HR)poYI{?%M7u3Fghq9c?htPIbU z(8cknEmfu@U5pd&&ckk;@h8u=<&^osUeV8&-{S3 z=L;&J3d`2^h$XhYEvRVG57W$uoj;UF2Fu;+&r3pre6kVfIGqbhNiO~CB*mPA9!hNe zPO~B7(VWI)c8t`2UyEP|1O+<^xQNEDI3CmODKj`v^X)fIbsy#)w^-g}-ah)#;d3US z7PqyDnj!@ zRXj_${=k6oZ`y1RV#*U@6D^!U%|a=A);@7Y+YC(0oQQ?zrXKBJBpTa8*!Fdf$t5aO zrk2&~x#pPFaZG*8^$1l;hEwO3f_ z>Ija|N!kM>d}j_wh||>a(|_y{OzDP)CPM1i;CK0hTfhJ)sarlrovlb{R^sfKtUtiLcBUJ&? z9a)1y_f(zO!JNa>kMpUq>`ASfikgf!fgCFw`2r*Y%$Ce4YOtVUE2wNkwR1DYqOn+` zN3y{C7(~x_H~b{eilbPsMBn;lm+Xqf&}lOOS#jFY3Rbe>j7@e`MjTXN_*aD`(Y+}u zQ=jcsPdKw!G4rNnBQSX7--5dJDtu_ZZbtK9->!n){5yr`peATFD8Qfz6dx&F0n5yl zh2J{p+8L3qmQ&7PG_r`it|{IiwoBpf(d=81q(DmyBHKmPr$ERbsS|(5U_!UO;L^<5 z-)9R!^YZohH9HtP zCrjXO-;6#T)F6TOOWogJ0iu0L6k!|81DP!Sq^7(AT6$@7XN#+m0TER>8OdsYVviow zX$PyC0orlvs>B%qzf52~oyH3lEcW4Xi(0-k!@x@;&dkEp@+FM$Lq3lq~_-#jMm~#i#2NZ40>~NscbhtOJFpl3V8t2b%sx+bFI{ zw-n)KmL;-8i7F<**Z%bqu&U-tvS!x6ewWqtdU5-lMp`nqM zAX#;n)KBLGI*Yxw*c{b`{agCXRRmv|xk$*|B-y997fdrpR5pT;zp28TfSk%wGT^7_ zsh~;BnXJ!MOzzxcnG$0P29e^7G)Gff*k?|cgCh-TUI6?PJRde|kQpY!qrz1*J6P8; zGJ7W}?Ssar@EFvUM?)JsOOU^i7~HG>qLKy&<7&^r3_97xFm=Bb@=DKn*l||#d^AC~ zL&GOs90lQO^C zPIlbfma4l>0&@e@qqEZZeZ9ZB9N*x*4L=cl>-4URo9MOf7E&}nf7)=yGF=v4>@tK` zw)jaKH=CQ|wpz_#aBbdCy{669PE5fe+X%gg+SDWaeBvRs_QdZ0c*f%v!%!+-4o+7< zKS@s8a{Y$HsnKJ7<7A@6j?e-Dc~Q<80db6xEOPJj$=5p3X#+PGq!lVmh?GeKa&io3 zPuco{&p^Q}i%U6X7TIQ~$qDwz%fIg#m>HJ@M>1J<>HvhJ@bYr>ITa3aMC1t{L)C=j z?Nt^ZJzT^FG;TUsHICM$(+=k1V~}a#UtFQGVYU9I9j`&@0V19$TdQ&uvo8CMX=EB_ z@QJ(51&gLVFb86STS$v6y$}&}lT|APD0h@2G`C-0;gw!7h7X4h zu_3g1Ly6J-rr+6J zaRu`bYyzgQ4?K)7lv9z#uhkO%73yc|*o@Lr$WfOlDb}u3Y71Th>`go0s)^s!FAD~h zPx+1J;YN)$6SIDB*pDm?Evokl_a};salX=P*DWY2i+p2utkjm(8B7JPPivolNH&8M zw}v+S)P7EMNxo+%QpnpMd3Dz&9J@BNaPXpDapq_CsjX2b3OgUhs9T0|bGB84JLH~j zlveB~&z>El2vPWOOys>mIAM>*b$|1pELb6__Q$1uU}0LYOiRS{3E^Kp6q2%Nhx1E|A00Ju=C;cy4eo zxB{1Q6b75r)n-Nv!a55mT>?*qF@5G88D{G9GAbbqf3mYas2HJX)KqgUCV}H>-b5WJ z#|K3wy;3XbmI3KZXM;h%1Z{3ZmEp_#=M}c_Ut#`jd6p3nRNl$||fm6W1H&P^OM# z0!^uCT0zeHa_?j)QUcfyr&=b9Xy=GyxCKTMB11#_v;zj=h#texwbJR=5m|s6L6r}n zW94Apss~uCUyT2XrRI&@YqvMOqg#4xJUCN|H|s?s~@b^^OzHz=lb%JPr_{92?fi7I((LK0ChXuYztZaf6~B zcF%UR@wti*=MFRRQ5Y*S=KyAR1&LIW6glpD%hxx3!ATS-5BC9;Z`@E6w>FmX*}3%} z`qug#Of0e$7Tkam)18-v4L`bB33F%K0&AU#_bS}h%EYDmrB;c33ek5Ljv4%dm!X)Xs7vj>KNcK6wE{iG&_G0SzDcww!$23e2 zuxl-Prdt0t`r9qpH%R-2(X%3cR~&zU5NI0^^SI&f0x%hT-9Z(dV-=#eg#F~$kFOn~ z*S2AP+l7G2(gy@zzWWmNY!xPhX(sBv-Z}<6*NfSgWWI|jb9p$u;(vMj&W~qjz*Ph0 zG2*GIGODH+%nuw#vSy93+*TSDg^tmNa!y&wzis6ZfL)=QIZX?su*FKAcw?r3by*mC z;|#}V>oisnY_d59ORz2bBgrM1g|oEtLv04*rH|`JX69mJ=>YFUMPSN!lu!);qG@&c z1b1G?)Y{}|zt!98x^+yoDcUE%s!1t4YnXLw&oK_sT?i|8?*Iri2OsSZ0>Q#khC8Tf zWorN>p@Z#8&Bb&jHgyHB!7bU45e*4NDmLM0#nJl~?2$&avhWNHCy?tZ^=OUPCZ<@0 zMQ|>X}}nG${D`cMglv2z2YE->6-JPL_LC`Dk%o z&!*leDf%R>sB&FkX%IEOYcH*U(XXePt&tpDP&D0M!pnkl?ZAmS0&0{APZTNosW*{K zD3;IoLLu23&xFmkT&HN=mURrE8|LL|1v(|w)H+oztzg&mf`0Y7s{2l+p}^w|1jRE? zc#CU#(uyuRx3JLUm%Asb%jKjV6-hg#XC8GuJ6H)O`JVP@B-irjwuANL}pyT6uhL#gND0^&7b)8GWFS-(m6z=FTq#({)4G4k1t$l1h%fG|6U`4zMud5whuNcNZkh(EAQG2kO?CIh z=_Y@9zjx6`gw$oYHsTJX%Y8GsJ^ZnA3~X&XqsF5Je_Ips@CW7xbqQ)s*JIUmpC{hh z7c9+iNM+*3%1WoTl4Ss>gx2Z%@9?MQ^y}1Y=|gt&prsV_R#vdFj9kUD#?Y(}8@`9K z(<2V93wR5~|0xv3qJ2W^gfLNo!cBfa&Zic~!Rv`DQFWc1oE#sg8Ke1G`gw8k zwo4nmzNHvp4&+Koj0r|jfYtbmr3yVE3^2&bbb_wD)?#a*>>OXUJ}M>H-KHRrHw|FA zGKE!`mjYdUR^tmkYgdnn$)~dU%Sr95Rq6P|8WyhfrxSusNj3qDN;>o@n`7 zUdAXO&e?T%cO7Q4Pw=1c04r!AtP^Bzd{b$ z+>@g*j`Y$z$K9!JI@aQ+j}kL1$A6hKCmfj0$LIJKNkqR3g*FVd z6p>2BFQK}bDUs)dRc0-MDO%cjQRf4=Q563JQ$Vc04ss^CEIlKrJ@E?p?|_bbE$f%I zhT22@uA|S|Sks6Xenm&+tRs))j@Jxc$4LC<>(!ih@uOY#k^FVB!Ro1N-+@4!WimbU`CvYdD_r z>psdq`N&_HD?#LDV;Y8f8 z;vi|c|7T;qEid&BSvKqOdvk^#9F;j}&h%Zk&Rl>C)<2{S+P!=DqcikY{o|P%Gu`oy zn1ngCqwYI-dUn}>BD*cNp!n=Id>5|T%6f3^5Iwj&=;fnC)XX?|MNB99NpgpJNm{4+ zNLojFNOJr7$8n~7fLk-V@)4$XL{T`v{s4TzMCEIiw^oeS2LnxT5O9?X;?cdM94G1K zC~>TqgC!A*ih8vtYt-$=s4zd*o0*=H9Aifw?9sp<*e8Xh41-57zks;}p#XuIwd}R9 zS0p1=^dkfQy1J@wuL1YyfmN^cAJDtJYT%I*WU`u`JNzg6t9)*_MYtfwf*zwU{aoqe#w+CwW?jE^$^N3ygrRNR}dUwsei+~rH{zc`h zgbddaqX`Mowqi+$mgTf)SH#e+tloOithP6SI>mFNfS&X_SPyZHTBern>C87D{(W&~ zvvB@}Zi%NEnSOlsmB*ZJ!^2{BJTJpu{L4S;o1xG7GmTA6WGViozAZ3}4BD?RqEj$@ zI?^TPn;QsKj+V)=UCILX%-I|#v4o_JMldZ#c;?uV0tLq4*D1j(8%`4cDgCnkH`#^H zTrHNoZI|JDUZDHzD*e(FbbqBo1{^C(mSnnYsDDMlGXyqIiDW57r@E{{YT5B1#`6Jm zCqXvTBx8h(dH)Nz2-(&?r^_b-P-RYz9#Fud9b70<@gj|F+Ee}f@`d9X>8=^Lys$?e z(Cf*?GYa%-GUCV{;e3x_I=o^5Wbnb5}iiU-$lpZs&_8NKXQ~Uc2$m&t{ z0?6p%>}5BuT)V3{`;iGlmS-d<*&T87mJECDiJd>_Gq6arsXkv>Q|%9r_DRS}FIqL| zrCD4jnMmbUHkH?q-?%IyCQ%xeh{MgJ@W4bVNZ7RY(;`7kvD8RQiz*hjU;&DV7FDF; zGjv@KSbI}ZHKVaLi^%3= zrFL^W6G3soK37mhF)Rh4SrwRN4SW+p)`c|v(A=K=t{lE?NcH$(RYw=xd2(>~0_}+E zN%q}SwdLrbe!25%XFOEtrxV3wKyHb9?4a9kdS~$+zZ+R~^Mujmizk%bn9-}^{Iipu zF3suV_x8xj?Q_diPQSHue>Bi{OGIhdCc4XLGQ>r><;VUOwqMxU4oXd`7;6}wAp?@X z$HPPlToj8libjzobcLwn86q4+IsrttmKmoCGfpwJRYOcvFc(}@s!@d~&6Ni6lRUrE z#xfmzRC*a(7Yc)ckyyVjx#9EbO0jvRKg?czkvHXfj_!B#plvICYV~Y=gmNH*TYN;%tinQig!L}$ zO&?Z}k*a`Hb{a2z(M`| z(?@%~hu1!~|E>i?9-2S8CjXB8bl>fC^y)QQfA+UO8d~jdOfAV@`s`h=^!4Z3q>spe zA^Mf0JHHxJ+S9HtQ|@kiMeAOC{~wM+S{)ilWy`lruJaff4%+BJ?XCoeW@5mrSz=^m zW|)kmU~)>|hwIPiAL<{!g4gQ1e@T)^W}vw3&tz(#K}sZ-xlB8#S1CnIzZzO;PmXh7 zIrzXbApDvti!^nYNoTgypnR_MFegGB+*6&Y}gSdcWnl+aD+$ zuzKdc)9=5vc6II4K4Y97sYGA6X<(m0dVZAtYUYo6hZX<%Ecb{X`gr97>mkz9f-RshTIfFLH!xwKc@57=be+VroHKB-47y zVwb39?qr7aZQQLODvPeEi2v|#0g8METpk|(IV$wXdsD2R|LD>Lnyjb({OlR!S^ z&*Ty)%IF{p1^d{@{S1>>egc7AsyVC=9Tn-^P0q?nOUv?Rd2_PUGSf1XL83XBx!kU6 zSG;yKr|t^A5YgqEJcuuj#Pw2jAk#}T&<~Ggq!RAT6~(29Wd;Tly`yQW8OE@Pv~Z@e z<{FnfY}U+LHK(VAHdwW_uf2+RP&6I(Qx*tlUy&tSc+C-y4-91Sf%_mf5Pb7gW6tfJ zOv&auhtbOpK8 z$TDI&pM{{Jd)-Df+k*CGT2A=TNZD3Q|FY4G2s-lE5PrZiG>V{$rAxp?o!yrCJw%&MX4t@h&Yz*`gwVX@-@mwW$499M;exG=~Ur2maEWVCo%|dnROD>C^wsp zaeD)cuofY`R5Mf^Z9I$kn7wd&+dx8eKCY*YW$G6c6qM2bcjdV~d3kw>F?8YFWu}Lz z0w5ZBLlF8|KfoTO%tXAoq`=3DkcCDs+rCudoI{S?u|3l*W$7R5KmN_WM}Bu>PKM$g z=kS)pJ0^@sM!QdzHZ-?Bkd@4`+p{n7h+z4mb3><_W_pZnf^tbW+5`-$=cN&3lu zj@SPJc@;|rZ#^-zXW!K|dyeqDigc&!}IWcvl|zU-CW#r)2#zm_IMUw9&>-~{K?a1 zG#!~R@18q`{!}`!O@B*&?~#w{CXTsfLhqs<;27NNnQ0e){Os|A4UavhHyruVw$_2U z8L&ny&s?jg=SBirDLSdzMY|TF)`ymqQOhXJ%=1o%BR@at*wFm*G=^0YOLe^1gxG}m zIMXZO(8BW2-9Bv1Mc2tM@7Le8WTeaQ(^H@q$H%4f{!kmo=Iuu7LaXOT~eY7-*p7JsN~ggHhS_fZ9)K zMLsn5sD@Rum=C(6tBR!7nr2%XFU9=ACQs6^Ho)a94M8261`TX7jAC&EB z>834bK#WigyMTTI2NsVUsvajv)P2&o`hn30pV{)_&>7OJYxP!K)PK;y7wY z8U!2CnJdh4(OQX-h9QX>viB9b%Dff>%2^Ic&j+$w@CjDJ3RM|ey?y~|qpx33UQoV3 zel(*pHY1&?0Wl5|JSHIwO-*%VLWpIv;&-t3bNDoj>#X0#JaZU0EA2^n1>JKKRSn7r zk`Z^@R-}NrXJ!$X<+wE_o9UMDO7jEjQgO=VC9e-Jy)ol8|1DK#^|LIa_!oH8@9@XR zPgQ;W;^Tj>>YqgF$dkJM(Jdp&R@CIIeQfwSmRS53JpYV7z`ysvmbDA^avO{FWTNj^ zf@T=ta?$%QWt%bi93FP=u<24ZE0f?z80`JN2NFh(Y{kBKYCm9K{I~vmbnFXyPWUW% z7jJB95AWg|{=TQ^uXPbM3Tzvvht?>hh14i$qDEm|i&3M{)%?KVv!mw+rgfMfsD=6B~M${GiNXE9YcDYyd4 zLJH)C=H;v2JaxIbTjrqU17>BUd6d>``(9tZ>UT%$XAhf}cS~t;{v9*;ex)+VRz>HN zM#V+V5h@5xFia!?O0UGSn+zEW9xurBN#_7P<_M~Evv`{^5|%0IH%*N%eW%M%kB~8fcZv``@(fcJI0eC8-JTSh;)1WB>Rd@O(4g zux;nb2*xxxJ?F(!!E?ar&!YAZN;OlK`AJ_`-w2~@dpU`(oqDskh zvHuk;*{NQuiQ=I&R+?F(8t;;2xeoDmZIWu15~V>FgVW>jWO_2_+c2Tz&_ZgAqr8c< zCD7P>noMoM%`0~g+WF7-19!LJgWLD+-A<=EMrjRfhU9rV`48Xu*ql6O^?+@x*ZK6L zOz*H1NGr0WSkD9oa?Or|bof(|H%1OZJi(tnFV*LPvj8X&aTf3xE}Q_Wo+(e%$Bk;- zzV;_K&S=@T>*?cM?oS)pf5_~I1Ix&kxwmh;i;8=K>Zq)rPh~x1y4KR!$~bs}@dmL- z11u3)!n}7#+GtkQnht@pC_~sq=8QyXl2Lsg4}}S_P8U1IQkkcqjK>)v`xX1@S~lRj zTJ;%3Zq@tN;UOINHt+!P8xfd%@9JSzn4|inP{AZ^5 z93Uf6N*mNf;}a4RQWBDLozDCmSO^>xIvnUv2p&8Gx7r}bHKX>ok?NYjT%z_DB~gAJOP?7> zPnO${fEPrZm6=rXN%%G-s%e;H7AwINigcFKI0-&wBj=bSq3$LjK0ZDvK8Z>=kCPpg zMW9Lab4k2f75*ogX!7>9Q7tbwtI~{>EqCjAc+CpR?QKrFZwdM2>P20~ZStnT+rQJ_ z9?pF7U?X*0LmXxkwOd1+CPmqXA$E_&-U+KAhI(m@%46g~Gma%vX%++qrYA1=5$J)- zFg(&mJM5Yy=3=?XKNUb9X`+!IgN|Z&AM{s@mRSte0Ry@WIUl5PXZ7++gy_>Q;pJzW z&*Bvq^%_Dh=w;{NV31t&Hyjj}!vbD?CDpa3Q(e0+T79$tay7-2OMgl$!kIO5O`-Y@qZ_&&kT27D zIMMKNH+MogQ98offR2*1~J3Pg!cHZAYTiP#*~LY!uvpG=>|H-VSa+niV%d z3&RbV8<43=ueY>>;|35DHz0bwa(1X;7nv569lc&z>!e;e{ePrh8EW{mqt`2^u`pSB zw0h;VuzF?9Qm;HWqF$NW^YT}n)hh>0@OJ8z(<1AYwf5?j*R`1S$|ZD>pk8@Z^m^sV zly-m-m>u-3NL168APNHN*aL<~CELs&VPy1%4+|}I;J%~0Tz9^ovr-vM5TI!(Arq0e zk1V==^Td#Ta^u^X1(Wp4ujyBtR@LDRc;JgT<|*lIa_;ay^sjO3l~?{m;wLN{v1{*B zwfN>Ucpg6Z;HNvE{)PUE{s;X}`iVcV+;O_jr`oA^4lZway>l9lPD`kFzSyFtgw{JV z8-?jXH-%a#E{jbf8#YM-WKx7!A@D`q`cNXQk4SSP#J*rU>wxQ@EAM~bTIe)Z3!UD1 zEp%GDwb0u4sfBLTKh}SSC*Z7RT!?ShkLm9<-!ixFx%qdL&&7_>bNViwf3EMmc59)P z)XZhygw;ZSvn(?e2^uRU?bkx5v0CW#uv+LevldzltA);tsD=I{dM$J#)qnSd*>hMP z&rdY4rIZ@gSmR`{WUw+B3@bWlZm0Gf9KMZU&#h6XAPjQx2jgGhOf7Djji{ zB_*3pHo!>+Y3eLb2V}c&iI|_mCkzvjOAp8`rWAGMx^uy#qY}iIo5zB--ae3QBFBI5 z=6Cw%EqL|5-?fm60cVep8G(Zz4j|u9QIF9gdY*l5JzIG0WW@VBB>-(#urill@7RN>u2bDr!sps8O=02gy3ah=Bm*(Cd{DC z2#yd2tvQhCVhL0>BqS$zsDT)d;+^?k8xuTM!?qm$2?CuQ!P{1Hv$i2{p8ON90kanT zXu_~9X=uAl4O=GES&T?s$j%!N)gpylXY-)~TV_#m?rp8HsfHSqXq$sMW-!IU>!-A`2~$fP z{DDl7APlqWs+hN#$AAA9f)C+4WOKgZd)W#z6xkHh?$!~F!t zcCz$8O(E>NjjD z$Q=6k{IXR?);~HWZ}9$yTHd`{EEN+nplZ{@4+QH7M=`AQ{%Cu&t}fYT0~XOB#cOHW zl4Aki7sDbNs(5)LGvg^8bxf&rboaC7C{$ek`^{10Q8)LVG}(UpOADSqd8+iTS88v@ zYggU7CZ8~L**FN{m}q$HFM$Qe7a zX8wc)MH`;n8Q50XU| z%rH_|UQ9B}Bx416V$mc^J;b>~d40-mezZ0H!I$Tr7`)~>`t)xP-qin&oGjGeV>?2w^1b6LLz!8A%K&rUZG4uy|2gO&NFn{;+U zWo6KXn!%1F@mWO2F;=#vAjL^l&}5jq$Lm}}w&*@q2?Bom>jUH(`n?HsogY1dgJ@A% z8s!p9ZVRq4JDORcRk~!|qTLlSv)IyjV?qiU`HDFfK!WhWp|!hSsNF3Luh|U_ zj!0p2+0aHNyT>Er7eDTMKIgwre4@AE*gx+2 zb9r&w-^uj-57jl`%i|W6+%)R0#XtWQ?u8xLjtA}9xOnc)(uJNSM&w=Y4(#EI0m1wJu~(C1!)|mZBKOQX#V%{8GA!~#=$NO zU2zE5|xZe4u1Bxlj_C*FGc@b6yw**kb#$eV}mdp}MCh-F9?W%kifTA02dor1nrvbiZ;&(61bx`h! zIoOBVGR77*+f<9g+Q#NOmkngu;XEK_sZ$(^ z^SDj_cCyN_H0WQ_WPOly^0}L5!$R!QbI*LG?M`@X9@%y6JopQ#94lh$IQw{vO_G9q zlE68GZb-?>8VURZ3paQ|c$Zz~%p1oS%|%xY?6xw)>rEHUIhoRIK3;&;CjFV0^*wTF z+d8TK+Ie0>DeAI*NNMmM+gD5f*NGd=mjMpoA2#7HD05P7q-w{ZYv=K2dP?W@v)&LN zd3*J<-hZclR{Ni=pWR89;?0oyJHc2eI#UwhKQVw9ObH({77+XzlwCm|EYEWAI(JHa zn{-weF6d0qYQ0LXplg{x<<+N^F%o#&s^fY3mV;$E!)&0a(NNMwZF|mW@V{h9M%85| zjN#T!M$|#xu0E}lSyM)-eAo@fFz^%r<_hMRD`F^j3S~(golH8tv0%0G4;(|@IZc^&C*vr^o< zKG7fk_~YZve}?*YdS0KU>z9TejmW2jygxIa(rY%~1V;vcOK3c>ZNsA2$>B#L&Z}vyBOx?%clb$6MboYE1a^>GyQ3{@3yo z{cj|1EnoA=Tc_W{JQ){F7EGSZh9`iiyF-nj5 z>=U{-wQv5-(<*!S>0W+ga+UtXG3+tA$|vu2mfm=f3e4BQp8KI*r8-z$gAa8_qbp4vi;^qo_gw$ zk=yTVy6XowZ+-gdt)q9`(RAU%5AnK7AAKZhA8x|h{sUMWo|kKDYqRC%-K77Y1N-&w zZZc~hoWIu}z67-o&flGS?f1OKoWA5ab_Ps{79Yqk;{z4|CmtkVBzH?J4m*hh<}frT zK>3J>9k_8BnT?mesbAGUe+945cbumj`6ej{yoaCB=aT~B(AVNk(DOz=DHpN%+!Y=- z$O!YBi&H5|@PJJ%otF-C-#Q(!5bl<1V9?lU9mf_9H{q71nnRQaYNe;Bb(V`q2uu`d zJDr;gt*Ue+v=duc1YeV3#uoS_&5OYRLxwE62@x4jvfeAtq=T?*9PlpWa^-r0@dt2b zKm?+UMIgvWTOVnu$w_ZIxB7u5yywQnzKKKd5q)Jt5s78`M?KX)K4t4U-x`C6zLsHu z2)2xA@F!nKMZuHI+pyBnD#B0wL42@@{%0(s^pwDs*`c3QtC{V-IwDSy5gw;7s!5{- zE7%0H#023IAGMG@Lal*;W2bc`oU!8|{y9u_s%5eU-B}+O`F*CtC84_TbT?B#LKy%% znu1a?B)K3+dW<*GjZx{Du;8O40;EWByAg6HyOSZYG%kit!|tUNN#+y@ zdnfu4wOzvBDVx$L_*Qz7fGpy;lnnC*-fg834>6`=zL*l?l}ZlI7qmnI79M9S;d_jD z8#WByC4p{E^BvUa@31{${?^F@<~Y?Yu29_~18s!98L|=|N53f;DzSJB!7=1Do6H9l z-?X4BkWv88Gsl{qEEy@aA^yTC;wgkF!S-CI%b({1ox)upfJ_kRO%>e7;|1Vms%cy~ z)bsBLFJqg2?c>+}UVJFyN2@kB$a+0q<9v4Q;$7sNzu}nvmj0doFa0;~yj8N}iML+d z{ltMaoHmQDUr;X4_XLc-Hm-JBV<8#ASco@T>?A&VoW#N@tRrV*)yzt~?Q%DGRPJk$gNhV``^3>D$cj ze)B0t*U_hcxElL)Qxp09j{W<=5l!kYe@ShPFBuk~2TOX2T)H9XdZueUgHGuL!&b;a zTaG4JVlnAjc%UT%GS)-f&MLQlBS*^2ZD!iW3^YySSUwu&UQ>?blhmynLfvw@Wv8bC zN<*=S#b~Llq6&?N2P(?@{a@zZ1U{>oepZnI^XeX=K$$z&2j62fF9gbX1hAv*y= z*w+vYiy$B(LWlt)q5`5Ih&xh>ks<9|iqujXd3k+#tF_kJT7RvjmXgfnf1Y#h zY)L@v`~E+_pC3aebMHO(oaa2}oM-($e%}pmuruM650fu@CUSi0F`J%~wys$4=3Wl< z$USwlX4c~)ct+J7cchw1s_u9!fB1b%9(<+m1Fiy3o>|*43-+@nq9?|RUy{8Ha{aIR zD%`5nf?6eP9B2fE65KI0H?x~US@97!dsMNX4rsxj{F_NGsMKAA8&qB2#q{bP>V9U0 zU3_yZEa9kx1b_@MC7T_|2B(r+qF7@UV{E7`HWoXu5bG=JeW9vHF~{mY-t&3D9Q)UI z*2^E@-_pX}m%t>;nepg7n{S`F^Ho~58;>BJYoR!suTh&c;OojhY7e5aN~N9^rq%Jc zqPBxl`({)gvIRf2vwY9dTgcsH%35zl?%W|C_*Sd;G*9#Z1YX4o9v)2hn^?hp`CWqj zme%kC_jdm950L+LbCWptV_#0#jrZig@>j)Pl#C9XwCgyH+PB1AJVezqzqtzXW#+L6 z0JU0CO-X~ASdEW@L);#6C-cT?zz-dCr-;-VQQf9I5qzIwHBUy#PP@}V1ud|egAc?_ zbQ`zDVNft20rEf3Zp|-XSdfPO7cchw?M;HLR|`8!w&o@($t1{CTev;cfja$>a@)H`j3MwDs!^ql){LzDc7aI?ec7TvY^F|a?OW@ES z9(89df*HzM>t9~ceY*7B{r!f&hqgF}GlO_2*Sx{oN3%ps!AvKk{ zw8SsvUs3&+$OB)Hb26660~j#HcrG|}0=yR>&iE`2L}m=NIK=pG;vrFHf&X4ayUn)u zw!lq9-khqm!Yek06e1B&c>pVks-)M9(`}sH$LRc(qltTNyJx=vuai5aL*1)(#~qy} z-}|xLhgBc<{2%UX=hAgA?0))9XQ(l7eu@0+n!AZr|K*q`Hl0SIs9Mz#*#@~{t zI?$#vpzQb{C$ffB7!S3nd|QR_Z!atUi*G9?e%ObluGCaoqS!fUD_)+(XpP_*jbx%qfNxI|Y@9377#!`a%c| zN??SGjI{kF{1-)i^UAV`+Y2h3BhfXEDsheYC{yIXWAS)PQ%0>d9?oY%@~bo+YUjyl z9Ve;$P$EIcsFG8x>~9)1CrPn>*(UhL(0kZf3*t;-$e9fA+if9tuz4k&h;f)43Wi49 zP=~Q2~8G;oF34@ zK1X&^2mHWa(*5K|L->IO5max0gb{syU@71S9zOUUDbx?FAPNtiPfWc-iJ^JOelOu{ ziF%Ex4D#(c$DktkoWu{kMHGPnuHi4K{LeAly!a6^5ixJ^P}cdxP`CCFw)$l9or+Vz zmKt(vu<_obOE%h#V8MrogCQ*V8XW52zKKC!z6cKQdD1%VQ`?VCwwebU_=UeHPVWjO zX8kql^VXpi19On$2IL_7LBR$kBGXMNUV*J-mx)#}#s4_wZ*4bq7!HH=S$gKcZL#aj0F9n#c|Z_>@eN(-NJMSGTgnRoMTK65wth@-`I+1@jf82#?KT zLC6wkiH)+7H<%3+y+8*t5!o_m^5#&X*0}R5?vgj)GpqKMZ2#MTc~{9hxe+WpSacja zc2NFphI{R$U;a+maL~Kc7jjL;vXV$7)5R7trdYJyCjk;M8j|tUDpB1kP}dSOrb7Yi z*(hX_47r!-BlCkEK~w^SdqTArcDE$a^8wmaQ44WciamvaHE4*^g2^@sn}WsRKN$*q zVR9I4-+B1xQQxu9gBvH#pk~Q~+ptT%yiLABjeFDTCrwvs#C{=uMfM0ivZDgD-lL1N z68Uok7A2odpXygbIkFx&v5g|pt63%()CBj%Z#xFvr~?1!g24UYWU^tDpPQAL?t&sH z786Sj(@?KA4UiTbzT_|yMQKR|N4JU|2Oesc~f8it}dqcmMrc`7>L0ho^WBS1LKe)^!!-md(nYbngpd&?DU6uOm7hPe;vJmu!$0CVuX`)=9JSZ5Q~tOwGd|&`T)2>t7&qDxA7y|2&ejz;lG&*z z-}pjE6spJ~iAQeql1DczkyA+)9I%a&ZJ$Ut5)Wh`r##n2?Vf5D9iaG<1G181(A_l4 zU_sy^u$HF7C&>0`8+<$Aqp3=}0z)vwXyk~@3};GQjM=DXCrWu<4> zlrMC(@}XKiI?w@iSb;u@R?1T|Xfvu1$NC|XExwen03ec*70IlE!57J9 zGVNrF!IVrLu(Ym+3RC!a;4<;699Le6S?>C!_lxuRB+hnjYA+E#I2Kh<)>kg}_UQ%F z##P9dYbdM|N=aY$*BnhDz0m0x@;|~{Rjem0@E4viEl^*Z4InNsfD{&%s>J)u@i{Mj zt~q4{asCmoEj$QNn_MTKsFnN6$^(6 zIlIDg$M=(ywSOPCb>lKRJ~B+vsS=PH)gI>q2mw}BYZqcx1*YXG>B`Cl#T21j^(D!v zks7M`f@7HoF&3Kry6)$Hlt1v6o)LR-wtV3bq*%gxj}f{q6X%jgR^H;halZHZ&bq-b zk5dwNd=~)b0P|CPX`ejyx&DXf9Cwy4YkpFIel>J0Wg| z$WAd;flB_G|!c;2RHlTR2)wn7yBm zrmhX0^a%5a2qR2AIOVqD0{zv!u~Q6ou|j8Hz&7CA{*}v!CLXz4A=_*jsP3%kD1*<0yD{%b7UChovCM zuS?q~PWV&bX*_X3<59$dTMvrzt1I{(A_+}_OY}B1he731&w?jmVs1J9pjcqu4Wx=TM#db{1kds0SNGA^y!hF4Z-gM51G0HXC4J`q*?f}3uo_?-Mf82 z0c4H@JlQu#JLT5|z?0XbZ6W=P54<0w-g%1N=j&v^ha7xUP%mlNy(4H40zZX(4|gai zI8ZN~7ZjiPP=g7chn+-+dqRAvJGb-21Nw_KyH+q2VHD3{$n^3zag6JVcSLd+` zFo1ly1W?0D;8oOp3@3mB{^qkL4{-xrQZV2+h3+O~BHc7WC01DA{_^$U`*W~z_8+Wg zxKv`VoF}Yba^?)*j@QZEKAZ-5D_-j@feG=&6w(|MBii$Q`WJl2UmRoY)n0g|!jF=z%=5V%~(WmPCbgH8$jVCrN5qk-~@AE#l}*;PSE4gP#$ z;P-eMtFrn34x@-a)~Wpu8W&X5;NA<<1_t^CV6LyRBS? zUuPkBLF3S)x>xn#T0Y>{wgygJ2?q-X)&XZSy$Z?tTBC8GP+-p^>MVs6;G;nlIV-=3 zOT2G>fnS5-$RFT$dZ1u-PZt|?|C*3->ru;zaK+P3t@A`#P+qzSUP@(!1RBW;X?|i? z&~J+9^I)t+nDD3NgdYjUTsM*ayN zzeWH`@#AQ`S2|fcU3BdKJr}svkkql8^%-IiTd?|Y&upSH{rR<^C`5TBgnETUBEow&5L(Wr_Lg~ru>|6L zm;nI$E{O9OqyRY*sg+{TWw@Xq3rGsgA{bc=fGxma76)JpK*xoQ|9bmh@?Xy2wa0Gjj zV_tw&9f*x0avXK_1Bnq)qsSsx4C@r%VDNPa&Y4ATQqg09aEZwTD3@_`uS-pFDFsB_ zhWrBBSBd+2{a@vO;xpX-XVyRPqqAopAfoL@*v`Lw4CbMAnFgPi-Rf)reBcUF$?I+- zM`SmR!MV?)wHhMB5L9UQ&jkcXWAIM1153b)Zzphc47!KnztI~-Iv2`i@(nL?Q-WK9 zx!~wrXbfhHi7f#Dn$E%nw2YiB&u#IKENA)iuSz}5P0Oq1_w>xfi_W};pXh>VsF@;N zzotrn08;#TYS27TObyt&!WEk@vkcJ1$hC=z&DU=kP`>xavmY`ySzW?*XpqN|9F!>MQBbAq0F1a@*}EjS!d@*y4h5aqTst z5R!Fe8*qg|`EiOFgI3K7`Cf^@CGs11QCNzNJJfR`sSJmDXzW7Il1a@kRFV!Kr11*W zXR>-35t{!u@rnO8+X5V_4=4^*3`#=HC$*X&be?#q=P3eIgo1ocF&g~QJG5*lyDmbK z`~v@N6cWp5wWXv`f4XTXgoY$)fE4Xk^4><_Bh#d^PqzHvA7!Us#h-qNt6o`rTK>Cy z1~96G-}ZePhi&8_w({O6_I^ zs{ulu{%x#=0bZ@|3*F%Tf?@4KekZuQz892(Z~|ZnsV9v0?+cO0LN=A@0q_E#1Peu$ z1_RZ_`fpGW$o=<$+-<@r1`r8M;9^0MI8rqTuTGCJ-4d`pmHaypuMR)NH~Dviz8gY( zoct%bO8$ZY*Zo-ju>xF&=i-<9pP+jJK5!jJ%YQ)rx<@ph&_MQw%{Lp

F>%9T;^P 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

LQCSMfD`9pAt=@hyBC-@$kBJ$xTOzz^{w z{1`vMPw_MS9KXOX@hkiqzrkJx+q57G=V1460{^OMN88%v@9)0%hL+9BCSL#(<-zotwyWU8nh;@MQhVK zv@Wej>(d6bA#Fq((wxa^|QXlnG zkp^fIO{PJbLQ`oPZBNr_h-T0ZG?Ql0Y#OE=X%6i~b7>y!OuNvov>WYCdyqmSa0A>( zB`U)$a4S4SD%=D&!^3a@JOGEnl~jR8s7f`s2ks?}=EGeyN;=iaAd?!jfGldlFJzNL z3u%nTX%Q`^J!vo68;+uVXkXfo_NN2rKstyHrbFmZI*bmdBj`vvijJmZ=vX?Aj;9mo zL^_F1rc>ZFI+ad?%jk4EgU+P0;0!n&zM-?}96FcIgNx~WIDsyp3+W=dm@c79=`y+; z&Y~;mO1g@!rfc9*IF_!3li*~!j;^O0=tjDUZl+u4R=SODr#t9Qx{L0nd+1)ekM5@j z=s|jj9;Qd=QF@FXrzhx1dWxQ=XXsgaj-IFg&zg%L|# zsD=~|!UeNx8tQ0R;n>wz(yWqGujuM{SEDN+s2>qa{g0{Uyb9S?18s{3~|2 zCOt3}wxFtQK}~A;s!AH0R5I&zMHtmKqib@T zpIVD|Ode6JjvBj!25n6*t0B#U@Sw;<6PXP1Of+7)K@qdYkp`!bHot31o5uVWk4imVJlLE}`jsyurs$Zy#^8 zkDt!R8@#}V(lDF0Wj1PRplDPBs!z{N{9KBI($lp zMOKc;YM5u`cn}=6G@}}H+-vvnzcO^%t?;mzdPnSed4eF**ZAJ@jEWDc{X}D12sHnVJLrq<2);Kp?JT|MnTFo}YdpacI1%bUB`|?5C zG|XmqSyL^wsWm+-TF@Ic#iL%gWG)*kHkuj>(7V}Lw0Ub}&=f2-RM*_{a$~ryb9AV# zR(Yo-HP-!KNZE>pa#c6EU|H2|B`kb(EOt|K8*MK&*I97XOHKDu<3aZJ zk>Sv|#u^%&ord#<~d(kKUPnL<4j0@2^nWXdQM2s3F$d0Jtw8-r1YGWwMa^h zq|``Cjil5_N{yt{NJ)*9)JRECs|(T`+FlE zmslJbJiu`+pey`B)6aM;y|9-z>xs>o!6beP5P!t}E!edcH zSR4q=sags$ za{}`M3moIZZ#*8YXjR8j%j|66rRqNOa@~$mRxNfgU=1UB_X5YXRrerdHPtd7m>3Av zHN!iYsU`NNh^XTw_C8|0d3&?asQN}%Qycercav!u z(o(f*&6a}<&5(m4vQvkySxTs(Hr;n*(XmV~nM^#9%5@G_EM?SoEdQ3+%$ayHo#+}< zS^3!+S7|moXNrzq=4 zwocjFWrs#pSL^O6)nLnn)6S+-Vwo%6fijVZCk3Ws3iD%W%~4j)nz)&dHP~Ma)3PU<|862e6yEifxE7t;*eU700!e30EV4bfDLurrCJR@gG;camZ- zdu_5sTeTeb-=Dg`(H63KHA<=%2=nEzV%igY!@a0>gk{GYxQ|>q#$2;gyXfs3yf^QY zPfu`9_pBz4ZfgyFQ8#OCsO~>HM^~(1&2*Y-H``gdS=CC4&LpC4HmtI`-H>#IEfTj9 zd>&oq&0OcK0rse6AD6@h>5(MqlY~!FKFRqc?~{yAvOY-*lJfl|{NZU|BJF!l`hF7r zorK>f;rmJZp{D%KNk5E)B))pWk0&XK-<0wt;!@Q2obW?U$*_xvrXn=kXw3%qh$-*W`D2BYS6oe%cCAfDjM5<n-TM_9(JTy6; zOQ(_^q}|7_+itPd8@AoO>oho8!e);E5A{ljFC}jvJ0EJs!V!m!wOz)WqHMhy{3cf$ z=!-P#8e29BTidLgGy+Y>2vyWNTlO99CD?4RU^_~>GZL(+3KK7DN}WB|yXsC;tW0%6 z8)uIQs#F4%ipGBWe*v(&UlDlPWANU=a3UyTBO_y9{k003oC5DowU literal 0 HcmV?d00001 diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/serif/GNU General Public License.txt b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/serif/GNU General Public License.txt new file mode 100644 index 0000000000..6db9098689 --- /dev/null +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/serif/GNU General Public License.txt @@ -0,0 +1,340 @@ +GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/serif/NimbusRoman-Bold.woff b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/serif/NimbusRoman-Bold.woff new file mode 100644 index 0000000000000000000000000000000000000000..02c5956996ef1475df1c291e594cc390094b05c2 GIT binary patch literal 109832 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

Z{_itY_&!Fu0niKy2IyGn`PPEnMdoS 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 L)wM~EVPO6T1NJoX literal 0 HcmV?d00001 diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/serif/NimbusRoman-BoldItalic.woff b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/serif/NimbusRoman-BoldItalic.woff new file mode 100644 index 0000000000000000000000000000000000000000..ca41be18b4d1cf5f9cbac5c856cb73e8b020878a GIT binary patch literal 116532 zcmZ6y1CVY#6D~ToZQHhO?wLKdZQHhO+qP}n+GF$1_t!mjPu*4ZbdsmLla=JHByXjc ztGt*P03ZMW0N^MK0P=4NY)A6H@^AM4|A>kGk^MC+`{i-|gGUN>y10m_*e^HqTc-R4 z6__w2mbikv@-KG_06<|603ax!Zoly^uB;;Tt2X+z>G{=Ba1fHQ$t%+{0RT{w{Blaa z&~x#c9x}AnxBKPX002NZ0RX_no_UtX4PBfF008Kler-&CQ75a2vteRqY7GFu@cSNM zwg3RI)}jP4UZ(nvzrJiyzcvv6FAz+v+<$%8k^lf5hyj51j~t=-QO%6?jefh)_G`oT zA7Eprk<5O{U+(vv0f>J=0zU(OY-a7`1^`%&^4mrg000aLGsi!1D_g@~yV}0rCg6TK z3Xs+`0c(9XI{?7exnDnm{{Z?5hG(O1ZT!pq)(2SkJE(@tgJ|=1wvJ8!fbDs|e!Bnw z81Z^i5Z`tV#=pKJe!qU@zvxQz43l>?HZb{}51QXH*nc3vQq%fP|C=R%C6cs`|I+!J zhTn1jE&I=B4p=ox|OqnWsXk(t1mz=4T@q1C|v13(D_{0y9ffYQ34_zY(&I)rkK$N8EkIBLyn;sM8vK< zMx6%f_%*4UxiL3v78K!q1eTEoNWp+H!3+WKkDR!l249^vhsUDi6gjjQh^k)^2JYbU7__DM)YMD7$ZX$p^7W zM%&@x2j8VG)X!eGbE5B9&5pF6!$Y+DpNH@JY+tt@?frt@^b-=AlSR?7^#KW+WcVZE zbz60V@K&oP9?U(iy*WQ+xpiP#V1CTCLo3`SpE*Nx(^Ph?lrE$vsn|=i)ym!oC(VNv z^V_X{U(60$vr`8A*zI1IXPiTK=eEsT`Ou$ZmC4GV^W{on9`P;De=oJTZq;Yay)jcb z>HPPZ@!GYcz2Bj$v7V?uBVX*rz2-09edK+o+lmH%9?KdFxx_qUa=1H;no4VjT{CZf zZjpUvd~#S!dm(zAeXzfL#JTtW?yVl)4D|jrpZr|?Kz~L5_;LNQ{qnv2Vbqfm5b6u@ z;{^-`90p_u)`iEx#lUsrtRo(y9Ah;To6E@)7R&{E0`o=qOx^Q^xyCcZJmfriVk{g5 ziGKS^<2CHTUqn7YJ3w!sBjG=C80(J1AA!T<_PF{m zerW4Htcj(@yy5Y=c!eMFW!_(gj7MIPTjM1(6}k@U38zC2m5ItqV_tfTJk_F@epmhKxS4+4*P>^kb*(T z)2>WDvN-UE+ZC&AaWq@eAmc^AM@rDSJb#n(@f?%hZb0o{rb)oSb)BHTyz%lAF z>Etq{yK?fF$vz2wrCeP{1(DHPgf-D0t5aqb7{Eg!230kKIZqZ3YXtv2Xt6{_5j_Yu z;Wu76lJL8zYyf!V{XN)g*???wuMm46TWYbk@=b#>49YD*4j3aq11Jn_k+=y& zLlwN0OXS35PR3+5TJIxNf(F@uXxo|!(MLTimf75 z6=?PqLPM1v^+@jFcAZd~B!tZBxX6}s=D2L@1I=GkmdEerCu1eq`Nwm7rZN1)jY;+F zON^L#QpO0@i4{qj$topf2JN!h$(t%UTlp#DycG&~N}Tt~D%7!#H$fJO>u$a!)$su(-Dc|1DZFND!67PUsgW+AW+|3kq?ob`XPv1ja+~6ldBzo!2ONiTb8-t+ zP0AJG9u+$70?TSlDzG_xC_3AB_4;l-?7QA=Xnu5pk8ma<3T~LS8bcsN#!P(dxG@8N zkRfsc^3XweLsl`~hx7wM-boh8VKG0plz#?oAoS?D2AO18_DE%Wij~`S)_INRH z_O&+eA_mwpOw;e`n2>43K}--2I$}EHG_fKV;t3~&<~xZ&=M3kKk}UjJT)g-^&t#T< zL87=%c^`&ABmhTVGPcK3jL-v)mFR}YiPxj3+YvZV)LrN%J&BpJ$cAt)A6fU^i-Azq1S8}{=zuJZUo(C z(y#&;4{N_a8D}3VQ+Sz-=Z8w&m{N*l5xUe!oPwaao$O2vO#-+R;v3^~VOnIY z_#u|oMTB@=wc0g+1FR5?9A609XHd6n#_UY30M3BtQ+WJVlyA9o=iK!AJC9Us?=2YI zmtpB2iAvuS1jY524LsfxW+TRHdyf7>zg6MO?C9N-<+?LBk~6m_&N`vA>HXunujFoD z4)3}MDZZ?CNG10Dhkn_XA~}mZ*0f+1^%jsKo@@C?TabMJ)l#R|k3^#uY^y`^cRRkk zLd>V^{YbwC_pj(e1>NML*Q~1Ot!Jdxaxh*^Rh^B=wzS}-ohlbJbvCs|`{6j9+8U(E zh?PXO%n#8>7 zGzr;A&wTSU@ z=t$mXTbykg75xlK8~crp;TwG^+GL8O?m%VMoGT8y7H1Ez?tC5kNWDCmOQ zvVFT7X#gcr637N)zHbx>QL}y-!K2_3u2PpQqB;FyG*Z=Hx`@#m%ZKS@QbEjMqQ4U8 zKQ>UU(f2$BG!APm5G7)HOjih{0 ze67>LC(a6J^7}1ZFH@8r<^Z0*kT0M{y6{bpVuJ!r(xjS21^QH2B?bFTZnL2;mA5(Y zH=MUVa68a@UtC?M35!bO=H(*7(DQa^YzE;FxRA{b?D6%fvx9%sO3h7|#8W8t1xwPS z**oh)+7HVY=gh!1rU+YB`Z8}25?)Kh9m zg&g#e{sH1p)r2$RJCnxqu9f%0`i?#?^{Oq^na{OX07*v`UQA_BK2fjKj_JF^w`Q}V zs7=1Msu(S!Sqt~4nV^E{8$DReJ-?$DyzheUb{=xO3d;` zy$0|+FG!HQ;2Lm8Y0O4GHc2y@He?s{sJ79rj~5ek4*WqPcrd%mQ~xedSs4)QgcwKb zUS{^I338U}Ugp2o60zI}+m`*`oC$T$dNAAas|k75s^Kyn3-PlcA27-Ot2T%=nWLBi zd}92vOGOZ@S-MPcUCz|i1lN`=i#F6>do4}DT#)1dS+@K;CKjE5k-N2#bSmZym6?cV z)z6g)D$`(4Y8o~DeT*k9R+q|>oJzFZ`QN=`?S_ZRx-M&U%U3mX+QS=iYqbow1{r-L zXLw56;9d%u&t`bE`he~5x-Mt6(&#+DLVXlkuLaHo`53|>hJF4 z`1Y5=9PHo-pqfp`di+yg4fhqC|2Ev3bH6W^e!UWn@ZoNQ2mR>_lyc>6a6k7^Q)P@s zCCqb!9zFE`5wR5zKW-CNns>24CR-7{N&EPuQ(0lQD0}GMuOf(i`Co**`_uFLC3#=2kk`6THR_`*A(m6TRjN{@kp;>tN6VgH3L5 zC}P#6`v(#FDaxF{)tv&{MQ(8BZOt9prH7(>jn$(P=E`bthV2Szn(Hd!S$G`gdV~+O zZW&ZlyDnLbHrt}$EmX~2on#CDeR$l)eZhi?qQ(nIj ziH%op5mYnO;8H>DX>>+jU)A)@AZ--b7ljWp2$IceN$& z7_Y8){&``+{D0d%(ILk}ZeDhgw^-wX-2BXC2So3L@CoQiCrIGxt53FxZuEm*3xbJl zzZL0JNxv1=6xyH_<5W)YI#*gZaHBheC%TEFUJHmxr+y2B3ABF8?fQ6-=-;Cr2CXRh zmVP_X%K^8;z{IOTyMmx;0Tv;v<~mMp?rv$!qU)zteS55DsO% zIBxfQrqf=XT-&kfL{P;uZRFatHU&MWLq?1oE3*INJ-Hq}Tp26q6PGs4IMy1M{Y=0g z-SU4t8nruFIU|5c)g{7muh%7_V*eXpJ0H0e zk1H=x*zA(kZiIAcxi4>AcWKy0?8#NV>6e3Lizr=@G)#63R%UP1EZISnUK=0!sRkMp zGn~R&uvYEGG;!UUs#w)i?dCl4r&s~^Mr(o?IZ#7Ztydz8Cr$`Ibsif#>ewONI7=Os z5gk~*T6}?$zgl_e+VEMv%KSb0Pxa`LY{e3YKkt!VSH0&O;IR$@J*(C4X+j)`F2O_& zn=r(Z+XxLg_-xA8+Nkd!eFK9v*BJ>6fd;UqL9Fr!>U}tb4dy*h( zNGuayQHrf9ZrKf}YBr$CU7R!E%GICZ0Ja&JA0;s4#~*)DAIqYL5=;SXpiwvuq{0?y zKM3FejrgNrReGxM4ri!E!)e6Gm+Tiq9p3@fD@BxA1!l<9QM><*uP%61ss?Mo@WXSv zXVTS*y4_tL&5l>*XrH>CTzlY=P#&nEM%saaDGpDry4-)unAEg2tn&(Chb*qLH_ioM$QSA?2X#fZ2u+O4M-KOk6~ z(U2oUuAg7%4xYYFi5z2hu9Kb0iR2v08`o=N48x2{2l#jQQgYA4P31<)!Z~H@*PB6u zo?}3>f{w4l$dZn$m?c-m8i#|M<||#zBK(eD_Jng@vSOSraAibJ&rj&t(StE8X|~${ zVcs?gem;qTpN{o$?86_nn%~NuE!_#H^BY%d7$jcP|x_63oIL0aBMC{4sY9GkgszPnGGKP3{PmX!%sp#w3ZxMBj zI|3T$1KwVRcho~r3+RqKHaTX>d(?=>Aw?*Dj;je6e9{Ufb8 zR;JXOJL1*ZU>d7x)lRv!4a0WP6B_^C58quUw_y6vgT--bmE7WW0;p)XA!XCj3BIlk zVNh;KOMZVK8|NE^Z!1iiT)C0_z8wlK!K^Yo(`W-rAxk`m&;4T{t4DpW7@wLeeDkyB z?-v1#Zx7Je*MO!zWLXR`lK`Ynr+sFp{ZIein#89pDeq?j)6C=A~!L4VZo%4}v+DADQVEtKO=$HUs zQyPrHWwq|gVlvm@{{Epk1q%h&5xByDrx0{}o`G1@n0NK5LsyoD(?Bk;Tn)b_wW>x0 z7qoa%bi;7cE!~M%W4-rk9naV9tk=lVMO6kzAm-YjP?4%us9K4F>JnWh$6EbQ&J#}g z$>Mc0-MRa{r`f6O*(`K3&?cdyizwIa_@{_^B}gV|bM`oA?5Jd|S_3U!>KbO51aS5E zO(z$U9C1l{jlA20{(;OjJi_(M35kPGSuD#k@iE=NuGGTeWY&42nsjE%zZ{Q57G0v<;h_IUt?l+CXXZ{T-ep+PRGVAZ4GS@$ zJGi>46A>Mqp9DtOJQR7`i9In;v)Oa`_F7JF#k|T!aysWt8GTw%@WTU#Q6=OAG>BGb z=Kr2vYHj2??UbxPxX^y*Il97rD+Kbh?7_pn3IX@b^--6T-`gam1fv!WQ*kP>_7R7-SlYEzFTE) z_&1OC2)!0+#vf9~F`H@KI>HAIELEMQhUJWp$n!ofVyAgX$*i1bB;maeQAKqyWZ|F@ zJ~p-rQ1!MSJsMXr-WipujW+gSkkAn;C5&&`|ACkcO8_C}OiaF{MU-c4GxwVb>rHvh z(wfeYrxj`5q1(+bR%o|XzKIX^9P6vOhgy{yLp;{%m301z-k|SQUcM(xZ&zoX939Z+ z)7O23YHs9fpSH^qDpk(EF}Rr@$|(%z6-R#fn^}fsUU0FlJYp)3;rr&K$glqBe*SjU zYckY(ig|?A1f^6=&x?=qY&-BKli{QEHh?U3hYkK+1XI{g^Uk zQrh)2KG}DD@bKn(<|*cL{n|a3lei%R_l|Xx?sXmRb^UrZRXdsw_1aL|%fbTpE6Sno zA=`gP9oGJj;q0?sO^hpo*H18ST4{~u;||z3bzBFOCuw?V-}djnnJZ7~#?sr+T7i45 z{J{e6l4~8QSvO_c_AbAo)hgX9$uSjToq;vzQV&}E+b*R=6)b0p%DBVSs3GN|^`|y& zmk_tC^<8tA!YO8P&*|0kwAP(0-deGQ!V||OC)S^m9^f_ zUo>AE3BGV6`o`UR{nBdUgEt68eSAVHBR@Mf;v!DNIv!o?5N1u(MwLC}=~oftJEaM2 zZ1?4CuAyNbWOczQ(zr?F>4$qswHa7l%Hh8?8K(H8TCF$rWar+=ard$&?!ml1b?#`$ zHM2bW3jBiaS+m$jIt@KA1DZPQmg@|!4<=yvPO(H4CyNG2J9n{u%}fd?iKpIz`Ic9G zr>Lh`CfxG7&>|D8?^>g)PRDBDzJJOc&gG-4EBiVBND05SLbtdKtdOm3nB~x4m`3iu zJ~f_3RO*q3&%dYd!K(6(KJX_3Urc)nAiBl*9E$Uk#vjGlSnD6yV9Xa$TWTxvSEi+A zPE6~NZr;VP>^KeGc?sr*weaE>U)pJVT2AsTDy+_S$n^|4YZF`kD+_E^C0I@ltdYD^ zal?E2Jkrg5&;479@rGE)6n26&{SHn3QW|yBWuvRvnaJp#4I1ybX!UyUN44YI0VSGwB} z5qu+num#p{jgT~;1EGU8X`_$Sg9sK$D3M)U2q*1+2+yZBxqdgPGcJ;;QkZ=AZ}x*T zlUmLpmP?W}o{k^%4)P@Klj`UP_?DzS!=h^2NG_R7xi`36)@_}sUK%$!a|yRSc^0KP zCW1u6=5M=0sFauFiG6bQ@r2a~SHC@<^Aw{?{3>m_)W^F5E7Ur1TVm9wlm*$>k{)%p zP`Qgxysvag1gPDi zh1&?>N3M_%;Pd?18m_bXpf0?lC3{xCPZY?D*7RfC4K}A$#8DgnlW6ddxkoA7&>YQq z#mh{n9C#H>riOld1r3!7p6M4Wo|7Bq(uet7Lwc3mHX+In5MXf?q*h ztr9}>&%hRK74m3De(pVF}>U%2}L*wLHYa@r)I5bFz^s7Hc* zG>Dl1SRwxtjeAfF>;grr|rF zX^nA>B?WV*pYP*=eEr*^wXMsPG)pry?o$inFvj-~Q`xHJW(mU?7PTHWgOYsCUFgJe z0hdLG*6h?YEt7*)h^lKm)2EmXTeVXUfgDCQMC8`N<9|GS!q7U?Zx{+=?WZHiO4p&! z-6Zvgw2kQVUDNNxy-&(tPKd*-T@%e+%aOXeu;_1?zq4YBnd=Nw?qW2WZsOjzQ+3mk z12~>RJKGaNz82nc06)OPf(BW-b2$jL&Z?OOu`V0<%sIxZ-eKDbqn<@VcHoJprRN^&`g>WZ%8~IhEsoUYy1Q0IO$9^%l8s$>}Y-b_Sw9j%UvfgR) zxAkO%XS=;-8KzbleaVre;uS)J@JNy_${hYE4*?=k#mxmhbD^gewj;lz<_WSRVa4~+ z#kTRll^`z(s9JevT&{oe6-vptyt3+Og`lVE;k#ZPp5I0=k+cTLZg#@P&}7&bv0=n= z^vk%I!%BEw#H|P~BZrO_4=jX|rEUopay>j=vCv|7W)o6rw=Evk86bw$v!BI4vd66q zIOdmkWklJ4!(eZ`FRLkv4>*6#5U=-zCwrqGzW9k7atD=+MrGeWVTnXn{FT;zI88v_ z7=xTXkugb)-vSuGdjtP8WoO1wNKG$B@@<>5yPy_Jsy2}T!5MWrTya0>s#-Qyo(@r9r`w3dhIfUDv8u69DC{;6^%lCM%Jl& z_{A1OyLe^NBALW;@4ZJVuGu2q%MX0jzZB0KpUQV#Am)=gXH(+(6|g#EY&`aC6=r8t zttoi%fc1|!a0$c@(qClV?7ewd225UA<`Q+N= z+QiY7+SRcQdwQF6tD7_=f89qtsCGvI)2sm+*2S+!VaG7LOTNdmuPU0rd+5ca$ulYm zt;ww*KrkLQzymQTDf`xObS9Sb!7jKEio~^F8FPW1(3=~BD@~so3KX_3qA z!sz#smL&p{ePGeUO)4Hf_qku0ho>5JSj24uMm|#z87c#pARSa3e4heRgz~l#&__ss z4cX_hk>F!7U*kiWoyr`4g}uAu2h#igZUE>B?}{Yg5l6yO&;zANoj@C0Q!;NFz#1ZI z8YCTdQX71n62U024-8*Dk3#R+2t(F*Wz#M}8U+=BKK0BSbkp11s|X-mRHAX5+fFI+ zhh=cp(Cd_(ryU+&<-IC0o-=A|V9YRT%G3yr_=VX4nb;B2Jt-bFs%yAQ^$^qhh|D_D z-mD8Gx;4)p1?#lHzW-xK&rY-QUV98c{H*fdvlw;)EBitn(&6epFFo(s_25}F2 z;0t3^Q{E!-?UxMSebQT%6sXasw4DPe$_8-nlFrz76fTLz4x_K@Evs3N;DT$OmjvxI z#?1%ftk-~5w$}|YHnnPx{)lwMT>mvHrrtY-%xZrU7#VdMUBEd-T9sZ$WKnEiQe;uO z-h^N;*vT}wGGLVM0DlbvBi96Vo7) zgEpUfH$VtI;{g|AUj$d%?TpLbqSNQI>!N^UYHfZVc(EE#s z1?l*JE|*tgwSLaK|TV2=+KUf1e&Qn}^5{%b{;$eIF5N5|4I9yPS%)+`KD?5HJ4L~UF%jgKc)bF0vdft3N&>id7zNY8R znBu}@FiLN5{!DK`nLYo3Tc2cWU{0XXR3OTWg`n-$JtIiBcFfe_V%HkjIeoir)}UHC z1Ny%0;ej$QoV)HiF}h^IfBzPArf>xulJ>yux`Ot_*7AiLjaVn+lOJJu^nl3RLeQCr z^TZ7C9>zJ`;~ZyrB8PC1{t>qsy`?#|0bk>})h!>z+xLR?_6;FJyY+>c?bNe6Hi@|j zUBkz`W5ihWqPS{irF6>tu5$N**KpJL%$L_-e)K^+(rgAN@ClVL!__e4T*OLHjl|Mg zw~Ra5QSzfI)a!U%V`=5qXn8R$k)5lFsXj4ACdS6l07di0pa#7GC*~T~zxI!&XL%qD zNUVvu0F?was>1jWdkJuI~(i7Es_&0x{Hhz5hSbhgptrO2-g~L^r7*Vs<#bPa%$IdAHl}5Ix z1+Nlz+(wv)^_#`53UNJbcr^4!-MSUEubn^CJj5}hyTacf(aLa77-BH%=6+_hP zE%0ODdtqWNexXb>;?@Yf?bpzr4~XY~>#DW1=N%1)Htp@3Gux_xlREHgZJJ}-CPn-r zFD8%PR;sO=TjqM-Iwv2LUh(Y!A?hFZA1Hixb%R}?q?$9#+r0Jat+ zGx+=cv_uNuQ?{gD1A1p!T(eNS8t_F_Ju?5{;V0sO$2w%il@Pv@&R6BozyP z+-0YV;L<3bun%?jHIIqXy{avDRNtc4qG%)3%*SF3Xd6-brcF#Hi2s_#S33W5jn~o^ zt>GJ=VsmhYYwrL6ITeVDby=@dg776hx^SAa5?qA2XWa>X@?pblMe$aG%~g?@5>nzs zl8VlC891Ijn;We-q%9Z{W0W6?FsqlFI`xclm&2S&HaEzJK#x4DSDQkSe$|rF9BJOo z==IT}PGP3X@ueQpiWkUD){-^aqWa_sKU1&X9(Lm+XO7jD zw|%5R*tZA_Q^=fOw2<33eBw4Z(M}gKX&<9``pp0^;09MKN-QXa5DX(z5{qD9PJXB4 zV@EZox#Aa2VKZj$-LRH+LhG@npox=(mAVwPFwf$t63YJsk6FBvCF-y0rLvr?gB$*L zMN6V~8PtsSc;Vk1U$+8h_;o^guW0h(@TroL`j*M`aaI^JpZTbZ&g_V=f)^<|awwQs zzEu)n&m}Q97P-G9fJg;BYabYl6v!_qW6v{K!DJh36tRBb=*1iM?Xd$TR>Hs(9Dl=T z!Tg}gU<>-6DCg9rK9wUyYZ$9OaZ<>Ic^-!!C-F274Zk`(YGQVaN2#tmn<(p#ab$(x z2fr7H1CL}RSgnc${sEcm^*@yd+yAqc0SC;iM*#F0uji|L#y)d`i2M*v^i}0cINylT z{q*p)8(`8No(%FTAM`^~k9D$&fUG%0S1(=^-VIcXih0(hi-S%+Bzc!!7omL6G=^p> z67#C{shEX)8eU82HAJdNQ4@YCqFUZYXcJL8+*+XYC)^{yC=R%&6o*b+g8rQL z%h(Slp`S^qhw^kxB%Ne+toh!$UFTc;4c?(}i-djB_2}jZ?X6~u%9nmO@n#aGUDhTQ ze+-vN#fRdDz;!bA7%!ddWx}al7cVZgAy4$yE!AUYlcKNmf^ zQ|RDswzoS|Cj$Wx1`eUqb*!StI!~f80ME@dojyR`on~R+PAkad8Z!lzl2-QAl0ogY zwIxk^NqRB3$FmJ&3GHUs!@e%h_0o`k+}*A|*soFxI}HUng=i>dGjM@S%CO}q>aZ_@ z^Xf@c2Evwin@Fb4I>d@foOnZ3kTYn15|9t(8UJQjlmi`f?fw8n!r*897c*(7XR_Y+ z8tk9!AH1A)eDzZa(I**q=l#@j^ zVMufnEk!OgAFDkAzq5U$f8tN(g*3!2&ul#W*cKX_qJ6|{=eU~^zlD4q|8QP60-z1x zL@}dd50BJ=q>PO;{z(~4sY|xPwKN!2tK2sQ!Sw$1NJF&YfU#+dLKMql+;!XKu*qWf z+1ul~nen{c>7s|<&-Vf_-5LjtJs@_&!Jj0*W6|l0bYrbO?R--tw+G{bJ!JqC6p=@y z2oOz!Ko1mc3PTMq5UD~>HfUU3#S-Z&rJr6s_eu}dE>?n0p?SUMWc9P*+HcwrCh05ExC+`RbE!LoJtAy5AdJb7-n2q+$UVt`-CnE z`Ek{CqDfNk3n=%f_@Dpy7Gbv${qWAhb==Up5yJ=` z1$9A)LB0?o7#>FfV46CWL2xjPRto{)$iamBf(gTh6kvo=3K(&S8ITGQ0_QOT)rR&t zqlO>C#DR1Kh(`2z65^szWcoyk43NkSp%&s|%F{y5$NFHVM93QAqH(4Mtfu-S(;`!E znH=t*PW1Wi<6?n6zA_b}U2o|w>cGM0!-&mrPvG^SK?r31VAh5G@)07B#Jb2L0SJ+Uk*nf^ft?)x?0#wvVLko8rZxNRLm>zqtC=#t zeE;0qGFg8AxC%T25p-tlBO_=qs|6lYr~hSO_>|V0{_@2h`u=&;1ro}U#HPv}%IGHn zNR~HX2oL}O_+hgAZ;h%}HFrg3M_G1*Tt`Mi(kLlr8la434N*z~02`3OLEjpN%+K~; zm>GiGMn4mK@$Ti+nYXG?X;mOVjE7hn=&%z(_`u`LF!CBKj7p)Ee8Eb} zZ139L&yzIZBvCYFQuEg={fc^CP3$}@7?0|7 zug4OtCLtAjHF(Z|=e zWd2d+t6`($*6cGN*ld6WJ&*T7)K`Z(49TPs&yRqLFM69KT+xCP6Ymvwm+cH#=onjD zd)6=W3dW)2&!4)0b;zg-xNpS!w~!!<8$!=nPxS_p5ldV$1U<6k)7@jK2BPBIGB>&6 zx0BH==oz6L015aRW87SgG*c8_XU7RmqK&cMjP&+rJV1r9Y0!l$OnadFX5&P5aD$_X zk0njiy{!Ua8jS~Q-keOiShZnqz6?xJ3Ja3%&IRCDoMocWI7*E1-VA0mDl<+(BoDHi z1#PGSR~k!rjt6V?DVbrq8Lc3YrJ=;evq^I`b>Q8Y`y7pd-~5E!iE1Q}TAzy#FD~(w zMfHG6ob~M-;wSnbHp|?INYg5a5*&W#-TDaKLfjM@YO`al`LYW%HPn>IO)2n;b;?F| z84gk=IPFiEs=&ck#~}yV-$acfB4uqzbFH@qsX>Y!!r*`hW0)sjIT;QEnO7ffIr4WY zr_v)lfwbqo*6{>!WiDqmIpP_bmkXB3d&cY&HNKifo=I=6e}?B5PUw^5P8+lLlG$)| zUSgFtTjlg(LCG|Uj@k5K;*FVTrJj-O{|w9*4`gibQna^fL8Ftt1AXQDd%x$CiQX>vn+Y2f?$Q#2+cD3#@f|B285AF;v7P}x7RtXili z{w0EMy=9;ikiCu*O`f8>&W|-}yZVZ^u~^*Cr}~S9n3L%f;C zhQ=4JR9)^#KfA4Jb7SDa;2pldH`vjFj`u>QzIGG=o};e&tBqtlOMKMX-FCPT`A0-l zkX?{J93}j`fMybl9VqD8pi^6!)hPzS76yy9V-RvQeIpQJHs4To(PqxUtUy#)8a!AY zSkSy$TUAMQgX3XIHG^jJfui)2PE%>B+sKDpNfBp2$;$MQpEEpZm;Pn<8j&TTNo>#FVRE0X67c#y0$Y`n{l{UTMal7+uI^ zL@Z-SN-YJoYun1(RH;Eb`;USyVqs(^Ke824Yvr?C3rgzex@-!_w$tz@?OopFHcGDW z4}~KNy16R?n^sp*15)y0LnHXh^JmJkacjM?v(ILC?1sJIqSm=0l(%fDl=a#OD_E&Z z5mCM|m7%zv*2#NTeZ0Jx!rO{7okH-X^2l`KDSaN}e)PG`TPmscM{h-%_W_@(qM1tO zMKOZ&RaF7tY;uR9`q0^*@;om4bGJokL0H1HhE=>>g0}rcW3CX*?@zb~bo;DE(}Wmc z-32G4f*HjsqAdqRcpG*NdNVq+3gDiy)%gJc9Uwc5uBugB=0yMoX6dPNAR6Y-e&Z7c zHGQ~1Y7gMIgy^ufGw95CA7N|;^V1lXgrqjp$a7(FJ}hR>`G(F;K2{yes0Qijp@{I(4H$xzV1!tW=Vc}?CNz&Xy>jySf)4H zkt>Lv#%LfFjcK3Sj=KAyhmBbHXGEyP*OG9tcW?%7-xE6hHZWM`6>+Pv`@x6lSGz7$ z@?$`_=sWzYW&hQ72FtV+vV%FKU!zy+7JRc#;8|^5^Ud$<0xT|e{r80v;Li^LyxYc9 zH>8*5a5F!jBRg#hx_X0=WQy^>1mj;xo6yY?!SBb@bi;_rRh48 ze4WMVIP*f|2m*1t5gaQ?-i=ZO%v#0;N(fTdvtQI%%uECdki;H$hBOZkK_tau(Po)1 zx!OU5WF8`vlb=#iokTGSSe@?gfbkoMTaJ!L>IJ^E%ua@7Gb=Jffj8$v1j3yE(U^p)>#6du|Ep=4c%-C4aD2ImENO zgW1#wUBB#C{Ru*kmZDX{wKeCBH0!B6k##t;q-5c1`vt;8*1HJAyuYKHPDZ|KNMlG! zcIKHe*YN7V15S|U!Lgwo(*LmJOXBog2S*3B_r2PsO8w8$=lBJzOI`}d7yMyi$#Kv0 zX()+=;>ZXwH2PqQO^Xs(L=gZM^b}x%g>sBZUny%t>QH!nNYDYaYuLcO!^Em5R13gU zB$0oR&2bgu_&5zS}{iZ1;Z*xNY=*z>2SS0SNq`17aN(YXQM2z>4>tB~oye zf|&nSDnWq;#g!Z(%o*{{0^kxrI>68ZY(Y{)B*y3g=b6vNij;t`SiFjM(x_7sMVcj2 zKnTo(ux7FBETc-ozC&-bRjyMwGZO^^C#d$;t{IRz5}F_#i$y`U<*AfRktQ*riv*m~ zDuHzY1tU$+hyf>({vDIB<;1E}xMl;NUubM;U0xddKF4&`lPvSKbj(a-VV&-J+p*;L z`i+l=*Qmuc%%&!3=!ZS#?R=zm4JkKWryp{dT!`js$#-|r|0y~AK|rYOF085u_81>~ z`Ugg2_<%d;`jddwslGCW=O0=&oL$^~MWzbr8oNXC{AW z9-e;l{%+o((sE{Pzs$`pE){Igt_eNn^#Qy1)ibgj zUWShI)lC~LZ>$Ng2h)1_lgxk4qIQn?g!q$Im%*-Q>}P}s0E!IIJZSOegySL+S1CMW z3Pl8x2LJqwC_;+F00->?)OP$tkRFLqA*kHakG^Hbu8(cPpOJ}8!^HR-7^{|f8uLGED;u7uO!)i~T z{a3PCh2?8F?q)20cJL{E?5!T=$#asQM7bs-sP+prqNyiySCw>hI!KIad4HZ;NLy>H zu+uyD)?o($ZKtPJai~v2DlG?Rx9!ag^;`y9#+31IFmODKRxW(uYTC$l^-$cqVX7sl zTi{z-S(nowMTd7tGp}L)y#s40G`i{-Z}z>1rA}ljejsl&7F`@ZWq2x=QnRff){w5X0Q0;x{W=vtQ!d1zhcx`Pgh~rLS!dO}qnn)9AmSMr(#tp@+ zOfnLtrt*X=7zq;#V96sx=u0FXSyHuMs<@xY~XL@#^4O z5uzdM7hyWb;{aXatjX!6tw!SG@e@HxP=?263g8oQgU$Ds}f_xZMX*^HiTwKEhp7IYcfh!){a9}h#{An6jUliz*M z?!WN2NHB6F4Pbldu;nJ*f8b-{5qUUxeMow&vri&IV07FPk`|!{!sr1_f66H=gl*^L z2DnuMBt-G2lev>5@hqUm8%q(+l@*o9B&tC$>462};iDOwj1Nl~-m=l`^^T2!G7N^d zKJzZU>=m%CZa)v*d3(l!zXz~(N@*E;i+0S@1jp)3eg9qx)|IZ$UUL6DMZWCI!{I{R zbbKV=H9}8bwC*eb|1_AmtH>f}m{A)%6SBn8DBvTO+9|NX4sh+@7#qk%>C+|t{z@By zL=xLy4Jg9_*$w`pjVY-YHA$S`zRx)dJtm0-66iq*MA>#ttQbqHm?ghIY?`axn?65X zjlc$VTEMy2im8*jbV|=`Z!#NK_cQFr|jP0*S^1 zU|gMY#DG#ju4%_a3_7PG1tmZ-)Cv2Z`^{K2OJYWC&a>Tt3y|5)gRBJo6%_X7L?p1~ z=gRRGr<-y&t*bQmOkdR5U-Q}hMqhtfZ=T!UL9QQQbg4X*69K4vq1E9x&9QK4wH};g z|JvWZDhwi13OunE?U}_k+p)1bisBKKS;)E}7Hni>gosasppF7UD&IdQAp6J~CO;Y7 zBJ?>qG17Sap;bnfmq(W>8HB=uZS&u>a!8}i+JP9F<}wkQVmKixoK@&*7_LD55(c`Y z7V7|9fztKz@Ui@-7hHHVJk9O<8q?7D4Dm6{t7#JhW<^+-sRZiLvTKkd$#c`NTi@cX z*re>Z*HMTqr%fGxjm7gg`=t%L;l>Mz)ohwSND0XWkv2`-Qjup^l@Za!i)lR7{72zW;N{{SsO(!cFcM!p-^ z)5fyRtSmtGZ2#-{LU`mZ_|;kV4d{N095{b~2%xodU-+0((TxZ@--*0dl1{7~K!4LD zL{f(I@p8m-n(9UTMW7j}h53NTXR(z_qD5L`%QVCh<3)6ULX;#$4<=E?*3AfvQl-h1 z&#fDVYZtE*2ibTXZiRXQe7$<#hT{IgyV$=!u;J#YuOMR1b?L9Ue{o-U!vJK6@;Yk8 z;asb};y>2i`pk{T^PM)fYaXYU%k%DVV|VDP(&Rax6!y zhJXM-m?B9>Hk?eGa;yTc+LX88-KkXQv~q0-Yx`(p=!_sHW$88vpuZ%`^Ak@~?v*zw&E% zaDR9I_bVyYZ}N`;r4Hy zq=ulX9B{U?5y>Hg_Js!R5HF}fJA)wO5sIuh2g^Bm>W|A);(93gde`av0*8f*SY&Zh z6GKwIxV7id79B(TSca0|zJmC8K`Z;>kN)RJ&vaD&_Mz6pzM7rv(hURG^!0Cw)^?W8 zYnaj7L{j466AMp$^6c%~pNfd*-OzQutYp=QGx%T^4t-Ilt)y?Z*Rqv|Ch3l8M zH|*f|z5Bwa6vf#r6R10d?LvHZGBkVi|3wtuXxuC@Z!ftT!Z9LVcuZ(#n6U6DttJ^i zJ%D_3JXr#X4KySfUSDxo0ymr~FWY+@>fX3>Zb|uXp4;#@_~e3eS4~Z%vdGaU_pXFn zbDll?2Uyx&^60=j>^1wk`sl1}^Vt6#D6cBn{PnT@+}`+@=pgSyKuigok$l8?q8}rK za08VDXi_B*$fOcws!~9M6qv#z14UvHWJ!NRVR+VC6>Y@LT@~f+ z?a_*Mj(2i)Klj;EkONE+J&)uF4*q1RQos%Vk)S+{q5megw z&q;Y3eB}iE`Ony6>@j}5M_?^ALf(m%Pyp-^3k}geA&CWe4aiXiWN;t6*COsT&ML#HlzaiJ$`!6TIBmwjIR}%p(o-m?YJYGpYihHdtY9+Yj?0}8(x`6$6RNq{v#4G z$US73D7LGKKV#D@OZbdI0E8kT5RG2^CRe;a;!oU4142k6i*QvpVpG`KVli25X1mQS z<$TP5mt^=T1=d+E!pNiS45fm?+noz~n6SH^={I?cCgw~z`~msPDSt$ zymys%?WGDVLygYB(1}mCkN&=CVA)LzVdk;rFI<;%&ui;`$iDi!9oPL9x*qu+l)kij z<#WrLw-6;a*L1F*-?r?waK$|P5|=kLqtxAJHWWEY{rvIOc`|?5_Qu!yZXADV*>K-_ z_Qz+~-@mZ)#z1vi)y!_;_SA(J(0=&_>CjxD2R#v~9?}RvAP2EN6YU=Y&g2c63UL|Zi$TOi z-Z1ncb<08Q>BcZ_j)=0eq*)5I4b=`a+J=}dR=t4ZHun;tDj5RbdXoBP{Emg?I<|3r zZuty$wZEc>_|)^NP$bK++0LJV8=JgdufScI@#*V@1r~$XEAcl{51rds;B;n4Dfm

xE6|6S5p0N? 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

A_8%V(z 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

BwLjy`93{Xb{J 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 literal 0 HcmV?d00001 diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/serif/NimbusRoman-Italic.woff b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/serif/NimbusRoman-Italic.woff new file mode 100644 index 0000000000000000000000000000000000000000..c4629c6860446949b5faf47ddb6a7eac09278fa1 GIT binary patch literal 115832 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 Hzf%AJm62my literal 0 HcmV?d00001 diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/fonts/AccessibleDfA-Regular.woff b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/fonts/AccessibleDfA-Regular.woff new file mode 100644 index 0000000000000000000000000000000000000000..20988e0de039de36677662c9a82d37ab64652605 GIT binary patch literal 89336 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 literal 0 HcmV?d00001 diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/fonts/AccessibleDfA-Regular.woff2 b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/fonts/AccessibleDfA-Regular.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..14dafdf7e1e4552c627334aff9efc28f5b29a251 GIT binary patch literal 65592 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 literal 0 HcmV?d00001 diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/fonts/LICENSE-AccessibleDfa b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/fonts/LICENSE-AccessibleDfa old mode 100755 new mode 100644 similarity index 100% rename from readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/fonts/LICENSE-AccessibleDfa rename to readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/fonts/LICENSE-AccessibleDfa diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/fonts/LICENSE-IaWriterDuospace.md b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/fonts/LICENSE-IaWriterDuospace.md old mode 100755 new mode 100644 similarity index 100% rename from readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/fonts/LICENSE-IaWriterDuospace.md rename to readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/fonts/LICENSE-IaWriterDuospace.md diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/fonts/iAWriterDuospace-Regular.ttf b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/fonts/iAWriterDuospace-Regular.ttf old mode 100755 new mode 100644 similarity index 100% rename from readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/fonts/iAWriterDuospace-Regular.ttf rename to readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/fonts/iAWriterDuospace-Regular.ttf diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/rtl/ReadiumCSS-after.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/rtl/ReadiumCSS-after.css new file mode 100644 index 0000000000..7594380f6a --- /dev/null +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/rtl/ReadiumCSS-after.css @@ -0,0 +1,452 @@ +/* + * Readium CSS (v. 2.0.0-alpha.5) + * Developers: Jiminy Panoz + * Copyright (c) 2017. Readium Foundation. All rights reserved. + * Use of this source code is governed by a BSD-style license which is detailed in the + * LICENSE file present in the project repository where this source code is maintained. +*/ + +@namespace url("http://www.w3.org/1999/xhtml"); + +@namespace epub url("http://www.idpf.org/2007/ops"); + +@namespace m url("http://www.w3.org/1998/Math/MathML"); + +@namespace svg url("http://www.w3.org/2000/svg"); + +:root{ + --RS__colWidth:100vw; + --RS__colCount:1; + --RS__colGap:0; + --RS__defaultLineLength:40rem; + --RS__pageGutter:0; + --RS__viewportWidth:100%; +} + +@page{ + margin:0 !important; +} + +:root{ + position:relative; + + -webkit-column-width:var(--RS__colWidth); + -moz-column-width:var(--RS__colWidth); + column-width:var(--RS__colWidth); + -webkit-column-count:var(--RS__colCount); + -moz-column-count:var(--RS__colCount); + column-count:var(--RS__colCount); + + -webkit-column-gap:var(--RS__colGap); + -moz-column-gap:var(--RS__colGap); + column-gap:var(--RS__colGap); + -moz-column-fill:auto; + column-fill:auto; + width:var(--RS__viewportWidth); + height:100vh; + max-width:var(--RS__viewportWidth); + max-height:100vh; + min-width:var(--RS__viewportWidth); + min-height:100vh; + padding:0 !important; + margin:0 !important; + font-size:100% !important; + + -webkit-text-size-adjust:100%; + box-sizing:border-box; + -webkit-touch-callout:none; +} + +body{ + width:100%; + max-width:var(--RS__defaultLineLength) !important; + padding:0 var(--RS__pageGutter) !important; + margin:0 auto !important; + overflow:hidden; + box-sizing:border-box; +} + +@supports (overflow: clip){ + + :root{ + overflow:clip; + } + + body{ + overflow:clip; + overflow-clip-margin:content-box; + } +} + +:root[style*="readium-scroll-on"]{ + -webkit-columns:auto auto !important; + -moz-columns:auto auto !important; + columns:auto auto !important; + width:auto !important; + height:auto !important; + max-width:none !important; + max-height:none !important; + min-width:0 !important; + min-height:0 !important; +} + +:root[style*="readium-scroll-on"] body{ + overflow:auto; + --RS__defaultLineLength:40rem !important; +} + +@supports (overflow: clip){ + + :root[style*="readium-scroll-on"]{ + overflow:auto; + } + + :root[style*="readium-scroll-on"] body{ + overflow:clip; + } +} + +:root[style*="readium-night-on"]{ + --RS__backgroundColor:#000000; + --RS__textColor:#FEFEFE; + + --RS__linkColor:#63caff; + --RS__visitedColor:#0099E5; + --RS__selectionBackgroundColor:#b4d8fe; + --RS__selectionTextColor:inherit; +} + +:root[style*="readium-night-on"] *:not(a){ + color:inherit !important; + background-color:transparent !important; + border-color:currentcolor !important; +} + +:root[style*="readium-night-on"] svg text{ + fill:currentcolor !important; + stroke:none !important; +} + +:root[style*="readium-night-on"] a:link, +:root[style*="readium-night-on"] a:link *{ + color:var(--RS__linkColor) !important; +} + +:root[style*="readium-night-on"] a:visited, +:root[style*="readium-night-on"] a:visited *{ + color:var(--RS__visitedColor) !important; +} + +:root[style*="readium-night-on"] img[class*="gaiji"], +:root[style*="readium-night-on"] *[epub\:type~="titlepage"] img:only-child, +:root[style*="readium-night-on"] *[epub|type~="titlepage"] img:only-child{ + -webkit-filter:invert(100%); + filter:invert(100%); +} + +:root[style*="readium-night-on"][style*="readium-darken-on"] img{ + -webkit-filter:brightness(80%); + filter:brightness(80%); +} + +:root[style*="readium-night-on"][style*="readium-invert-on"] img{ + -webkit-filter:invert(100%); + filter:invert(100%); +} + +:root[style*="readium-night-on"][style*="readium-darken-on"][style*="readium-invert-on"] img{ + -webkit-filter:brightness(80%) invert(100%); + filter:brightness(80%) invert(100%); +} + +:root[style*="readium-sepia-on"]{ + --RS__backgroundColor:#faf4e8; + --RS__textColor:#121212; + + --RS__linkColor:#0000EE; + --RS__visitedColor:#551A8B; + --RS__selectionBackgroundColor:#b4d8fe; + --RS__selectionTextColor:inherit; + + --RS__defaultLineLength:40.01rem; +} + +:root[style*="readium-sepia-on"] *:not(a){ + color:inherit !important; + background-color:transparent !important; +} + +:root[style*="readium-sepia-on"] a:link, +:root[style*="readium-sepia-on"] a:link *{ + color:var(--RS__linkColor); +} + +:root[style*="readium-sepia-on"] a:visited, +:root[style*="readium-sepia-on"] a:visited *{ + color:var(--RS__visitedColor); +} + +:root[style*="readium-sepia-on"] svg, +:root[style*="readium-sepia-on"] img{ + background-color:transparent !important; + mix-blend-mode:multiply; +} + +@media screen and (-ms-high-contrast: active){ + + :root{ + color:windowText !important; + background-color:window !important; + } + + :root :not(#\#):not(#\#):not(#\#), + :root :not(#\#):not(#\#):not(#\#) :not(#\#):not(#\#):not(#\#) + :root :not(#\#):not(#\#):not(#\#) :not(#\#):not(#\#):not(#\#) :not(#\#):not(#\#):not(#\#){ + color:inherit !important; + background-color:inherit !important; + } + + .readiumCSS-mo-active-default{ + color:highlightText !important; + background-color:highlight !important; + } +} + +@media screen and (-ms-high-contrast: white-on-black){ + + :root[style*="readium-night-on"] img[class*="gaiji"], + :root[style*="readium-night-on"] *[epub\:type~="titlepage"] img:only-child, + :root[style*="readium-night-on"] *[epub|type~="titlepage"] img:only-child{ + -webkit-filter:none !important; + filter:none !important; + } + + :root[style*="readium-night-on"][style*="readium-invert-on"] img{ + -webkit-filter:none !important; + filter:none !important; + } + + :root[style*="readium-night-on"][style*="readium-darken-on"][style*="readium-invert-on"] img{ + -webkit-filter:brightness(80%); + filter:brightness(80%); + } +} + +@media screen and (inverted-colors){ + + :root[style*="readium-night-on"] img[class*="gaiji"], + :root[style*="readium-night-on"] *[epub\:type~="titlepage"] img:only-child, + :root[style*="readium-night-on"] *[epub|type~="titlepage"] img:only-child{ + -webkit-filter:none !important; + filter:none !important; + } + + :root[style*="readium-night-on"][style*="readium-invert-on"] img{ + -webkit-filter:none !important; + filter:none !important; + } + + :root[style*="readium-night-on"][style*="readium-darken-on"][style*="readium-invert-on"] img{ + -webkit-filter:brightness(80%); + filter:brightness(80%); + } +} + +@media screen and (monochrome){ +} + +@media screen and (prefers-reduced-motion){ +} + +:root[style*="--USER__colCount"]{ + -webkit-column-count:var(--USER__colCount); + -moz-column-count:var(--USER__colCount); + column-count:var(--USER__colCount); + + --RS__colWidth:auto; +} + +:root[style*="--USER__colCount: 0"], +:root[style*="--USER__colCount:0"]{ + -webkit-column-count:1; + -moz-column-count:1; + column-count:1; +} + +:root[style*="--USER__colCount: 0"], +:root[style*="--USER__colCount:0"], +:root[style*="--USER__colCount: 1"], +:root[style*="--USER__colCount:1"]{ + --RS__colWidth:100vw; +} + +:root[style*="--USER__lineLength"] body{ + max-width:var(--USER__lineLength) !important; + } + +:root[style*="--USER__backgroundColor"]{ + background-color:var(--USER__backgroundColor) !important; +} + +:root[style*="--USER__backgroundColor"] *{ + background-color:transparent !important; +} + +:root[style*="--USER__textColor"]{ + color:var(--USER__textColor) !important; +} + +:root[style*="--USER__textColor"] *:not(h1):not(h2):not(h3):not(h4):not(h5):not(h6):not(pre){ + color:inherit !important; +} + +:root[style*="readium-advanced-on"][style*="--USER__textAlign"]{ + text-align:var(--USER__textAlign); +} + +:root[style*="readium-advanced-on"][style*="--USER__textAlign"] body, +:root[style*="readium-advanced-on"][style*="--USER__textAlign"] *:not(blockquote):not(figcaption) p, +:root[style*="readium-advanced-on"][style*="--USER__textAlign"] li{ + text-align:var(--USER__textAlign) !important; + -moz-text-align-last:auto !important; + -epub-text-align-last:auto !important; + text-align-last:auto !important; +} + +:root[style*="readium-font-on"][style*="--USER__fontFamily"]{ + font-family:var(--USER__fontFamily) !important; +} + +:root[style*="readium-font-on"][style*="--USER__fontFamily"] *:not(code):not(var):not(kbd):not(samp){ + font-family:inherit !important; +} + +:root[style*="--USER__fontSize"]{ + zoom:var(--USER__fontSize) !important; +} + +@supports not (zoom: 1){ + + :root[style*="--USER__fontSize"]{ + font-size:var(--USER__fontSize) !important; + } +} + +:root[style*="readium-advanced-on"][style*="--USER__lineHeight"]{ + line-height:var(--USER__lineHeight) !important; +} + +:root[style*="readium-advanced-on"][style*="--USER__lineHeight"] body, +:root[style*="readium-advanced-on"][style*="--USER__lineHeight"] p, +:root[style*="readium-advanced-on"][style*="--USER__lineHeight"] li, +:root[style*="readium-advanced-on"][style*="--USER__lineHeight"] div{ + line-height:inherit; +} + +:root[style*="readium-advanced-on"][style*="--USER__paraSpacing"] p{ + margin-top:var(--USER__paraSpacing) !important; + margin-bottom:var(--USER__paraSpacing) !important; +} + +:root[style*="readium-advanced-on"][style*="--USER__paraIndent"] p{ + text-indent:var(--USER__paraIndent) !important; +} + +:root[style*="readium-advanced-on"][style*="--USER__paraIndent"] p *, +:root[style*="readium-advanced-on"][style*="--USER__paraIndent"] p:first-letter{ + text-indent:0 !important; +} + +:root[style*="readium-advanced-on"][style*="--USER__wordSpacing"] h1, +:root[style*="readium-advanced-on"][style*="--USER__wordSpacing"] h2, +:root[style*="readium-advanced-on"][style*="--USER__wordSpacing"] h3, +:root[style*="readium-advanced-on"][style*="--USER__wordSpacing"] h4, +:root[style*="readium-advanced-on"][style*="--USER__wordSpacing"] h5, +:root[style*="readium-advanced-on"][style*="--USER__wordSpacing"] h6, +:root[style*="readium-advanced-on"][style*="--USER__wordSpacing"] p, +:root[style*="readium-advanced-on"][style*="--USER__wordSpacing"] li, +:root[style*="readium-advanced-on"][style*="--USER__wordSpacing"] div{ + word-spacing:var(--USER__wordSpacing); +} + +:root[style*="readium-advanced-on"][style*="--USER__arabicLigatures"]{ + font-variant-ligatures:var(--USER__ligatures) !important; +} + +:root[style*="readium-advanced-on"][style*="--USER__arabicLigatures"] *{ + font-variant-ligatures:inherit !important; +} + +:root[style*="readium-font-on"][style*="--USER__fontWeight"] body{ + font-weight:var(--USER__fontWeight) !important; +} + +:root[style*="readium-font-on"][style*="--USER__fontWeight"] b, +:root[style*="readium-font-on"][style*="--USER__fontWeight"] strong{ + font-weight:bolder; +} + +:root[style*="readium-font-on"][style*="--USER__fontWidth"] body{ + font-stretch:var(--USER__fontWidth) !important; +} + +:root[style*="readium-font-on"][style*="--USER__fontOpticalSizing"] body{ + font-optical-sizing:var(--USER__fontOpticalSizing) !important; +} + +@supports not (zoom: 1){ + + :root[style*="readium-advanced-on"]{ + --USER__typeScale:1.2; + } + + :root[style*="readium-advanced-on"] p, + :root[style*="readium-advanced-on"] li, + :root[style*="readium-advanced-on"] div, + :root[style*="readium-advanced-on"] pre, + :root[style*="readium-advanced-on"] dd{ + font-size:1rem !important; + } + + :root[style*="readium-advanced-on"] h1{ + font-size:1.75rem !important; + font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important; + } + + :root[style*="readium-advanced-on"] h2{ + font-size:1.5rem !important; + font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important; + } + + :root[style*="readium-advanced-on"] h3{ + font-size:1.25rem !important; + font-size:calc(1rem * var(--USER__typeScale)) !important; + } + + :root[style*="readium-advanced-on"] h4, + :root[style*="readium-advanced-on"] h5, + :root[style*="readium-advanced-on"] h6{ + font-size:1rem !important; + } + + :root[style*="readium-advanced-on"] small{ + font-size:smaller !important; + } + + :root[style*="readium-advanced-on"] sub, + :root[style*="readium-advanced-on"] sup{ + font-size:67.5% !important; + } + + :root[style*="readium-advanced-on"][style*="--USER__typeScale"] h1{ + font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important; + } + + :root[style*="readium-advanced-on"][style*="--USER__typeScale"] h2{ + font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important; + } + + :root[style*="readium-advanced-on"][style*="--USER__typeScale"] h3{ + font-size:calc(1rem * var(--USER__typeScale)) !important; + } +} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/rtl/ReadiumCSS-before.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/rtl/ReadiumCSS-before.css new file mode 100644 index 0000000000..b4bfa36c26 --- /dev/null +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/rtl/ReadiumCSS-before.css @@ -0,0 +1,397 @@ +/* + * Readium CSS (v. 2.0.0-alpha.5) + * Developers: Jiminy Panoz + * Copyright (c) 2017. Readium Foundation. All rights reserved. + * Use of this source code is governed by a BSD-style license which is detailed in the + * LICENSE file present in the project repository where this source code is maintained. +*/ + +@namespace url("http://www.w3.org/1999/xhtml"); + +@namespace epub url("http://www.idpf.org/2007/ops"); + +@namespace m url("http://www.w3.org/1998/Math/MathML"); + +@namespace svg url("http://www.w3.org/2000/svg"); + +@-ms-viewport{ + width:device-width; +} + +@viewport{ + width:device-width; + zoom:1; +} + +:root{ + --RS__oldStyleTf:"Iowan Old Style", sitka, "Sitka Text", palatino, "Book Antiqua", "URW Palladio L", p052, serif; + --RS__modernTf:athelas, constantia, charter, "Bitstream Charter", cambria, "Georgia Pro", georgia, serif; + --RS__sansTf:-ui-sans-serif, -apple-system, system-ui, blinkmacsystemfont, "Segoe UI Variable", "Segoe UI", inter, roboto, "Helvetica Neue", "Arial Nova", "Liberation Sans", arial, sans-serif; + --RS__humanistTf:seravek, calibri, "Gill Sans Nova", roboto, ubuntu, "DejaVu Sans", source-sans-pro, sans-serif; + --RS__monospaceTf:ui-monospace, "Andale Mono", "Cascadia Code", "Source Code Pro", menlo, consolas, "DejaVu Sans Mono", monospace; + --RS__baseFontFamily:var(--RS__oldStyleTf); + --RS__lineHeightCompensation:1; + --RS__baseLineHeight:calc((1em + (2ex - 1ch) - ((1rem - 16px) * 0.1667)) * var(--RS__lineHeightCompensation)); +} + +html{ + font-family:var(--RS__baseFontFamily); + line-height:1.6; + line-height:var(--RS__baseLineHeight); + text-rendering:optimizelegibility; +} + +h1, h2, h3{ + line-height:normal; +} + +:lang(ja), +:lang(zh), +:lang(ko){ + word-wrap:break-word; + -webkit-line-break:strict; + -epub-line-break:strict; + line-break:strict; +} + +math{ + font-family:"Latin Modern Math", "STIX Two Math", "XITS Math", "STIX Math", "Libertinus Math", "TeX Gyre Termes Math", "TeX Gyre Bonum Math", "TeX Gyre Schola", "DejaVu Math TeX Gyre", "TeX Gyre Pagella Math", "Asana Math", "Cambria Math", "Lucida Bright Math", "Minion Math", STIXGeneral, STIXSizeOneSym, Symbol, "Times New Roman", serif; +} + +:lang(am){ + --RS__baseFontFamily:kefa, nyala, roboto, noto, "Noto Sans Ethiopic", serif; + --RS__lineHeightCompensation:1.167; +} + +:lang(ar){ + --RS__baseFontFamily:"Geeza Pro", "Arabic Typesetting", roboto, noto, "Noto Naskh Arabic", "Times New Roman", serif; +} + +:lang(bn){ + --RS__baseFontFamily:"Kohinoor Bangla", "Bangla Sangam MN", vrinda, roboto, noto, "Noto Sans Bengali", sans-serif; + --RS__lineHeightCompensation:1.067; +} + +:lang(bo){ + --RS__baseFontFamily:kailasa, "Microsoft Himalaya", roboto, noto, "Noto Sans Tibetan", sans-serif; +} + +:lang(chr){ + --RS__baseFontFamily:"Plantagenet Cherokee", roboto, noto, "Noto Sans Cherokee"; + --RS__lineHeightCompensation:1.167; +} + +:lang(fa){ + --RS__baseFontFamily:"Geeza Pro", "Arabic Typesetting", roboto, noto, "Noto Naskh Arabic", "Times New Roman", serif; +} + +:lang(gu){ + --RS__baseFontFamily:"Gujarati Sangam MN", "Nirmala UI", shruti, roboto, noto, "Noto Sans Gujarati", sans-serif; + --RS__lineHeightCompensation:1.167; +} + +:lang(he){ + --RS__baseFontFamily:"New Peninim MT", "Arial Hebrew", gisha, "Times New Roman", roboto, noto, "Noto Sans Hebrew" sans-serif; + --RS__lineHeightCompensation:1.1; +} + +:lang(hi){ + --RS__baseFontFamily:"Kohinoor Devanagari", "Devanagari Sangam MN", kokila, "Nirmala UI", roboto, noto, "Noto Sans Devanagari", sans-serif; + + --RS__lineHeightCompensation:1.1; +} + +:lang(hy){ + --RS__baseFontFamily:mshtakan, sylfaen, roboto, noto, "Noto Serif Armenian", serif; +} + +:lang(iu){ + --RS__baseFontFamily:"Euphemia UCAS", euphemia, roboto, noto, "Noto Sans Canadian Aboriginal", sans-serif; +} + +:lang(ja){ + --RS__baseFontFamily:yugothic, "Hiragino Maru Gothic ProN", "Hiragino Sans", "Yu Gothic UI", "Meiryo UI", "MS Gothic", roboto, noto, "Noto Sans CJK JP", sans-serif; + --RS__lineHeightCompensation:1.167; + --RS__serif-ja:"Hiragino Mincho ProN", "Hiragino Mincho Pro", "YuMincho", "BIZ UDPMincho", "Yu Mincho", "MS P明朝", "MS PMincho", serif; + --RS__sans-serif-ja:"Hiragino Sans", "Hiragino Kaku Gothic ProN", "Hiragino Kaku Gothic Pro", "ヒラギノ角ゴ W3", "YuGothic", "Yu Gothic Medium", "BIZ UDPGothic", "Yu Gothic", "MS Pゴシック", "MS PGothic", sans-serif; + --RS__serif-ja-v:"Hiragino Mincho ProN", "Hiragino Mincho Pro", "YuMincho", "BIZ UDMincho", "Yu Mincho", "MS明朝", "MS Mincho", serif; + --RS__sans-serif-ja-v:"Hiragino Sans", "Hiragino Kaku Gothic ProN", "Hiragino Kaku Gothic Pro", "ヒラギノ角ゴ W3", "YuGothic", "Yu Gothic Medium", "BIZ UDGothic", "Yu Gothic", "MSゴシック", "MS Gothic", sans-serif; +} + +:lang(km){ + --RS__baseFontFamily:"Khmer Sangam MN", "Leelawadee UI", "Khmer UI", roboto, noto, "Noto Sans Khmer", sans-serif; + --RS__lineHeightCompensation:1.067; +} + +:lang(kn){ + --RS__baseFontFamily:"Kannada Sangam MN", "Nirmala UI", tunga, roboto, noto, "Noto Sans Kannada", sans-serif; + --RS__lineHeightCompensation:1.1; +} + +:lang(ko){ + --RS__baseFontFamily:"Nanum Gothic", "Apple SD Gothic Neo", "Malgun Gothic", roboto, noto, "Noto Sans CJK KR", sans-serif; + --RS__lineHeightCompensation:1.167; +} + +:lang(lo){ + --RS__baseFontFamily:"Lao Sangam MN", "Leelawadee UI", "Lao UI", roboto, noto, "Noto Sans Lao", sans-serif; +} + +:lang(ml){ + --RS__baseFontFamily:"Malayalam Sangam MN", "Nirmala UI", kartika, roboto, noto, "Noto Sans Malayalam", sans-serif; + --RS__lineHeightCompensation:1.067; +} + +:lang(or){ + --RS__baseFontFamily:"Oriya Sangam MN", "Nirmala UI", kalinga, roboto, noto, "Noto Sans Oriya", sans-serif; + --RS__lineHeightCompensation:1.167; +} + +:lang(pa){ + --RS__baseFontFamily:"Gurmukhi MN", "Nirmala UI", kartika, roboto, noto, "Noto Sans Gurmukhi", sans-serif; + --RS__lineHeightCompensation:1.1; +} + +:lang(si){ + --RS__baseFontFamily:"Sinhala Sangam MN", "Nirmala UI", "Iskoola Pota", roboto, noto, "Noto Sans Sinhala", sans-serif; + --RS__lineHeightCompensation:1.167; +} + +:lang(ta){ + --RS__baseFontFamily:"Tamil Sangam MN", "Nirmala UI", latha, roboto, noto, "Noto Sans Tamil", sans-serif; + --RS__lineHeightCompensation:1.067; +} + +:lang(te){ + --RS__baseFontFamily:"Kohinoor Telugu", "Telugu Sangam MN", "Nirmala UI", gautami, roboto, noto, "Noto Sans Telugu", sans-serif; +} + +:lang(th){ + --RS__baseFontFamily:"Thonburi", "Leelawadee UI", "Cordia New", roboto, noto, "Noto Sans Thai", sans-serif; + --RS__lineHeightCompensation:1.067; +} + +:lang(zh){ + --RS__baseFontFamily:"方体", "PingFang SC", "黑体", "Heiti SC", "Microsoft JhengHei UI", "Microsoft JhengHei", roboto, noto, "Noto Sans CJK SC", sans-serif; + --RS__lineHeightCompensation:1.167; +} + +:lang(zh-Hant), +:lang(zh-TW){ + --RS__baseFontFamily:"方體", "PingFang TC", "黑體", "Heiti TC", "Microsoft JhengHei UI", "Microsoft JhengHei", roboto, noto, "Noto Sans CJK TC", sans-serif; + --RS__lineHeightCompensation:1.167; +} + +:lang(zh-HK){ + --RS__baseFontFamily:"方體", "PingFang HK", "方體", "PingFang TC", "黑體", "Heiti TC", "Microsoft JhengHei UI", "Microsoft JhengHei", roboto, noto, "Noto Sans CJK TC", sans-serif; + --RS__lineHeightCompensation:1.167; +} + +:root{ + --RS__backgroundColor:#FFFFFF; + --RS__textColor:#121212; + --RS__selectionBackgroundColor:#b4d8fe; + --RS__selectionTextColor:inherit; +} + +:root{ + color:var(--RS__textColor) !important; + background-color:var(--RS__backgroundColor) !important; +} + +::-moz-selection{ + color:var(--RS__selectionTextColor); + background-color:var(--RS__selectionBackgroundColor); +} + +::selection{ + color:var(--RS__selectionTextColor); + background-color:var(--RS__selectionBackgroundColor); +} + +body{ + widows:2; + orphans:2; +} + +figcaption, th, td{ + widows:1; + orphans:1; +} + +h2, h3, h4, h5, h6, dt, +hr, caption{ + -webkit-column-break-after:avoid; + page-break-after:avoid; + break-after:avoid; +} + +h1, h2, h3, h4, h5, h6, dt, +figure, tr{ + -webkit-column-break-inside:avoid; + page-break-inside:avoid; + break-inside:avoid; +} + +body{ + -webkit-hyphenate-character:"\002D"; + -moz-hyphenate-character:"\002D"; + -ms-hyphenate-character:"\002D"; + hyphenate-character:"\002D"; + -webkit-hyphenate-limit-lines:3; + -ms-hyphenate-limit-lines:3; + hyphenate-limit-lines:3; +} + +h1, h2, h3, h4, h5, h6, dt, +figcaption, pre, caption, address, +center, code, var{ + -ms-hyphens:none; + -moz-hyphens:none; + -webkit-hyphens:none; + -epub-hyphens:none; + hyphens:none; +} + +body{ + font-variant-numeric:oldstyle-nums proportional-nums; +} + +:lang(ja) body, +:lang(zh) body, +:lang(ko) body{ + font-variant-numeric:lining-nums proportional-nums; +} + +h1, h2, h3, h4, h5, h6, dt{ + font-variant-numeric:lining-nums proportional-nums; +} + +table{ + font-variant-numeric:lining-nums tabular-nums; +} + +code, var{ + font-variant-ligatures:none; + font-variant-numeric:lining-nums tabular-nums slashed-zero; +} + +rt{ + font-variant-east-asian:ruby; +} + +:lang(ar){ + font-variant-ligatures:common-ligatures; +} + +:lang(ko){ + font-kerning:normal; +} + +hr{ + color:inherit; + border-color:currentcolor; +} + +table, th, td{ + border-color:currentcolor; +} + +figure, blockquote{ + margin:1em 5%; +} + +ul, ol{ + padding-left:5%; +} + +dd{ + margin-left:5%; +} + +pre{ + white-space:pre-wrap; + -ms-tab-size:2; + -moz-tab-size:2; + -webkit-tab-size:2; + tab-size:2; +} + +abbr[title], acronym[title]{ + text-decoration:dotted underline; +} + +nobr wbr{ + white-space:normal; +} + +ruby > rt, ruby > rp{ + -webkit-user-select:none; + -moz-user-select:none; + -ms-user-select:none; + user-select:none; +} + +*:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)), +*:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)), +*:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)), +:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)) cite, +:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)) dfn, +:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)) em, +:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)) i, +:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)) cite, +:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)) dfn, +:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)) em, +:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)) i, +:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)) cite, +:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)) dfn, +:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)) em, +:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)) i{ + font-style:normal; +} + +:lang(ja) a, +:lang(zh) a, +:lang(ko) a{ + text-decoration:none; +} + +:root{ + --RS__maxMediaWidth:100%; + --RS__maxMediaHeight:95vh; + --RS__boxSizingMedia:border-box; + --RS__boxSizingTable:border-box; +} + +a, a span, span a, h1, h2, h3, h4, h5, h6{ + word-wrap:break-word; +} + +div{ + max-width:var(--RS__maxMediaWidth); +} + +img, svg|svg, video{ + object-fit:contain; + + width:auto; + height:auto; + max-width:var(--RS__maxMediaWidth); + max-height:var(--RS__maxMediaHeight) !important; + box-sizing:var(--RS__boxSizingMedia); + -webkit-column-break-inside:avoid; + page-break-inside:avoid; + break-inside:avoid; +} + +audio{ + max-width:100%; + -webkit-column-break-inside:avoid; + page-break-inside:avoid; + break-inside:avoid; + } + +table{ + max-width:var(--RS__maxMediaWidth); + box-sizing:var(--RS__boxSizingTable); +} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/rtl/ReadiumCSS-default.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/rtl/ReadiumCSS-default.css new file mode 100644 index 0000000000..03f9e7dbe8 --- /dev/null +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/rtl/ReadiumCSS-default.css @@ -0,0 +1,152 @@ +/* + * Readium CSS (v. 2.0.0-alpha.5) + * Developers: Jiminy Panoz + * Copyright (c) 2017. Readium Foundation. All rights reserved. + * Use of this source code is governed by a BSD-style license which is detailed in the + * LICENSE file present in the project repository where this source code is maintained. +*/ + +@namespace url("http://www.w3.org/1999/xhtml"); + +@namespace epub url("http://www.idpf.org/2007/ops"); + +@namespace m url("http://www.w3.org/1998/Math/MathML"); + +@namespace svg url("http://www.w3.org/2000/svg"); + +:root{ + --RS__compFontFamily:var(--RS__baseFontFamily); + --RS__codeFontFamily:var(--RS__monospaceTf); + + --RS__typeScale:1.125; + --RS__baseFontSize:100%; + + --RS__flowSpacing:1.5rem; + --RS__paraSpacing:0; + --RS__paraIndent:1em; + + --RS__linkColor:#0000EE; + --RS__visitedColor:#551A8B; + + --RS__primaryColor:; + --RS__secondaryColor:; +} + +body{ + font-size:var(--RS__baseFontSize); + text-align:justify; +} + +h1, h2, h3, h4, h5, h6{ + font-family:var(--RS__compFontFamily); + text-align:right; +} + +blockquote, figure, p, pre, +aside, footer, form, hr{ + margin-top:var(--RS__flowSpacing); + margin-bottom:var(--RS__flowSpacing); +} + +p{ + margin-top:var(--RS__paraSpacing); + margin-bottom:var(--RS__paraSpacing); + text-indent:var(--RS__paraIndent); +} + +h1 + p, h2 + p, h3 + p, h4 + p, h5 + p, h6 + p, +hr + p{ + text-indent:0; +} + +pre{ + font-family:var(--RS__codeFontFamily); +} + +code, kbd, samp, tt{ + font-family:var(--RS__codeFontFamily); +} + +sub, sup{ + position:relative; + font-size:67.5%; + line-height:1; +} + +sub{ + bottom:-0.2ex; +} + +sup{ + bottom:0; +} + +:link{ + color:var(--RS__linkColor); +} + +:visited{ + color:var(--RS__visitedColor); +} + +h1{ + margin-top:calc(var(--RS__flowSpacing) * 2); + margin-bottom:calc(var(--RS__flowSpacing) * 2); + font-size:calc(((1em * var(--RS__typeScale)) * var(--RS__typeScale)) * var(--RS__typeScale)); +} + +h2{ + margin-top:calc(var(--RS__flowSpacing) * 2); + margin-bottom:var(--RS__flowSpacing); + font-size:calc((1em * var(--RS__typeScale)) * var(--RS__typeScale)); +} + +h3{ + margin-top:var(--RS__flowSpacing); + margin-bottom:var(--RS__flowSpacing); + font-size:calc(1em * var(--RS__typeScale)); +} + +h4{ + margin-top:var(--RS__flowSpacing); + margin-bottom:var(--RS__flowSpacing); + font-size:1em; +} + +h5{ + margin-top:var(--RS__flowSpacing); + margin-bottom:var(--RS__flowSpacing); + font-size:smaller; +} + +h6{ + margin-top:var(--RS__flowSpacing); + margin-bottom:0; + font-size:smaller; + font-weight:normal; +} + +dl, ol, ul{ + margin-top:var(--RS__flowSpacing); + margin-bottom:var(--RS__flowSpacing); +} + +table{ + margin:var(--RS__flowSpacing) 0; + border:1px solid currentcolor; + border-collapse:collapse; + empty-cells:show; +} + +thead, tbody, tfoot, table > tr{ + vertical-align:top; +} + +th{ + text-align:initial; +} + +th, td{ + padding:4px; + border:1px solid currentcolor; +} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/reflowable-injectable-script.js b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js similarity index 100% rename from readium/navigators/web/src/main/assets/readium/navigators/web/reflowable-injectable-script.js rename to readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/reflowable-injectable-script.js.map b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map similarity index 100% rename from readium/navigators/web/src/main/assets/readium/navigators/web/reflowable-injectable-script.js.map rename to readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/prepaginated-double-index.html b/readium/navigators/web/src/main/assets/readium/navigators/web/prepaginated-double-index.html deleted file mode 100644 index d6041ae251..0000000000 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/prepaginated-double-index.html +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - -
- - - -
- - - - diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/prepaginated-single-index.html b/readium/navigators/web/src/main/assets/readium/navigators/web/prepaginated-single-index.html deleted file mode 100644 index dfae3d6ce2..0000000000 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/prepaginated-single-index.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - -
- -
- - - diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadiumCSS-after.css b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadiumCSS-after.css deleted file mode 100644 index 042ad48e55..0000000000 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadiumCSS-after.css +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Readium CSS (v. 1.0.0-beta.3) - * Developers: Jiminy Panoz - * Copyright (c) 2017. Readium Foundation. All rights reserved. - * Use of this source code is governed by a BSD-style license which is detailed in the - * LICENSE file present in the project repository where this source code is maintained. -*/@namespace url("http://www.w3.org/1999/xhtml");@namespace epub url("http://www.idpf.org/2007/ops");@namespace m url("http://www.w3.org/1998/Math/MathML/");@namespace svg url("http://www.w3.org/2000/svg");:root{--RS__colWidth:45em;--RS__colCount:1;--RS__colGap:0;--RS__maxLineLength:40rem;--RS__pageGutter:20px;--RS__viewportWidth:100%}@page{margin:0!important}:root{position:relative;-webkit-column-width:var(--RS__colWidth);-moz-column-width:var(--RS__colWidth);column-width:var(--RS__colWidth);-webkit-column-count:var(--RS__colCount);-moz-column-count:var(--RS__colCount);column-count:var(--RS__colCount);-webkit-column-gap:var(--RS__colGap);-moz-column-gap:var(--RS__colGap);column-gap:var(--RS__colGap);-moz-column-fill:auto;column-fill:auto;width:var(--RS__viewportWidth);height:100vh;max-width:var(--RS__viewportWidth);max-height:100vh;min-width:var(--RS__viewportWidth);min-height:100vh;padding:0!important;margin:0!important;font-size:100%!important;-webkit-text-size-adjust:100%;box-sizing:border-box;-webkit-perspective:1;-webkit-touch-callout:none}body{width:100%;max-width:var(--RS__maxLineLength)!important;padding:0 var(--RS__pageGutter)!important;margin:0 auto!important;box-sizing:border-box}@media screen and (min-width:35em){:root{--RS__pageGutter:30px}}@media screen and (min-width:45em){:root{--RS__pageGutter:40px}}@media screen and (min-width:75em){:root{--RS__pageGutter:50px}}@media screen and (min-width:60em),screen and (min-device-width:36em) and (max-device-width:47em) and (orientation:landscape){:root{--RS__colWidth:20em;--RS__colCount:2;--RS__maxLineLength:39.99rem}}:root[style*=readium-scroll-on]{-webkit-columns:auto auto!important;-moz-columns:auto auto!important;columns:auto auto!important;width:auto!important;height:auto!important;max-width:none!important;max-height:none!important;min-width:0!important;min-height:0!important}:root[style*=readium-scroll-on] body{--RS__maxLineLength:40rem!important}:root[style*=readium-night-on]{--RS__backgroundColor:#000000;--RS__textColor:#FEFEFE;--RS__linkColor:#63caff;--RS__visitedColor:#0099E5;--RS__selectionBackgroundColor:#b4d8fe;--RS__selectionTextColor:inherit}:root[style*=readium-night-on] :not(a){color:inherit!important;background-color:transparent!important;border-color:currentColor!important}:root[style*=readium-night-on] svg text{fill:currentColor!important;stroke:none!important}:root[style*=readium-night-on] a:link,:root[style*=readium-night-on] a:link *{color:var(--RS__linkColor)!important}:root[style*=readium-night-on] a:visited,:root[style*=readium-night-on] a:visited *{color:var(--RS__visitedColor)!important}:root[style*=readium-night-on] [epub\:type~=titlepage] img:only-child,:root[style*=readium-night-on] [epub|type~=titlepage] img:only-child,:root[style*=readium-night-on] img[class*=gaiji]{-webkit-filter:invert(100%);filter:invert(100%)}:root[style*=readium-night-on][style*=readium-darken-on] img{-webkit-filter:brightness(80%);filter:brightness(80%)}:root[style*=readium-night-on][style*=readium-invert-on] img{-webkit-filter:invert(100%);filter:invert(100%)}:root[style*=readium-night-on][style*=readium-darken-on][style*=readium-invert-on] img{-webkit-filter:brightness(80%) invert(100%);filter:brightness(80%) invert(100%)}:root[style*=readium-sepia-on]{--RS__backgroundColor:#faf4e8;--RS__textColor:#121212;--RS__linkColor:#0000EE;--RS__visitedColor:#551A8B;--RS__selectionBackgroundColor:#b4d8fe;--RS__selectionTextColor:inherit;--RS__maxLineLength:40.01rem}:root[style*=readium-sepia-on] :not(a){color:inherit!important;background-color:transparent!important}:root[style*=readium-sepia-on] a:link,:root[style*=readium-sepia-on] a:link *{color:var(--RS__linkColor)}:root[style*=readium-sepia-on] a:visited,:root[style*=readium-sepia-on] a:visited *{color:var(--RS__visitedColor)}:root[style*=readium-sepia-on] img,:root[style*=readium-sepia-on] svg{background-color:transparent!important;mix-blend-mode:multiply}@media screen and (-ms-high-contrast:active){:root{color:windowText!important;background-color:window!important}:root :not(#\#):not(#\#):not(#\#),:root :not(#\#):not(#\#):not(#\#) :not(#\#):not(#\#):not(#\#) :root :not(#\#):not(#\#):not(#\#) :not(#\#):not(#\#):not(#\#) :not(#\#):not(#\#):not(#\#){color:inherit!important;background-color:inherit!important}.readiumCSS-mo-active-default{color:highlightText!important;background-color:highlight!important}}@media screen and (-ms-high-contrast:white-on-black){:root[style*=readium-night-on] [epub\:type~=titlepage] img:only-child,:root[style*=readium-night-on] [epub|type~=titlepage] img:only-child,:root[style*=readium-night-on] img[class*=gaiji]{-webkit-filter:none!important;filter:none!important}:root[style*=readium-night-on][style*=readium-invert-on] img{-webkit-filter:none!important;filter:none!important}:root[style*=readium-night-on][style*=readium-darken-on][style*=readium-invert-on] img{-webkit-filter:brightness(80%);filter:brightness(80%)}}@media screen and (inverted-colors){:root[style*=readium-night-on] [epub\:type~=titlepage] img:only-child,:root[style*=readium-night-on] [epub|type~=titlepage] img:only-child,:root[style*=readium-night-on] img[class*=gaiji]{-webkit-filter:none!important;filter:none!important}:root[style*=readium-night-on][style*=readium-invert-on] img{-webkit-filter:none!important;filter:none!important}:root[style*=readium-night-on][style*=readium-darken-on][style*=readium-invert-on] img{-webkit-filter:brightness(80%);filter:brightness(80%)}}@media screen and (min-width:60em),screen and (min-device-width:36em) and (max-device-width:47em) and (orientation:landscape){:root[style*="--USER__colCount: 1"],:root[style*="--USER__colCount: 2"],:root[style*="--USER__colCount:1"],:root[style*="--USER__colCount:2"]{-webkit-column-count:var(--USER__colCount);-moz-column-count:var(--USER__colCount);column-count:var(--USER__colCount)}:root[style*="--USER__colCount: 1"],:root[style*="--USER__colCount:1"]{--RS__maxLineLength:40rem!important;--RS__colWidth:100vw}:root[style*="--USER__colCount: 2"],:root[style*="--USER__colCount:2"]{--RS__colWidth:auto}}:root[style*="--USER__pageMargins"] body{padding:0 calc(var(--RS__pageGutter) * var(--USER__pageMargins))!important}:root[style*="--USER__backgroundColor"]{background-color:var(--USER__backgroundColor)!important}:root[style*="--USER__backgroundColor"] *{background-color:transparent!important}:root[style*="--USER__textColor"]{color:var(--USER__textColor)!important}:root[style*="--USER__textColor"] :not(h1):not(h2):not(h3):not(h4):not(h5):not(h6):not(pre){color:inherit!important}:root[style*=readium-advanced-on][style*="--USER__textAlign"]{text-align:var(--USER__textAlign)}:root[style*=readium-advanced-on][style*="--USER__textAlign"] :not(blockquote):not(figcaption) p,:root[style*=readium-advanced-on][style*="--USER__textAlign"] body,:root[style*=readium-advanced-on][style*="--USER__textAlign"] li{text-align:inherit!important;-moz-text-align-last:auto!important;-epub-text-align-last:auto!important;text-align-last:auto!important}:root[style*=readium-advanced-on][dir=rtl][style*="--USER__textAlign: left"],:root[style*=readium-advanced-on][dir=rtl][style*="--USER__textAlign:left"],:root[style*=readium-advanced-on][style*="--USER__textAlign: left"] [dir=rtl],:root[style*=readium-advanced-on][style*="--USER__textAlign:left"] [dir=rtl]{text-align:right}:root[style*=readium-advanced-on][dir=rtl][style*="--USER__textAlign: start"],:root[style*=readium-advanced-on][dir=rtl][style*="--USER__textAlign:start"]{text-align:right}:root[style*=readium-advanced-on][style*="--USER__textAlign: justify"] body,:root[style*=readium-advanced-on][style*="--USER__textAlign:justify"] body{-webkit-hyphens:auto;-moz-hyphens:auto;-ms-hyphens:auto;-epub-hyphens:auto;hyphens:auto}:root[style*=readium-advanced-on][style*="--USER__textAlign: left"] body,:root[style*=readium-advanced-on][style*="--USER__textAlign: right"] body,:root[style*=readium-advanced-on][style*="--USER__textAlign:left"] body,:root[style*=readium-advanced-on][style*="--USER__textAlign:right"] body{-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;-epub-hyphens:none;hyphens:none}:root[style*=readium-advanced-on][style*="--USER__bodyHyphens"]{-webkit-hyphens:var(--USER__bodyHyphens)!important;-moz-hyphens:var(--USER__bodyHyphens)!important;-ms-hyphens:var(--USER__bodyHyphens)!important;-epub-hyphens:var(--USER__bodyHyphens)!important;hyphens:var(--USER__bodyHyphens)!important}:root[style*=readium-advanced-on][style*="--USER__bodyHyphens"] body,:root[style*=readium-advanced-on][style*="--USER__bodyHyphens"] dd,:root[style*=readium-advanced-on][style*="--USER__bodyHyphens"] div,:root[style*=readium-advanced-on][style*="--USER__bodyHyphens"] li,:root[style*=readium-advanced-on][style*="--USER__bodyHyphens"] p{-webkit-hyphens:inherit;-moz-hyphens:inherit;-ms-hyphens:inherit;-epub-hyphens:inherit;hyphens:inherit}:root[style*=readium-font-on][style*="--USER__fontFamily"]{font-family:var(--USER__fontFamily)!important}:root[style*=readium-font-on][style*="--USER__fontFamily"] body,:root[style*=readium-font-on][style*="--USER__fontFamily"] dd,:root[style*=readium-font-on][style*="--USER__fontFamily"] div,:root[style*=readium-font-on][style*="--USER__fontFamily"] dt,:root[style*=readium-font-on][style*="--USER__fontFamily"] li,:root[style*=readium-font-on][style*="--USER__fontFamily"] p{font-family:inherit!important}:root[style*=readium-font-on][style*="--USER__fontFamily"] b:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] b:not([xml\:lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] cite:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] cite:not([xml\:lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] em:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] em:not([xml\:lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] i:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] i:not([xml\:lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] span:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] span:not([xml\:lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] strong:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] strong:not([xml\:lang]){font-family:inherit!important}:root[style*=readium-font-on][style*=AccessibleDfA]{font-family:AccessibleDfA,Verdana,Tahoma,"Trebuchet MS",sans-serif!important;--RS__lineHeightCompensation:1.167}:root[style*=readium-font-on][style*="IA Writer Duospace"]{font-family:"IA Writer Duospace",Menlo,"DejaVu Sans Mono","Bitstream Vera Sans Mono",Courier,monospace!important;--RS__lineHeightCompensation:1.167}:root[style*=readium-font-on][style*=readium-a11y-on]{font-family:var(--USER__fontFamily)!important;--RS__lineHeightCompensation:1.167}:root[style*=readium-font-on][style*="IA Writer Duospace"],:root[style*=readium-font-on][style*=AccessibleDfA],:root[style*=readium-font-on][style*=readium-a11y-on]{font-style:normal!important;font-weight:400!important}:root[style*=readium-font-on][style*="IA Writer Duospace"] :not(code):not(var):not(kbd):not(samp),:root[style*=readium-font-on][style*=AccessibleDfA] :not(code):not(var):not(kbd):not(samp),:root[style*=readium-font-on][style*=readium-a11y-on] :not(code):not(var):not(kbd):not(samp){font-family:inherit!important;font-style:inherit!important;font-weight:inherit!important}:root[style*=readium-font-on][style*="IA Writer Duospace"] *,:root[style*=readium-font-on][style*=AccessibleDfA] *,:root[style*=readium-font-on][style*=readium-a11y-on] *{text-decoration:none!important;font-variant-caps:normal!important;font-variant-numeric:normal!important;font-variant-position:normal!important}:root[style*=readium-font-on][style*="IA Writer Duospace"] sub,:root[style*=readium-font-on][style*="IA Writer Duospace"] sup,:root[style*=readium-font-on][style*=AccessibleDfA] sub,:root[style*=readium-font-on][style*=AccessibleDfA] sup,:root[style*=readium-font-on][style*=readium-a11y-on] sub,:root[style*=readium-font-on][style*=readium-a11y-on] sup{font-size:1rem!important;vertical-align:baseline!important}:root[style*="--USER__fontSize"]{font-size:var(--USER__fontSize)!important}:root[style*=readium-advanced-on][style*="--USER__lineHeight"]{line-height:var(--USER__lineHeight)!important}:root[style*=readium-advanced-on][style*="--USER__lineHeight"] body,:root[style*=readium-advanced-on][style*="--USER__lineHeight"] div,:root[style*=readium-advanced-on][style*="--USER__lineHeight"] li,:root[style*=readium-advanced-on][style*="--USER__lineHeight"] p{line-height:inherit}:root[style*=readium-advanced-on][style*="--USER__paraSpacing"] p{margin-top:var(--USER__paraSpacing)!important;margin-bottom:var(--USER__paraSpacing)!important}:root[style*=readium-advanced-on][style*="--USER__paraIndent"] p{text-indent:var(--USER__paraIndent)!important}:root[style*=readium-advanced-on][style*="--USER__paraIndent"] p *,:root[style*=readium-advanced-on][style*="--USER__paraIndent"] p:first-letter{text-indent:0!important}:root[style*=readium-advanced-on][style*="--USER__wordSpacing"] div,:root[style*=readium-advanced-on][style*="--USER__wordSpacing"] h1,:root[style*=readium-advanced-on][style*="--USER__wordSpacing"] h2,:root[style*=readium-advanced-on][style*="--USER__wordSpacing"] h3,:root[style*=readium-advanced-on][style*="--USER__wordSpacing"] h4,:root[style*=readium-advanced-on][style*="--USER__wordSpacing"] h5,:root[style*=readium-advanced-on][style*="--USER__wordSpacing"] h6,:root[style*=readium-advanced-on][style*="--USER__wordSpacing"] li,:root[style*=readium-advanced-on][style*="--USER__wordSpacing"] p{word-spacing:var(--USER__wordSpacing)}:root[style*=readium-advanced-on][style*="--USER__letterSpacing"] div,:root[style*=readium-advanced-on][style*="--USER__letterSpacing"] h1,:root[style*=readium-advanced-on][style*="--USER__letterSpacing"] h2,:root[style*=readium-advanced-on][style*="--USER__letterSpacing"] h3,:root[style*=readium-advanced-on][style*="--USER__letterSpacing"] h4,:root[style*=readium-advanced-on][style*="--USER__letterSpacing"] h5,:root[style*=readium-advanced-on][style*="--USER__letterSpacing"] h6,:root[style*=readium-advanced-on][style*="--USER__letterSpacing"] li,:root[style*=readium-advanced-on][style*="--USER__letterSpacing"] p{letter-spacing:var(--USER__letterSpacing);font-variant:none}:root[style*=readium-advanced-on]{--USER__typeScale:1.2}:root[style*=readium-advanced-on] dd,:root[style*=readium-advanced-on] div,:root[style*=readium-advanced-on] li,:root[style*=readium-advanced-on] p,:root[style*=readium-advanced-on] pre{font-size:1rem!important}:root[style*=readium-advanced-on] h1{font-size:1.75rem!important;font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale))!important}:root[style*=readium-advanced-on] h2{font-size:1.5rem!important;font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale))!important}:root[style*=readium-advanced-on] h3{font-size:1.25rem!important;font-size:calc(1rem * var(--USER__typeScale))!important}:root[style*=readium-advanced-on] h4,:root[style*=readium-advanced-on] h5,:root[style*=readium-advanced-on] h6{font-size:1rem!important}:root[style*=readium-advanced-on] small{font-size:smaller!important}:root[style*=readium-advanced-on] sub,:root[style*=readium-advanced-on] sup{font-size:67.5%!important}:root[style*=readium-advanced-on][style*="--USER__typeScale"] h1{font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale))!important}:root[style*=readium-advanced-on][style*="--USER__typeScale"] h2{font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale))!important}:root[style*=readium-advanced-on][style*="--USER__typeScale"] h3{font-size:calc(1rem * var(--USER__typeScale))!important} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadiumCSS-before.css b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadiumCSS-before.css deleted file mode 100644 index 3a224ba632..0000000000 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadiumCSS-before.css +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Readium CSS (v. 1.0.0-beta.3) - * Developers: Jiminy Panoz - * Copyright (c) 2017. Readium Foundation. All rights reserved. - * Use of this source code is governed by a BSD-style license which is detailed in the - * LICENSE file present in the project repository where this source code is maintained. -*/@namespace url("http://www.w3.org/1999/xhtml");@namespace epub url("http://www.idpf.org/2007/ops");@namespace m url("http://www.w3.org/1998/Math/MathML/");@namespace svg url("http://www.w3.org/2000/svg");@-ms-viewport{width:device-width}@viewport{width:device-width;zoom:1}:root{--RS__oldStyleTf:"Iowan Old Style","Sitka Text",Palatino,"Book Antiqua",serif;--RS__modernTf:Athelas,Constantia,Georgia,serif;--RS__sansTf:-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;--RS__humanistTf:Seravek,Calibri,Roboto,Arial,sans-serif;--RS__monospaceTf:"Andale Mono",Consolas,monospace;--RS__baseFontFamily:var(--RS__oldStyleTf);--RS__lineHeightCompensation:1;--RS__baseLineHeight:calc((1em + (2ex - 1ch) - ((1rem - 16px) * 0.1667)) * var(--RS__lineHeightCompensation))}html{font-family:var(--RS__baseFontFamily);line-height:1.6;line-height:var(--RS__baseLineHeight);text-rendering:optimizeLegibility}h1,h2,h3{line-height:normal}:lang(ja),:lang(ko),:lang(zh){word-wrap:break-word;-webkit-line-break:strict;-epub-line-break:strict;line-break:strict}math{font-family:"Latin Modern Math","STIX Two Math","XITS Math","STIX Math","Libertinus Math","TeX Gyre Termes Math","TeX Gyre Bonum Math","TeX Gyre Schola","DejaVu Math TeX Gyre","TeX Gyre Pagella Math","Asana Math","Cambria Math","Lucida Bright Math","Minion Math",STIXGeneral,STIXSizeOneSym,Symbol,"Times New Roman",serif}:lang(am){--RS__baseFontFamily:Kefa,Nyala,Roboto,Noto,"Noto Sans Ethiopic",serif;--RS__lineHeightCompensation:1.167}:lang(ar){--RS__baseFontFamily:"Geeza Pro","Arabic Typesetting",Roboto,Noto,"Noto Naskh Arabic","Times New Roman",serif}:lang(bn){--RS__baseFontFamily:"Kohinoor Bangla","Bangla Sangam MN",Vrinda,Roboto,Noto,"Noto Sans Bengali",sans-serif;--RS__lineHeightCompensation:1.067}:lang(bo){--RS__baseFontFamily:Kailasa,"Microsoft Himalaya",Roboto,Noto,"Noto Sans Tibetan",sans-serif}:lang(chr){--RS__baseFontFamily:"Plantagenet Cherokee",Roboto,Noto,"Noto Sans Cherokee";--RS__lineHeightCompensation:1.167}:lang(fa){--RS__baseFontFamily:"Geeza Pro","Arabic Typesetting",Roboto,Noto,"Noto Naskh Arabic","Times New Roman",serif}:lang(gu){--RS__baseFontFamily:"Gujarati Sangam MN","Nirmala UI",Shruti,Roboto,Noto,"Noto Sans Gujarati",sans-serif;--RS__lineHeightCompensation:1.167}:lang(he){--RS__baseFontFamily:"New Peninim MT","Arial Hebrew",Gisha,"Times New Roman",Roboto,Noto,"Noto Sans Hebrew" sans-serif;--RS__lineHeightCompensation:1.1}:lang(hi){--RS__baseFontFamily:"Kohinoor Devanagari","Devanagari Sangam MN",Kokila,"Nirmala UI",Roboto,Noto,"Noto Sans Devanagari",sans-serif;--RS__lineHeightCompensation:1.1}:lang(hy){--RS__baseFontFamily:Mshtakan,Sylfaen,Roboto,Noto,"Noto Serif Armenian",serif}:lang(iu){--RS__baseFontFamily:"Euphemia UCAS",Euphemia,Roboto,Noto,"Noto Sans Canadian Aboriginal",sans-serif}:lang(ja){--RS__baseFontFamily:"游ゴシック体",YuGothic,"ヒラギノ丸ゴ","Hiragino Sans","Yu Gothic UI","Meiryo UI","MS Gothic",Roboto,Noto,"Noto Sans CJK JP",sans-serif;--RS__lineHeightCompensation:1.167;--RS__serif-ja:"MS P明朝","MS PMincho","Hiragino Mincho Pro","ヒラギノ明朝 Pro W3","游明朝","YuMincho","MS 明朝","MS Mincho","Hiragino Mincho ProN",serif;--RS__sans-serif-ja:"MS Pゴシック","MS PGothic","Hiragino Kaku Gothic Pro W3","ヒラギノ角ゴ Pro W3","Hiragino Sans GB","ヒラギノ角ゴシック W3","游ゴシック","YuGothic","MS ゴシック","MS Gothic","Hiragino Sans",sans-serif;--RS__serif-ja-v:"MS 明朝","MS Mincho","Hiragino Mincho Pro","ヒラギノ明朝 Pro W3","游明朝","YuMincho","MS P明朝","MS PMincho","Hiragino Mincho ProN",serif;--RS__sans-serif-ja-v:"MS ゴシック","MS Gothic","Hiragino Kaku Gothic Pro W3","ヒラギノ角ゴ Pro W3","Hiragino Sans GB","ヒラギノ角ゴシック W3","游ゴシック","YuGothic","MS Pゴシック","MS PGothic","Hiragino Sans",sans-serif}:lang(km){--RS__baseFontFamily:"Khmer Sangam MN","Leelawadee UI","Khmer UI",Roboto,Noto,"Noto Sans Khmer",sans-serif;--RS__lineHeightCompensation:1.067}:lang(kn){--RS__baseFontFamily:"Kannada Sangam MN","Nirmala UI",Tunga,Roboto,Noto,"Noto Sans Kannada",sans-serif;--RS__lineHeightCompensation:1.1}:lang(ko){--RS__baseFontFamily:"Nanum Gothic","Apple SD Gothic Neo","Malgun Gothic",Roboto,Noto,"Noto Sans CJK KR",sans-serif;--RS__lineHeightCompensation:1.167}:lang(lo){--RS__baseFontFamily:"Lao Sangam MN","Leelawadee UI","Lao UI",Roboto,Noto,"Noto Sans Lao",sans-serif}:lang(ml){--RS__baseFontFamily:"Malayalam Sangam MN","Nirmala UI",Kartika,Roboto,Noto,"Noto Sans Malayalam",sans-serif;--RS__lineHeightCompensation:1.067}:lang(or){--RS__baseFontFamily:"Oriya Sangam MN","Nirmala UI",Kalinga,Roboto,Noto,"Noto Sans Oriya",sans-serif;--RS__lineHeightCompensation:1.167}:lang(pa){--RS__baseFontFamily:"Gurmukhi MN","Nirmala UI",Kartika,Roboto,Noto,"Noto Sans Gurmukhi",sans-serif;--RS__lineHeightCompensation:1.1}:lang(si){--RS__baseFontFamily:"Sinhala Sangam MN","Nirmala UI","Iskoola Pota",Roboto,Noto,"Noto Sans Sinhala",sans-serif;--RS__lineHeightCompensation:1.167}:lang(ta){--RS__baseFontFamily:"Tamil Sangam MN","Nirmala UI",Latha,Roboto,Noto,"Noto Sans Tamil",sans-serif;--RS__lineHeightCompensation:1.067}:lang(te){--RS__baseFontFamily:"Kohinoor Telugu","Telugu Sangam MN","Nirmala UI",Gautami,Roboto,Noto,"Noto Sans Telugu",sans-serif}:lang(th){--RS__baseFontFamily:"Thonburi","Leelawadee UI","Cordia New",Roboto,Noto,"Noto Sans Thai",sans-serif;--RS__lineHeightCompensation:1.067}:lang(zh){--RS__baseFontFamily:"方体","PingFang SC","黑体","Heiti SC","Microsoft JhengHei UI","Microsoft JhengHei",Roboto,Noto,"Noto Sans CJK SC",sans-serif;--RS__lineHeightCompensation:1.167}:lang(zh-Hant),:lang(zh-TW){--RS__baseFontFamily:"方體","PingFang TC","黑體","Heiti TC","Microsoft JhengHei UI","Microsoft JhengHei",Roboto,Noto,"Noto Sans CJK TC",sans-serif;--RS__lineHeightCompensation:1.167}:lang(zh-HK){--RS__baseFontFamily:"方體","PingFang HK","方體","PingFang TC","黑體","Heiti TC","Microsoft JhengHei UI","Microsoft JhengHei",Roboto,Noto,"Noto Sans CJK TC",sans-serif;--RS__lineHeightCompensation:1.167}:root{--RS__backgroundColor:#FFFFFF;--RS__textColor:#121212;--RS__selectionBackgroundColor:#b4d8fe;--RS__selectionTextColor:inherit}:root{color:var(--RS__textColor)!important;background-color:var(--RS__backgroundColor)!important}::-moz-selection{color:var(--RS__selectionTextColor);background-color:var(--RS__selectionBackgroundColor)}::selection{color:var(--RS__selectionTextColor);background-color:var(--RS__selectionBackgroundColor)}@font-face{font-family:AccessibleDfA;font-style:normal;font-weight:400;src:local("AccessibleDfA"),url(fonts/AccessibleDfA.otf) format("opentype")}@font-face{font-family:"IA Writer Duospace";font-style:normal;font-weight:400;src:local("iAWriterDuospace-Regular"),url(fonts/iAWriterDuospace-Regular.ttf) format("truetype")}body{widows:2;orphans:2}figcaption,td,th{widows:1;orphans:1}caption,dt,h2,h3,h4,h5,h6,hr{-webkit-column-break-after:avoid;page-break-after:avoid;break-after:avoid}dt,figure,h1,h2,h3,h4,h5,h6,tr{-webkit-column-break-inside:avoid;page-break-inside:avoid;break-inside:avoid}body{-webkit-hyphenate-character:"\002D";-moz-hyphenate-character:"\002D";-ms-hyphenate-character:"\002D";hyphenate-character:"\002D";-webkit-hyphenate-limit-lines:3;-ms-hyphenate-limit-lines:3;hyphenate-limit-lines:3}address,caption,center,code,dt,figcaption,h1,h2,h3,h4,h5,h6,pre,var{-ms-hyphens:none;-moz-hyphens:none;-webkit-hyphens:none;-epub-hyphens:none;hyphens:none}body{font-variant-numeric:oldstyle-nums proportional-nums}:lang(ja) body,:lang(ko) body,:lang(zh) body{font-variant-numeric:lining-nums proportional-nums}dt,h1,h2,h3,h4,h5,h6{font-variant-numeric:lining-nums proportional-nums}table{font-variant-numeric:lining-nums tabular-nums}code,var{font-variant-ligatures:none;font-variant-numeric:lining-nums tabular-nums slashed-zero}rt{font-variant-east-asian:ruby}:lang(ar){font-variant-ligatures:common-ligatures}:lang(ko){font-kerning:normal}hr{color:inherit;border-color:currentColor}table,td,th{border-color:currentColor}blockquote,figure{margin:1em 5%}ol,ul{padding-left:5%}dd{margin-left:5%}pre{white-space:pre-wrap;-ms-tab-size:2;-moz-tab-size:2;-webkit-tab-size:2;tab-size:2}abbr[title],acronym[title]{text-decoration:dotted underline}nobr wbr{white-space:normal}ruby>rp,ruby>rt{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}:lang(ja),:lang(ja) cite,:lang(ja) dfn,:lang(ja) em,:lang(ja) i,:lang(ko),:lang(ko) cite,:lang(ko) dfn,:lang(ko) em,:lang(ko) i,:lang(zh),:lang(zh) cite,:lang(zh) dfn,:lang(zh) em,:lang(zh) i{font-style:normal}:lang(ja) a,:lang(ko) a,:lang(zh) a{text-decoration:none}:root{--RS__maxMediaWidth:100%;--RS__maxMediaHeight:95vh;--RS__boxSizingMedia:border-box;--RS__boxSizingTable:border-box}html{-webkit-line-box-contain:block glyphs replaced}:lang(ja){-webkit-line-box-contain:block inline replaced}a,h1,h2,h3,h4,h5,h6{word-wrap:break-word}div{max-width:var(--RS__maxMediaWidth)}audio,img,svg,video{object-fit:contain;width:auto;height:auto;max-width:var(--RS__maxMediaWidth);max-height:var(--RS__maxMediaHeight)!important;box-sizing:var(--RS__boxSizingMedia);-webkit-column-break-inside:avoid;page-break-inside:avoid;break-inside:avoid}table{max-width:var(--RS__maxMediaWidth);box-sizing:var(--RS__boxSizingTable)} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadiumCSS-default.css b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadiumCSS-default.css deleted file mode 100644 index b19b562c86..0000000000 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadiumCSS-default.css +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Readium CSS (v. 1.0.0-beta.3) - * Developers: Jiminy Panoz - * Copyright (c) 2017. Readium Foundation. All rights reserved. - * Use of this source code is governed by a BSD-style license which is detailed in the - * LICENSE file present in the project repository where this source code is maintained. -*/@namespace url("http://www.w3.org/1999/xhtml");@namespace epub url("http://www.idpf.org/2007/ops");@namespace m url("http://www.w3.org/1998/Math/MathML/");@namespace svg url("http://www.w3.org/2000/svg");:root{--RS__compFontFamily:var(--RS__baseFontFamily);--RS__codeFontFamily:var(--RS__monospaceTf);--RS__typeScale:1.125;--RS__baseFontSize:100%;--RS__flowSpacing:1.5rem;--RS__paraSpacing:0;--RS__paraIndent:1em;--RS__linkColor:#0000EE;--RS__visitedColor:#551A8B}body{font-size:var(--RS__baseFontSize)}h1,h2,h3,h4,h5,h6{font-family:var(--RS__compFontFamily)}aside,blockquote,figure,footer,form,hr,p,pre{margin-top:var(--RS__flowSpacing);margin-bottom:var(--RS__flowSpacing)}p{margin-top:var(--RS__paraSpacing);margin-bottom:var(--RS__paraSpacing);text-indent:var(--RS__paraIndent)}h1+p,h2+p,h3+p,h4+p,h5+p,h6+p,hr+p{text-indent:0}pre{font-family:var(--RS__codeFontFamily)}code,kbd,samp,tt{font-family:var(--RS__codeFontFamily)}sub,sup{position:relative;font-size:67.5%;line-height:1}sub{bottom:-.2ex}sup{bottom:0}:link{color:var(--RS__linkColor)}:visited{color:var(--RS__visitedColor)}h1{margin-top:calc(var(--RS__flowSpacing) * 2);margin-bottom:calc(var(--RS__flowSpacing) * 2);font-size:calc(((1em * var(--RS__typeScale)) * var(--RS__typeScale)) * var(--RS__typeScale))}h2{margin-top:calc(var(--RS__flowSpacing) * 2);margin-bottom:var(--RS__flowSpacing);font-size:calc((1em * var(--RS__typeScale)) * var(--RS__typeScale))}h3{margin-top:var(--RS__flowSpacing);margin-bottom:var(--RS__flowSpacing);font-size:calc(1em * var(--RS__typeScale))}h4{margin-top:var(--RS__flowSpacing);margin-bottom:var(--RS__flowSpacing);font-size:1em}h5{margin-top:var(--RS__flowSpacing);margin-bottom:var(--RS__flowSpacing);font-size:1em;font-variant:small-caps}h6{margin-top:var(--RS__flowSpacing);margin-bottom:0;font-size:1em;text-transform:lowercase;font-variant:small-caps}dl,ol,ul{margin-top:var(--RS__flowSpacing);margin-bottom:var(--RS__flowSpacing)}table{margin:var(--RS__flowSpacing) 0;border:1px solid currentColor;border-collapse:collapse;empty-cells:show}table>tr,tbody,tfoot,thead{vertical-align:top}th{text-align:left}td,th{padding:4px;border:1px solid currentColor} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadiumCSS-ebpaj_fonts_patch.css b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadiumCSS-ebpaj_fonts_patch.css deleted file mode 100644 index b73eb6744f..0000000000 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/ReadiumCSS-ebpaj_fonts_patch.css +++ /dev/null @@ -1,80 +0,0 @@ -/* Readium CSS - EBPAJ Fonts Patch module - - A stylesheet improving EBPAJ @font-face declarations to cover all platforms - - Repo: https://github.com/readium/readium-css */ - -/* EBPAJ template only references fonts from MS Windows… - so we must reference fonts from other platforms - and override authors’ stylesheets. - What we do there is keeping their default value and providing fallbacks. - - /!\ /!\ /!\ /!\ /!\ - FYI, you might want to load this polyfill only if you find - one of the following metadata items in the OPF package: - - version 1: - ebpaj-guide-1.0 - - version 1.1: - 1.1 - */ - -/* 横組み用 (horizontal writing) */ - -@font-face { - font-family: "serif-ja"; - src: local("MS P明朝"), - local("MS PMincho"), - local("Hiragino Mincho Pro"), - local("ヒラギノ明朝 Pro W3"), - local("游明朝"), - local("YuMincho"), - local("MS 明朝"), - local("MS Mincho"), - local("Hiragino Mincho ProN"); -} - -@font-face { - font-family: "sans-serif-ja"; - src: local("MS Pゴシック"), - local("MS PGothic"), - local("Hiragino Kaku Gothic Pro W3"), - local("ヒラギノ角ゴ Pro W3"), - local("Hiragino Sans GB"), - local("ヒラギノ角ゴシック W3"), - local("游ゴシック"), - local("YuGothic"), - local("MS ゴシック"), - local("MS Gothic"), - local("Hiragino Sans"); -} - -/* 縦組み用 (vertical writing) */ - -@font-face { - font-family: "serif-ja-v"; - src: local("MS 明朝"), - local("MS Mincho"), - local("Hiragino Mincho Pro"), - local("ヒラギノ明朝 Pro W3"), - local("游明朝"), - local("YuMincho"), - local("MS P明朝"), - local("MS PMincho"), - local("Hiragino Mincho ProN"); -} - -@font-face { - font-family: "sans-serif-ja-v"; - src: local("MS ゴシック"), - local("MS Gothic"), - local("Hiragino Kaku Gothic Pro W3"), - local("ヒラギノ角ゴ Pro W3"), - local("Hiragino Sans GB"), - local("ヒラギノ角ゴシック W3"), - local("游ゴシック"), - local("YuGothic"), - local("MS Pゴシック"), - local("MS PGothic"), - local("Hiragino Sans"); -} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-horizontal/ReadiumCSS-after.css b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-horizontal/ReadiumCSS-after.css deleted file mode 100644 index fa397b4146..0000000000 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-horizontal/ReadiumCSS-after.css +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Readium CSS (v. 1.0.0-beta.3) - * Developers: Jiminy Panoz - * Copyright (c) 2017. Readium Foundation. All rights reserved. - * Use of this source code is governed by a BSD-style license which is detailed in the - * LICENSE file present in the project repository where this source code is maintained. -*/@namespace url("http://www.w3.org/1999/xhtml");@namespace epub url("http://www.idpf.org/2007/ops");@namespace m url("http://www.w3.org/1998/Math/MathML/");@namespace svg url("http://www.w3.org/2000/svg");:root{--RS__colWidth:45em;--RS__colCount:1;--RS__colGap:0;--RS__maxLineLength:40rem;--RS__pageGutter:20px;--RS__viewportWidth:100%}@page{margin:0!important}:root{position:relative;-webkit-column-width:var(--RS__colWidth);-moz-column-width:var(--RS__colWidth);column-width:var(--RS__colWidth);-webkit-column-count:var(--RS__colCount);-moz-column-count:var(--RS__colCount);column-count:var(--RS__colCount);-webkit-column-gap:var(--RS__colGap);-moz-column-gap:var(--RS__colGap);column-gap:var(--RS__colGap);-moz-column-fill:auto;column-fill:auto;width:var(--RS__viewportWidth);height:100vh;max-width:var(--RS__viewportWidth);max-height:100vh;min-width:var(--RS__viewportWidth);min-height:100vh;padding:0!important;margin:0!important;font-size:100%!important;-webkit-text-size-adjust:100%;box-sizing:border-box;-webkit-perspective:1;-webkit-touch-callout:none}body{width:100%;max-width:var(--RS__maxLineLength)!important;padding:0 var(--RS__pageGutter)!important;margin:0 auto!important;box-sizing:border-box}@media screen and (min-width:35em){:root{--RS__pageGutter:30px}}@media screen and (min-width:45em){:root{--RS__pageGutter:40px}}@media screen and (min-width:75em){:root{--RS__pageGutter:50px}}@media screen and (min-width:60em),screen and (min-device-width:36em) and (max-device-width:47em) and (orientation:landscape){:root{--RS__colWidth:20em;--RS__colCount:2;--RS__maxLineLength:39.99rem}}:root[style*=readium-scroll-on]{-webkit-columns:auto auto!important;-moz-columns:auto auto!important;columns:auto auto!important;width:auto!important;height:auto!important;max-width:none!important;max-height:none!important;min-width:0!important;min-height:0!important}:root[style*=readium-scroll-on] body{--RS__maxLineLength:40rem!important}:root[style*=readium-night-on]{--RS__backgroundColor:#000000;--RS__textColor:#FEFEFE;--RS__linkColor:#63caff;--RS__visitedColor:#0099E5;--RS__selectionBackgroundColor:#b4d8fe;--RS__selectionTextColor:inherit}:root[style*=readium-night-on] :not(a){color:inherit!important;background-color:transparent!important;border-color:currentColor!important}:root[style*=readium-night-on] svg text{fill:currentColor!important;stroke:none!important}:root[style*=readium-night-on] a:link,:root[style*=readium-night-on] a:link *{color:var(--RS__linkColor)!important}:root[style*=readium-night-on] a:visited,:root[style*=readium-night-on] a:visited *{color:var(--RS__visitedColor)!important}:root[style*=readium-night-on] [epub\:type~=titlepage] img:only-child,:root[style*=readium-night-on] [epub|type~=titlepage] img:only-child,:root[style*=readium-night-on] img[class*=gaiji]{-webkit-filter:invert(100%);filter:invert(100%)}:root[style*=readium-night-on][style*=readium-darken-on] img{-webkit-filter:brightness(80%);filter:brightness(80%)}:root[style*=readium-night-on][style*=readium-invert-on] img{-webkit-filter:invert(100%);filter:invert(100%)}:root[style*=readium-night-on][style*=readium-darken-on][style*=readium-invert-on] img{-webkit-filter:brightness(80%) invert(100%);filter:brightness(80%) invert(100%)}:root[style*=readium-sepia-on]{--RS__backgroundColor:#faf4e8;--RS__textColor:#121212;--RS__linkColor:#0000EE;--RS__visitedColor:#551A8B;--RS__selectionBackgroundColor:#b4d8fe;--RS__selectionTextColor:inherit;--RS__maxLineLength:40.01rem}:root[style*=readium-sepia-on] :not(a){color:inherit!important;background-color:transparent!important}:root[style*=readium-sepia-on] a:link,:root[style*=readium-sepia-on] a:link *{color:var(--RS__linkColor)}:root[style*=readium-sepia-on] a:visited,:root[style*=readium-sepia-on] a:visited *{color:var(--RS__visitedColor)}:root[style*=readium-sepia-on] img,:root[style*=readium-sepia-on] svg{background-color:transparent!important;mix-blend-mode:multiply}@media screen and (-ms-high-contrast:active){:root{color:windowText!important;background-color:window!important}:root :not(#\#):not(#\#):not(#\#),:root :not(#\#):not(#\#):not(#\#) :not(#\#):not(#\#):not(#\#) :root :not(#\#):not(#\#):not(#\#) :not(#\#):not(#\#):not(#\#) :not(#\#):not(#\#):not(#\#){color:inherit!important;background-color:inherit!important}.readiumCSS-mo-active-default{color:highlightText!important;background-color:highlight!important}}@media screen and (-ms-high-contrast:white-on-black){:root[style*=readium-night-on] [epub\:type~=titlepage] img:only-child,:root[style*=readium-night-on] [epub|type~=titlepage] img:only-child,:root[style*=readium-night-on] img[class*=gaiji]{-webkit-filter:none!important;filter:none!important}:root[style*=readium-night-on][style*=readium-invert-on] img{-webkit-filter:none!important;filter:none!important}:root[style*=readium-night-on][style*=readium-darken-on][style*=readium-invert-on] img{-webkit-filter:brightness(80%);filter:brightness(80%)}}@media screen and (inverted-colors){:root[style*=readium-night-on] [epub\:type~=titlepage] img:only-child,:root[style*=readium-night-on] [epub|type~=titlepage] img:only-child,:root[style*=readium-night-on] img[class*=gaiji]{-webkit-filter:none!important;filter:none!important}:root[style*=readium-night-on][style*=readium-invert-on] img{-webkit-filter:none!important;filter:none!important}:root[style*=readium-night-on][style*=readium-darken-on][style*=readium-invert-on] img{-webkit-filter:brightness(80%);filter:brightness(80%)}}@media screen and (min-width:60em),screen and (min-device-width:36em) and (max-device-width:47em) and (orientation:landscape){:root[style*="--USER__colCount: 1"],:root[style*="--USER__colCount: 2"],:root[style*="--USER__colCount:1"],:root[style*="--USER__colCount:2"]{-webkit-column-count:var(--USER__colCount);-moz-column-count:var(--USER__colCount);column-count:var(--USER__colCount)}:root[style*="--USER__colCount: 1"],:root[style*="--USER__colCount:1"]{--RS__maxLineLength:40rem!important;--RS__colWidth:100vw}:root[style*="--USER__colCount: 2"],:root[style*="--USER__colCount:2"]{--RS__colWidth:auto}}:root[style*="--USER__pageMargins"] body{padding:0 calc(var(--RS__pageGutter) * var(--USER__pageMargins))!important}:root[style*="--USER__backgroundColor"]{background-color:var(--USER__backgroundColor)!important}:root[style*="--USER__backgroundColor"] *{background-color:transparent!important}:root[style*="--USER__textColor"]{color:var(--USER__textColor)!important}:root[style*="--USER__textColor"] :not(h1):not(h2):not(h3):not(h4):not(h5):not(h6):not(pre){color:inherit!important}:root[style*=readium-font-on][style*="--USER__fontFamily"]{font-family:var(--USER__fontFamily)!important}:root[style*=readium-font-on][style*="--USER__fontFamily"] body,:root[style*=readium-font-on][style*="--USER__fontFamily"] dd,:root[style*=readium-font-on][style*="--USER__fontFamily"] div,:root[style*=readium-font-on][style*="--USER__fontFamily"] dt,:root[style*=readium-font-on][style*="--USER__fontFamily"] li,:root[style*=readium-font-on][style*="--USER__fontFamily"] p{font-family:inherit!important}:root[style*=readium-font-on][style*="--USER__fontFamily"] b:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] b:not([xml\:lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] cite:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] cite:not([xml\:lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] em:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] em:not([xml\:lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] i:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] i:not([xml\:lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] span:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] span:not([xml\:lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] strong:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] strong:not([xml\:lang]){font-family:inherit!important}:root[style*="--USER__fontSize"]{font-size:var(--USER__fontSize)!important}:root[style*=readium-advanced-on][style*="--USER__lineHeight"]{line-height:var(--USER__lineHeight)!important}:root[style*=readium-advanced-on][style*="--USER__lineHeight"] body,:root[style*=readium-advanced-on][style*="--USER__lineHeight"] div,:root[style*=readium-advanced-on][style*="--USER__lineHeight"] li,:root[style*=readium-advanced-on][style*="--USER__lineHeight"] p{line-height:inherit}:root[style*=readium-advanced-on][style*="--USER__paraSpacing"] p{margin-top:var(--USER__paraSpacing)!important;margin-bottom:var(--USER__paraSpacing)!important}:root[style*=readium-advanced-on]{--USER__typeScale:1.2}:root[style*=readium-advanced-on] dd,:root[style*=readium-advanced-on] div,:root[style*=readium-advanced-on] li,:root[style*=readium-advanced-on] p,:root[style*=readium-advanced-on] pre{font-size:1rem!important}:root[style*=readium-advanced-on] h1{font-size:1.75rem!important;font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale))!important}:root[style*=readium-advanced-on] h2{font-size:1.5rem!important;font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale))!important}:root[style*=readium-advanced-on] h3{font-size:1.25rem!important;font-size:calc(1rem * var(--USER__typeScale))!important}:root[style*=readium-advanced-on] h4,:root[style*=readium-advanced-on] h5,:root[style*=readium-advanced-on] h6{font-size:1rem!important}:root[style*=readium-advanced-on] small{font-size:smaller!important}:root[style*=readium-advanced-on] sub,:root[style*=readium-advanced-on] sup{font-size:67.5%!important}:root[style*=readium-advanced-on][style*="--USER__typeScale"] h1{font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale))!important}:root[style*=readium-advanced-on][style*="--USER__typeScale"] h2{font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale))!important}:root[style*=readium-advanced-on][style*="--USER__typeScale"] h3{font-size:calc(1rem * var(--USER__typeScale))!important} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-horizontal/ReadiumCSS-before.css b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-horizontal/ReadiumCSS-before.css deleted file mode 100644 index faee9a5bca..0000000000 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-horizontal/ReadiumCSS-before.css +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Readium CSS (v. 1.0.0-beta.3) - * Developers: Jiminy Panoz - * Copyright (c) 2017. Readium Foundation. All rights reserved. - * Use of this source code is governed by a BSD-style license which is detailed in the - * LICENSE file present in the project repository where this source code is maintained. -*/@namespace url("http://www.w3.org/1999/xhtml");@namespace epub url("http://www.idpf.org/2007/ops");@namespace m url("http://www.w3.org/1998/Math/MathML/");@namespace svg url("http://www.w3.org/2000/svg");@-ms-viewport{width:device-width}@viewport{width:device-width;zoom:1}:root{--RS__oldStyleTf:"Iowan Old Style","Sitka Text",Palatino,"Book Antiqua",serif;--RS__modernTf:Athelas,Constantia,Georgia,serif;--RS__sansTf:-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;--RS__humanistTf:Seravek,Calibri,Roboto,Arial,sans-serif;--RS__monospaceTf:"Andale Mono",Consolas,monospace;--RS__baseFontFamily:var(--RS__oldStyleTf);--RS__lineHeightCompensation:1;--RS__baseLineHeight:calc((1em + (2ex - 1ch) - ((1rem - 16px) * 0.1667)) * var(--RS__lineHeightCompensation))}html{font-family:var(--RS__baseFontFamily);line-height:1.6;line-height:var(--RS__baseLineHeight);text-rendering:optimizeLegibility}h1,h2,h3{line-height:normal}:lang(ja),:lang(ko),:lang(zh){word-wrap:break-word;-webkit-line-break:strict;-epub-line-break:strict;line-break:strict}math{font-family:"Latin Modern Math","STIX Two Math","XITS Math","STIX Math","Libertinus Math","TeX Gyre Termes Math","TeX Gyre Bonum Math","TeX Gyre Schola","DejaVu Math TeX Gyre","TeX Gyre Pagella Math","Asana Math","Cambria Math","Lucida Bright Math","Minion Math",STIXGeneral,STIXSizeOneSym,Symbol,"Times New Roman",serif}:lang(am){--RS__baseFontFamily:Kefa,Nyala,Roboto,Noto,"Noto Sans Ethiopic",serif;--RS__lineHeightCompensation:1.167}:lang(ar){--RS__baseFontFamily:"Geeza Pro","Arabic Typesetting",Roboto,Noto,"Noto Naskh Arabic","Times New Roman",serif}:lang(bn){--RS__baseFontFamily:"Kohinoor Bangla","Bangla Sangam MN",Vrinda,Roboto,Noto,"Noto Sans Bengali",sans-serif;--RS__lineHeightCompensation:1.067}:lang(bo){--RS__baseFontFamily:Kailasa,"Microsoft Himalaya",Roboto,Noto,"Noto Sans Tibetan",sans-serif}:lang(chr){--RS__baseFontFamily:"Plantagenet Cherokee",Roboto,Noto,"Noto Sans Cherokee";--RS__lineHeightCompensation:1.167}:lang(fa){--RS__baseFontFamily:"Geeza Pro","Arabic Typesetting",Roboto,Noto,"Noto Naskh Arabic","Times New Roman",serif}:lang(gu){--RS__baseFontFamily:"Gujarati Sangam MN","Nirmala UI",Shruti,Roboto,Noto,"Noto Sans Gujarati",sans-serif;--RS__lineHeightCompensation:1.167}:lang(he){--RS__baseFontFamily:"New Peninim MT","Arial Hebrew",Gisha,"Times New Roman",Roboto,Noto,"Noto Sans Hebrew" sans-serif;--RS__lineHeightCompensation:1.1}:lang(hi){--RS__baseFontFamily:"Kohinoor Devanagari","Devanagari Sangam MN",Kokila,"Nirmala UI",Roboto,Noto,"Noto Sans Devanagari",sans-serif;--RS__lineHeightCompensation:1.1}:lang(hy){--RS__baseFontFamily:Mshtakan,Sylfaen,Roboto,Noto,"Noto Serif Armenian",serif}:lang(iu){--RS__baseFontFamily:"Euphemia UCAS",Euphemia,Roboto,Noto,"Noto Sans Canadian Aboriginal",sans-serif}:lang(ja){--RS__baseFontFamily:"游ゴシック体",YuGothic,"ヒラギノ丸ゴ","Hiragino Sans","Yu Gothic UI","Meiryo UI","MS Gothic",Roboto,Noto,"Noto Sans CJK JP",sans-serif;--RS__lineHeightCompensation:1.167;--RS__serif-ja:"MS P明朝","MS PMincho","Hiragino Mincho Pro","ヒラギノ明朝 Pro W3","游明朝","YuMincho","MS 明朝","MS Mincho","Hiragino Mincho ProN",serif;--RS__sans-serif-ja:"MS Pゴシック","MS PGothic","Hiragino Kaku Gothic Pro W3","ヒラギノ角ゴ Pro W3","Hiragino Sans GB","ヒラギノ角ゴシック W3","游ゴシック","YuGothic","MS ゴシック","MS Gothic","Hiragino Sans",sans-serif;--RS__serif-ja-v:"MS 明朝","MS Mincho","Hiragino Mincho Pro","ヒラギノ明朝 Pro W3","游明朝","YuMincho","MS P明朝","MS PMincho","Hiragino Mincho ProN",serif;--RS__sans-serif-ja-v:"MS ゴシック","MS Gothic","Hiragino Kaku Gothic Pro W3","ヒラギノ角ゴ Pro W3","Hiragino Sans GB","ヒラギノ角ゴシック W3","游ゴシック","YuGothic","MS Pゴシック","MS PGothic","Hiragino Sans",sans-serif}:lang(km){--RS__baseFontFamily:"Khmer Sangam MN","Leelawadee UI","Khmer UI",Roboto,Noto,"Noto Sans Khmer",sans-serif;--RS__lineHeightCompensation:1.067}:lang(kn){--RS__baseFontFamily:"Kannada Sangam MN","Nirmala UI",Tunga,Roboto,Noto,"Noto Sans Kannada",sans-serif;--RS__lineHeightCompensation:1.1}:lang(ko){--RS__baseFontFamily:"Nanum Gothic","Apple SD Gothic Neo","Malgun Gothic",Roboto,Noto,"Noto Sans CJK KR",sans-serif;--RS__lineHeightCompensation:1.167}:lang(lo){--RS__baseFontFamily:"Lao Sangam MN","Leelawadee UI","Lao UI",Roboto,Noto,"Noto Sans Lao",sans-serif}:lang(ml){--RS__baseFontFamily:"Malayalam Sangam MN","Nirmala UI",Kartika,Roboto,Noto,"Noto Sans Malayalam",sans-serif;--RS__lineHeightCompensation:1.067}:lang(or){--RS__baseFontFamily:"Oriya Sangam MN","Nirmala UI",Kalinga,Roboto,Noto,"Noto Sans Oriya",sans-serif;--RS__lineHeightCompensation:1.167}:lang(pa){--RS__baseFontFamily:"Gurmukhi MN","Nirmala UI",Kartika,Roboto,Noto,"Noto Sans Gurmukhi",sans-serif;--RS__lineHeightCompensation:1.1}:lang(si){--RS__baseFontFamily:"Sinhala Sangam MN","Nirmala UI","Iskoola Pota",Roboto,Noto,"Noto Sans Sinhala",sans-serif;--RS__lineHeightCompensation:1.167}:lang(ta){--RS__baseFontFamily:"Tamil Sangam MN","Nirmala UI",Latha,Roboto,Noto,"Noto Sans Tamil",sans-serif;--RS__lineHeightCompensation:1.067}:lang(te){--RS__baseFontFamily:"Kohinoor Telugu","Telugu Sangam MN","Nirmala UI",Gautami,Roboto,Noto,"Noto Sans Telugu",sans-serif}:lang(th){--RS__baseFontFamily:"Thonburi","Leelawadee UI","Cordia New",Roboto,Noto,"Noto Sans Thai",sans-serif;--RS__lineHeightCompensation:1.067}:lang(zh){--RS__baseFontFamily:"方体","PingFang SC","黑体","Heiti SC","Microsoft JhengHei UI","Microsoft JhengHei",Roboto,Noto,"Noto Sans CJK SC",sans-serif;--RS__lineHeightCompensation:1.167}:lang(zh-Hant),:lang(zh-TW){--RS__baseFontFamily:"方體","PingFang TC","黑體","Heiti TC","Microsoft JhengHei UI","Microsoft JhengHei",Roboto,Noto,"Noto Sans CJK TC",sans-serif;--RS__lineHeightCompensation:1.167}:lang(zh-HK){--RS__baseFontFamily:"方體","PingFang HK","方體","PingFang TC","黑體","Heiti TC","Microsoft JhengHei UI","Microsoft JhengHei",Roboto,Noto,"Noto Sans CJK TC",sans-serif;--RS__lineHeightCompensation:1.167}:root{--RS__backgroundColor:#FFFFFF;--RS__textColor:#121212;--RS__selectionBackgroundColor:#b4d8fe;--RS__selectionTextColor:inherit}:root{color:var(--RS__textColor)!important;background-color:var(--RS__backgroundColor)!important}::-moz-selection{color:var(--RS__selectionTextColor);background-color:var(--RS__selectionBackgroundColor)}::selection{color:var(--RS__selectionTextColor);background-color:var(--RS__selectionBackgroundColor)}body{widows:2;orphans:2}figcaption,td,th{widows:1;orphans:1}caption,dt,h2,h3,h4,h5,h6,hr{-webkit-column-break-after:avoid;page-break-after:avoid;break-after:avoid}dt,figure,h1,h2,h3,h4,h5,h6,tr{-webkit-column-break-inside:avoid;page-break-inside:avoid;break-inside:avoid}body{-webkit-hyphenate-character:"\002D";-moz-hyphenate-character:"\002D";-ms-hyphenate-character:"\002D";hyphenate-character:"\002D";-webkit-hyphenate-limit-lines:3;-ms-hyphenate-limit-lines:3;hyphenate-limit-lines:3}address,caption,center,code,dt,figcaption,h1,h2,h3,h4,h5,h6,pre,var{-ms-hyphens:none;-moz-hyphens:none;-webkit-hyphens:none;-epub-hyphens:none;hyphens:none}body{font-variant-numeric:oldstyle-nums proportional-nums}:lang(ja) body,:lang(ko) body,:lang(zh) body{font-variant-numeric:lining-nums proportional-nums}dt,h1,h2,h3,h4,h5,h6{font-variant-numeric:lining-nums proportional-nums}table{font-variant-numeric:lining-nums tabular-nums}code,var{font-variant-ligatures:none;font-variant-numeric:lining-nums tabular-nums slashed-zero}rt{font-variant-east-asian:ruby}:lang(ar){font-variant-ligatures:common-ligatures}:lang(ko){font-kerning:normal}hr{color:inherit;border-color:currentColor}table,td,th{border-color:currentColor}blockquote,figure{margin:1em 5%}ol,ul{padding-left:5%}dd{margin-left:5%}pre{white-space:pre-wrap;-ms-tab-size:2;-moz-tab-size:2;-webkit-tab-size:2;tab-size:2}abbr[title],acronym[title]{text-decoration:dotted underline}nobr wbr{white-space:normal}ruby>rp,ruby>rt{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}:lang(ja),:lang(ja) cite,:lang(ja) dfn,:lang(ja) em,:lang(ja) i,:lang(ko),:lang(ko) cite,:lang(ko) dfn,:lang(ko) em,:lang(ko) i,:lang(zh),:lang(zh) cite,:lang(zh) dfn,:lang(zh) em,:lang(zh) i{font-style:normal}:lang(ja) a,:lang(ko) a,:lang(zh) a{text-decoration:none}:root{--RS__maxMediaWidth:100%;--RS__maxMediaHeight:95vh;--RS__boxSizingMedia:border-box;--RS__boxSizingTable:border-box}html{-webkit-line-box-contain:block glyphs replaced}:lang(ja){-webkit-line-box-contain:block inline replaced}a,h1,h2,h3,h4,h5,h6{word-wrap:break-word}div{max-width:var(--RS__maxMediaWidth)}audio,img,svg,video{object-fit:contain;width:auto;height:auto;max-width:var(--RS__maxMediaWidth);max-height:var(--RS__maxMediaHeight)!important;box-sizing:var(--RS__boxSizingMedia);-webkit-column-break-inside:avoid;page-break-inside:avoid;break-inside:avoid}table{max-width:var(--RS__maxMediaWidth);box-sizing:var(--RS__boxSizingTable)} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-horizontal/ReadiumCSS-default.css b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-horizontal/ReadiumCSS-default.css deleted file mode 100644 index e6984a4855..0000000000 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-horizontal/ReadiumCSS-default.css +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Readium CSS (v. 1.0.0-beta.3) - * Developers: Jiminy Panoz - * Copyright (c) 2017. Readium Foundation. All rights reserved. - * Use of this source code is governed by a BSD-style license which is detailed in the - * LICENSE file present in the project repository where this source code is maintained. -*/@namespace url("http://www.w3.org/1999/xhtml");@namespace epub url("http://www.idpf.org/2007/ops");@namespace m url("http://www.w3.org/1998/Math/MathML/");@namespace svg url("http://www.w3.org/2000/svg");:root{--RS__compFontFamily:var(--RS__baseFontFamily);--RS__codeFontFamily:var(--RS__monospaceTf);--RS__typeScale:1.125;--RS__baseFontSize:87.5%;--RS__flowSpacing:1.5rem;--RS__paraSpacing:0;--RS__paraIndent:1em;--RS__linkColor:#0000EE;--RS__visitedColor:#551A8B}:root:lang(zh){--RS__paraIndent:2em}:root{quotes:"\201c" "\201d" "\2018" "\2019"}body{font-size:var(--RS__baseFontSize);text-align:justify;text-justify:inter-character}h1,h2,h3,h4,h5,h6{font-family:var(--RS__baseFontFamily);text-align:left;text-align:start}aside,blockquote,figure,footer,form,hr,p,pre{margin-top:var(--RS__flowSpacing);margin-bottom:var(--RS__flowSpacing)}p{margin-top:var(--RS__paraSpacing);margin-bottom:var(--RS__paraSpacing);text-indent:var(--RS__paraIndent)}pre{font-family:var(--RS__codeFontFamily)}code,kbd,samp,tt{font-family:var(--RS__codeFontFamily)}sub,sup{position:relative;font-size:67.5%;line-height:1}sub{bottom:-.2ex}sup{bottom:0}em{-webkit-text-emphasis:dot;-epub-text-emphasis:dot;text-emphasis:dot}:link{color:var(--RS__linkColor)}:visited{color:var(--RS__visitedColor)}h1{margin-top:calc(var(--RS__flowSpacing) * 2);margin-bottom:calc(var(--RS__flowSpacing) * 2);font-size:calc(((1em * var(--RS__typeScale)) * var(--RS__typeScale)) * var(--RS__typeScale));text-align:center}h2{margin-top:calc(var(--RS__flowSpacing) * 2);margin-bottom:var(--RS__flowSpacing);font-size:calc((1em * var(--RS__typeScale)) * var(--RS__typeScale));text-align:center}h3{margin-top:var(--RS__flowSpacing);margin-bottom:var(--RS__flowSpacing);font-size:calc(1em * var(--RS__typeScale));text-align:center}h4{margin-top:var(--RS__flowSpacing);margin-bottom:var(--RS__flowSpacing);font-family:var(--RS__compFontFamily);font-size:1em}h5{margin-top:var(--RS__flowSpacing);margin-bottom:var(--RS__flowSpacing);font-family:var(--RS__compFontFamily);font-size:smaller}h6{margin-top:var(--RS__flowSpacing);margin-bottom:0;font-family:var(--RS__compFontFamily);font-size:smaller;font-weight:400}dl,ol,ul{margin-top:var(--RS__flowSpacing);margin-bottom:var(--RS__flowSpacing)}table{margin:var(--RS__flowSpacing) 0;border:1px solid currentColor;border-collapse:collapse;empty-cells:show}table>tr,tbody,tfoot,thead{vertical-align:top}th{text-align:left}td,th{padding:4px;border:1px solid currentColor} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-vertical/ReadiumCSS-after.css b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-vertical/ReadiumCSS-after.css deleted file mode 100644 index d68fd908be..0000000000 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-vertical/ReadiumCSS-after.css +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Readium CSS (v. 1.0.0-beta.3) - * Developers: Jiminy Panoz - * Copyright (c) 2017. Readium Foundation. All rights reserved. - * Use of this source code is governed by a BSD-style license which is detailed in the - * LICENSE file present in the project repository where this source code is maintained. -*/@namespace url("http://www.w3.org/1999/xhtml");@namespace epub url("http://www.idpf.org/2007/ops");@namespace m url("http://www.w3.org/1998/Math/MathML/");@namespace svg url("http://www.w3.org/2000/svg");:root{--RS__colWidth:100vh;--RS__colCount:1;--RS__colGap:0;--RS__maxLineLength:40rem;--RS__pageGutter:20px}@page{margin:0!important}:root{position:relative;-webkit-column-width:var(--RS__colWidth);-moz-column-width:var(--RS__colWidth);column-width:var(--RS__colWidth);-webkit-column-count:var(--RS__colCount);-moz-column-count:var(--RS__colCount);column-count:var(--RS__colCount);-webkit-column-gap:var(--RS__colGap);-moz-column-gap:var(--RS__colGap);column-gap:var(--RS__colGap);-moz-column-fill:auto;column-fill:auto;width:100%;height:100vh;max-width:100%;max-height:100vh;min-width:100%;min-height:100vh;padding:0 var(--RS__pageGutter)!important;margin:0!important;font-size:100%!important;-webkit-text-size-adjust:100%;box-sizing:border-box;hanging-punctuation:last allow-end;-webkit-perspective:1;-webkit-touch-callout:none;-ms-writing-mode:tb-rl;-webkit-writing-mode:vertical-rl;writing-mode:vertical-rl}:root:lang(mn-Mong){-ms-writing-mode:tb;-webkit-writing-mode:vertical-lr;writing-mode:vertical-lr}body{width:100%;max-height:var(--RS__maxLineLength)!important;padding:var(--RS__pageGutter) 0!important;margin:auto 0!important;box-sizing:border-box}@media screen and (min-width:35em){:root{--RS__pageGutter:30px}}@media screen and (min-width:45em){:root{--RS__pageGutter:40px}}@media screen and (min-width:60em){:root{--RS__pageGutter:50px}}@media screen and (min-width:75em){:root{--RS__pageGutter:60px}}:root[style*=readium-scroll-on]{-webkit-columns:auto auto!important;-moz-columns:auto auto!important;columns:auto auto!important;width:auto!important;max-width:none!important;max-height:100vh!important;min-width:0!important}:root[style*=readium-scroll-on] body{--RS__maxLineLength:40.01rem!important}:root[style*=readium-night-on]{--RS__backgroundColor:#000000;--RS__textColor:#FEFEFE;--RS__linkColor:#63caff;--RS__visitedColor:#0099E5;--RS__selectionBackgroundColor:#b4d8fe;--RS__selectionTextColor:inherit}:root[style*=readium-night-on] :not(a){color:inherit!important;background-color:transparent!important;border-color:currentColor!important}:root[style*=readium-night-on] svg text{fill:currentColor!important;stroke:none!important}:root[style*=readium-night-on] a:link,:root[style*=readium-night-on] a:link *{color:var(--RS__linkColor)!important}:root[style*=readium-night-on] a:visited,:root[style*=readium-night-on] a:visited *{color:var(--RS__visitedColor)!important}:root[style*=readium-night-on] [epub\:type~=titlepage] img:only-child,:root[style*=readium-night-on] [epub|type~=titlepage] img:only-child,:root[style*=readium-night-on] img[class*=gaiji]{-webkit-filter:invert(100%);filter:invert(100%)}:root[style*=readium-night-on][style*=readium-darken-on] img{-webkit-filter:brightness(80%);filter:brightness(80%)}:root[style*=readium-night-on][style*=readium-invert-on] img{-webkit-filter:invert(100%);filter:invert(100%)}:root[style*=readium-night-on][style*=readium-darken-on][style*=readium-invert-on] img{-webkit-filter:brightness(80%) invert(100%);filter:brightness(80%) invert(100%)}:root[style*=readium-sepia-on]{--RS__backgroundColor:#faf4e8;--RS__textColor:#121212;--RS__linkColor:#0000EE;--RS__visitedColor:#551A8B;--RS__selectionBackgroundColor:#b4d8fe;--RS__selectionTextColor:inherit;--RS__maxLineLength:40.01rem}:root[style*=readium-sepia-on] :not(a){color:inherit!important;background-color:transparent!important}:root[style*=readium-sepia-on] a:link,:root[style*=readium-sepia-on] a:link *{color:var(--RS__linkColor)}:root[style*=readium-sepia-on] a:visited,:root[style*=readium-sepia-on] a:visited *{color:var(--RS__visitedColor)}:root[style*=readium-sepia-on] img,:root[style*=readium-sepia-on] svg{background-color:transparent!important;mix-blend-mode:multiply}@media screen and (-ms-high-contrast:active){:root{color:windowText!important;background-color:window!important}:root :not(#\#):not(#\#):not(#\#),:root :not(#\#):not(#\#):not(#\#) :not(#\#):not(#\#):not(#\#) :root :not(#\#):not(#\#):not(#\#) :not(#\#):not(#\#):not(#\#) :not(#\#):not(#\#):not(#\#){color:inherit!important;background-color:inherit!important}.readiumCSS-mo-active-default{color:highlightText!important;background-color:highlight!important}}@media screen and (-ms-high-contrast:white-on-black){:root[style*=readium-night-on] [epub\:type~=titlepage] img:only-child,:root[style*=readium-night-on] [epub|type~=titlepage] img:only-child,:root[style*=readium-night-on] img[class*=gaiji]{-webkit-filter:none!important;filter:none!important}:root[style*=readium-night-on][style*=readium-invert-on] img{-webkit-filter:none!important;filter:none!important}:root[style*=readium-night-on][style*=readium-darken-on][style*=readium-invert-on] img{-webkit-filter:brightness(80%);filter:brightness(80%)}}@media screen and (inverted-colors){:root[style*=readium-night-on] [epub\:type~=titlepage] img:only-child,:root[style*=readium-night-on] [epub|type~=titlepage] img:only-child,:root[style*=readium-night-on] img[class*=gaiji]{-webkit-filter:none!important;filter:none!important}:root[style*=readium-night-on][style*=readium-invert-on] img{-webkit-filter:none!important;filter:none!important}:root[style*=readium-night-on][style*=readium-darken-on][style*=readium-invert-on] img{-webkit-filter:brightness(80%);filter:brightness(80%)}}:root[style*="--USER__pageMargins"] body{padding:calc(var(--RS__pageGutter) * var(--USER__pageMargins)) 0!important}:root[style*="--USER__backgroundColor"]{background-color:var(--USER__backgroundColor)!important}:root[style*="--USER__backgroundColor"] *{background-color:transparent!important}:root[style*="--USER__textColor"]{color:var(--USER__textColor)!important}:root[style*="--USER__textColor"] :not(h1):not(h2):not(h3):not(h4):not(h5):not(h6):not(pre){color:inherit!important}:root[style*=readium-font-on][style*="--USER__fontFamily"]{font-family:var(--USER__fontFamily)!important}:root[style*=readium-font-on][style*="--USER__fontFamily"] body,:root[style*=readium-font-on][style*="--USER__fontFamily"] dd,:root[style*=readium-font-on][style*="--USER__fontFamily"] div,:root[style*=readium-font-on][style*="--USER__fontFamily"] dt,:root[style*=readium-font-on][style*="--USER__fontFamily"] li,:root[style*=readium-font-on][style*="--USER__fontFamily"] p{font-family:inherit!important}:root[style*=readium-font-on][style*="--USER__fontFamily"] b:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] b:not([xml\:lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] cite:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] cite:not([xml\:lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] em:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] em:not([xml\:lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] i:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] i:not([xml\:lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] span:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] span:not([xml\:lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] strong:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] strong:not([xml\:lang]){font-family:inherit!important}:root[style*="--USER__fontSize"]{font-size:var(--USER__fontSize)!important}:root[style*=readium-advanced-on][style*="--USER__lineHeight"]{line-height:var(--USER__lineHeight)!important}:root[style*=readium-advanced-on][style*="--USER__lineHeight"] body,:root[style*=readium-advanced-on][style*="--USER__lineHeight"] div,:root[style*=readium-advanced-on][style*="--USER__lineHeight"] li,:root[style*=readium-advanced-on][style*="--USER__lineHeight"] p{line-height:inherit}:root[style*=readium-advanced-on][style*="--USER__paraSpacing"] p{margin-right:var(--USER__paraSpacing)!important;margin-left:var(--USER__paraSpacing)!important}:root[style*=readium-advanced-on]{--USER__typeScale:1.2}:root[style*=readium-advanced-on] dd,:root[style*=readium-advanced-on] div,:root[style*=readium-advanced-on] li,:root[style*=readium-advanced-on] p,:root[style*=readium-advanced-on] pre{font-size:1rem!important}:root[style*=readium-advanced-on] h1{font-size:1.75rem!important;font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale))!important}:root[style*=readium-advanced-on] h2{font-size:1.5rem!important;font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale))!important}:root[style*=readium-advanced-on] h3{font-size:1.25rem!important;font-size:calc(1rem * var(--USER__typeScale))!important}:root[style*=readium-advanced-on] h4,:root[style*=readium-advanced-on] h5,:root[style*=readium-advanced-on] h6{font-size:1rem!important}:root[style*=readium-advanced-on] small{font-size:smaller!important}:root[style*=readium-advanced-on] sub,:root[style*=readium-advanced-on] sup{font-size:67.5%!important}:root[style*=readium-advanced-on][style*="--USER__typeScale"] h1{font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale))!important}:root[style*=readium-advanced-on][style*="--USER__typeScale"] h2{font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale))!important}:root[style*=readium-advanced-on][style*="--USER__typeScale"] h3{font-size:calc(1rem * var(--USER__typeScale))!important} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-vertical/ReadiumCSS-before.css b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-vertical/ReadiumCSS-before.css deleted file mode 100644 index a57efed01a..0000000000 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-vertical/ReadiumCSS-before.css +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Readium CSS (v. 1.0.0-beta.3) - * Developers: Jiminy Panoz - * Copyright (c) 2017. Readium Foundation. All rights reserved. - * Use of this source code is governed by a BSD-style license which is detailed in the - * LICENSE file present in the project repository where this source code is maintained. -*/@namespace url("http://www.w3.org/1999/xhtml");@namespace epub url("http://www.idpf.org/2007/ops");@namespace m url("http://www.w3.org/1998/Math/MathML/");@namespace svg url("http://www.w3.org/2000/svg");@-ms-viewport{width:device-width}@viewport{width:device-width;zoom:1}:root{--RS__oldStyleTf:"Iowan Old Style","Sitka Text",Palatino,"Book Antiqua",serif;--RS__modernTf:Athelas,Constantia,Georgia,serif;--RS__sansTf:-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;--RS__humanistTf:Seravek,Calibri,Roboto,Arial,sans-serif;--RS__monospaceTf:"Andale Mono",Consolas,monospace;--RS__baseFontFamily:var(--RS__oldStyleTf);--RS__lineHeightCompensation:1;--RS__baseLineHeight:calc((1em + (2ex - 1ch) - ((1rem - 16px) * 0.1667)) * var(--RS__lineHeightCompensation))}html{font-family:var(--RS__baseFontFamily);line-height:1.6;line-height:var(--RS__baseLineHeight);text-rendering:optimizeLegibility}h1,h2,h3{line-height:normal}:lang(ja),:lang(ko),:lang(zh){word-wrap:break-word;-webkit-line-break:strict;-epub-line-break:strict;line-break:strict}math{font-family:"Latin Modern Math","STIX Two Math","XITS Math","STIX Math","Libertinus Math","TeX Gyre Termes Math","TeX Gyre Bonum Math","TeX Gyre Schola","DejaVu Math TeX Gyre","TeX Gyre Pagella Math","Asana Math","Cambria Math","Lucida Bright Math","Minion Math",STIXGeneral,STIXSizeOneSym,Symbol,"Times New Roman",serif}:lang(am){--RS__baseFontFamily:Kefa,Nyala,Roboto,Noto,"Noto Sans Ethiopic",serif;--RS__lineHeightCompensation:1.167}:lang(ar){--RS__baseFontFamily:"Geeza Pro","Arabic Typesetting",Roboto,Noto,"Noto Naskh Arabic","Times New Roman",serif}:lang(bn){--RS__baseFontFamily:"Kohinoor Bangla","Bangla Sangam MN",Vrinda,Roboto,Noto,"Noto Sans Bengali",sans-serif;--RS__lineHeightCompensation:1.067}:lang(bo){--RS__baseFontFamily:Kailasa,"Microsoft Himalaya",Roboto,Noto,"Noto Sans Tibetan",sans-serif}:lang(chr){--RS__baseFontFamily:"Plantagenet Cherokee",Roboto,Noto,"Noto Sans Cherokee";--RS__lineHeightCompensation:1.167}:lang(fa){--RS__baseFontFamily:"Geeza Pro","Arabic Typesetting",Roboto,Noto,"Noto Naskh Arabic","Times New Roman",serif}:lang(gu){--RS__baseFontFamily:"Gujarati Sangam MN","Nirmala UI",Shruti,Roboto,Noto,"Noto Sans Gujarati",sans-serif;--RS__lineHeightCompensation:1.167}:lang(he){--RS__baseFontFamily:"New Peninim MT","Arial Hebrew",Gisha,"Times New Roman",Roboto,Noto,"Noto Sans Hebrew" sans-serif;--RS__lineHeightCompensation:1.1}:lang(hi){--RS__baseFontFamily:"Kohinoor Devanagari","Devanagari Sangam MN",Kokila,"Nirmala UI",Roboto,Noto,"Noto Sans Devanagari",sans-serif;--RS__lineHeightCompensation:1.1}:lang(hy){--RS__baseFontFamily:Mshtakan,Sylfaen,Roboto,Noto,"Noto Serif Armenian",serif}:lang(iu){--RS__baseFontFamily:"Euphemia UCAS",Euphemia,Roboto,Noto,"Noto Sans Canadian Aboriginal",sans-serif}:lang(ja){--RS__baseFontFamily:"游ゴシック体",YuGothic,"ヒラギノ丸ゴ","Hiragino Sans","Yu Gothic UI","Meiryo UI","MS Gothic",Roboto,Noto,"Noto Sans CJK JP",sans-serif;--RS__lineHeightCompensation:1.167;--RS__serif-ja:"MS P明朝","MS PMincho","Hiragino Mincho Pro","ヒラギノ明朝 Pro W3","游明朝","YuMincho","MS 明朝","MS Mincho","Hiragino Mincho ProN",serif;--RS__sans-serif-ja:"MS Pゴシック","MS PGothic","Hiragino Kaku Gothic Pro W3","ヒラギノ角ゴ Pro W3","Hiragino Sans GB","ヒラギノ角ゴシック W3","游ゴシック","YuGothic","MS ゴシック","MS Gothic","Hiragino Sans",sans-serif;--RS__serif-ja-v:"MS 明朝","MS Mincho","Hiragino Mincho Pro","ヒラギノ明朝 Pro W3","游明朝","YuMincho","MS P明朝","MS PMincho","Hiragino Mincho ProN",serif;--RS__sans-serif-ja-v:"MS ゴシック","MS Gothic","Hiragino Kaku Gothic Pro W3","ヒラギノ角ゴ Pro W3","Hiragino Sans GB","ヒラギノ角ゴシック W3","游ゴシック","YuGothic","MS Pゴシック","MS PGothic","Hiragino Sans",sans-serif}:lang(km){--RS__baseFontFamily:"Khmer Sangam MN","Leelawadee UI","Khmer UI",Roboto,Noto,"Noto Sans Khmer",sans-serif;--RS__lineHeightCompensation:1.067}:lang(kn){--RS__baseFontFamily:"Kannada Sangam MN","Nirmala UI",Tunga,Roboto,Noto,"Noto Sans Kannada",sans-serif;--RS__lineHeightCompensation:1.1}:lang(ko){--RS__baseFontFamily:"Nanum Gothic","Apple SD Gothic Neo","Malgun Gothic",Roboto,Noto,"Noto Sans CJK KR",sans-serif;--RS__lineHeightCompensation:1.167}:lang(lo){--RS__baseFontFamily:"Lao Sangam MN","Leelawadee UI","Lao UI",Roboto,Noto,"Noto Sans Lao",sans-serif}:lang(ml){--RS__baseFontFamily:"Malayalam Sangam MN","Nirmala UI",Kartika,Roboto,Noto,"Noto Sans Malayalam",sans-serif;--RS__lineHeightCompensation:1.067}:lang(or){--RS__baseFontFamily:"Oriya Sangam MN","Nirmala UI",Kalinga,Roboto,Noto,"Noto Sans Oriya",sans-serif;--RS__lineHeightCompensation:1.167}:lang(pa){--RS__baseFontFamily:"Gurmukhi MN","Nirmala UI",Kartika,Roboto,Noto,"Noto Sans Gurmukhi",sans-serif;--RS__lineHeightCompensation:1.1}:lang(si){--RS__baseFontFamily:"Sinhala Sangam MN","Nirmala UI","Iskoola Pota",Roboto,Noto,"Noto Sans Sinhala",sans-serif;--RS__lineHeightCompensation:1.167}:lang(ta){--RS__baseFontFamily:"Tamil Sangam MN","Nirmala UI",Latha,Roboto,Noto,"Noto Sans Tamil",sans-serif;--RS__lineHeightCompensation:1.067}:lang(te){--RS__baseFontFamily:"Kohinoor Telugu","Telugu Sangam MN","Nirmala UI",Gautami,Roboto,Noto,"Noto Sans Telugu",sans-serif}:lang(th){--RS__baseFontFamily:"Thonburi","Leelawadee UI","Cordia New",Roboto,Noto,"Noto Sans Thai",sans-serif;--RS__lineHeightCompensation:1.067}:lang(zh){--RS__baseFontFamily:"方体","PingFang SC","黑体","Heiti SC","Microsoft JhengHei UI","Microsoft JhengHei",Roboto,Noto,"Noto Sans CJK SC",sans-serif;--RS__lineHeightCompensation:1.167}:lang(zh-Hant),:lang(zh-TW){--RS__baseFontFamily:"方體","PingFang TC","黑體","Heiti TC","Microsoft JhengHei UI","Microsoft JhengHei",Roboto,Noto,"Noto Sans CJK TC",sans-serif;--RS__lineHeightCompensation:1.167}:lang(zh-HK){--RS__baseFontFamily:"方體","PingFang HK","方體","PingFang TC","黑體","Heiti TC","Microsoft JhengHei UI","Microsoft JhengHei",Roboto,Noto,"Noto Sans CJK TC",sans-serif;--RS__lineHeightCompensation:1.167}:root{--RS__backgroundColor:#FFFFFF;--RS__textColor:#121212;--RS__selectionBackgroundColor:#b4d8fe;--RS__selectionTextColor:inherit}:root{color:var(--RS__textColor)!important;background-color:var(--RS__backgroundColor)!important}::-moz-selection{color:var(--RS__selectionTextColor);background-color:var(--RS__selectionBackgroundColor)}::selection{color:var(--RS__selectionTextColor);background-color:var(--RS__selectionBackgroundColor)}body{widows:2;orphans:2}figcaption,td,th{widows:1;orphans:1}caption,dt,h2,h3,h4,h5,h6,hr{-webkit-column-break-after:avoid;page-break-after:avoid;break-after:avoid}dt,figure,h1,h2,h3,h4,h5,h6,tr{-webkit-column-break-inside:avoid;page-break-inside:avoid;break-inside:avoid}body{-webkit-hyphenate-character:"\002D";-moz-hyphenate-character:"\002D";-ms-hyphenate-character:"\002D";hyphenate-character:"\002D";-webkit-hyphenate-limit-lines:3;-ms-hyphenate-limit-lines:3;hyphenate-limit-lines:3}address,caption,center,code,dt,figcaption,h1,h2,h3,h4,h5,h6,pre,var{-ms-hyphens:none;-moz-hyphens:none;-webkit-hyphens:none;-epub-hyphens:none;hyphens:none}body{font-variant-numeric:oldstyle-nums proportional-nums}:lang(ja) body,:lang(ko) body,:lang(zh) body{font-variant-numeric:lining-nums proportional-nums}dt,h1,h2,h3,h4,h5,h6{font-variant-numeric:lining-nums proportional-nums}table{font-variant-numeric:lining-nums tabular-nums}code,var{font-variant-ligatures:none;font-variant-numeric:lining-nums tabular-nums slashed-zero}rt{font-variant-east-asian:ruby}:lang(ar){font-variant-ligatures:common-ligatures}:lang(ko){font-kerning:normal}hr{color:inherit;border-color:currentColor}table,td,th{border-color:currentColor}blockquote,figure{margin:1em 5%}ol,ul{padding-left:5%}dd{margin-left:5%}pre{white-space:pre-wrap;-ms-tab-size:2;-moz-tab-size:2;-webkit-tab-size:2;tab-size:2}abbr[title],acronym[title]{text-decoration:dotted underline}nobr wbr{white-space:normal}ruby>rp,ruby>rt{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}:lang(ja),:lang(ja) cite,:lang(ja) dfn,:lang(ja) em,:lang(ja) i,:lang(ko),:lang(ko) cite,:lang(ko) dfn,:lang(ko) em,:lang(ko) i,:lang(zh),:lang(zh) cite,:lang(zh) dfn,:lang(zh) em,:lang(zh) i{font-style:normal}:lang(ja) a,:lang(ko) a,:lang(zh) a{text-decoration:none}:root{--RS__maxMediaWidth:100%;--RS__maxMediaHeight:100vw;--RS__boxSizingMedia:border-box;--RS__boxSizingTable:border-box}html{-webkit-line-box-contain:block glyphs replaced}:lang(ja){-webkit-line-box-contain:block inline replaced}a,h1,h2,h3,h4,h5,h6{word-wrap:break-word}div{max-width:var(--RS__maxMediaHeight)}audio,img,svg,video{object-fit:contain;width:auto;height:auto;max-width:var(--RS__maxMediaHeight);max-height:var(--RS__maxMediaWidth)!important;box-sizing:var(--RS__boxSizingMedia);-webkit-column-break-inside:avoid;page-break-inside:avoid;break-inside:avoid}table{max-height:var(--RS__maxMediaWidth);box-sizing:var(--RS__boxSizingTable)} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-vertical/ReadiumCSS-default.css b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-vertical/ReadiumCSS-default.css deleted file mode 100644 index 0a12c3d1fe..0000000000 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/cjk-vertical/ReadiumCSS-default.css +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Readium CSS (v. 1.0.0-beta.3) - * Developers: Jiminy Panoz - * Copyright (c) 2017. Readium Foundation. All rights reserved. - * Use of this source code is governed by a BSD-style license which is detailed in the - * LICENSE file present in the project repository where this source code is maintained. -*/@namespace url("http://www.w3.org/1999/xhtml");@namespace epub url("http://www.idpf.org/2007/ops");@namespace m url("http://www.w3.org/1998/Math/MathML/");@namespace svg url("http://www.w3.org/2000/svg");:root{--RS__compFontFamily:var(--RS__baseFontFamily);--RS__codeFontFamily:var(--RS__monospaceTf);--RS__typeScale:1.125;--RS__baseFontSize:87.5%;--RS__flowSpacing:1.5rem;--RS__paraSpacing:0;--RS__paraIndent:1em;--RS__linkColor:#0000EE;--RS__visitedColor:#551A8B}:root:lang(zh){--RS__paraIndent:2em}:lang("mn-Mong"){--RS__baseFontSize:100%}body{font-size:var(--RS__baseFontSize);text-align:justify;text-justify:inter-character}h1,h2,h3,h4,h5,h6{font-family:var(--RS__baseFontFamily);text-align:left;text-align:start}aside,blockquote,figure,footer,form,hr,p,pre{margin-right:var(--RS__flowSpacing);margin-left:var(--RS__flowSpacing)}p{margin-right:var(--RS__paraSpacing);margin-left:var(--RS__paraSpacing);text-indent:var(--RS__paraIndent)}pre{font-family:var(--RS__codeFontFamily)}code,kbd,samp,tt{font-family:var(--RS__codeFontFamily)}sub,sup{position:relative;font-size:67.5%;line-height:1}sub{left:-.2ex}sup{right:0}em{-webkit-text-emphasis:sesame;-epub-text-emphasis:sesame;text-emphasis:sesame}:link{color:var(--RS__linkColor)}:visited{color:var(--RS__visitedColor)}h1{margin-right:calc(var(--RS__flowSpacing) * 2);margin-left:calc(var(--RS__flowSpacing) * 2);font-size:calc(((1em * var(--RS__typeScale)) * var(--RS__typeScale)) * var(--RS__typeScale));text-indent:2rem}h2{margin-right:calc(var(--RS__flowSpacing) * 2);margin-left:var(--RS__flowSpacing);font-size:calc((1em * var(--RS__typeScale)) * var(--RS__typeScale));text-indent:3rem}h3{margin-right:var(--RS__flowSpacing);margin-left:var(--RS__flowSpacing);font-size:calc(1em * var(--RS__typeScale));text-indent:4rem}h4{margin-right:var(--RS__flowSpacing);margin-left:var(--RS__flowSpacing);font-family:var(--RS__compFontFamily);font-size:1em;text-indent:4rem}h5{margin-right:var(--RS__flowSpacing);margin-left:var(--RS__flowSpacing);font-family:var(--RS__compFontFamily);font-size:smaller;text-indent:4rem}h6{margin-right:var(--RS__flowSpacing);margin-left:0;font-family:var(--RS__compFontFamily);font-size:smaller;font-weight:400;text-indent:4rem}dl,ol,ul{margin-right:var(--RS__flowSpacing);margin-left:var(--RS__flowSpacing)}table{margin:0 var(--RS__flowSpacing);border:1px solid currentColor;border-collapse:collapse;empty-cells:show}table>tr,tbody,tfoot,thead{vertical-align:top}th{text-align:left}td,th{padding:4px;border:1px solid currentColor} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/fonts/AccessibleDfA.otf b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/fonts/AccessibleDfA.otf deleted file mode 100755 index 69c02218a5ab163c634edcc34b14e8a735513f82..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 145384 zcmeFa2Y40L);GS-^hxi%ob+DK%$yXlkaC79AWgvnAqgZB5=fybSU^R z|DYmc{zIECVa!!b{K(pIHRHRjy_I&e@);Aq8&lIZo<*?~D(_0l3~8vZsmpu(>{!}= zm9~-w$_RD`Tu9eT#HTlmYo9##nimffPlaUMHLhmzc>S3HbjX!WUrKY$xcaC&GhbmW zFM%=X-0>}K?Wa6!GL=vFz}(E`oEp1$rS;gkBZANV$?ei8gRxzUE-!cJyCa)NozQ+i z?vBf?y|!s=~DSkB5r5j zHPiVPlNb};VNSa+`8{^E_=+o3dY64E-@%fklWd%JGaIIy$Hs}f**3{?rAsy&DsN*i zDc`UU#0BgkX)60d9Le61R2g07D!p*( zki7ELJK_pUZH3mGKR$mwU2jq}i-d&SnkLAvQ`J&C2CqHbx%L zHVbF7DPrKMC!~Yyd7*)AQ{Q3t$!@krj%DNJGPYihptjn>?w9J>7;4nfatK=??PMNh zHR~m9WTx~qE0PwlP&#kDxWYA+=q6<@ZL6s-GT9Gw&&z15p>4K2pSAOIqS!h)%H`I} zU4hc2>`uC`Rdmf;H0qpl4@yJXV&dN>`nt0TKe29dD%(QGZWInuUq-p!k%qd`=-MfC z?SpjP+Rkk*xVy`kBT@6njce;M*)YoM;qlp!R%9 zT}d>6ZIafp3#ILBp0pQKyox<3&Z7HR%|gUMY>2dvT~6)%wDd8JN7|@AnmhNeb=ryc zFQwy;oViKQuydr}=^CQ)cU0e48oN$AB(PaZJg8H5>0-8t)4NzRZwtB~PUF}%C70^_ zA#39GpUawf8^y94IgMnuJJh-Nzf#3RbM=y{*x8bso})SJH7e(Mr%dSx+aY{HW6z=Kr+#**G?3bs zs94HYOGi!(5DZs0ryuE>r=4q@PZuwbKlK=LNQY5>O6@HBuT;B*O;$gmzWA2P+{kX| zI^W?XgWBO0wqA;67t0Gc?Qxn%{wR4Zs}r}en;j}20VVztK5m@;bH>oWLA5%zg8F@^ zyo1J=)6X>4NY7Ntk*wce=tW8kyQAwq{}pxm_+K4&j*$-e^B?Wv z>ACoak4pOH%uK2Se@^6??6IzKeCF}4ePQpZ6J7iNC(_g7ymNea-6OThpPsd@{4Uzn z#$EcOE5D0&wRsmWPr-Qa;vITs+wk&Mk}h_1>LTWM=6Qd&FOeSlyL@>ws}eVoZkob| z((_gJcjx@C%%kU~n^T_fBpdqglq>aM3;vz+{#TqM?`3EIJLO1jc5T;rQrI8+;@f}U z#$D(BJ5)T#RyyYi5iCyliZ#)8pTkRiT|Be@LB5Z4C{=z(VldzK23Cr0oVG$#H z{lEU9c3{HDQ^%xWRz>x?k+#MEsuXD$yXvpU#VM>8mGh?PX3r@-r4HH}{(8>e@xmU~ zEY|)pR)zQ2gI(tdSFzs05T-D8^0dyxu@hvvQGdL}CK1M7Kz%ey8u;h_AiHyXS2_Q? zsj&3V?JlgQzMwp+8{Nh~|B#*PjH7>f&Og8UKS%zjT0maICj3vy`j4Fdw7`E_;QzfA zaD24?TWc+iWhpB8H7dg~dwU+4a&Gc9!xM@}()Pl3(*7 z%Xg?ekSUIT?d*4b&MZTUB0KL0>(_P6p;9YrRECm`(4TqE%>O@eziWP_>)vQSatF=P zoc2MT`Ia+z=R9YA6}mb2RoB|sU41Q-$|eR z>($B@wnN>)o>of!OleM&`+r^Zuh;!6-kE>-XUEAu7-rx|5KFYPb8i2PyMQYHn;KD`|I+b|C;~*Do^8`&!7Ew>;HH23;*4+{&U@b zTHrq|@PAJW(7cWxZHs7fVo?BN`(@`{g!4{qD$Uc(_+yjDGJj|8=JXcD7SMGY=sncw zcMeXgsJj?{V;PXo<~zKQ$y&%hYEg!>7KcCc(=~79psngo}S-PcF?

!C0KHonOXtp~cd3Rl*L5LL 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%0A_=a#T64x>QXKCd^D! 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 diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/rtl/ReadiumCSS-after.css b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/rtl/ReadiumCSS-after.css deleted file mode 100644 index 494e90a0d9..0000000000 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/rtl/ReadiumCSS-after.css +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Readium CSS (v. 1.0.0-beta.3) - * Developers: Jiminy Panoz - * Copyright (c) 2017. Readium Foundation. All rights reserved. - * Use of this source code is governed by a BSD-style license which is detailed in the - * LICENSE file present in the project repository where this source code is maintained. -*/@namespace url("http://www.w3.org/1999/xhtml");@namespace epub url("http://www.idpf.org/2007/ops");@namespace m url("http://www.w3.org/1998/Math/MathML/");@namespace svg url("http://www.w3.org/2000/svg");:root{--RS__colWidth:45em;--RS__colCount:1;--RS__colGap:0;--RS__maxLineLength:40rem;--RS__pageGutter:20px;--RS__viewportWidth:100%}@page{margin:0!important}:root{position:relative;-webkit-column-width:var(--RS__colWidth);-moz-column-width:var(--RS__colWidth);column-width:var(--RS__colWidth);-webkit-column-count:var(--RS__colCount);-moz-column-count:var(--RS__colCount);column-count:var(--RS__colCount);-webkit-column-gap:var(--RS__colGap);-moz-column-gap:var(--RS__colGap);column-gap:var(--RS__colGap);-moz-column-fill:auto;column-fill:auto;width:var(--RS__viewportWidth);height:100vh;max-width:var(--RS__viewportWidth);max-height:100vh;min-width:var(--RS__viewportWidth);min-height:100vh;padding:0!important;margin:0!important;font-size:100%!important;-webkit-text-size-adjust:100%;box-sizing:border-box;-webkit-perspective:1;-webkit-touch-callout:none}body{width:100%;max-width:var(--RS__maxLineLength)!important;padding:0 var(--RS__pageGutter)!important;margin:0 auto!important;box-sizing:border-box}@media screen and (min-width:35em){:root{--RS__pageGutter:30px}}@media screen and (min-width:45em){:root{--RS__pageGutter:40px}}@media screen and (min-width:75em){:root{--RS__pageGutter:50px}}@media screen and (min-width:60em),screen and (min-device-width:36em) and (max-device-width:47em) and (orientation:landscape){:root{--RS__colWidth:20em;--RS__colCount:2;--RS__maxLineLength:39.99rem}}:root[style*=readium-scroll-on]{-webkit-columns:auto auto!important;-moz-columns:auto auto!important;columns:auto auto!important;width:auto!important;height:auto!important;max-width:none!important;max-height:none!important;min-width:0!important;min-height:0!important}:root[style*=readium-scroll-on] body{--RS__maxLineLength:40rem!important}:root[style*=readium-night-on]{--RS__backgroundColor:#000000;--RS__textColor:#FEFEFE;--RS__linkColor:#63caff;--RS__visitedColor:#0099E5;--RS__selectionBackgroundColor:#b4d8fe;--RS__selectionTextColor:inherit}:root[style*=readium-night-on] :not(a){color:inherit!important;background-color:transparent!important;border-color:currentColor!important}:root[style*=readium-night-on] svg text{fill:currentColor!important;stroke:none!important}:root[style*=readium-night-on] a:link,:root[style*=readium-night-on] a:link *{color:var(--RS__linkColor)!important}:root[style*=readium-night-on] a:visited,:root[style*=readium-night-on] a:visited *{color:var(--RS__visitedColor)!important}:root[style*=readium-night-on] [epub\:type~=titlepage] img:only-child,:root[style*=readium-night-on] [epub|type~=titlepage] img:only-child,:root[style*=readium-night-on] img[class*=gaiji]{-webkit-filter:invert(100%);filter:invert(100%)}:root[style*=readium-night-on][style*=readium-darken-on] img{-webkit-filter:brightness(80%);filter:brightness(80%)}:root[style*=readium-night-on][style*=readium-invert-on] img{-webkit-filter:invert(100%);filter:invert(100%)}:root[style*=readium-night-on][style*=readium-darken-on][style*=readium-invert-on] img{-webkit-filter:brightness(80%) invert(100%);filter:brightness(80%) invert(100%)}:root[style*=readium-sepia-on]{--RS__backgroundColor:#faf4e8;--RS__textColor:#121212;--RS__linkColor:#0000EE;--RS__visitedColor:#551A8B;--RS__selectionBackgroundColor:#b4d8fe;--RS__selectionTextColor:inherit;--RS__maxLineLength:40.01rem}:root[style*=readium-sepia-on] :not(a){color:inherit!important;background-color:transparent!important}:root[style*=readium-sepia-on] a:link,:root[style*=readium-sepia-on] a:link *{color:var(--RS__linkColor)}:root[style*=readium-sepia-on] a:visited,:root[style*=readium-sepia-on] a:visited *{color:var(--RS__visitedColor)}:root[style*=readium-sepia-on] img,:root[style*=readium-sepia-on] svg{background-color:transparent!important;mix-blend-mode:multiply}@media screen and (-ms-high-contrast:active){:root{color:windowText!important;background-color:window!important}:root :not(#\#):not(#\#):not(#\#),:root :not(#\#):not(#\#):not(#\#) :not(#\#):not(#\#):not(#\#) :root :not(#\#):not(#\#):not(#\#) :not(#\#):not(#\#):not(#\#) :not(#\#):not(#\#):not(#\#){color:inherit!important;background-color:inherit!important}.readiumCSS-mo-active-default{color:highlightText!important;background-color:highlight!important}}@media screen and (-ms-high-contrast:white-on-black){:root[style*=readium-night-on] [epub\:type~=titlepage] img:only-child,:root[style*=readium-night-on] [epub|type~=titlepage] img:only-child,:root[style*=readium-night-on] img[class*=gaiji]{-webkit-filter:none!important;filter:none!important}:root[style*=readium-night-on][style*=readium-invert-on] img{-webkit-filter:none!important;filter:none!important}:root[style*=readium-night-on][style*=readium-darken-on][style*=readium-invert-on] img{-webkit-filter:brightness(80%);filter:brightness(80%)}}@media screen and (inverted-colors){:root[style*=readium-night-on] [epub\:type~=titlepage] img:only-child,:root[style*=readium-night-on] [epub|type~=titlepage] img:only-child,:root[style*=readium-night-on] img[class*=gaiji]{-webkit-filter:none!important;filter:none!important}:root[style*=readium-night-on][style*=readium-invert-on] img{-webkit-filter:none!important;filter:none!important}:root[style*=readium-night-on][style*=readium-darken-on][style*=readium-invert-on] img{-webkit-filter:brightness(80%);filter:brightness(80%)}}@media screen and (min-width:60em),screen and (min-device-width:36em) and (max-device-width:47em) and (orientation:landscape){:root[style*="--USER__colCount: 1"],:root[style*="--USER__colCount: 2"],:root[style*="--USER__colCount:1"],:root[style*="--USER__colCount:2"]{-webkit-column-count:var(--USER__colCount);-moz-column-count:var(--USER__colCount);column-count:var(--USER__colCount)}:root[style*="--USER__colCount: 1"],:root[style*="--USER__colCount:1"]{--RS__maxLineLength:40rem!important;--RS__colWidth:100vw}:root[style*="--USER__colCount: 2"],:root[style*="--USER__colCount:2"]{--RS__colWidth:auto}}:root[style*="--USER__pageMargins"] body{padding:0 calc(var(--RS__pageGutter) * var(--USER__pageMargins))!important}:root[style*="--USER__backgroundColor"]{background-color:var(--USER__backgroundColor)!important}:root[style*="--USER__backgroundColor"] *{background-color:transparent!important}:root[style*="--USER__textColor"]{color:var(--USER__textColor)!important}:root[style*="--USER__textColor"] :not(h1):not(h2):not(h3):not(h4):not(h5):not(h6):not(pre){color:inherit!important}:root[style*=readium-advanced-on][style*="--USER__textAlign"]{text-align:var(--USER__textAlign)}:root[style*=readium-advanced-on][style*="--USER__textAlign"] :not(blockquote):not(figcaption) p,:root[style*=readium-advanced-on][style*="--USER__textAlign"] body,:root[style*=readium-advanced-on][style*="--USER__textAlign"] li{text-align:inherit!important;-moz-text-align-last:auto!important;-epub-text-align-last:auto!important;text-align-last:auto!important}:root[style*=readium-advanced-on][dir=rtl][style*="--USER__textAlign: left"],:root[style*=readium-advanced-on][dir=rtl][style*="--USER__textAlign:left"],:root[style*=readium-advanced-on][style*="--USER__textAlign: left"] [dir=rtl],:root[style*=readium-advanced-on][style*="--USER__textAlign:left"] [dir=rtl]{text-align:right}:root[style*=readium-advanced-on][dir=rtl][style*="--USER__textAlign: start"],:root[style*=readium-advanced-on][dir=rtl][style*="--USER__textAlign:start"]{text-align:right}:root[style*=readium-font-on][style*="--USER__fontFamily"]{font-family:var(--USER__fontFamily)!important}:root[style*=readium-font-on][style*="--USER__fontFamily"] body,:root[style*=readium-font-on][style*="--USER__fontFamily"] dd,:root[style*=readium-font-on][style*="--USER__fontFamily"] div,:root[style*=readium-font-on][style*="--USER__fontFamily"] dt,:root[style*=readium-font-on][style*="--USER__fontFamily"] li,:root[style*=readium-font-on][style*="--USER__fontFamily"] p{font-family:inherit!important}:root[style*=readium-font-on][style*="--USER__fontFamily"] b:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] b:not([xml\:lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] cite:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] cite:not([xml\:lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] em:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] em:not([xml\:lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] i:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] i:not([xml\:lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] span:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] span:not([xml\:lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] strong:not([lang]),:root[style*=readium-font-on][style*="--USER__fontFamily"] strong:not([xml\:lang]){font-family:inherit!important}:root[style*="--USER__fontSize"]{font-size:var(--USER__fontSize)!important}:root[style*=readium-advanced-on][style*="--USER__lineHeight"]{line-height:var(--USER__lineHeight)!important}:root[style*=readium-advanced-on][style*="--USER__lineHeight"] body,:root[style*=readium-advanced-on][style*="--USER__lineHeight"] div,:root[style*=readium-advanced-on][style*="--USER__lineHeight"] li,:root[style*=readium-advanced-on][style*="--USER__lineHeight"] p{line-height:inherit}:root[style*=readium-advanced-on][style*="--USER__paraSpacing"] p{margin-top:var(--USER__paraSpacing)!important;margin-bottom:var(--USER__paraSpacing)!important}:root[style*=readium-advanced-on][style*="--USER__paraIndent"] p{text-indent:var(--USER__paraIndent)!important}:root[style*=readium-advanced-on][style*="--USER__paraIndent"] p *,:root[style*=readium-advanced-on][style*="--USER__paraIndent"] p:first-letter{text-indent:0!important}:root[style*=readium-advanced-on][style*="--USER__arabicLigatures"]{font-variant-ligatures:var(--USER__ligatures)!important}:root[style*=readium-advanced-on][style*="--USER__arabicLigatures"] *{font-variant-ligatures:inherit!important}:root[style*=readium-advanced-on]{--USER__typeScale:1.2}:root[style*=readium-advanced-on] dd,:root[style*=readium-advanced-on] div,:root[style*=readium-advanced-on] li,:root[style*=readium-advanced-on] p,:root[style*=readium-advanced-on] pre{font-size:1rem!important}:root[style*=readium-advanced-on] h1{font-size:1.75rem!important;font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale))!important}:root[style*=readium-advanced-on] h2{font-size:1.5rem!important;font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale))!important}:root[style*=readium-advanced-on] h3{font-size:1.25rem!important;font-size:calc(1rem * var(--USER__typeScale))!important}:root[style*=readium-advanced-on] h4,:root[style*=readium-advanced-on] h5,:root[style*=readium-advanced-on] h6{font-size:1rem!important}:root[style*=readium-advanced-on] small{font-size:smaller!important}:root[style*=readium-advanced-on] sub,:root[style*=readium-advanced-on] sup{font-size:67.5%!important}:root[style*=readium-advanced-on][style*="--USER__typeScale"] h1{font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale))!important}:root[style*=readium-advanced-on][style*="--USER__typeScale"] h2{font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale))!important}:root[style*=readium-advanced-on][style*="--USER__typeScale"] h3{font-size:calc(1rem * var(--USER__typeScale))!important} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/rtl/ReadiumCSS-before.css b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/rtl/ReadiumCSS-before.css deleted file mode 100644 index faee9a5bca..0000000000 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/rtl/ReadiumCSS-before.css +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Readium CSS (v. 1.0.0-beta.3) - * Developers: Jiminy Panoz - * Copyright (c) 2017. Readium Foundation. All rights reserved. - * Use of this source code is governed by a BSD-style license which is detailed in the - * LICENSE file present in the project repository where this source code is maintained. -*/@namespace url("http://www.w3.org/1999/xhtml");@namespace epub url("http://www.idpf.org/2007/ops");@namespace m url("http://www.w3.org/1998/Math/MathML/");@namespace svg url("http://www.w3.org/2000/svg");@-ms-viewport{width:device-width}@viewport{width:device-width;zoom:1}:root{--RS__oldStyleTf:"Iowan Old Style","Sitka Text",Palatino,"Book Antiqua",serif;--RS__modernTf:Athelas,Constantia,Georgia,serif;--RS__sansTf:-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;--RS__humanistTf:Seravek,Calibri,Roboto,Arial,sans-serif;--RS__monospaceTf:"Andale Mono",Consolas,monospace;--RS__baseFontFamily:var(--RS__oldStyleTf);--RS__lineHeightCompensation:1;--RS__baseLineHeight:calc((1em + (2ex - 1ch) - ((1rem - 16px) * 0.1667)) * var(--RS__lineHeightCompensation))}html{font-family:var(--RS__baseFontFamily);line-height:1.6;line-height:var(--RS__baseLineHeight);text-rendering:optimizeLegibility}h1,h2,h3{line-height:normal}:lang(ja),:lang(ko),:lang(zh){word-wrap:break-word;-webkit-line-break:strict;-epub-line-break:strict;line-break:strict}math{font-family:"Latin Modern Math","STIX Two Math","XITS Math","STIX Math","Libertinus Math","TeX Gyre Termes Math","TeX Gyre Bonum Math","TeX Gyre Schola","DejaVu Math TeX Gyre","TeX Gyre Pagella Math","Asana Math","Cambria Math","Lucida Bright Math","Minion Math",STIXGeneral,STIXSizeOneSym,Symbol,"Times New Roman",serif}:lang(am){--RS__baseFontFamily:Kefa,Nyala,Roboto,Noto,"Noto Sans Ethiopic",serif;--RS__lineHeightCompensation:1.167}:lang(ar){--RS__baseFontFamily:"Geeza Pro","Arabic Typesetting",Roboto,Noto,"Noto Naskh Arabic","Times New Roman",serif}:lang(bn){--RS__baseFontFamily:"Kohinoor Bangla","Bangla Sangam MN",Vrinda,Roboto,Noto,"Noto Sans Bengali",sans-serif;--RS__lineHeightCompensation:1.067}:lang(bo){--RS__baseFontFamily:Kailasa,"Microsoft Himalaya",Roboto,Noto,"Noto Sans Tibetan",sans-serif}:lang(chr){--RS__baseFontFamily:"Plantagenet Cherokee",Roboto,Noto,"Noto Sans Cherokee";--RS__lineHeightCompensation:1.167}:lang(fa){--RS__baseFontFamily:"Geeza Pro","Arabic Typesetting",Roboto,Noto,"Noto Naskh Arabic","Times New Roman",serif}:lang(gu){--RS__baseFontFamily:"Gujarati Sangam MN","Nirmala UI",Shruti,Roboto,Noto,"Noto Sans Gujarati",sans-serif;--RS__lineHeightCompensation:1.167}:lang(he){--RS__baseFontFamily:"New Peninim MT","Arial Hebrew",Gisha,"Times New Roman",Roboto,Noto,"Noto Sans Hebrew" sans-serif;--RS__lineHeightCompensation:1.1}:lang(hi){--RS__baseFontFamily:"Kohinoor Devanagari","Devanagari Sangam MN",Kokila,"Nirmala UI",Roboto,Noto,"Noto Sans Devanagari",sans-serif;--RS__lineHeightCompensation:1.1}:lang(hy){--RS__baseFontFamily:Mshtakan,Sylfaen,Roboto,Noto,"Noto Serif Armenian",serif}:lang(iu){--RS__baseFontFamily:"Euphemia UCAS",Euphemia,Roboto,Noto,"Noto Sans Canadian Aboriginal",sans-serif}:lang(ja){--RS__baseFontFamily:"游ゴシック体",YuGothic,"ヒラギノ丸ゴ","Hiragino Sans","Yu Gothic UI","Meiryo UI","MS Gothic",Roboto,Noto,"Noto Sans CJK JP",sans-serif;--RS__lineHeightCompensation:1.167;--RS__serif-ja:"MS P明朝","MS PMincho","Hiragino Mincho Pro","ヒラギノ明朝 Pro W3","游明朝","YuMincho","MS 明朝","MS Mincho","Hiragino Mincho ProN",serif;--RS__sans-serif-ja:"MS Pゴシック","MS PGothic","Hiragino Kaku Gothic Pro W3","ヒラギノ角ゴ Pro W3","Hiragino Sans GB","ヒラギノ角ゴシック W3","游ゴシック","YuGothic","MS ゴシック","MS Gothic","Hiragino Sans",sans-serif;--RS__serif-ja-v:"MS 明朝","MS Mincho","Hiragino Mincho Pro","ヒラギノ明朝 Pro W3","游明朝","YuMincho","MS P明朝","MS PMincho","Hiragino Mincho ProN",serif;--RS__sans-serif-ja-v:"MS ゴシック","MS Gothic","Hiragino Kaku Gothic Pro W3","ヒラギノ角ゴ Pro W3","Hiragino Sans GB","ヒラギノ角ゴシック W3","游ゴシック","YuGothic","MS Pゴシック","MS PGothic","Hiragino Sans",sans-serif}:lang(km){--RS__baseFontFamily:"Khmer Sangam MN","Leelawadee UI","Khmer UI",Roboto,Noto,"Noto Sans Khmer",sans-serif;--RS__lineHeightCompensation:1.067}:lang(kn){--RS__baseFontFamily:"Kannada Sangam MN","Nirmala UI",Tunga,Roboto,Noto,"Noto Sans Kannada",sans-serif;--RS__lineHeightCompensation:1.1}:lang(ko){--RS__baseFontFamily:"Nanum Gothic","Apple SD Gothic Neo","Malgun Gothic",Roboto,Noto,"Noto Sans CJK KR",sans-serif;--RS__lineHeightCompensation:1.167}:lang(lo){--RS__baseFontFamily:"Lao Sangam MN","Leelawadee UI","Lao UI",Roboto,Noto,"Noto Sans Lao",sans-serif}:lang(ml){--RS__baseFontFamily:"Malayalam Sangam MN","Nirmala UI",Kartika,Roboto,Noto,"Noto Sans Malayalam",sans-serif;--RS__lineHeightCompensation:1.067}:lang(or){--RS__baseFontFamily:"Oriya Sangam MN","Nirmala UI",Kalinga,Roboto,Noto,"Noto Sans Oriya",sans-serif;--RS__lineHeightCompensation:1.167}:lang(pa){--RS__baseFontFamily:"Gurmukhi MN","Nirmala UI",Kartika,Roboto,Noto,"Noto Sans Gurmukhi",sans-serif;--RS__lineHeightCompensation:1.1}:lang(si){--RS__baseFontFamily:"Sinhala Sangam MN","Nirmala UI","Iskoola Pota",Roboto,Noto,"Noto Sans Sinhala",sans-serif;--RS__lineHeightCompensation:1.167}:lang(ta){--RS__baseFontFamily:"Tamil Sangam MN","Nirmala UI",Latha,Roboto,Noto,"Noto Sans Tamil",sans-serif;--RS__lineHeightCompensation:1.067}:lang(te){--RS__baseFontFamily:"Kohinoor Telugu","Telugu Sangam MN","Nirmala UI",Gautami,Roboto,Noto,"Noto Sans Telugu",sans-serif}:lang(th){--RS__baseFontFamily:"Thonburi","Leelawadee UI","Cordia New",Roboto,Noto,"Noto Sans Thai",sans-serif;--RS__lineHeightCompensation:1.067}:lang(zh){--RS__baseFontFamily:"方体","PingFang SC","黑体","Heiti SC","Microsoft JhengHei UI","Microsoft JhengHei",Roboto,Noto,"Noto Sans CJK SC",sans-serif;--RS__lineHeightCompensation:1.167}:lang(zh-Hant),:lang(zh-TW){--RS__baseFontFamily:"方體","PingFang TC","黑體","Heiti TC","Microsoft JhengHei UI","Microsoft JhengHei",Roboto,Noto,"Noto Sans CJK TC",sans-serif;--RS__lineHeightCompensation:1.167}:lang(zh-HK){--RS__baseFontFamily:"方體","PingFang HK","方體","PingFang TC","黑體","Heiti TC","Microsoft JhengHei UI","Microsoft JhengHei",Roboto,Noto,"Noto Sans CJK TC",sans-serif;--RS__lineHeightCompensation:1.167}:root{--RS__backgroundColor:#FFFFFF;--RS__textColor:#121212;--RS__selectionBackgroundColor:#b4d8fe;--RS__selectionTextColor:inherit}:root{color:var(--RS__textColor)!important;background-color:var(--RS__backgroundColor)!important}::-moz-selection{color:var(--RS__selectionTextColor);background-color:var(--RS__selectionBackgroundColor)}::selection{color:var(--RS__selectionTextColor);background-color:var(--RS__selectionBackgroundColor)}body{widows:2;orphans:2}figcaption,td,th{widows:1;orphans:1}caption,dt,h2,h3,h4,h5,h6,hr{-webkit-column-break-after:avoid;page-break-after:avoid;break-after:avoid}dt,figure,h1,h2,h3,h4,h5,h6,tr{-webkit-column-break-inside:avoid;page-break-inside:avoid;break-inside:avoid}body{-webkit-hyphenate-character:"\002D";-moz-hyphenate-character:"\002D";-ms-hyphenate-character:"\002D";hyphenate-character:"\002D";-webkit-hyphenate-limit-lines:3;-ms-hyphenate-limit-lines:3;hyphenate-limit-lines:3}address,caption,center,code,dt,figcaption,h1,h2,h3,h4,h5,h6,pre,var{-ms-hyphens:none;-moz-hyphens:none;-webkit-hyphens:none;-epub-hyphens:none;hyphens:none}body{font-variant-numeric:oldstyle-nums proportional-nums}:lang(ja) body,:lang(ko) body,:lang(zh) body{font-variant-numeric:lining-nums proportional-nums}dt,h1,h2,h3,h4,h5,h6{font-variant-numeric:lining-nums proportional-nums}table{font-variant-numeric:lining-nums tabular-nums}code,var{font-variant-ligatures:none;font-variant-numeric:lining-nums tabular-nums slashed-zero}rt{font-variant-east-asian:ruby}:lang(ar){font-variant-ligatures:common-ligatures}:lang(ko){font-kerning:normal}hr{color:inherit;border-color:currentColor}table,td,th{border-color:currentColor}blockquote,figure{margin:1em 5%}ol,ul{padding-left:5%}dd{margin-left:5%}pre{white-space:pre-wrap;-ms-tab-size:2;-moz-tab-size:2;-webkit-tab-size:2;tab-size:2}abbr[title],acronym[title]{text-decoration:dotted underline}nobr wbr{white-space:normal}ruby>rp,ruby>rt{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}:lang(ja),:lang(ja) cite,:lang(ja) dfn,:lang(ja) em,:lang(ja) i,:lang(ko),:lang(ko) cite,:lang(ko) dfn,:lang(ko) em,:lang(ko) i,:lang(zh),:lang(zh) cite,:lang(zh) dfn,:lang(zh) em,:lang(zh) i{font-style:normal}:lang(ja) a,:lang(ko) a,:lang(zh) a{text-decoration:none}:root{--RS__maxMediaWidth:100%;--RS__maxMediaHeight:95vh;--RS__boxSizingMedia:border-box;--RS__boxSizingTable:border-box}html{-webkit-line-box-contain:block glyphs replaced}:lang(ja){-webkit-line-box-contain:block inline replaced}a,h1,h2,h3,h4,h5,h6{word-wrap:break-word}div{max-width:var(--RS__maxMediaWidth)}audio,img,svg,video{object-fit:contain;width:auto;height:auto;max-width:var(--RS__maxMediaWidth);max-height:var(--RS__maxMediaHeight)!important;box-sizing:var(--RS__boxSizingMedia);-webkit-column-break-inside:avoid;page-break-inside:avoid;break-inside:avoid}table{max-width:var(--RS__maxMediaWidth);box-sizing:var(--RS__boxSizingTable)} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/rtl/ReadiumCSS-default.css b/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/rtl/ReadiumCSS-default.css deleted file mode 100644 index 44530f93cb..0000000000 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/readium-css/rtl/ReadiumCSS-default.css +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Readium CSS (v. 1.0.0-beta.3) - * Developers: Jiminy Panoz - * Copyright (c) 2017. Readium Foundation. All rights reserved. - * Use of this source code is governed by a BSD-style license which is detailed in the - * LICENSE file present in the project repository where this source code is maintained. -*/@namespace url("http://www.w3.org/1999/xhtml");@namespace epub url("http://www.idpf.org/2007/ops");@namespace m url("http://www.w3.org/1998/Math/MathML/");@namespace svg url("http://www.w3.org/2000/svg");:root{--RS__compFontFamily:var(--RS__baseFontFamily);--RS__codeFontFamily:var(--RS__monospaceTf);--RS__typeScale:1.125;--RS__baseFontSize:100%;--RS__flowSpacing:1.5rem;--RS__paraSpacing:0;--RS__paraIndent:1em;--RS__linkColor:#0000EE;--RS__visitedColor:#551A8B}body{font-size:var(--RS__baseFontSize);text-align:justify}h1,h2,h3,h4,h5,h6{font-family:var(--RS__compFontFamily);text-align:right}aside,blockquote,figure,footer,form,hr,p,pre{margin-top:var(--RS__flowSpacing);margin-bottom:var(--RS__flowSpacing)}p{margin-top:var(--RS__paraSpacing);margin-bottom:var(--RS__paraSpacing);text-indent:var(--RS__paraIndent)}h1+p,h2+p,h3+p,h4+p,h5+p,h6+p,hr+p{text-indent:0}pre{font-family:var(--RS__codeFontFamily)}code,kbd,samp,tt{font-family:var(--RS__codeFontFamily)}sub,sup{position:relative;font-size:67.5%;line-height:1}sub{bottom:-.2ex}sup{bottom:0}:link{color:var(--RS__linkColor)}:visited{color:var(--RS__visitedColor)}h1{margin-top:calc(var(--RS__flowSpacing) * 2);margin-bottom:calc(var(--RS__flowSpacing) * 2);font-size:calc(((1em * var(--RS__typeScale)) * var(--RS__typeScale)) * var(--RS__typeScale))}h2{margin-top:calc(var(--RS__flowSpacing) * 2);margin-bottom:var(--RS__flowSpacing);font-size:calc((1em * var(--RS__typeScale)) * var(--RS__typeScale))}h3{margin-top:var(--RS__flowSpacing);margin-bottom:var(--RS__flowSpacing);font-size:calc(1em * var(--RS__typeScale))}h4{margin-top:var(--RS__flowSpacing);margin-bottom:var(--RS__flowSpacing);font-size:1em}h5{margin-top:var(--RS__flowSpacing);margin-bottom:var(--RS__flowSpacing);font-size:smaller}h6{margin-top:var(--RS__flowSpacing);margin-bottom:0;font-size:smaller;font-weight:400}dl,ol,ul{margin-top:var(--RS__flowSpacing);margin-bottom:var(--RS__flowSpacing)}table{margin:var(--RS__flowSpacing) 0;border:1px solid currentColor;border-collapse:collapse;empty-cells:show}table>tr,tbody,tfoot,thead{vertical-align:top}th{text-align:initial}td,th{padding:4px;border:1px solid currentColor} \ No newline at end of file diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionState.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionState.kt index 9453fa8813..6c354650a8 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionState.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionState.kt @@ -73,7 +73,7 @@ public class FixedWebRenditionState internal constructor( private val htmlInjector: (Resource, MediaType) -> Resource = { resource, mediaType -> resource.injectHtml( charset = mediaType.charset, - injectableScript = RelativeUrl("readium/navigators/web/fixed-injectable-script.js")!!, + injectableScript = RelativeUrl("readium/navigators/web/generated/fixed-injectable-script.js")!!, assetsBaseHref = assetsBaseHref, disableSelection = isRestricted ) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt index 01c38fcd0c..b4715c1f23 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt @@ -21,6 +21,7 @@ import org.readium.navigator.common.OverflowController import org.readium.navigator.common.RenditionState import org.readium.navigator.common.SettingsController import org.readium.navigator.web.css.ReadiumCss +import org.readium.navigator.web.css.RsProperties import org.readium.navigator.web.layout.ReadingOrder import org.readium.navigator.web.location.ReflowableWebGoLocation import org.readium.navigator.web.location.ReflowableWebLocation @@ -51,6 +52,7 @@ public class ReflowableWebRenditionState internal constructor( isRestricted: Boolean, initialSettings: ReflowableWebSettings, initialLocation: ReflowableWebGoLocation, + private val rsProperties: RsProperties = RsProperties(), ) : RenditionState { private val navigatorState: MutableState = @@ -71,7 +73,8 @@ public class ReflowableWebRenditionState internal constructor( derivedStateOf { ReadiumCss( assetsBaseHref = assetsBaseHref, - readiumCssAssets = RelativeUrl("readium/navigators/web/readium-css/")!! + readiumCssAssets = RelativeUrl("readium/navigators/web/generated/readium-css/")!!, + rsProperties = rsProperties ).update( settings = layoutDelegate.settings.value, useReadiumCssFontSize = true @@ -82,7 +85,7 @@ public class ReflowableWebRenditionState internal constructor( resource.injectHtmlReflowable( charset = mediaType.charset, readiumCss = readiumCss.value, - injectableScript = RelativeUrl("readium/navigators/web/reflowable-injectable-script.js")!!, + injectableScript = RelativeUrl("readium/navigators/web/generated/reflowable-injectable-script.js")!!, assetsBaseHref = assetsBaseHref, disableSelection = isRestricted ) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/Properties.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/Properties.kt index 6c66bc1068..06098b6082 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/Properties.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/Properties.kt @@ -226,7 +226,7 @@ public data class RsProperties( val colWidth: Length? = null, val colCount: Int? = null, val colGap: Length.Absolute? = null, - val pageGutter: Length.Absolute? = null, + val pageGutter: Length.Px? = null, // Vertical rhythm val flowSpacing: Length? = null, diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebDefaults.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebDefaults.kt index 415d75f866..afd424411f 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebDefaults.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebDefaults.kt @@ -31,6 +31,7 @@ public data class ReflowableWebDefaults( val letterSpacing: Double? = null, val ligatures: Boolean? = null, val lineHeight: Double? = null, + val pageMargins: Double? = null, val paragraphIndent: Double? = null, val paragraphSpacing: Double? = null, val publisherStyles: Boolean? = null, diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferences.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferences.kt index ecb3648cd1..41b0effe8e 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferences.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferences.kt @@ -26,6 +26,7 @@ import org.readium.r2.shared.util.Language * @param letterSpacing Space between letters. * @param ligatures Enable ligatures in Arabic. * @param lineHeight Leading line height. + * @param pageMargins Factor applied to horizontal margins. * @param paragraphIndent Text indentation for paragraphs. * @param paragraphSpacing Vertical margins for paragraphs. * @param publisherStyles Indicates whether the original publisher styles should be observed. @@ -58,6 +59,7 @@ public data class ReflowableWebPreferences( val letterSpacing: Double? = null, val ligatures: Boolean? = null, val lineHeight: Double? = null, + val pageMargins: Double? = null, val paragraphIndent: Double? = null, val paragraphSpacing: Double? = null, val publisherStyles: Boolean? = null, @@ -77,6 +79,7 @@ public data class ReflowableWebPreferences( require(fontSize == null || fontSize >= 0) require(fontWeight == null || fontWeight in 0.0..2.5) require(letterSpacing == null || letterSpacing >= 0) + require(pageMargins == null || pageMargins >= 0) require(paragraphSpacing == null || paragraphSpacing >= 0) require(spread in listOf(null, Spread.NEVER, Spread.ALWAYS)) require(wordSpacing == null || wordSpacing >= 0) @@ -96,6 +99,7 @@ public data class ReflowableWebPreferences( letterSpacing = other.letterSpacing ?: letterSpacing, ligatures = other.ligatures ?: ligatures, lineHeight = other.lineHeight ?: lineHeight, + pageMargins = other.pageMargins ?: pageMargins, paragraphIndent = other.paragraphIndent ?: paragraphIndent, paragraphSpacing = other.paragraphSpacing ?: paragraphSpacing, publisherStyles = other.publisherStyles ?: publisherStyles, diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesEditor.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesEditor.kt index 595d52c8e4..45e6b547a9 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesEditor.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesEditor.kt @@ -263,6 +263,23 @@ public class ReflowableWebPreferencesEditor internal constructor( valueFormatter = { it.format(5) } ) + /** + * Factor applied to horizontal margins. Default to 1. + * + * Only effective with reflowable publications. + */ + @ExperimentalReadiumApi + public val pageMargins: RangePreference = + RangePreferenceDelegate( + getValue = { preferences.pageMargins }, + getEffectiveValue = { state.settings.pageMargins }, + getIsEffective = { true }, + updateValue = { value -> updateValues { it.copy(pageMargins = value) } }, + supportedRange = 0.0..4.0, + progressionStrategy = DoubleIncrement(0.3), + valueFormatter = { it.format(5) } + ) + /** * Text indentation for paragraphs. * diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettings.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettings.kt index 3da736b5a3..df2f0bed80 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettings.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettings.kt @@ -42,6 +42,7 @@ public data class ReflowableWebSettings( val letterSpacing: Double?, val ligatures: Boolean?, val lineHeight: Double?, + val pageMargins: Double, val paragraphIndent: Double?, val paragraphSpacing: Double?, val publisherStyles: Boolean, @@ -78,6 +79,9 @@ internal fun ReadiumCss.update(settings: ReflowableWebSettings, useReadiumCssFon return with(settings) { copy( layout = Layout.from(settings), + rsProperties = rsProperties.copy( + pageGutter = Length.Px((rsProperties.pageGutter?.value ?: 20.0) * pageMargins) + ), userProperties = userProperties.copy( view = when (scroll) { false -> View.PAGED diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettingsResolver.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettingsResolver.kt index 314e5a759f..06a4859d09 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettingsResolver.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettingsResolver.kt @@ -50,6 +50,7 @@ internal class ReflowableWebSettingsResolver( letterSpacing = preferences.letterSpacing ?: defaults.letterSpacing, ligatures = preferences.ligatures ?: defaults.ligatures, lineHeight = preferences.lineHeight ?: defaults.lineHeight, + pageMargins = preferences.pageMargins ?: defaults.pageMargins ?: 1.0, paragraphIndent = preferences.paragraphIndent ?: defaults.paragraphIndent, paragraphSpacing = preferences.paragraphSpacing ?: defaults.paragraphSpacing, publisherStyles = preferences.publisherStyles ?: defaults.publisherStyles ?: true, diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/util/HtmlInjector.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/util/HtmlInjector.kt index 208ea75b57..e6289670eb 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/util/HtmlInjector.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/util/HtmlInjector.kt @@ -68,9 +68,7 @@ internal fun Resource.injectHtmlReflowable( val injectables = buildList { add( script( - assetsBaseHref.resolve( - Url("readium/navigators/web/reflowable-injectable-script.js")!! - ) + assetsBaseHref.resolve(injectableScript) ) ) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/webapi/FixedDoubleApi.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/webapi/FixedDoubleApi.kt index 05766953c2..d31fb03a00 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/webapi/FixedDoubleApi.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/webapi/FixedDoubleApi.kt @@ -24,7 +24,7 @@ internal class FixedDoubleApi( suspend fun getPageContent(assetManager: AssetManager, assetsUrl: AbsoluteUrl): String = withContext(Dispatchers.IO) { - assetManager.open("readium/navigators/web/fixed-double-index.html") + assetManager.open("readium/navigators/web/generated/fixed-double-index.html") .bufferedReader() .use { it.readText() } .replace("{{ASSETS_URL}}", assetsUrl.toString()) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/webapi/FixedSingleApi.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/webapi/FixedSingleApi.kt index dfccc2ebf8..6ee26a5066 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/webapi/FixedSingleApi.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/webapi/FixedSingleApi.kt @@ -24,7 +24,7 @@ internal class FixedSingleApi( suspend fun getPageContent(assetManager: AssetManager, assetsUrl: AbsoluteUrl): String = withContext(Dispatchers.IO) { - assetManager.open("readium/navigators/web/fixed-single-index.html") + assetManager.open("readium/navigators/web/generated/fixed-single-index.html") .bufferedReader() .use { it.readText() } .replace("{{ASSETS_URL}}", assetsUrl.toString()) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/RelaxedWebView.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/RelaxedWebView.kt index 47bcb632e3..bae57fd0f5 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/RelaxedWebView.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/RelaxedWebView.kt @@ -21,7 +21,7 @@ internal class RelaxedWebView(context: Context) : WebView(context) { verticalScrollRange - verticalScrollExtent val canScrollRight: Boolean get() = - scrollX < maxScrollY + scrollX < maxScrollX val canScrollLeft: Boolean get() = scrollX > 0 From 3a67b278cfc1c676237089c793af462cadc77349 Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Tue, 10 Dec 2024 21:21:35 +0100 Subject: [PATCH 04/88] Implement scroll mode --- .../navigator/web/FixedWebRendition.kt | 2 + .../navigator/web/ReflowableWebRendition.kt | 10 +- .../navigator/web/pager/NavigatorPager.kt | 59 +++++++--- .../ScrollPagerNestedScrollConnection.kt | 104 ++++++++++++++++++ .../web/reflowable/ReflowableResource.kt | 59 ++++++---- .../ScrollReflowableNestedScrollConnection.kt | 51 +++++++++ .../navigator/web/webview/RelaxedWebView.kt | 6 + .../web/webview/WebViewLayoutInfoProvider.kt | 23 +++- 8 files changed, 269 insertions(+), 45 deletions(-) create mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollPagerNestedScrollConnection.kt create mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ScrollReflowableNestedScrollConnection.kt diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt index dd7deb730c..61cd58f19b 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt @@ -7,6 +7,7 @@ package org.readium.navigator.web import android.annotation.SuppressLint +import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.displayCutout @@ -92,6 +93,7 @@ public fun FixedWebRendition( NavigatorPager( modifier = modifier, state = state.pagerState, + orientation = Orientation.Horizontal, beyondViewportPageCount = 2, key = { index -> state.layoutDelegate.layout.value.pageIndexForSpread(index) }, reverseLayout = reverseLayout diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt index 313229d4c5..439644b06b 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt @@ -7,6 +7,7 @@ package org.readium.navigator.web import android.annotation.SuppressLint +import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.displayCutout @@ -83,7 +84,13 @@ public fun ReflowableWebRendition( modifier = modifier, state = state.pagerState, beyondViewportPageCount = 2, - reverseLayout = reverseLayout + reverseLayout = reverseLayout, + orientation = + if (state.layoutDelegate.settings.value.scroll) { + Orientation.Vertical + } else { + Orientation.Horizontal + } ) { index -> ReflowableResource( href = state.readingOrder.items[index].href, @@ -91,6 +98,7 @@ public fun ReflowableWebRendition( webViewClient = state.webViewClient, displayArea = displayArea.value, reverseLayout = reverseLayout, + scroll = state.layoutDelegate.settings.value.scroll, rsProperties = state.readiumCss.value.rsProperties, userProperties = state.readiumCss.value.userProperties, onTap = { inputListener.onTap(it, TapContext(viewportSize)) }, diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/NavigatorPager.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/NavigatorPager.kt index 0a3f419cb8..2af2722496 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/NavigatorPager.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/NavigatorPager.kt @@ -12,6 +12,7 @@ import androidx.compose.foundation.pager.PagerDefaults import androidx.compose.foundation.pager.PagerScope import androidx.compose.foundation.pager.PagerSnapDistance import androidx.compose.foundation.pager.PagerState +import androidx.compose.foundation.pager.VerticalPager import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -19,6 +20,7 @@ import androidx.compose.ui.Modifier internal fun NavigatorPager( modifier: Modifier = Modifier, state: PagerState, + orientation: Orientation, reverseLayout: Boolean, beyondViewportPageCount: Int = 2, key: ((index: Int) -> Any)? = null, @@ -29,22 +31,43 @@ internal fun NavigatorPager( pagerSnapDistance = PagerSnapDistance.atMost(0) ) - HorizontalPager( - modifier = modifier, - // Pages must intercept all scroll gestures so the pager moves - // only through the PagerNestedScrollConnection. - userScrollEnabled = false, - state = state, - beyondViewportPageCount = beyondViewportPageCount, - reverseLayout = reverseLayout, - flingBehavior = flingBehavior, - key = key, - pageNestedScrollConnection = - PagerNestedScrollConnection( - state, - flingBehavior, - Orientation.Horizontal - ), - pageContent = pageContent - ) + if (orientation == Orientation.Horizontal) { + HorizontalPager( + modifier = modifier, + // Pages must intercept all scroll gestures so the pager moves + // only through the PagerNestedScrollConnection. + userScrollEnabled = false, + state = state, + beyondViewportPageCount = beyondViewportPageCount, + reverseLayout = reverseLayout, + flingBehavior = flingBehavior, + key = key, + pageNestedScrollConnection = + PagerNestedScrollConnection( + state, + flingBehavior, + Orientation.Horizontal + ), + pageContent = pageContent + ) + } else { + VerticalPager( + modifier = modifier, + // Pages must intercept all scroll gestures so the pager moves + // only through the PagerNestedScrollConnection. + userScrollEnabled = false, + state = state, + beyondViewportPageCount = beyondViewportPageCount, + reverseLayout = reverseLayout, + flingBehavior = flingBehavior, + key = key, + pageNestedScrollConnection = + ScrollPagerNestedScrollConnection( + state, + flingBehavior, + Orientation.Vertical + ), + pageContent = pageContent + ) + } } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollPagerNestedScrollConnection.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollPagerNestedScrollConnection.kt new file mode 100644 index 0000000000..f17edfee15 --- /dev/null +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollPagerNestedScrollConnection.kt @@ -0,0 +1,104 @@ +/* + * Copyright 2024 Readium Foundation. All rights reserved. + * Use of this source code is governed by the BSD-style license + * available in the top-level LICENSE file of the project. + */ + +package org.readium.navigator.web.pager + +import androidx.compose.foundation.MutatePriority +import androidx.compose.foundation.gestures.Orientation +import androidx.compose.foundation.gestures.TargetedFlingBehavior +import androidx.compose.foundation.pager.PagerState +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.input.nestedscroll.NestedScrollConnection +import androidx.compose.ui.input.nestedscroll.NestedScrollSource +import androidx.compose.ui.unit.Velocity +import kotlin.math.abs + +internal class ScrollPagerNestedScrollConnection( + private val state: PagerState, + private val flingBehavior: TargetedFlingBehavior, + private val orientation: Orientation, +) : NestedScrollConnection { + + private val PagerState.firstVisibleOffset get() = + layoutInfo.visiblePagesInfo.first().offset + + private val PagerState.lastVisibleOffset get() = + layoutInfo.visiblePagesInfo.last().offset + + override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { + if (state.layoutInfo.visiblePagesInfo.size <= 1) { + return Offset.Zero + } + + // rounding and drag only + if (source != NestedScrollSource.UserInput || abs(state.currentPageOffsetFraction) < 1e-6) { + return Offset.Zero + } + + val delta = if (orientation == Orientation.Horizontal) available.x else available.y + + val minBound = -(state.layoutInfo.pageSize + state.firstVisibleOffset).toFloat() + + val maxBound = (state.layoutInfo.pageSize - state.lastVisibleOffset).toFloat() + + val coerced = delta.coerceIn(minBound, maxBound) + // dispatch and return reversed as usual + val consumed = -state.dispatchRawDelta(-coerced) + + check(state.layoutInfo.visiblePagesInfo.size == 1 || abs(consumed - available.y) < 1) + return Offset( + x = if (orientation == Orientation.Horizontal) consumed else available.x, + y = if (orientation == Orientation.Vertical) consumed else available.y + ) + } + + override suspend fun onPreFling(available: Velocity): Velocity { + if (state.layoutInfo.visiblePagesInfo.size > 1) { + var remaining: Float = available.y + state.scroll(scrollPriority = MutatePriority.Default) { + with(flingBehavior) { + remaining = -performFling(-available.y) + } + } + + if ((available.y - remaining).isNaN()) { + return available + } + + return Velocity(0f, available.y - remaining) + } + + return Velocity.Zero + } + + override fun onPostScroll( + consumed: Offset, + available: Offset, + source: NestedScrollSource, + ): Offset { + val consumedY = -state.dispatchRawDelta(-available.y) + return Offset(0f, consumedY) + } + + override suspend fun onPostFling( + consumed: Velocity, + available: Velocity, + ): Velocity { + var remaining = available.y + + state.scroll(scrollPriority = MutatePriority.Default) { + with(flingBehavior) { + remaining = -performFling(-available.y) + } + } + + if ((available.y - remaining).isNaN()) { + return available + } + + return Velocity(available.x, available.y - remaining) + } +} diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt index 086070ea1a..915ff93620 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt @@ -62,6 +62,7 @@ internal fun ReflowableResource( webViewClient: WebViewClient, displayArea: DisplayArea, reverseLayout: Boolean, + scroll: Boolean, userProperties: UserProperties, rsProperties: RsProperties, onTap: (TapEvent) -> Unit, @@ -142,24 +143,34 @@ internal fun ReflowableResource( val scrollableState = remember { WebViewScrollable2DState() } val reflowableNestedScrollConnection = - ReflowableNestedScrollConnection(scrollableState) + if (scroll) { + ScrollReflowableNestedScrollConnection(scrollableState) + } else { + ReflowableNestedScrollConnection(scrollableState) + } val density = LocalDensity.current - val flingBehavior = (webViewState.webView as? RelaxedWebView) - ?.let { - pagingFlingBehavior( - WebViewLayoutInfoProvider( - density, - Orientation.Horizontal, - reverseLayout, - displayArea, - scrollableState, - it - ) - ) + val scrollOrientation = if (scroll) Orientation.Vertical else Orientation.Horizontal + + val flingBehavior = + if (scroll) { + null + } else { + (webViewState.webView as? RelaxedWebView) + ?.let { + pagingFlingBehavior( + WebViewLayoutInfoProvider( + density, + scrollOrientation, + reverseLayout, + displayArea, + it + ) + ) + } + ?.toFling2DBehavior(orientation = scrollOrientation) } - ?.toFling2DBehavior(orientation = Orientation.Horizontal) WebView( modifier = Modifier @@ -168,7 +179,7 @@ internal fun ReflowableResource( state = scrollableState, flingBehavior = flingBehavior, reverseDirection = !reverseLayout, - orientation = Orientation.Horizontal + orientation = scrollOrientation ) .fillMaxSize() .nestedScroll(reflowableNestedScrollConnection), @@ -187,14 +198,16 @@ internal fun ReflowableResource( webview.isHorizontalScrollBarEnabled = false webview.setBackgroundColor(backgroundColor.toArgb()) webview.setLayerType(View.LAYER_TYPE_HARDWARE, null) - // Prevents vertical scrolling towards blank space. - // See https://github.com/readium/readium-css/issues/158 - webview.setOnTouchListener(object : View.OnTouchListener { - @SuppressLint("ClickableViewAccessibility") - override fun onTouch(view: View, event: MotionEvent): Boolean { - return (event.action == MotionEvent.ACTION_MOVE) - } - }) + if (!scroll) { + // Prevents vertical scrolling towards blank space. + // See https://github.com/readium/readium-css/issues/158 + webview.setOnTouchListener(object : View.OnTouchListener { + @SuppressLint("ClickableViewAccessibility") + override fun onTouch(view: View, event: MotionEvent): Boolean { + return (event.action == MotionEvent.ACTION_MOVE) + } + }) + } }, onDispose = { scrollableState.webView = null diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ScrollReflowableNestedScrollConnection.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ScrollReflowableNestedScrollConnection.kt new file mode 100644 index 0000000000..19b4cf7d3c --- /dev/null +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ScrollReflowableNestedScrollConnection.kt @@ -0,0 +1,51 @@ +/* + * Copyright 2024 Readium Foundation. All rights reserved. + * Use of this source code is governed by the BSD-style license + * available in the top-level LICENSE file of the project. + */ + +package org.readium.navigator.web.reflowable + +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.input.nestedscroll.NestedScrollConnection +import androidx.compose.ui.input.nestedscroll.NestedScrollSource +import androidx.compose.ui.unit.Velocity +import org.readium.navigator.web.webview.RelaxedWebView +import org.readium.navigator.web.webview.WebViewScrollable2DState + +internal class ScrollReflowableNestedScrollConnection( + private val webviewState: WebViewScrollable2DState, +) : NestedScrollConnection { + + override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { + val webViewNow = webviewState.webView ?: return Offset.Zero + + val webViewCannotScrollVertically = + (webViewNow.scrollY < 3 && available.y > 0) || + ((webViewNow.maxScrollY - webViewNow.scrollY) < 3 && available.y < 0) + + if (webViewCannotScrollVertically) { + snapWebview(webViewNow) + } + + return Offset(0f, available.y) + } + + override suspend fun onPreFling(available: Velocity): Velocity { + return Velocity(available.x, 0f) + } + + override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity { + val webViewNow = webviewState.webView ?: return Velocity.Zero + snapWebview(webViewNow) + return Velocity.Zero + } + + private fun snapWebview(webview: RelaxedWebView) { + if ((webview.maxScrollY - webview.scrollY) < 15) { + webview.scrollTo(webview.scrollX, webview.maxScrollY) + } else if (webview.scrollY in (0 until 15)) { + webview.scrollTo(webview.scrollX, 0) + } + } +} diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/RelaxedWebView.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/RelaxedWebView.kt index bae57fd0f5..fc14b7997e 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/RelaxedWebView.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/RelaxedWebView.kt @@ -26,6 +26,12 @@ internal class RelaxedWebView(context: Context) : WebView(context) { val canScrollLeft: Boolean get() = scrollX > 0 + val canScrollTop: Boolean get() = + scrollY > 0 + + val canScrollBottom: Boolean get() = + scrollY < maxScrollY + val verticalScrollRange: Int get() = computeVerticalScrollRange() diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewLayoutInfoProvider.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewLayoutInfoProvider.kt index 069eaa8f8c..16611487d1 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewLayoutInfoProvider.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewLayoutInfoProvider.kt @@ -14,7 +14,6 @@ internal class WebViewLayoutInfoProvider( override val orientation: Orientation, override val reverseLayout: Boolean, private val displayArea: DisplayArea, - private val webViewScrollState: WebViewScrollable2DState, private val webView: RelaxedWebView, ) : PagingLayoutInfo { @@ -48,10 +47,28 @@ internal class WebViewLayoutInfoProvider( } override val canScrollForward: Boolean - get() = if (reverseLayout) webView.canScrollLeft else webView.canScrollRight + get() = when { + orientation == Orientation.Horizontal && reverseLayout -> + webView.canScrollLeft + orientation == Orientation.Horizontal -> + webView.canScrollRight + orientation == Orientation.Vertical && reverseLayout -> + webView.canScrollTop + else -> + webView.canScrollBottom + } override val canScrollBackward: Boolean - get() = if (reverseLayout) webView.canScrollRight else webView.canScrollLeft + get() = when { + orientation == Orientation.Horizontal && reverseLayout -> + webView.canScrollRight + orientation == Orientation.Horizontal -> + webView.canScrollLeft + orientation == Orientation.Vertical && reverseLayout -> + webView.canScrollBottom + else -> + webView.canScrollTop + } } internal val DefaultPositionThreshold = 56.dp From 52b2a5b0adf545e748b8cfe162f4fd697728f4fc Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Fri, 20 Dec 2024 14:15:13 +0100 Subject: [PATCH 05/88] Fix padding and background color --- .../navigator/common/SelectionController.kt | 37 +++++++++++++++++++ .../navigator/web/ReflowableWebRendition.kt | 34 ++++++++++++++--- .../web/reflowable/ReflowableResource.kt | 4 -- 3 files changed, 66 insertions(+), 9 deletions(-) create mode 100644 readium/navigators/common/src/main/java/org/readium/navigator/common/SelectionController.kt diff --git a/readium/navigators/common/src/main/java/org/readium/navigator/common/SelectionController.kt b/readium/navigators/common/src/main/java/org/readium/navigator/common/SelectionController.kt new file mode 100644 index 0000000000..dd61e3a392 --- /dev/null +++ b/readium/navigators/common/src/main/java/org/readium/navigator/common/SelectionController.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2024 Readium Foundation. All rights reserved. + * Use of this source code is governed by the BSD-style license + * available in the top-level LICENSE file of the project. + */ + +package org.readium.navigator.common + +import androidx.compose.runtime.State +import androidx.compose.ui.unit.DpRect + +/** + * A navigator supporting user selection. + */ +public interface Selectable { + + /** Currently selected content. */ + public suspend fun currentSelection(): State?> + + /** Clears the current selection. */ + public fun clearSelection() +} + +/** + * Represents a user content selection in a navigator. + * + * @param text The user selected text. + * @param rect Frame of the bounding rect for the selection, in the coordinate of the navigator + * view. This is only useful in the context of a VisualNavigator. + */ +public data class Selection( + val text: String, + val rect: DpRect, + val position: S, +) + +public interface SelectionLocation diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt index 439644b06b..b3e2c70641 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt @@ -7,21 +7,26 @@ package org.readium.navigator.web import android.annotation.SuppressLint +import android.content.res.Configuration +import androidx.compose.foundation.background import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.displayCutout import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.material3.MaterialTheme +import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.LayoutDirection +import androidx.compose.ui.unit.dp import kotlinx.coroutines.launch import org.readium.navigator.common.HyperlinkListener import org.readium.navigator.common.HyperlinkLocation @@ -50,7 +55,6 @@ public fun ReflowableWebRendition( state: ReflowableWebRenditionState, modifier: Modifier = Modifier, windowInsets: WindowInsets = WindowInsets.displayCutout, - backgroundColor: Color = MaterialTheme.colorScheme.background, inputListener: InputListener = state.controller ?.let { defaultInputListener(controller = it) } ?: NullInputListener(), @@ -59,8 +63,29 @@ public fun ReflowableWebRendition( ?.let { defaultHyperlinkListener(controller = it) } ?: NullHyperlinkListener(), ) { + val paginatedVerticalPadding = + when (LocalConfiguration.current.orientation) { + Configuration.ORIENTATION_LANDSCAPE -> 20.dp + else -> 40.dp + } + + val verticalPadding = + if (state.layoutDelegate.settings.value.scroll) { + 0.dp + } else { + paginatedVerticalPadding + } + + val backgroundColor = ( + state.layoutDelegate.settings.value.backgroundColor?.int + ?: state.layoutDelegate.settings.value.theme.backgroundColor + ) + BoxWithConstraints( - modifier = Modifier.fillMaxSize(), + modifier = Modifier.fillMaxSize() + .background(Color(backgroundColor)) + .padding(windowInsets.asPaddingValues()) + .padding(vertical = verticalPadding), propagateMinConstraints = true ) { val viewportSize = DpSize(maxWidth, maxHeight) @@ -106,8 +131,7 @@ public fun ReflowableWebRendition( coroutineScope.launch { onLinkActivated(url, outerHtml, state, hyperlinkListener) } - }, - backgroundColor = backgroundColor + } ) } } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt index 915ff93620..adfc422135 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt @@ -22,8 +22,6 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.DpOffset @@ -67,7 +65,6 @@ internal fun ReflowableResource( rsProperties: RsProperties, onTap: (TapEvent) -> Unit, onLinkActivated: (Url, String) -> Unit, - backgroundColor: Color, ) { Box( modifier = Modifier.fillMaxSize(), @@ -196,7 +193,6 @@ internal fun ReflowableResource( webview.settings.useWideViewPort = false webview.isVerticalScrollBarEnabled = false webview.isHorizontalScrollBarEnabled = false - webview.setBackgroundColor(backgroundColor.toArgb()) webview.setLayerType(View.LAYER_TYPE_HARDWARE, null) if (!scroll) { // Prevents vertical scrolling towards blank space. From 2b7e402bf51d9014c799b26b55645e1d4f905d64 Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Fri, 20 Dec 2024 14:40:39 +0100 Subject: [PATCH 06/88] Use FontFamilyDeclarations --- .../web/ReflowableWebNavigatorFactory.kt | 4 +++- .../web/ReflowableWebRenditionState.kt | 17 ++++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebNavigatorFactory.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebNavigatorFactory.kt index 61d9d15f30..7b2deb9fe9 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebNavigatorFactory.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebNavigatorFactory.kt @@ -44,6 +44,7 @@ public class ReflowableWebNavigatorFactory private constructor( public operator fun invoke( application: Application, publication: Publication, + defaults: ReflowableWebDefaults = ReflowableWebDefaults(), ): ReflowableWebNavigatorFactory? { if (!publication.conformsTo(Publication.Profile.EPUB) || publication.metadata.presentation.layout != EpubLayout.REFLOWABLE @@ -99,7 +100,8 @@ public class ReflowableWebNavigatorFactory private constructor( initialLocation = initialLocation ?: ReflowableWebGoLocation( readingOrderItems[0].href ), - container = publication.container + container = publication.container, + fontFamilyDeclarations = emptyList() ) return Try.success(state) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt index b4715c1f23..9d455478cd 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt @@ -20,8 +20,10 @@ import org.readium.navigator.common.Overflow import org.readium.navigator.common.OverflowController import org.readium.navigator.common.RenditionState import org.readium.navigator.common.SettingsController +import org.readium.navigator.web.css.FontFamilyDeclaration import org.readium.navigator.web.css.ReadiumCss import org.readium.navigator.web.css.RsProperties +import org.readium.navigator.web.css.buildFontFamilyDeclaration import org.readium.navigator.web.layout.ReadingOrder import org.readium.navigator.web.location.ReflowableWebGoLocation import org.readium.navigator.web.location.ReflowableWebLocation @@ -34,6 +36,7 @@ import org.readium.navigator.web.util.WebViewServer.Companion.assetsBaseHref import org.readium.navigator.web.util.injectHtmlReflowable import org.readium.r2.navigator.SimpleOverflow import org.readium.r2.navigator.preferences.Axis +import org.readium.r2.navigator.preferences.FontFamily import org.readium.r2.shared.ExperimentalReadiumApi import org.readium.r2.shared.InternalReadiumApi import org.readium.r2.shared.util.RelativeUrl @@ -53,6 +56,7 @@ public class ReflowableWebRenditionState internal constructor( initialSettings: ReflowableWebSettings, initialLocation: ReflowableWebGoLocation, private val rsProperties: RsProperties = RsProperties(), + fontFamilyDeclarations: List, ) : RenditionState { private val navigatorState: MutableState = @@ -69,12 +73,23 @@ public class ReflowableWebRenditionState internal constructor( internal val hyperlinkProcessor = HyperlinkProcessor(container) + private val fontFamilyDeclarations = fontFamilyDeclarations + + buildFontFamilyDeclaration( + fontFamily = FontFamily.OPEN_DYSLEXIC.name, + alternates = emptyList() + ) { + addFontFace { + addSource("readium/fonts/OpenDyslexic-Regular.otf") + } + } + internal val readiumCss: State = derivedStateOf { ReadiumCss( assetsBaseHref = assetsBaseHref, readiumCssAssets = RelativeUrl("readium/navigators/web/generated/readium-css/")!!, - rsProperties = rsProperties + rsProperties = rsProperties, + fontFamilyDeclarations = fontFamilyDeclarations ).update( settings = layoutDelegate.settings.value, useReadiumCssFontSize = true From 865d806b4848fee3db61c812d873671c807303b1 Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Fri, 20 Dec 2024 17:03:51 +0100 Subject: [PATCH 07/88] Invalidates Webview when stylesheet to inject has changed --- .../navigator/web/ReflowableWebRendition.kt | 9 +- .../web/ReflowableWebRenditionState.kt | 27 +++--- .../readium/navigator/web/css/Properties.kt | 3 + .../readium/navigator/web/css/ReadiumCss.kt | 85 ++++++++++++++++++ .../web/preferences/ReflowableWebSettings.kt | 88 ------------------ .../web/reflowable/ReflowableResource.kt | 90 ++++++++++--------- 6 files changed, 158 insertions(+), 144 deletions(-) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt index b3e2c70641..3b12cd44db 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt @@ -112,10 +112,14 @@ public fun ReflowableWebRendition( reverseLayout = reverseLayout, orientation = if (state.layoutDelegate.settings.value.scroll) { - Orientation.Vertical + if (state.layoutDelegate.settings.value.verticalText) { + Orientation.Horizontal + } else { + Orientation.Vertical + } } else { Orientation.Horizontal - } + }, ) { index -> ReflowableResource( href = state.readingOrder.items[index].href, @@ -126,6 +130,7 @@ public fun ReflowableWebRendition( scroll = state.layoutDelegate.settings.value.scroll, rsProperties = state.readiumCss.value.rsProperties, userProperties = state.readiumCss.value.userProperties, + layout = state.readiumCss.value.layout, onTap = { inputListener.onTap(it, TapContext(viewportSize)) }, onLinkActivated = { url, outerHtml -> coroutineScope.launch { diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt index 9d455478cd..672cc692cb 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt @@ -24,11 +24,11 @@ import org.readium.navigator.web.css.FontFamilyDeclaration import org.readium.navigator.web.css.ReadiumCss import org.readium.navigator.web.css.RsProperties import org.readium.navigator.web.css.buildFontFamilyDeclaration +import org.readium.navigator.web.css.update import org.readium.navigator.web.layout.ReadingOrder import org.readium.navigator.web.location.ReflowableWebGoLocation import org.readium.navigator.web.location.ReflowableWebLocation import org.readium.navigator.web.preferences.ReflowableWebSettings -import org.readium.navigator.web.preferences.update import org.readium.navigator.web.util.HyperlinkProcessor import org.readium.navigator.web.util.WebViewClient import org.readium.navigator.web.util.WebViewServer @@ -73,23 +73,26 @@ public class ReflowableWebRenditionState internal constructor( internal val hyperlinkProcessor = HyperlinkProcessor(container) - private val fontFamilyDeclarations = fontFamilyDeclarations + - buildFontFamilyDeclaration( - fontFamily = FontFamily.OPEN_DYSLEXIC.name, - alternates = emptyList() - ) { - addFontFace { - addSource("readium/fonts/OpenDyslexic-Regular.otf") - } - } - internal val readiumCss: State = derivedStateOf { ReadiumCss( assetsBaseHref = assetsBaseHref, readiumCssAssets = RelativeUrl("readium/navigators/web/generated/readium-css/")!!, rsProperties = rsProperties, - fontFamilyDeclarations = fontFamilyDeclarations + fontFamilyDeclarations = + buildList { + addAll(fontFamilyDeclarations) + add( + buildFontFamilyDeclaration( + fontFamily = FontFamily.OPEN_DYSLEXIC.name, + alternates = emptyList() + ) { + addFontFace { + addSource("readium/fonts/OpenDyslexic-Regular.otf") + } + } + ) + } ).update( settings = layoutDelegate.settings.value, useReadiumCssFontSize = true diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/Properties.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/Properties.kt index 06098b6082..8ccdb2242f 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/Properties.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/Properties.kt @@ -275,6 +275,9 @@ public data class RsProperties( ) : Properties { override fun toCssProperties(): Map = buildMap { + // Properties not exposed through RsProperties + putCss("--RS__disablePagination", flag("noVerticalPagination", true)) + // Pagination putCss("--RS__colWidth", colWidth) putCss("--RS__colCount", colCount) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCss.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCss.kt index da79008eca..a90db9c7f1 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCss.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCss.kt @@ -10,10 +10,19 @@ import android.net.Uri import org.jsoup.Jsoup import org.jsoup.nodes.Document import org.jsoup.nodes.Element +import org.readium.navigator.web.css.Color as CssColor +import org.readium.navigator.web.css.TextAlign as CssTextAlign +import org.readium.navigator.web.preferences.ReflowableWebSettings +import org.readium.r2.navigator.preferences.Color import org.readium.r2.navigator.preferences.FontFamily +import org.readium.r2.navigator.preferences.ImageFilter import org.readium.r2.navigator.preferences.ReadingProgression +import org.readium.r2.navigator.preferences.TextAlign +import org.readium.r2.navigator.preferences.Theme import org.readium.r2.shared.ExperimentalReadiumApi import org.readium.r2.shared.util.AbsoluteUrl +import org.readium.r2.shared.util.Either +import org.readium.r2.shared.util.Either.Companion.invoke import org.readium.r2.shared.util.RelativeUrl import org.readium.r2.shared.util.Url @@ -266,3 +275,79 @@ private val dirRegex = Regex( """(<(?:html|body)[^\>]*)\s+dir=[\"']\w*[\"']""", setOf(RegexOption.IGNORE_CASE, RegexOption.MULTILINE) ) + +@OptIn(ExperimentalReadiumApi::class) +internal fun ReadiumCss.update(settings: ReflowableWebSettings, useReadiumCssFontSize: Boolean): ReadiumCss { + fun resolveFontStack(fontFamily: String): List = buildList { + add(fontFamily) + + val alternates = fontFamilyDeclarations + .firstOrNull { it.fontFamily == fontFamily } + ?.alternates + ?: emptyList() + + addAll(alternates.flatMap(::resolveFontStack)) + } + + fun FontFamily.toCss(): List = + resolveFontStack(name) + + fun Color.toCss(): CssColor = + CssColor.Int(int) + + return with(settings) { + copy( + layout = Layout.from(settings), + rsProperties = rsProperties.copy( + pageGutter = Length.Px((rsProperties.pageGutter?.value ?: 20.0) * pageMargins) + ), + userProperties = userProperties.copy( + view = when (scroll) { + false -> View.PAGED + true -> View.SCROLL + }, + colCount = columnCount, + appearance = when (theme) { + Theme.LIGHT -> null + Theme.DARK -> Appearance.NIGHT + Theme.SEPIA -> Appearance.SEPIA + }, + darkenImages = imageFilter == ImageFilter.DARKEN, + invertImages = imageFilter == ImageFilter.INVERT, + textColor = textColor?.toCss(), + backgroundColor = backgroundColor?.toCss(), + fontOverride = (fontFamily != null || textNormalization), + fontFamily = fontFamily?.toCss(), + fontSize = if (useReadiumCssFontSize) { + Length.Percent(fontSize) + } else { + null + }, + advancedSettings = !publisherStyles, + textAlign = when (textAlign) { + TextAlign.JUSTIFY -> CssTextAlign.JUSTIFY + TextAlign.LEFT -> CssTextAlign.LEFT + TextAlign.RIGHT -> CssTextAlign.RIGHT + TextAlign.START, TextAlign.CENTER, TextAlign.END -> CssTextAlign.START + null -> null + }, + lineHeight = lineHeight?.let { Either(it) }, + paraSpacing = paragraphSpacing?.let { Length.Rem(it) }, + paraIndent = paragraphIndent?.let { Length.Rem(it) }, + wordSpacing = wordSpacing?.let { Length.Rem(it) }, + letterSpacing = letterSpacing?.let { Length.Rem(it / 2) }, + bodyHyphens = hyphens?.let { if (it) Hyphens.AUTO else Hyphens.NONE }, + ligatures = ligatures?.let { if (it) Ligatures.COMMON else Ligatures.NONE }, + a11yNormalize = textNormalization, + overrides = mapOf( + "font-weight" to + if (fontWeight != null) { + (FontWeight.NORMAL.value * fontWeight).toInt().coerceIn(1, 1000).toString() + } else { + "" + } + ) + ) + ) + } +} diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettings.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettings.kt index df2f0bed80..f67babf567 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettings.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettings.kt @@ -6,16 +6,6 @@ package org.readium.navigator.web.preferences -import org.readium.navigator.web.css.Appearance -import org.readium.navigator.web.css.Color as CssColor -import org.readium.navigator.web.css.FontWeight -import org.readium.navigator.web.css.Hyphens -import org.readium.navigator.web.css.Layout -import org.readium.navigator.web.css.Length -import org.readium.navigator.web.css.Ligatures -import org.readium.navigator.web.css.ReadiumCss -import org.readium.navigator.web.css.TextAlign as CssTextAlign -import org.readium.navigator.web.css.View import org.readium.r2.navigator.preferences.Color import org.readium.r2.navigator.preferences.Configurable import org.readium.r2.navigator.preferences.FontFamily @@ -25,8 +15,6 @@ import org.readium.r2.navigator.preferences.Spread import org.readium.r2.navigator.preferences.TextAlign import org.readium.r2.navigator.preferences.Theme import org.readium.r2.shared.ExperimentalReadiumApi -import org.readium.r2.shared.util.Either -import org.readium.r2.shared.util.Either.Companion.invoke import org.readium.r2.shared.util.Language @ExperimentalReadiumApi @@ -56,79 +44,3 @@ public data class ReflowableWebSettings( val verticalText: Boolean, val wordSpacing: Double?, ) : Configurable.Settings - -@OptIn(ExperimentalReadiumApi::class) -internal fun ReadiumCss.update(settings: ReflowableWebSettings, useReadiumCssFontSize: Boolean): ReadiumCss { - fun resolveFontStack(fontFamily: String): List = buildList { - add(fontFamily) - - val alternates = fontFamilyDeclarations - .firstOrNull { it.fontFamily == fontFamily } - ?.alternates - ?: emptyList() - - addAll(alternates.flatMap(::resolveFontStack)) - } - - fun FontFamily.toCss(): List = - resolveFontStack(name) - - fun Color.toCss(): CssColor = - CssColor.Int(int) - - return with(settings) { - copy( - layout = Layout.from(settings), - rsProperties = rsProperties.copy( - pageGutter = Length.Px((rsProperties.pageGutter?.value ?: 20.0) * pageMargins) - ), - userProperties = userProperties.copy( - view = when (scroll) { - false -> View.PAGED - true -> View.SCROLL - }, - colCount = columnCount, - appearance = when (theme) { - Theme.LIGHT -> null - Theme.DARK -> Appearance.NIGHT - Theme.SEPIA -> Appearance.SEPIA - }, - darkenImages = imageFilter == ImageFilter.DARKEN, - invertImages = imageFilter == ImageFilter.INVERT, - textColor = textColor?.toCss(), - backgroundColor = backgroundColor?.toCss(), - fontOverride = (fontFamily != null || textNormalization), - fontFamily = fontFamily?.toCss(), - fontSize = if (useReadiumCssFontSize) { - Length.Percent(fontSize) - } else { - null - }, - advancedSettings = !publisherStyles, - textAlign = when (textAlign) { - TextAlign.JUSTIFY -> CssTextAlign.JUSTIFY - TextAlign.LEFT -> CssTextAlign.LEFT - TextAlign.RIGHT -> CssTextAlign.RIGHT - TextAlign.START, TextAlign.CENTER, TextAlign.END -> CssTextAlign.START - null -> null - }, - lineHeight = lineHeight?.let { Either(it) }, - paraSpacing = paragraphSpacing?.let { Length.Rem(it) }, - paraIndent = paragraphIndent?.let { Length.Rem(it) }, - wordSpacing = wordSpacing?.let { Length.Rem(it) }, - letterSpacing = letterSpacing?.let { Length.Rem(it / 2) }, - bodyHyphens = hyphens?.let { if (it) Hyphens.AUTO else Hyphens.NONE }, - ligatures = ligatures?.let { if (it) Ligatures.COMMON else Ligatures.NONE }, - a11yNormalize = textNormalization, - overrides = mapOf( - "font-weight" to - if (fontWeight != null) { - (FontWeight.NORMAL.value * fontWeight).toInt().coerceIn(1, 1000).toString() - } else { - "" - } - ) - ) - ) - } -} diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt index adfc422135..84eb0093ff 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt @@ -18,6 +18,7 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.key import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier @@ -31,6 +32,7 @@ import androidx.webkit.WebViewCompat import androidx.webkit.WebViewFeature import kotlin.Float import org.readium.navigator.common.TapEvent +import org.readium.navigator.web.css.Layout import org.readium.navigator.web.css.RsProperties import org.readium.navigator.web.css.UserProperties import org.readium.navigator.web.gestures.Fling2DBehavior @@ -63,6 +65,7 @@ internal fun ReflowableResource( scroll: Boolean, userProperties: UserProperties, rsProperties: RsProperties, + layout: Layout, onTap: (TapEvent) -> Unit, onLinkActivated: (Url, String) -> Unit, ) { @@ -70,9 +73,10 @@ internal fun ReflowableResource( modifier = Modifier.fillMaxSize(), propagateMinConstraints = true ) { - val webViewState = rememberWebViewState( - url = publicationBaseUrl.resolve(href).toString() - ) + val webViewState = + rememberWebViewState( + url = publicationBaseUrl.resolve(href).toString() + ) val scriptsLoaded = remember(webViewState.webView) { mutableStateOf(false) @@ -169,46 +173,48 @@ internal fun ReflowableResource( ?.toFling2DBehavior(orientation = scrollOrientation) } - WebView( - modifier = Modifier - .scrollable2D( - enabled = contentIsLaidOut.value, - state = scrollableState, - flingBehavior = flingBehavior, - reverseDirection = !reverseLayout, - orientation = scrollOrientation - ) - .fillMaxSize() - .nestedScroll(reflowableNestedScrollConnection), - state = webViewState, - factory = { RelaxedWebView(it) }, - client = webViewClient, - onCreated = { webview -> - scrollableState.webView = webview - webview.settings.javaScriptEnabled = true - webview.settings.setSupportZoom(false) - webview.settings.builtInZoomControls = false - webview.settings.displayZoomControls = false - webview.settings.loadWithOverviewMode = false - webview.settings.useWideViewPort = false - webview.isVerticalScrollBarEnabled = false - webview.isHorizontalScrollBarEnabled = false - webview.setLayerType(View.LAYER_TYPE_HARDWARE, null) - if (!scroll) { - // Prevents vertical scrolling towards blank space. - // See https://github.com/readium/readium-css/issues/158 - webview.setOnTouchListener(object : View.OnTouchListener { - @SuppressLint("ClickableViewAccessibility") - override fun onTouch(view: View, event: MotionEvent): Boolean { - return (event.action == MotionEvent.ACTION_MOVE) - } - }) + key(layout) { + WebView( + modifier = Modifier + .scrollable2D( + enabled = contentIsLaidOut.value, + state = scrollableState, + flingBehavior = flingBehavior, + reverseDirection = !reverseLayout, + orientation = scrollOrientation + ) + .fillMaxSize() + .nestedScroll(reflowableNestedScrollConnection), + state = webViewState, + factory = { RelaxedWebView(it) }, + client = webViewClient, + onCreated = { webview -> + scrollableState.webView = webview + webview.settings.javaScriptEnabled = true + webview.settings.setSupportZoom(false) + webview.settings.builtInZoomControls = false + webview.settings.displayZoomControls = false + webview.settings.loadWithOverviewMode = false + webview.settings.useWideViewPort = false + webview.isVerticalScrollBarEnabled = false + webview.isHorizontalScrollBarEnabled = false + webview.setLayerType(View.LAYER_TYPE_HARDWARE, null) + if (!scroll) { + // Prevents vertical scrolling towards blank space. + // See https://github.com/readium/readium-css/issues/158 + webview.setOnTouchListener(object : View.OnTouchListener { + @SuppressLint("ClickableViewAccessibility") + override fun onTouch(view: View, event: MotionEvent): Boolean { + return (event.action == MotionEvent.ACTION_MOVE) + } + }) + } + }, + onDispose = { + scrollableState.webView = null } - }, - onDispose = { - scrollableState.webView = null - } - ) + ) + } } } From 54b0c274d9099003807ab37774a66d775388a32e Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Fri, 20 Dec 2024 18:48:57 +0100 Subject: [PATCH 08/88] Fix scroll with vertical writings --- .../navigator/web/ReflowableWebRendition.kt | 39 ++++---------- .../navigator/web/pager/NavigatorPager.kt | 2 +- ...> PaginatedPagerNestedScrollConnection.kt} | 2 +- .../ScrollPagerNestedScrollConnection.kt | 53 +++++++++++++------ ...inatedReflowableNestedScrollConnection.kt} | 2 +- .../web/reflowable/ReflowableResource.kt | 26 +++++---- .../web/snapping/PagingFlingBehavior.kt | 16 ++++++ .../web/webview/WebViewLayoutInfoProvider.kt | 6 +-- 8 files changed, 84 insertions(+), 62 deletions(-) rename readium/navigators/web/src/main/java/org/readium/navigator/web/pager/{PagerNestedScrollConnection.kt => PaginatedPagerNestedScrollConnection.kt} (98%) rename readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/{ReflowableNestedScrollConnection.kt => PaginatedReflowableNestedScrollConnection.kt} (97%) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt index 3b12cd44db..addd74f3e5 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt @@ -22,7 +22,6 @@ import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalConfiguration -import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.LayoutDirection @@ -39,8 +38,6 @@ import org.readium.navigator.common.defaultInputListener import org.readium.navigator.web.location.ReflowableWebLocation import org.readium.navigator.web.pager.NavigatorPager import org.readium.navigator.web.reflowable.ReflowableResource -import org.readium.navigator.web.util.AbsolutePaddingValues -import org.readium.navigator.web.util.DisplayArea import org.readium.navigator.web.util.WebViewServer import org.readium.r2.navigator.preferences.ReadingProgression import org.readium.r2.shared.ExperimentalReadiumApi @@ -88,10 +85,7 @@ public fun ReflowableWebRendition( .padding(vertical = verticalPadding), propagateMinConstraints = true ) { - val viewportSize = DpSize(maxWidth, maxHeight) - - val safeDrawingPadding = windowInsets.asAbsolutePaddingValues() - val displayArea = rememberUpdatedState(DisplayArea(viewportSize, safeDrawingPadding)) + val viewportSize = rememberUpdatedState(DpSize(maxWidth, maxHeight)) val readingProgression = state.layoutDelegate.settings.value.readingProgression @@ -110,28 +104,24 @@ public fun ReflowableWebRendition( state = state.pagerState, beyondViewportPageCount = 2, reverseLayout = reverseLayout, - orientation = - if (state.layoutDelegate.settings.value.scroll) { - if (state.layoutDelegate.settings.value.verticalText) { - Orientation.Horizontal - } else { - Orientation.Vertical - } - } else { - Orientation.Horizontal - }, + orientation = when { + state.layoutDelegate.settings.value.verticalText -> Orientation.Horizontal + state.layoutDelegate.settings.value.scroll -> Orientation.Vertical + else -> Orientation.Horizontal + } ) { index -> ReflowableResource( href = state.readingOrder.items[index].href, publicationBaseUrl = WebViewServer.publicationBaseHref, webViewClient = state.webViewClient, - displayArea = displayArea.value, + viewportSize = viewportSize.value, reverseLayout = reverseLayout, scroll = state.layoutDelegate.settings.value.scroll, + verticalText = state.layoutDelegate.settings.value.verticalText, rsProperties = state.readiumCss.value.rsProperties, userProperties = state.readiumCss.value.userProperties, layout = state.readiumCss.value.layout, - onTap = { inputListener.onTap(it, TapContext(viewportSize)) }, + onTap = { inputListener.onTap(it, TapContext(viewportSize.value)) }, onLinkActivated = { url, outerHtml -> coroutineScope.launch { onLinkActivated(url, outerHtml, state, hyperlinkListener) @@ -142,17 +132,6 @@ public fun ReflowableWebRendition( } } -@Composable -private fun WindowInsets.asAbsolutePaddingValues(): AbsolutePaddingValues { - val density = LocalDensity.current - val layoutDirection = LocalLayoutDirection.current - val top = with(density) { getTop(density).toDp() } - val right = with(density) { getRight(density, layoutDirection).toDp() } - val bottom = with(density) { getBottom(density).toDp() } - val left = with(density) { getLeft(density, layoutDirection).toDp() } - return AbsolutePaddingValues(top = top, right = right, bottom = bottom, left = left) -} - private fun LayoutDirection.toReadingProgression(): ReadingProgression = when (this) { LayoutDirection.Ltr -> ReadingProgression.LTR diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/NavigatorPager.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/NavigatorPager.kt index 2af2722496..4afb67c5eb 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/NavigatorPager.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/NavigatorPager.kt @@ -43,7 +43,7 @@ internal fun NavigatorPager( flingBehavior = flingBehavior, key = key, pageNestedScrollConnection = - PagerNestedScrollConnection( + PaginatedPagerNestedScrollConnection( state, flingBehavior, Orientation.Horizontal diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/PagerNestedScrollConnection.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/PaginatedPagerNestedScrollConnection.kt similarity index 98% rename from readium/navigators/web/src/main/java/org/readium/navigator/web/pager/PagerNestedScrollConnection.kt rename to readium/navigators/web/src/main/java/org/readium/navigator/web/pager/PaginatedPagerNestedScrollConnection.kt index b5c1cb239a..b6483ceea7 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/PagerNestedScrollConnection.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/PaginatedPagerNestedScrollConnection.kt @@ -16,7 +16,7 @@ import androidx.compose.ui.input.nestedscroll.NestedScrollSource import androidx.compose.ui.unit.Velocity import kotlin.math.abs -internal class PagerNestedScrollConnection( +internal class PaginatedPagerNestedScrollConnection( private val state: PagerState, private val flingBehavior: TargetedFlingBehavior, private val orientation: Orientation, diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollPagerNestedScrollConnection.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollPagerNestedScrollConnection.kt index f17edfee15..6024c073cf 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollPagerNestedScrollConnection.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollPagerNestedScrollConnection.kt @@ -48,7 +48,6 @@ internal class ScrollPagerNestedScrollConnection( // dispatch and return reversed as usual val consumed = -state.dispatchRawDelta(-coerced) - check(state.layoutInfo.visiblePagesInfo.size == 1 || abs(consumed - available.y) < 1) return Offset( x = if (orientation == Orientation.Horizontal) consumed else available.x, y = if (orientation == Orientation.Vertical) consumed else available.y @@ -57,18 +56,27 @@ internal class ScrollPagerNestedScrollConnection( override suspend fun onPreFling(available: Velocity): Velocity { if (state.layoutInfo.visiblePagesInfo.size > 1) { - var remaining: Float = available.y + val availableDir = + if (orientation == Orientation.Horizontal) available.x else available.y + + var remaining: Float = availableDir state.scroll(scrollPriority = MutatePriority.Default) { with(flingBehavior) { - remaining = -performFling(-available.y) + remaining = -performFling(-availableDir) } } - if ((available.y - remaining).isNaN()) { - return available - } + val consumed = + if ((availableDir - remaining).isNaN()) { + availableDir + } else { + availableDir - remaining + } - return Velocity(0f, available.y - remaining) + return Velocity( + x = if (orientation == Orientation.Horizontal) consumed else 0f, + y = if (orientation == Orientation.Vertical) consumed else 0f + ) } return Velocity.Zero @@ -79,26 +87,41 @@ internal class ScrollPagerNestedScrollConnection( available: Offset, source: NestedScrollSource, ): Offset { - val consumedY = -state.dispatchRawDelta(-available.y) - return Offset(0f, consumedY) + val availableDir = + if (orientation == Orientation.Horizontal) available.x else available.y + + val consumed = -state.dispatchRawDelta(-availableDir) + return Offset( + x = if (orientation == Orientation.Horizontal) consumed else 0f, + y = if (orientation == Orientation.Vertical) consumed else 0f + ) } override suspend fun onPostFling( consumed: Velocity, available: Velocity, ): Velocity { - var remaining = available.y + val availableDir = + if (orientation == Orientation.Horizontal) available.x else available.y + + var remaining = availableDir state.scroll(scrollPriority = MutatePriority.Default) { with(flingBehavior) { - remaining = -performFling(-available.y) + remaining = -performFling(-availableDir) } } - if ((available.y - remaining).isNaN()) { - return available - } + val consumed = + if ((availableDir - remaining).isNaN()) { + availableDir + } else { + availableDir - remaining + } - return Velocity(available.x, available.y - remaining) + return Velocity( + x = if (orientation == Orientation.Horizontal) consumed else available.x, + y = if (orientation == Orientation.Vertical) consumed else available.y + ) } } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableNestedScrollConnection.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/PaginatedReflowableNestedScrollConnection.kt similarity index 97% rename from readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableNestedScrollConnection.kt rename to readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/PaginatedReflowableNestedScrollConnection.kt index 5405cfccac..67ade2f5a3 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableNestedScrollConnection.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/PaginatedReflowableNestedScrollConnection.kt @@ -13,7 +13,7 @@ import androidx.compose.ui.unit.Velocity import org.readium.navigator.web.webview.RelaxedWebView import org.readium.navigator.web.webview.WebViewScrollable2DState -internal class ReflowableNestedScrollConnection( +internal class PaginatedReflowableNestedScrollConnection( private val webviewState: WebViewScrollable2DState, ) : NestedScrollConnection { diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt index 84eb0093ff..d30a62c0a0 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt @@ -26,6 +26,7 @@ import androidx.compose.ui.geometry.Offset import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.DpOffset +import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.Velocity import androidx.core.view.postDelayed import androidx.webkit.WebViewCompat @@ -38,7 +39,6 @@ import org.readium.navigator.web.css.UserProperties import org.readium.navigator.web.gestures.Fling2DBehavior import org.readium.navigator.web.gestures.Scroll2DScope import org.readium.navigator.web.gestures.scrollable2D -import org.readium.navigator.web.util.DisplayArea import org.readium.navigator.web.util.WebViewClient import org.readium.navigator.web.webapi.CssApi import org.readium.navigator.web.webapi.GesturesApi @@ -60,9 +60,10 @@ internal fun ReflowableResource( href: Url, publicationBaseUrl: AbsoluteUrl, webViewClient: WebViewClient, - displayArea: DisplayArea, + viewportSize: DpSize, reverseLayout: Boolean, scroll: Boolean, + verticalText: Boolean, userProperties: UserProperties, rsProperties: RsProperties, layout: Layout, @@ -143,16 +144,19 @@ internal fun ReflowableResource( val scrollableState = remember { WebViewScrollable2DState() } - val reflowableNestedScrollConnection = - if (scroll) { - ScrollReflowableNestedScrollConnection(scrollableState) - } else { - ReflowableNestedScrollConnection(scrollableState) - } + val reflowableNestedScrollConnection = when { + verticalText -> PaginatedReflowableNestedScrollConnection(scrollableState) + scroll -> ScrollReflowableNestedScrollConnection(scrollableState) + else -> PaginatedReflowableNestedScrollConnection(scrollableState) + } val density = LocalDensity.current - val scrollOrientation = if (scroll) Orientation.Vertical else Orientation.Horizontal + val scrollOrientation = when { + verticalText -> Orientation.Horizontal + scroll -> Orientation.Vertical + else -> Orientation.Horizontal + } val flingBehavior = if (scroll) { @@ -165,7 +169,7 @@ internal fun ReflowableResource( density, scrollOrientation, reverseLayout, - displayArea, + viewportSize, it ) ) @@ -199,7 +203,7 @@ internal fun ReflowableResource( webview.isVerticalScrollBarEnabled = false webview.isHorizontalScrollBarEnabled = false webview.setLayerType(View.LAYER_TYPE_HARDWARE, null) - if (!scroll) { + if (verticalText || !scroll) { // Prevents vertical scrolling towards blank space. // See https://github.com/readium/readium-css/issues/158 webview.setOnTouchListener(object : View.OnTouchListener { diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/PagingFlingBehavior.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/PagingFlingBehavior.kt index 281d528ddd..2cc329ed3c 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/PagingFlingBehavior.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/PagingFlingBehavior.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + import androidx.annotation.FloatRange import androidx.compose.animation.core.AnimationSpec import androidx.compose.animation.core.DecayAnimationSpec diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewLayoutInfoProvider.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewLayoutInfoProvider.kt index 16611487d1..ae6ca29537 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewLayoutInfoProvider.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewLayoutInfoProvider.kt @@ -3,17 +3,17 @@ package org.readium.navigator.web.webview import androidx.compose.foundation.gestures.Orientation import androidx.compose.ui.geometry.Offset import androidx.compose.ui.unit.Density +import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp import kotlin.math.ceil import kotlin.math.roundToInt import org.readium.navigator.web.snapping.PagingLayoutInfo -import org.readium.navigator.web.util.DisplayArea internal class WebViewLayoutInfoProvider( override val density: Density, override val orientation: Orientation, override val reverseLayout: Boolean, - private val displayArea: DisplayArea, + private val viewportSize: DpSize, private val webView: RelaxedWebView, ) : PagingLayoutInfo { @@ -24,7 +24,7 @@ internal class WebViewLayoutInfoProvider( } override val pageSize: Int = - with(density) { displayArea.viewportSize.width.toPx().roundToInt() } + with(density) { viewportSize.width.toPx().roundToInt() } override val pageSpacing: Int = 0 From c50feead227124869d70c9e93ea19bfbaf7ed9bd Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Fri, 20 Dec 2024 20:28:26 +0100 Subject: [PATCH 09/88] Factorise nested scroll connections --- .../navigator/web/FixedWebRendition.kt | 4 +- .../navigator/web/ReflowableWebRendition.kt | 4 +- ...tion.kt => PagerNestedScrollConnection.kt} | 18 ++- .../PaginatedPagerNestedScrollConnection.kt | 113 ------------------ .../{NavigatorPager.kt => RenditionPager.kt} | 22 ++-- ...ginatedReflowableNestedScrollConnection.kt | 52 -------- .../web/reflowable/ReflowableResource.kt | 10 +- .../ScrollReflowableNestedScrollConnection.kt | 51 -------- 8 files changed, 29 insertions(+), 245 deletions(-) rename readium/navigators/web/src/main/java/org/readium/navigator/web/pager/{ScrollPagerNestedScrollConnection.kt => PagerNestedScrollConnection.kt} (90%) delete mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/pager/PaginatedPagerNestedScrollConnection.kt rename readium/navigators/web/src/main/java/org/readium/navigator/web/pager/{NavigatorPager.kt => RenditionPager.kt} (83%) delete mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/PaginatedReflowableNestedScrollConnection.kt delete mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ScrollReflowableNestedScrollConnection.kt diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt index 61cd58f19b..bbed050665 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt @@ -39,7 +39,7 @@ import org.readium.navigator.web.fixed.SingleViewportSpread import org.readium.navigator.web.layout.DoubleViewportSpread import org.readium.navigator.web.layout.SingleViewportSpread import org.readium.navigator.web.location.FixedWebLocation -import org.readium.navigator.web.pager.NavigatorPager +import org.readium.navigator.web.pager.RenditionPager import org.readium.navigator.web.util.AbsolutePaddingValues import org.readium.navigator.web.util.DisplayArea import org.readium.navigator.web.util.WebViewServer @@ -90,7 +90,7 @@ public fun FixedWebRendition( val coroutineScope = rememberCoroutineScope() - NavigatorPager( + RenditionPager( modifier = modifier, state = state.pagerState, orientation = Orientation.Horizontal, diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt index addd74f3e5..b8977506eb 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt @@ -36,7 +36,7 @@ import org.readium.navigator.common.TapContext import org.readium.navigator.common.defaultHyperlinkListener import org.readium.navigator.common.defaultInputListener import org.readium.navigator.web.location.ReflowableWebLocation -import org.readium.navigator.web.pager.NavigatorPager +import org.readium.navigator.web.pager.RenditionPager import org.readium.navigator.web.reflowable.ReflowableResource import org.readium.navigator.web.util.WebViewServer import org.readium.r2.navigator.preferences.ReadingProgression @@ -99,7 +99,7 @@ public fun ReflowableWebRendition( val coroutineScope = rememberCoroutineScope() - NavigatorPager( + RenditionPager( modifier = modifier, state = state.pagerState, beyondViewportPageCount = 2, diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollPagerNestedScrollConnection.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/PagerNestedScrollConnection.kt similarity index 90% rename from readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollPagerNestedScrollConnection.kt rename to readium/navigators/web/src/main/java/org/readium/navigator/web/pager/PagerNestedScrollConnection.kt index 6024c073cf..d1722adfa1 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollPagerNestedScrollConnection.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/PagerNestedScrollConnection.kt @@ -16,12 +16,14 @@ import androidx.compose.ui.input.nestedscroll.NestedScrollSource import androidx.compose.ui.unit.Velocity import kotlin.math.abs -internal class ScrollPagerNestedScrollConnection( +internal class PagerNestedScrollConnection( private val state: PagerState, private val flingBehavior: TargetedFlingBehavior, private val orientation: Orientation, ) : NestedScrollConnection { + private var consumedCrossAxis = false + private val PagerState.firstVisibleOffset get() = layoutInfo.visiblePagesInfo.first().offset @@ -45,7 +47,6 @@ internal class ScrollPagerNestedScrollConnection( val maxBound = (state.layoutInfo.pageSize - state.lastVisibleOffset).toFloat() val coerced = delta.coerceIn(minBound, maxBound) - // dispatch and return reversed as usual val consumed = -state.dispatchRawDelta(-coerced) return Offset( @@ -87,6 +88,13 @@ internal class ScrollPagerNestedScrollConnection( available: Offset, source: NestedScrollSource, ): Offset { + if (orientation == Orientation.Horizontal && abs(consumed.y) > 0 || + orientation == Orientation.Vertical && abs(consumed.x) > 0 + ) { + consumedCrossAxis = true + return Offset.Zero + } + val availableDir = if (orientation == Orientation.Horizontal) available.x else available.y @@ -101,11 +109,15 @@ internal class ScrollPagerNestedScrollConnection( consumed: Velocity, available: Velocity, ): Velocity { + if (consumedCrossAxis) { + consumedCrossAxis = false + return Velocity.Zero + } + val availableDir = if (orientation == Orientation.Horizontal) available.x else available.y var remaining = availableDir - state.scroll(scrollPriority = MutatePriority.Default) { with(flingBehavior) { remaining = -performFling(-availableDir) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/PaginatedPagerNestedScrollConnection.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/PaginatedPagerNestedScrollConnection.kt deleted file mode 100644 index b6483ceea7..0000000000 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/PaginatedPagerNestedScrollConnection.kt +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2024 Readium Foundation. All rights reserved. - * Use of this source code is governed by the BSD-style license - * available in the top-level LICENSE file of the project. - */ - -package org.readium.navigator.web.pager - -import androidx.compose.foundation.MutatePriority -import androidx.compose.foundation.gestures.Orientation -import androidx.compose.foundation.gestures.TargetedFlingBehavior -import androidx.compose.foundation.pager.PagerState -import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.input.nestedscroll.NestedScrollConnection -import androidx.compose.ui.input.nestedscroll.NestedScrollSource -import androidx.compose.ui.unit.Velocity -import kotlin.math.abs - -internal class PaginatedPagerNestedScrollConnection( - private val state: PagerState, - private val flingBehavior: TargetedFlingBehavior, - private val orientation: Orientation, -) : NestedScrollConnection { - - private var spreadConsumedVertically = false - - private val PagerState.firstVisibleOffset get() = - layoutInfo.visiblePagesInfo.first().offset - - private val PagerState.lastVisibleOffset get() = - layoutInfo.visiblePagesInfo.last().offset - - override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { - if (state.layoutInfo.visiblePagesInfo.size <= 1) { - return Offset.Zero - } - - // rounding and drag only - if (source != NestedScrollSource.UserInput || abs(state.currentPageOffsetFraction) < 1e-6) { - return Offset.Zero - } - - val delta = if (orientation == Orientation.Horizontal) available.x else available.y - - val minBound = -(state.layoutInfo.pageSize + state.firstVisibleOffset).toFloat() - - val maxBound = (state.layoutInfo.pageSize - state.lastVisibleOffset).toFloat() - - val coerced = delta.coerceIn(minBound, maxBound) - // dispatch and return reversed as usual - val consumed = -state.dispatchRawDelta(-coerced) - - check(state.layoutInfo.visiblePagesInfo.size == 1 || abs(consumed - available.x) < 1) - return Offset( - x = if (orientation == Orientation.Horizontal) consumed else available.x, - y = if (orientation == Orientation.Vertical) consumed else available.y - ) - } - - override suspend fun onPreFling(available: Velocity): Velocity { - if (state.layoutInfo.visiblePagesInfo.size > 1) { - state.scroll(scrollPriority = MutatePriority.Default) { - with(flingBehavior) { - performFling(-available.x) - } - } - - return available - } - - return Velocity.Zero - } - - override fun onPostScroll( - consumed: Offset, - available: Offset, - source: NestedScrollSource, - ): Offset { - if (abs(consumed.y) > 0) { - spreadConsumedVertically = true - } - - if (spreadConsumedVertically) { - return Offset.Zero - } - val consumedX = -state.dispatchRawDelta(-available.x) - return Offset(consumedX, 0f) - } - - override suspend fun onPostFling( - consumed: Velocity, - available: Velocity, - ): Velocity { - if (spreadConsumedVertically) { - spreadConsumedVertically = false - return Velocity.Zero - } - - var remaining = available.x - - state.scroll(scrollPriority = MutatePriority.Default) { - with(flingBehavior) { - remaining = -performFling(-available.x) - } - } - - if ((available.x - remaining).isNaN()) { - return available - } - - return Velocity(available.x - remaining, available.y) - } -} diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/NavigatorPager.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/RenditionPager.kt similarity index 83% rename from readium/navigators/web/src/main/java/org/readium/navigator/web/pager/NavigatorPager.kt rename to readium/navigators/web/src/main/java/org/readium/navigator/web/pager/RenditionPager.kt index 4afb67c5eb..ecc2b77303 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/NavigatorPager.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/RenditionPager.kt @@ -17,7 +17,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @Composable -internal fun NavigatorPager( +internal fun RenditionPager( modifier: Modifier = Modifier, state: PagerState, orientation: Orientation, @@ -31,6 +31,12 @@ internal fun NavigatorPager( pagerSnapDistance = PagerSnapDistance.atMost(0) ) + val nestedScrollConnection = PagerNestedScrollConnection( + state, + flingBehavior, + orientation + ) + if (orientation == Orientation.Horizontal) { HorizontalPager( modifier = modifier, @@ -42,12 +48,7 @@ internal fun NavigatorPager( reverseLayout = reverseLayout, flingBehavior = flingBehavior, key = key, - pageNestedScrollConnection = - PaginatedPagerNestedScrollConnection( - state, - flingBehavior, - Orientation.Horizontal - ), + pageNestedScrollConnection = nestedScrollConnection, pageContent = pageContent ) } else { @@ -61,12 +62,7 @@ internal fun NavigatorPager( reverseLayout = reverseLayout, flingBehavior = flingBehavior, key = key, - pageNestedScrollConnection = - ScrollPagerNestedScrollConnection( - state, - flingBehavior, - Orientation.Vertical - ), + pageNestedScrollConnection = nestedScrollConnection, pageContent = pageContent ) } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/PaginatedReflowableNestedScrollConnection.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/PaginatedReflowableNestedScrollConnection.kt deleted file mode 100644 index 67ade2f5a3..0000000000 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/PaginatedReflowableNestedScrollConnection.kt +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2024 Readium Foundation. All rights reserved. - * Use of this source code is governed by the BSD-style license - * available in the top-level LICENSE file of the project. - */ - -package org.readium.navigator.web.reflowable - -import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.input.nestedscroll.NestedScrollConnection -import androidx.compose.ui.input.nestedscroll.NestedScrollSource -import androidx.compose.ui.unit.Velocity -import org.readium.navigator.web.webview.RelaxedWebView -import org.readium.navigator.web.webview.WebViewScrollable2DState - -internal class PaginatedReflowableNestedScrollConnection( - private val webviewState: WebViewScrollable2DState, -) : NestedScrollConnection { - - override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { - val webViewNow = webviewState.webView ?: return Offset.Zero - - // For some reason, scrollX can vary by 1 or 2 pixels without any call to scrollTo. - val webViewCannotScrollHorizontally = - (webViewNow.scrollX < 3 && available.x > 0) || - ((webViewNow.maxScrollX - webViewNow.scrollX) < 3 && available.x < 0) - - if (webViewCannotScrollHorizontally) { - snapWebview(webViewNow) - } - - return Offset(0f, available.y) - } - - override suspend fun onPreFling(available: Velocity): Velocity { - return Velocity(0f, available.y) - } - - override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity { - val webViewNow = webviewState.webView ?: return Velocity.Zero - snapWebview(webViewNow) - return Velocity.Zero - } - - private fun snapWebview(webview: RelaxedWebView) { - if ((webview.maxScrollX - webview.scrollX) < 15) { - webview.scrollTo(webview.maxScrollX, webview.scrollY) - } else if (webview.scrollX in (0 until 15)) { - webview.scrollTo(0, webview.scrollY) - } - } -} diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt index d30a62c0a0..28c8c8558b 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt @@ -23,7 +23,6 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.DpOffset import androidx.compose.ui.unit.DpSize @@ -144,12 +143,6 @@ internal fun ReflowableResource( val scrollableState = remember { WebViewScrollable2DState() } - val reflowableNestedScrollConnection = when { - verticalText -> PaginatedReflowableNestedScrollConnection(scrollableState) - scroll -> ScrollReflowableNestedScrollConnection(scrollableState) - else -> PaginatedReflowableNestedScrollConnection(scrollableState) - } - val density = LocalDensity.current val scrollOrientation = when { @@ -187,8 +180,7 @@ internal fun ReflowableResource( reverseDirection = !reverseLayout, orientation = scrollOrientation ) - .fillMaxSize() - .nestedScroll(reflowableNestedScrollConnection), + .fillMaxSize(), state = webViewState, factory = { RelaxedWebView(it) }, client = webViewClient, diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ScrollReflowableNestedScrollConnection.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ScrollReflowableNestedScrollConnection.kt deleted file mode 100644 index 19b4cf7d3c..0000000000 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ScrollReflowableNestedScrollConnection.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2024 Readium Foundation. All rights reserved. - * Use of this source code is governed by the BSD-style license - * available in the top-level LICENSE file of the project. - */ - -package org.readium.navigator.web.reflowable - -import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.input.nestedscroll.NestedScrollConnection -import androidx.compose.ui.input.nestedscroll.NestedScrollSource -import androidx.compose.ui.unit.Velocity -import org.readium.navigator.web.webview.RelaxedWebView -import org.readium.navigator.web.webview.WebViewScrollable2DState - -internal class ScrollReflowableNestedScrollConnection( - private val webviewState: WebViewScrollable2DState, -) : NestedScrollConnection { - - override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { - val webViewNow = webviewState.webView ?: return Offset.Zero - - val webViewCannotScrollVertically = - (webViewNow.scrollY < 3 && available.y > 0) || - ((webViewNow.maxScrollY - webViewNow.scrollY) < 3 && available.y < 0) - - if (webViewCannotScrollVertically) { - snapWebview(webViewNow) - } - - return Offset(0f, available.y) - } - - override suspend fun onPreFling(available: Velocity): Velocity { - return Velocity(available.x, 0f) - } - - override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity { - val webViewNow = webviewState.webView ?: return Velocity.Zero - snapWebview(webViewNow) - return Velocity.Zero - } - - private fun snapWebview(webview: RelaxedWebView) { - if ((webview.maxScrollY - webview.scrollY) < 15) { - webview.scrollTo(webview.scrollX, webview.maxScrollY) - } else if (webview.scrollY in (0 until 15)) { - webview.scrollTo(webview.scrollX, 0) - } - } -} From ea7e32d3508f41d270a95006e54227bc3d12c649 Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Sat, 21 Dec 2024 09:29:13 +0100 Subject: [PATCH 10/88] Fix tap offsets --- .../src/index-reflowable-injectable.ts | 4 +- .../generated/reflowable-injectable-script.js | 2 +- .../reflowable-injectable-script.js.map | 2 +- .../navigator/web/ReflowableWebRendition.kt | 66 +++++++++++-------- .../web/reflowable/ReflowableResource.kt | 27 +++++++- .../readium/navigator/web/util/DisplayArea.kt | 23 ++++++- 6 files changed, 92 insertions(+), 32 deletions(-) diff --git a/readium/navigators/web/scripts/src/index-reflowable-injectable.ts b/readium/navigators/web/scripts/src/index-reflowable-injectable.ts index 1c42c5c145..b22b34998b 100644 --- a/readium/navigators/web/scripts/src/index-reflowable-injectable.ts +++ b/readium/navigators/web/scripts/src/index-reflowable-injectable.ts @@ -29,8 +29,8 @@ const bridgeListener = new BridgeGesturesAdapter(window.gestures) const gesturesListener = { onTap: (event: MouseEvent) => { const tapEvent = { - x: event.clientX * visualViewport!.scale, - y: event.clientY * visualViewport!.scale, + x: (event.clientX - visualViewport!.offsetLeft) * visualViewport!.scale, + y: (event.clientY - visualViewport!.offsetTop) * visualViewport!.scale, } bridgeListener.onTap(tapEvent) }, diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js index fc276e0e28..3258e9f4d3 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js @@ -1,2 +1,2 @@ -!function(){"use strict";const t=new class{constructor(t){this.nativeApi=t}onTap(t){this.nativeApi.onTap(JSON.stringify(t))}onLinkActivated(t,e){this.nativeApi.onLinkActivated(t,e)}}(window.gestures),e={onTap:e=>{const n={x:e.clientX*visualViewport.scale,y:e.clientY*visualViewport.scale};t.onTap(n)},onLinkActivated:(e,n)=>{t.onLinkActivated(e,n)}};new class{constructor(t,e){this.window=t,this.listener=e,document.addEventListener("click",(t=>{this.onClick(t)}),!1)}onClick(t){if(t.defaultPrevented)return;const e=this.window.getSelection();if(e&&"Range"==e.type)return;let n;n=t.target instanceof HTMLElement?this.nearestInteractiveElement(t.target):null,n?n instanceof HTMLAnchorElement&&this.listener.onLinkActivated(n.href,n.outerHTML):this.listener.onTap(t),t.stopPropagation(),t.preventDefault()}nearestInteractiveElement(t){return null==t?null:-1!=["a","audio","button","canvas","details","input","label","option","select","submit","textarea","video"].indexOf(t.nodeName.toLowerCase())||t.hasAttribute("contenteditable")&&"false"!=t.getAttribute("contenteditable").toLowerCase()?t:t.parentElement?this.nearestInteractiveElement(t.parentElement):null}}(window,e),Window.prototype.readiumcss=new class{constructor(t){this.document=t}setProperties(t){for(const[e,n]of t)this.setProperty(e,n)}setProperty(t,e){null===e||""===e?this.removeProperty(t):document.documentElement.style.setProperty(t,e,"important")}removeProperty(t){document.documentElement.style.removeProperty(t)}}(window.document),window.initialization.onScriptsLoaded(),window.addEventListener("load",(t=>{window.initialization.onDocumentLoaded()}))}(); +!function(){"use strict";const t=new class{constructor(t){this.nativeApi=t}onTap(t){this.nativeApi.onTap(JSON.stringify(t))}onLinkActivated(t,e){this.nativeApi.onLinkActivated(t,e)}}(window.gestures),e={onTap:e=>{const n={x:(e.clientX-visualViewport.offsetLeft)*visualViewport.scale,y:(e.clientY-visualViewport.offsetTop)*visualViewport.scale};t.onTap(n)},onLinkActivated:(e,n)=>{t.onLinkActivated(e,n)}};new class{constructor(t,e){this.window=t,this.listener=e,document.addEventListener("click",(t=>{this.onClick(t)}),!1)}onClick(t){if(t.defaultPrevented)return;const e=this.window.getSelection();if(e&&"Range"==e.type)return;let n;n=t.target instanceof HTMLElement?this.nearestInteractiveElement(t.target):null,n?n instanceof HTMLAnchorElement&&this.listener.onLinkActivated(n.href,n.outerHTML):this.listener.onTap(t),t.stopPropagation(),t.preventDefault()}nearestInteractiveElement(t){return null==t?null:-1!=["a","audio","button","canvas","details","input","label","option","select","submit","textarea","video"].indexOf(t.nodeName.toLowerCase())||t.hasAttribute("contenteditable")&&"false"!=t.getAttribute("contenteditable").toLowerCase()?t:t.parentElement?this.nearestInteractiveElement(t.parentElement):null}}(window,e),Window.prototype.readiumcss=new class{constructor(t){this.document=t}setProperties(t){for(const[e,n]of t)this.setProperty(e,n)}setProperty(t,e){null===e||""===e?this.removeProperty(t):document.documentElement.style.setProperty(t,e,"important")}removeProperty(t){document.documentElement.style.removeProperty(t)}}(window.document),window.initialization.onScriptsLoaded(),window.addEventListener("load",(t=>{window.initialization.onDocumentLoaded()}))}(); //# sourceMappingURL=reflowable-injectable-script.js.map \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map index bef877ff64..4e7ae30b5d 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map @@ -1 +1 @@ -{"version":3,"file":"reflowable-injectable-script.js","mappings":"yBAWA,MAAMA,EAAiB,ICXhB,MACH,WAAAC,CAAYC,GACRC,KAAKC,UAAYF,CACrB,CACA,KAAAG,CAAMC,GACFH,KAAKC,UAAUC,MAAME,KAAKC,UAAUF,GACxC,CACA,eAAAG,CAAgBC,EAAMC,GAClBR,KAAKC,UAAUK,gBAAgBC,EAAMC,EACzC,GDE6CC,OAAOC,UAClDC,EAAmB,CACrBT,MAAQC,IACJ,MAAMS,EAAW,CACbC,EAAGV,EAAMW,QAAUC,eAAeC,MAClCC,EAAGd,EAAMe,QAAUH,eAAeC,OAEtCnB,EAAeK,MAAMU,EAAS,EAElCN,gBAAiB,CAACC,EAAMC,KACpBX,EAAeS,gBAAgBC,EAAMC,EAAU,GAGvD,IExBO,MACH,WAAAV,CAAYW,EAAQU,GAChBnB,KAAKS,OAASA,EACdT,KAAKmB,SAAWA,EAChBC,SAASC,iBAAiB,SAAUlB,IAChCH,KAAKsB,QAAQnB,EAAM,IACpB,EACP,CACA,OAAAmB,CAAQnB,GACJ,GAAIA,EAAMoB,iBACN,OAEJ,MAAMC,EAAYxB,KAAKS,OAAOgB,eAC9B,GAAID,GAA+B,SAAlBA,EAAUE,KAIvB,OAEJ,IAAIC,EAEAA,EADAxB,EAAMyB,kBAAkBC,YACP7B,KAAK8B,0BAA0B3B,EAAMyB,QAGrC,KAEjBD,EACIA,aAA0BI,mBAC1B/B,KAAKmB,SAASb,gBAAgBqB,EAAepB,KAAMoB,EAAeK,WAItEhC,KAAKmB,SAASjB,MAAMC,GAExBA,EAAM8B,kBACN9B,EAAM+B,gBACV,CAEA,yBAAAJ,CAA0BK,GACtB,OAAe,MAAXA,EACO,MAgBqD,GAdxC,CACpB,IACA,QACA,SACA,SACA,UACA,QACA,QACA,SACA,SACA,SACA,WACA,SAEgBC,QAAQD,EAAQE,SAASC,gBAIzCH,EAAQI,aAAa,oBACoC,SAAzDJ,EAAQK,aAAa,mBAAmBF,cAJjCH,EAQPA,EAAQM,cACDzC,KAAK8B,0BAA0BK,EAAQM,eAE3C,IACX,GF7CiBhC,OAAQE,GAC7B+B,OAAOC,UAAUC,WAAa,IGzBvB,MACH,WAAA9C,CAAYsB,GACRpB,KAAKoB,SAAWA,CACpB,CACA,aAAAyB,CAAcC,GACV,IAAK,MAAOC,EAAKC,KAAUF,EACvB9C,KAAKiD,YAAYF,EAAKC,EAE9B,CAEA,WAAAC,CAAYF,EAAKC,GACC,OAAVA,GAA4B,KAAVA,EAClBhD,KAAKkD,eAAeH,GAGP3B,SAAS+B,gBAGjBC,MAAMH,YAAYF,EAAKC,EAAO,YAE3C,CAEA,cAAAE,CAAeH,GACE3B,SAAS+B,gBACjBC,MAAMF,eAAeH,EAC9B,GHAwCtC,OAAOW,UACnDX,OAAO4C,eAAeC,kBAEtB7C,OAAOY,iBAAiB,QAASlB,IAC7BM,OAAO4C,eAAeE,kBAAkB,G","sources":["webpack://readium-js/./src/index-reflowable-injectable.ts","webpack://readium-js/./src/bridge/all-gestures-bridge.ts","webpack://readium-js/./src/common/gestures.ts","webpack://readium-js/./src/bridge/reflowable-css-bridge.ts"],"sourcesContent":["//\n// Copyright 2024 Readium Foundation. All rights reserved.\n// Use of this source code is governed by the BSD-style license\n// available in the top-level LICENSE file of the project.\n//\n/**\n * Script loaded by reflowable resources.\n */\nimport { BridgeGesturesAdapter, } from \"./bridge/all-gestures-bridge\";\nimport { CssBridge } from \"./bridge/reflowable-css-bridge\";\nimport { GesturesDetector } from \"./common/gestures\";\nconst bridgeListener = new BridgeGesturesAdapter(window.gestures);\nconst gesturesListener = {\n onTap: (event) => {\n const tapEvent = {\n x: event.clientX * visualViewport.scale,\n y: event.clientY * visualViewport.scale,\n };\n bridgeListener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n bridgeListener.onLinkActivated(href, outerHtml);\n },\n};\nnew GesturesDetector(window, gesturesListener);\nWindow.prototype.readiumcss = new CssBridge(window.document);\nwindow.initialization.onScriptsLoaded();\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nwindow.addEventListener(\"load\", (event) => {\n window.initialization.onDocumentLoaded();\n});\n","export class BridgeGesturesAdapter {\n constructor(gesturesApi) {\n this.nativeApi = gesturesApi;\n }\n onTap(event) {\n this.nativeApi.onTap(JSON.stringify(event));\n }\n onLinkActivated(href, outerHtml) {\n this.nativeApi.onLinkActivated(href, outerHtml);\n }\n}\n","export class GesturesDetector {\n constructor(window, listener) {\n this.window = window;\n this.listener = listener;\n document.addEventListener(\"click\", (event) => {\n this.onClick(event);\n }, false);\n }\n onClick(event) {\n if (event.defaultPrevented) {\n return;\n }\n const selection = this.window.getSelection();\n if (selection && selection.type == \"Range\") {\n // There's an on-going selection, the tap will dismiss it so we don't forward it.\n // selection.type might be None (collapsed) or Caret with a collapsed range\n // when there is not true selection.\n return;\n }\n let nearestElement;\n if (event.target instanceof HTMLElement) {\n nearestElement = this.nearestInteractiveElement(event.target);\n }\n else {\n nearestElement = null;\n }\n if (nearestElement) {\n if (nearestElement instanceof HTMLAnchorElement) {\n this.listener.onLinkActivated(nearestElement.href, nearestElement.outerHTML);\n }\n }\n else {\n this.listener.onTap(event);\n }\n event.stopPropagation();\n event.preventDefault();\n }\n // See. https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling\n nearestInteractiveElement(element) {\n if (element == null) {\n return null;\n }\n const interactiveTags = [\n \"a\",\n \"audio\",\n \"button\",\n \"canvas\",\n \"details\",\n \"input\",\n \"label\",\n \"option\",\n \"select\",\n \"submit\",\n \"textarea\",\n \"video\",\n ];\n if (interactiveTags.indexOf(element.nodeName.toLowerCase()) != -1) {\n return element;\n }\n // Checks whether the element is editable by the user.\n if (element.hasAttribute(\"contenteditable\") &&\n element.getAttribute(\"contenteditable\").toLowerCase() != \"false\") {\n return element;\n }\n // Checks parents recursively because the touch might be for example on an inside a .\n if (element.parentElement) {\n return this.nearestInteractiveElement(element.parentElement);\n }\n return null;\n }\n}\n","export class CssBridge {\n constructor(document) {\n this.document = document;\n }\n setProperties(properties) {\n for (const [key, value] of properties) {\n this.setProperty(key, value);\n }\n }\n // For setting user setting.\n setProperty(key, value) {\n if (value === null || value === \"\") {\n this.removeProperty(key);\n }\n else {\n const root = document.documentElement;\n // The `!important` annotation is added with `setProperty()` because if it's part of the\n // `value`, it will be ignored by the Web View.\n root.style.setProperty(key, value, \"important\");\n }\n }\n // For removing user setting.\n removeProperty(key) {\n const root = document.documentElement;\n root.style.removeProperty(key);\n }\n}\n"],"names":["bridgeListener","constructor","gesturesApi","this","nativeApi","onTap","event","JSON","stringify","onLinkActivated","href","outerHtml","window","gestures","gesturesListener","tapEvent","x","clientX","visualViewport","scale","y","clientY","listener","document","addEventListener","onClick","defaultPrevented","selection","getSelection","type","nearestElement","target","HTMLElement","nearestInteractiveElement","HTMLAnchorElement","outerHTML","stopPropagation","preventDefault","element","indexOf","nodeName","toLowerCase","hasAttribute","getAttribute","parentElement","Window","prototype","readiumcss","setProperties","properties","key","value","setProperty","removeProperty","documentElement","style","initialization","onScriptsLoaded","onDocumentLoaded"],"sourceRoot":""} \ No newline at end of file +{"version":3,"file":"reflowable-injectable-script.js","mappings":"yBAWA,MAAMA,EAAiB,ICXhB,MACH,WAAAC,CAAYC,GACRC,KAAKC,UAAYF,CACrB,CACA,KAAAG,CAAMC,GACFH,KAAKC,UAAUC,MAAME,KAAKC,UAAUF,GACxC,CACA,eAAAG,CAAgBC,EAAMC,GAClBR,KAAKC,UAAUK,gBAAgBC,EAAMC,EACzC,GDE6CC,OAAOC,UAClDC,EAAmB,CACrBT,MAAQC,IACJ,MAAMS,EAAW,CACbC,GAAIV,EAAMW,QAAUC,eAAeC,YAAcD,eAAeE,MAChEC,GAAIf,EAAMgB,QAAUJ,eAAeK,WAAaL,eAAeE,OAEnEpB,EAAeK,MAAMU,EAAS,EAElCN,gBAAiB,CAACC,EAAMC,KACpBX,EAAeS,gBAAgBC,EAAMC,EAAU,GAGvD,IExBO,MACH,WAAAV,CAAYW,EAAQY,GAChBrB,KAAKS,OAASA,EACdT,KAAKqB,SAAWA,EAChBC,SAASC,iBAAiB,SAAUpB,IAChCH,KAAKwB,QAAQrB,EAAM,IACpB,EACP,CACA,OAAAqB,CAAQrB,GACJ,GAAIA,EAAMsB,iBACN,OAEJ,MAAMC,EAAY1B,KAAKS,OAAOkB,eAC9B,GAAID,GAA+B,SAAlBA,EAAUE,KAIvB,OAEJ,IAAIC,EAEAA,EADA1B,EAAM2B,kBAAkBC,YACP/B,KAAKgC,0BAA0B7B,EAAM2B,QAGrC,KAEjBD,EACIA,aAA0BI,mBAC1BjC,KAAKqB,SAASf,gBAAgBuB,EAAetB,KAAMsB,EAAeK,WAItElC,KAAKqB,SAASnB,MAAMC,GAExBA,EAAMgC,kBACNhC,EAAMiC,gBACV,CAEA,yBAAAJ,CAA0BK,GACtB,OAAe,MAAXA,EACO,MAgBqD,GAdxC,CACpB,IACA,QACA,SACA,SACA,UACA,QACA,QACA,SACA,SACA,SACA,WACA,SAEgBC,QAAQD,EAAQE,SAASC,gBAIzCH,EAAQI,aAAa,oBACoC,SAAzDJ,EAAQK,aAAa,mBAAmBF,cAJjCH,EAQPA,EAAQM,cACD3C,KAAKgC,0BAA0BK,EAAQM,eAE3C,IACX,GF7CiBlC,OAAQE,GAC7BiC,OAAOC,UAAUC,WAAa,IGzBvB,MACH,WAAAhD,CAAYwB,GACRtB,KAAKsB,SAAWA,CACpB,CACA,aAAAyB,CAAcC,GACV,IAAK,MAAOC,EAAKC,KAAUF,EACvBhD,KAAKmD,YAAYF,EAAKC,EAE9B,CAEA,WAAAC,CAAYF,EAAKC,GACC,OAAVA,GAA4B,KAAVA,EAClBlD,KAAKoD,eAAeH,GAGP3B,SAAS+B,gBAGjBC,MAAMH,YAAYF,EAAKC,EAAO,YAE3C,CAEA,cAAAE,CAAeH,GACE3B,SAAS+B,gBACjBC,MAAMF,eAAeH,EAC9B,GHAwCxC,OAAOa,UACnDb,OAAO8C,eAAeC,kBAEtB/C,OAAOc,iBAAiB,QAASpB,IAC7BM,OAAO8C,eAAeE,kBAAkB,G","sources":["webpack://readium-js/./src/index-reflowable-injectable.ts","webpack://readium-js/./src/bridge/all-gestures-bridge.ts","webpack://readium-js/./src/common/gestures.ts","webpack://readium-js/./src/bridge/reflowable-css-bridge.ts"],"sourcesContent":["//\n// Copyright 2024 Readium Foundation. All rights reserved.\n// Use of this source code is governed by the BSD-style license\n// available in the top-level LICENSE file of the project.\n//\n/**\n * Script loaded by reflowable resources.\n */\nimport { BridgeGesturesAdapter, } from \"./bridge/all-gestures-bridge\";\nimport { CssBridge } from \"./bridge/reflowable-css-bridge\";\nimport { GesturesDetector } from \"./common/gestures\";\nconst bridgeListener = new BridgeGesturesAdapter(window.gestures);\nconst gesturesListener = {\n onTap: (event) => {\n const tapEvent = {\n x: (event.clientX - visualViewport.offsetLeft) * visualViewport.scale,\n y: (event.clientY - visualViewport.offsetTop) * visualViewport.scale,\n };\n bridgeListener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n bridgeListener.onLinkActivated(href, outerHtml);\n },\n};\nnew GesturesDetector(window, gesturesListener);\nWindow.prototype.readiumcss = new CssBridge(window.document);\nwindow.initialization.onScriptsLoaded();\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nwindow.addEventListener(\"load\", (event) => {\n window.initialization.onDocumentLoaded();\n});\n","export class BridgeGesturesAdapter {\n constructor(gesturesApi) {\n this.nativeApi = gesturesApi;\n }\n onTap(event) {\n this.nativeApi.onTap(JSON.stringify(event));\n }\n onLinkActivated(href, outerHtml) {\n this.nativeApi.onLinkActivated(href, outerHtml);\n }\n}\n","export class GesturesDetector {\n constructor(window, listener) {\n this.window = window;\n this.listener = listener;\n document.addEventListener(\"click\", (event) => {\n this.onClick(event);\n }, false);\n }\n onClick(event) {\n if (event.defaultPrevented) {\n return;\n }\n const selection = this.window.getSelection();\n if (selection && selection.type == \"Range\") {\n // There's an on-going selection, the tap will dismiss it so we don't forward it.\n // selection.type might be None (collapsed) or Caret with a collapsed range\n // when there is not true selection.\n return;\n }\n let nearestElement;\n if (event.target instanceof HTMLElement) {\n nearestElement = this.nearestInteractiveElement(event.target);\n }\n else {\n nearestElement = null;\n }\n if (nearestElement) {\n if (nearestElement instanceof HTMLAnchorElement) {\n this.listener.onLinkActivated(nearestElement.href, nearestElement.outerHTML);\n }\n }\n else {\n this.listener.onTap(event);\n }\n event.stopPropagation();\n event.preventDefault();\n }\n // See. https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling\n nearestInteractiveElement(element) {\n if (element == null) {\n return null;\n }\n const interactiveTags = [\n \"a\",\n \"audio\",\n \"button\",\n \"canvas\",\n \"details\",\n \"input\",\n \"label\",\n \"option\",\n \"select\",\n \"submit\",\n \"textarea\",\n \"video\",\n ];\n if (interactiveTags.indexOf(element.nodeName.toLowerCase()) != -1) {\n return element;\n }\n // Checks whether the element is editable by the user.\n if (element.hasAttribute(\"contenteditable\") &&\n element.getAttribute(\"contenteditable\").toLowerCase() != \"false\") {\n return element;\n }\n // Checks parents recursively because the touch might be for example on an inside a .\n if (element.parentElement) {\n return this.nearestInteractiveElement(element.parentElement);\n }\n return null;\n }\n}\n","export class CssBridge {\n constructor(document) {\n this.document = document;\n }\n setProperties(properties) {\n for (const [key, value] of properties) {\n this.setProperty(key, value);\n }\n }\n // For setting user setting.\n setProperty(key, value) {\n if (value === null || value === \"\") {\n this.removeProperty(key);\n }\n else {\n const root = document.documentElement;\n // The `!important` annotation is added with `setProperty()` because if it's part of the\n // `value`, it will be ignored by the Web View.\n root.style.setProperty(key, value, \"important\");\n }\n }\n // For removing user setting.\n removeProperty(key) {\n const root = document.documentElement;\n root.style.removeProperty(key);\n }\n}\n"],"names":["bridgeListener","constructor","gesturesApi","this","nativeApi","onTap","event","JSON","stringify","onLinkActivated","href","outerHtml","window","gestures","gesturesListener","tapEvent","x","clientX","visualViewport","offsetLeft","scale","y","clientY","offsetTop","listener","document","addEventListener","onClick","defaultPrevented","selection","getSelection","type","nearestElement","target","HTMLElement","nearestInteractiveElement","HTMLAnchorElement","outerHTML","stopPropagation","preventDefault","element","indexOf","nodeName","toLowerCase","hasAttribute","getAttribute","parentElement","Window","prototype","readiumcss","setProperties","properties","key","value","setProperty","removeProperty","documentElement","style","initialization","onScriptsLoaded","onDocumentLoaded"],"sourceRoot":""} \ No newline at end of file diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt index b8977506eb..58e8595397 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt @@ -8,20 +8,18 @@ package org.readium.navigator.web import android.annotation.SuppressLint import android.content.res.Configuration -import androidx.compose.foundation.background import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.displayCutout import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.LayoutDirection @@ -38,6 +36,7 @@ import org.readium.navigator.common.defaultInputListener import org.readium.navigator.web.location.ReflowableWebLocation import org.readium.navigator.web.pager.RenditionPager import org.readium.navigator.web.reflowable.ReflowableResource +import org.readium.navigator.web.util.AbsolutePaddingValues import org.readium.navigator.web.util.WebViewServer import org.readium.r2.navigator.preferences.ReadingProgression import org.readium.r2.shared.ExperimentalReadiumApi @@ -60,29 +59,8 @@ public fun ReflowableWebRendition( ?.let { defaultHyperlinkListener(controller = it) } ?: NullHyperlinkListener(), ) { - val paginatedVerticalPadding = - when (LocalConfiguration.current.orientation) { - Configuration.ORIENTATION_LANDSCAPE -> 20.dp - else -> 40.dp - } - - val verticalPadding = - if (state.layoutDelegate.settings.value.scroll) { - 0.dp - } else { - paginatedVerticalPadding - } - - val backgroundColor = ( - state.layoutDelegate.settings.value.backgroundColor?.int - ?: state.layoutDelegate.settings.value.theme.backgroundColor - ) - BoxWithConstraints( - modifier = Modifier.fillMaxSize() - .background(Color(backgroundColor)) - .padding(windowInsets.asPaddingValues()) - .padding(vertical = verticalPadding), + modifier = Modifier.fillMaxSize(), propagateMinConstraints = true ) { val viewportSize = rememberUpdatedState(DpSize(maxWidth, maxHeight)) @@ -99,6 +77,26 @@ public fun ReflowableWebRendition( val coroutineScope = rememberCoroutineScope() + val paginatedVerticalPadding = + when (LocalConfiguration.current.orientation) { + Configuration.ORIENTATION_LANDSCAPE -> AbsolutePaddingValues(vertical = 20.dp) + else -> AbsolutePaddingValues(vertical = 40.dp) + } + + val insetsPaddingValues = windowInsets.asAbsolutePaddingValues() + + val padding = + if (state.layoutDelegate.settings.value.scroll) { + insetsPaddingValues + } else { + insetsPaddingValues + paginatedVerticalPadding + } + + val backgroundColor = ( + state.layoutDelegate.settings.value.backgroundColor?.int + ?: state.layoutDelegate.settings.value.theme.backgroundColor + ) + RenditionPager( modifier = modifier, state = state.pagerState, @@ -115,13 +113,18 @@ public fun ReflowableWebRendition( publicationBaseUrl = WebViewServer.publicationBaseHref, webViewClient = state.webViewClient, viewportSize = viewportSize.value, + backgroundColor = Color(backgroundColor), + padding = padding, reverseLayout = reverseLayout, scroll = state.layoutDelegate.settings.value.scroll, verticalText = state.layoutDelegate.settings.value.verticalText, rsProperties = state.readiumCss.value.rsProperties, userProperties = state.readiumCss.value.userProperties, layout = state.readiumCss.value.layout, - onTap = { inputListener.onTap(it, TapContext(viewportSize.value)) }, + initialProgression = if (index <= itemIndex) 0.0 else 100.0, + onTap = { tapEvent -> + inputListener.onTap(tapEvent, TapContext(viewportSize.value)) + }, onLinkActivated = { url, outerHtml -> coroutineScope.launch { onLinkActivated(url, outerHtml, state, hyperlinkListener) @@ -132,6 +135,17 @@ public fun ReflowableWebRendition( } } +@Composable +private fun WindowInsets.asAbsolutePaddingValues(): AbsolutePaddingValues { + val density = LocalDensity.current + val layoutDirection = LocalLayoutDirection.current + val top = with(density) { getTop(density).toDp() } + val right = with(density) { getRight(density, layoutDirection).toDp() } + val bottom = with(density) { getBottom(density).toDp() } + val left = with(density) { getLeft(density, layoutDirection).toDp() } + return AbsolutePaddingValues(top = top, right = right, bottom = bottom, left = left) +} + private fun LayoutDirection.toReadingProgression(): ReadingProgression = when (this) { LayoutDirection.Ltr -> ReadingProgression.LTR diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt index 28c8c8558b..7ec70d2034 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt @@ -11,6 +11,7 @@ package org.readium.navigator.web.reflowable import android.annotation.SuppressLint import android.view.MotionEvent import android.view.View +import androidx.compose.foundation.background import androidx.compose.foundation.gestures.FlingBehavior import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.gestures.ScrollScope @@ -23,6 +24,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.DpOffset import androidx.compose.ui.unit.DpSize @@ -31,6 +33,8 @@ import androidx.core.view.postDelayed import androidx.webkit.WebViewCompat import androidx.webkit.WebViewFeature import kotlin.Float +import kotlin.math.ceil +import kotlin.math.floor import org.readium.navigator.common.TapEvent import org.readium.navigator.web.css.Layout import org.readium.navigator.web.css.RsProperties @@ -38,7 +42,9 @@ import org.readium.navigator.web.css.UserProperties import org.readium.navigator.web.gestures.Fling2DBehavior import org.readium.navigator.web.gestures.Scroll2DScope import org.readium.navigator.web.gestures.scrollable2D +import org.readium.navigator.web.util.AbsolutePaddingValues import org.readium.navigator.web.util.WebViewClient +import org.readium.navigator.web.util.absolutePadding import org.readium.navigator.web.webapi.CssApi import org.readium.navigator.web.webapi.GesturesApi import org.readium.navigator.web.webapi.GesturesListener @@ -60,12 +66,15 @@ internal fun ReflowableResource( publicationBaseUrl: AbsoluteUrl, webViewClient: WebViewClient, viewportSize: DpSize, + backgroundColor: Color, + padding: AbsolutePaddingValues, reverseLayout: Boolean, scroll: Boolean, verticalText: Boolean, userProperties: UserProperties, rsProperties: RsProperties, layout: Layout, + initialProgression: Double, onTap: (TapEvent) -> Unit, onLinkActivated: (Url, String) -> Unit, ) { @@ -126,7 +135,11 @@ internal fun ReflowableResource( val gesturesApi = remember(onTap) { val listener = object : GesturesListener { override fun onTap(offset: DpOffset) { - onTap(TapEvent(offset)) + val shiftedOffset = DpOffset( + x = offset.x + padding.left, + y = offset.y + padding.top + ) + onTap(TapEvent(shiftedOffset)) } override fun onLinkActivated(href: AbsoluteUrl, outerHtml: String) { @@ -151,6 +164,16 @@ internal fun ReflowableResource( else -> Orientation.Horizontal } + LaunchedEffect(contentIsLaidOut, contentIsLaidOut.value, scrollableState.webView) { + scrollableState.webView?.let { webview -> + if (scrollOrientation == Orientation.Horizontal) { + webview.scrollTo(floor(initialProgression * webview.maxScrollX).toInt(), 0) + } else { + webview.scrollTo(0, ceil(initialProgression * webview.maxScrollY).toInt()) + } + } + } + val flingBehavior = if (scroll) { null @@ -180,6 +203,8 @@ internal fun ReflowableResource( reverseDirection = !reverseLayout, orientation = scrollOrientation ) + .background(backgroundColor) + .absolutePadding(padding) .fillMaxSize(), state = webViewState, factory = { RelaxedWebView(it) }, diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/util/DisplayArea.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/util/DisplayArea.kt index 23983ac2d2..3db94f4ab1 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/util/DisplayArea.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/util/DisplayArea.kt @@ -6,8 +6,11 @@ package org.readium.navigator.web.util +import androidx.compose.foundation.layout.absolutePadding +import androidx.compose.ui.Modifier import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.DpSize +import androidx.compose.ui.unit.dp internal data class DisplayArea( val viewportSize: DpSize, @@ -19,4 +22,22 @@ internal data class AbsolutePaddingValues( val right: Dp, val bottom: Dp, val left: Dp, -) +) { + constructor(vertical: Dp = 0.dp, horizontal: Dp = 0.dp) : + this(top = vertical, right = horizontal, bottom = vertical, left = horizontal) + + operator fun plus(other: AbsolutePaddingValues) = copy( + top = top + other.top, + right = right + other.right, + bottom = bottom + other.bottom, + left = left + other.left + ) +} + +internal fun Modifier.absolutePadding(paddingValues: AbsolutePaddingValues): Modifier = + this.absolutePadding( + top = paddingValues.top, + right = paddingValues.right, + bottom = paddingValues.bottom, + left = paddingValues.left + ) From 5b8f7e637887ad1d233c0510b157435490e46b41 Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Sat, 21 Dec 2024 10:13:29 +0100 Subject: [PATCH 11/88] Detect tap on padding --- .../navigator/web/ReflowableWebRenditionState.kt | 12 +++++++----- .../navigator/web/reflowable/ReflowableResource.kt | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt index 672cc692cb..a038f3e72a 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt @@ -210,11 +210,13 @@ internal class ReflowableNavigationDelegate( override val overflow: State = derivedStateOf { - SimpleOverflow( - settings.value.readingProgression, - false, - Axis.HORIZONTAL - ) + with(settings.value) { + SimpleOverflow( + readingProgression = readingProgression, + scroll = scroll, + axis = if (scroll && !verticalText) Axis.VERTICAL else Axis.HORIZONTAL + ) + } } override val canMoveForward: Boolean diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt index 7ec70d2034..403309de31 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt @@ -15,6 +15,7 @@ import androidx.compose.foundation.background import androidx.compose.foundation.gestures.FlingBehavior import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.gestures.ScrollScope +import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable @@ -25,6 +26,7 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color +import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.DpOffset import androidx.compose.ui.unit.DpSize @@ -196,6 +198,18 @@ internal fun ReflowableResource( key(layout) { WebView( modifier = Modifier + // Detect taps on padding + .pointerInput(Unit) { + detectTapGestures( + onTap = { + if (it.x >= 0 && it.y >= 0) { + val offset = DpOffset(x = it.x.toDp(), y = it.y.toDp()) + val event = TapEvent(offset) + onTap(event) + } + } + ) + } .scrollable2D( enabled = contentIsLaidOut.value, state = scrollableState, From c4b0a8a8ed429955c09b928f9a1ee2552b40fe1c Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Sat, 21 Dec 2024 15:52:27 +0100 Subject: [PATCH 12/88] Fix regression in snapping related to padding --- .../navigator/web/reflowable/ReflowableResource.kt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt index 403309de31..73b1fc963d 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt @@ -176,6 +176,11 @@ internal fun ReflowableResource( } } + val webViewViewport = DpSize( + width = viewportSize.width - padding.left - padding.right, + height = viewportSize.height - padding.top - padding.bottom + ) + val flingBehavior = if (scroll) { null @@ -187,7 +192,7 @@ internal fun ReflowableResource( density, scrollOrientation, reverseLayout, - viewportSize, + webViewViewport, it ) ) @@ -217,9 +222,9 @@ internal fun ReflowableResource( reverseDirection = !reverseLayout, orientation = scrollOrientation ) + .fillMaxSize() .background(backgroundColor) - .absolutePadding(padding) - .fillMaxSize(), + .absolutePadding(padding), state = webViewState, factory = { RelaxedWebView(it) }, client = webViewClient, From 6d7f5b6fbbe06c8f61db85d9f6e12f7ba7d22355 Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Sun, 5 Jan 2025 18:14:44 +0100 Subject: [PATCH 13/88] Try to fix scroll position of previous pages --- .../src/bridge/all-initialization-bridge.ts | 1 + .../src/index-reflowable-injectable.ts | 7 ++ .../generated/reflowable-injectable-script.js | 2 +- .../reflowable-injectable-script.js.map | 2 +- .../navigator/web/ReflowableWebRendition.kt | 36 +++++++++- .../web/ReflowableWebRenditionState.kt | 7 +- .../web/fixed/DoubleViewportSpread.kt | 3 +- .../web/fixed/SingleViewportSpread.kt | 3 +- .../navigator/web/fixed/SpreadWebView.kt | 4 +- .../navigator/web/location/LocationTypes.kt | 2 +- .../web/reflowable/ReflowableResource.kt | 69 ++++++++++++++----- .../navigator/web/util/WebViewClient.kt | 11 +++ .../navigator/web/webapi/InitializationApi.kt | 6 ++ .../web/webview/ComposableWebView.kt | 22 +++--- 14 files changed, 137 insertions(+), 38 deletions(-) diff --git a/readium/navigators/web/scripts/src/bridge/all-initialization-bridge.ts b/readium/navigators/web/scripts/src/bridge/all-initialization-bridge.ts index 5bd2e3d6b7..c60e8c463f 100644 --- a/readium/navigators/web/scripts/src/bridge/all-initialization-bridge.ts +++ b/readium/navigators/web/scripts/src/bridge/all-initialization-bridge.ts @@ -1,4 +1,5 @@ export interface InitializationBridge { onScriptsLoaded: () => void onDocumentLoaded: () => void + onDocumentResized: () => void } diff --git a/readium/navigators/web/scripts/src/index-reflowable-injectable.ts b/readium/navigators/web/scripts/src/index-reflowable-injectable.ts index b22b34998b..afd966ee7d 100644 --- a/readium/navigators/web/scripts/src/index-reflowable-injectable.ts +++ b/readium/navigators/web/scripts/src/index-reflowable-injectable.ts @@ -46,5 +46,12 @@ Window.prototype.readiumcss = new CssBridge(window.document) window.initialization.onScriptsLoaded() // eslint-disable-next-line @typescript-eslint/no-unused-vars window.addEventListener("load", (event) => { + const observer = new ResizeObserver(() => { + requestAnimationFrame(() => { + window.initialization.onDocumentResized() + }) + }) + observer.observe(document.body) + window.initialization.onDocumentLoaded() }) diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js index 3258e9f4d3..7de859a679 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js @@ -1,2 +1,2 @@ -!function(){"use strict";const t=new class{constructor(t){this.nativeApi=t}onTap(t){this.nativeApi.onTap(JSON.stringify(t))}onLinkActivated(t,e){this.nativeApi.onLinkActivated(t,e)}}(window.gestures),e={onTap:e=>{const n={x:(e.clientX-visualViewport.offsetLeft)*visualViewport.scale,y:(e.clientY-visualViewport.offsetTop)*visualViewport.scale};t.onTap(n)},onLinkActivated:(e,n)=>{t.onLinkActivated(e,n)}};new class{constructor(t,e){this.window=t,this.listener=e,document.addEventListener("click",(t=>{this.onClick(t)}),!1)}onClick(t){if(t.defaultPrevented)return;const e=this.window.getSelection();if(e&&"Range"==e.type)return;let n;n=t.target instanceof HTMLElement?this.nearestInteractiveElement(t.target):null,n?n instanceof HTMLAnchorElement&&this.listener.onLinkActivated(n.href,n.outerHTML):this.listener.onTap(t),t.stopPropagation(),t.preventDefault()}nearestInteractiveElement(t){return null==t?null:-1!=["a","audio","button","canvas","details","input","label","option","select","submit","textarea","video"].indexOf(t.nodeName.toLowerCase())||t.hasAttribute("contenteditable")&&"false"!=t.getAttribute("contenteditable").toLowerCase()?t:t.parentElement?this.nearestInteractiveElement(t.parentElement):null}}(window,e),Window.prototype.readiumcss=new class{constructor(t){this.document=t}setProperties(t){for(const[e,n]of t)this.setProperty(e,n)}setProperty(t,e){null===e||""===e?this.removeProperty(t):document.documentElement.style.setProperty(t,e,"important")}removeProperty(t){document.documentElement.style.removeProperty(t)}}(window.document),window.initialization.onScriptsLoaded(),window.addEventListener("load",(t=>{window.initialization.onDocumentLoaded()}))}(); +!function(){"use strict";const e=new class{constructor(e){this.nativeApi=e}onTap(e){this.nativeApi.onTap(JSON.stringify(e))}onLinkActivated(e,t){this.nativeApi.onLinkActivated(e,t)}}(window.gestures),t={onTap:t=>{const n={x:(t.clientX-visualViewport.offsetLeft)*visualViewport.scale,y:(t.clientY-visualViewport.offsetTop)*visualViewport.scale};e.onTap(n)},onLinkActivated:(t,n)=>{e.onLinkActivated(t,n)}};new class{constructor(e,t){this.window=e,this.listener=t,document.addEventListener("click",(e=>{this.onClick(e)}),!1)}onClick(e){if(e.defaultPrevented)return;const t=this.window.getSelection();if(t&&"Range"==t.type)return;let n;n=e.target instanceof HTMLElement?this.nearestInteractiveElement(e.target):null,n?n instanceof HTMLAnchorElement&&this.listener.onLinkActivated(n.href,n.outerHTML):this.listener.onTap(e),e.stopPropagation(),e.preventDefault()}nearestInteractiveElement(e){return null==e?null:-1!=["a","audio","button","canvas","details","input","label","option","select","submit","textarea","video"].indexOf(e.nodeName.toLowerCase())||e.hasAttribute("contenteditable")&&"false"!=e.getAttribute("contenteditable").toLowerCase()?e:e.parentElement?this.nearestInteractiveElement(e.parentElement):null}}(window,t),Window.prototype.readiumcss=new class{constructor(e){this.document=e}setProperties(e){for(const[t,n]of e)this.setProperty(t,n)}setProperty(e,t){null===t||""===t?this.removeProperty(e):document.documentElement.style.setProperty(e,t,"important")}removeProperty(e){document.documentElement.style.removeProperty(e)}}(window.document),window.initialization.onScriptsLoaded(),window.addEventListener("load",(e=>{new ResizeObserver((()=>{requestAnimationFrame((()=>{window.initialization.onDocumentResized()}))})).observe(document.body),window.initialization.onDocumentLoaded()}))}(); //# sourceMappingURL=reflowable-injectable-script.js.map \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map index 4e7ae30b5d..389107393a 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map @@ -1 +1 @@ -{"version":3,"file":"reflowable-injectable-script.js","mappings":"yBAWA,MAAMA,EAAiB,ICXhB,MACH,WAAAC,CAAYC,GACRC,KAAKC,UAAYF,CACrB,CACA,KAAAG,CAAMC,GACFH,KAAKC,UAAUC,MAAME,KAAKC,UAAUF,GACxC,CACA,eAAAG,CAAgBC,EAAMC,GAClBR,KAAKC,UAAUK,gBAAgBC,EAAMC,EACzC,GDE6CC,OAAOC,UAClDC,EAAmB,CACrBT,MAAQC,IACJ,MAAMS,EAAW,CACbC,GAAIV,EAAMW,QAAUC,eAAeC,YAAcD,eAAeE,MAChEC,GAAIf,EAAMgB,QAAUJ,eAAeK,WAAaL,eAAeE,OAEnEpB,EAAeK,MAAMU,EAAS,EAElCN,gBAAiB,CAACC,EAAMC,KACpBX,EAAeS,gBAAgBC,EAAMC,EAAU,GAGvD,IExBO,MACH,WAAAV,CAAYW,EAAQY,GAChBrB,KAAKS,OAASA,EACdT,KAAKqB,SAAWA,EAChBC,SAASC,iBAAiB,SAAUpB,IAChCH,KAAKwB,QAAQrB,EAAM,IACpB,EACP,CACA,OAAAqB,CAAQrB,GACJ,GAAIA,EAAMsB,iBACN,OAEJ,MAAMC,EAAY1B,KAAKS,OAAOkB,eAC9B,GAAID,GAA+B,SAAlBA,EAAUE,KAIvB,OAEJ,IAAIC,EAEAA,EADA1B,EAAM2B,kBAAkBC,YACP/B,KAAKgC,0BAA0B7B,EAAM2B,QAGrC,KAEjBD,EACIA,aAA0BI,mBAC1BjC,KAAKqB,SAASf,gBAAgBuB,EAAetB,KAAMsB,EAAeK,WAItElC,KAAKqB,SAASnB,MAAMC,GAExBA,EAAMgC,kBACNhC,EAAMiC,gBACV,CAEA,yBAAAJ,CAA0BK,GACtB,OAAe,MAAXA,EACO,MAgBqD,GAdxC,CACpB,IACA,QACA,SACA,SACA,UACA,QACA,QACA,SACA,SACA,SACA,WACA,SAEgBC,QAAQD,EAAQE,SAASC,gBAIzCH,EAAQI,aAAa,oBACoC,SAAzDJ,EAAQK,aAAa,mBAAmBF,cAJjCH,EAQPA,EAAQM,cACD3C,KAAKgC,0BAA0BK,EAAQM,eAE3C,IACX,GF7CiBlC,OAAQE,GAC7BiC,OAAOC,UAAUC,WAAa,IGzBvB,MACH,WAAAhD,CAAYwB,GACRtB,KAAKsB,SAAWA,CACpB,CACA,aAAAyB,CAAcC,GACV,IAAK,MAAOC,EAAKC,KAAUF,EACvBhD,KAAKmD,YAAYF,EAAKC,EAE9B,CAEA,WAAAC,CAAYF,EAAKC,GACC,OAAVA,GAA4B,KAAVA,EAClBlD,KAAKoD,eAAeH,GAGP3B,SAAS+B,gBAGjBC,MAAMH,YAAYF,EAAKC,EAAO,YAE3C,CAEA,cAAAE,CAAeH,GACE3B,SAAS+B,gBACjBC,MAAMF,eAAeH,EAC9B,GHAwCxC,OAAOa,UACnDb,OAAO8C,eAAeC,kBAEtB/C,OAAOc,iBAAiB,QAASpB,IAC7BM,OAAO8C,eAAeE,kBAAkB,G","sources":["webpack://readium-js/./src/index-reflowable-injectable.ts","webpack://readium-js/./src/bridge/all-gestures-bridge.ts","webpack://readium-js/./src/common/gestures.ts","webpack://readium-js/./src/bridge/reflowable-css-bridge.ts"],"sourcesContent":["//\n// Copyright 2024 Readium Foundation. All rights reserved.\n// Use of this source code is governed by the BSD-style license\n// available in the top-level LICENSE file of the project.\n//\n/**\n * Script loaded by reflowable resources.\n */\nimport { BridgeGesturesAdapter, } from \"./bridge/all-gestures-bridge\";\nimport { CssBridge } from \"./bridge/reflowable-css-bridge\";\nimport { GesturesDetector } from \"./common/gestures\";\nconst bridgeListener = new BridgeGesturesAdapter(window.gestures);\nconst gesturesListener = {\n onTap: (event) => {\n const tapEvent = {\n x: (event.clientX - visualViewport.offsetLeft) * visualViewport.scale,\n y: (event.clientY - visualViewport.offsetTop) * visualViewport.scale,\n };\n bridgeListener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n bridgeListener.onLinkActivated(href, outerHtml);\n },\n};\nnew GesturesDetector(window, gesturesListener);\nWindow.prototype.readiumcss = new CssBridge(window.document);\nwindow.initialization.onScriptsLoaded();\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nwindow.addEventListener(\"load\", (event) => {\n window.initialization.onDocumentLoaded();\n});\n","export class BridgeGesturesAdapter {\n constructor(gesturesApi) {\n this.nativeApi = gesturesApi;\n }\n onTap(event) {\n this.nativeApi.onTap(JSON.stringify(event));\n }\n onLinkActivated(href, outerHtml) {\n this.nativeApi.onLinkActivated(href, outerHtml);\n }\n}\n","export class GesturesDetector {\n constructor(window, listener) {\n this.window = window;\n this.listener = listener;\n document.addEventListener(\"click\", (event) => {\n this.onClick(event);\n }, false);\n }\n onClick(event) {\n if (event.defaultPrevented) {\n return;\n }\n const selection = this.window.getSelection();\n if (selection && selection.type == \"Range\") {\n // There's an on-going selection, the tap will dismiss it so we don't forward it.\n // selection.type might be None (collapsed) or Caret with a collapsed range\n // when there is not true selection.\n return;\n }\n let nearestElement;\n if (event.target instanceof HTMLElement) {\n nearestElement = this.nearestInteractiveElement(event.target);\n }\n else {\n nearestElement = null;\n }\n if (nearestElement) {\n if (nearestElement instanceof HTMLAnchorElement) {\n this.listener.onLinkActivated(nearestElement.href, nearestElement.outerHTML);\n }\n }\n else {\n this.listener.onTap(event);\n }\n event.stopPropagation();\n event.preventDefault();\n }\n // See. https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling\n nearestInteractiveElement(element) {\n if (element == null) {\n return null;\n }\n const interactiveTags = [\n \"a\",\n \"audio\",\n \"button\",\n \"canvas\",\n \"details\",\n \"input\",\n \"label\",\n \"option\",\n \"select\",\n \"submit\",\n \"textarea\",\n \"video\",\n ];\n if (interactiveTags.indexOf(element.nodeName.toLowerCase()) != -1) {\n return element;\n }\n // Checks whether the element is editable by the user.\n if (element.hasAttribute(\"contenteditable\") &&\n element.getAttribute(\"contenteditable\").toLowerCase() != \"false\") {\n return element;\n }\n // Checks parents recursively because the touch might be for example on an inside a .\n if (element.parentElement) {\n return this.nearestInteractiveElement(element.parentElement);\n }\n return null;\n }\n}\n","export class CssBridge {\n constructor(document) {\n this.document = document;\n }\n setProperties(properties) {\n for (const [key, value] of properties) {\n this.setProperty(key, value);\n }\n }\n // For setting user setting.\n setProperty(key, value) {\n if (value === null || value === \"\") {\n this.removeProperty(key);\n }\n else {\n const root = document.documentElement;\n // The `!important` annotation is added with `setProperty()` because if it's part of the\n // `value`, it will be ignored by the Web View.\n root.style.setProperty(key, value, \"important\");\n }\n }\n // For removing user setting.\n removeProperty(key) {\n const root = document.documentElement;\n root.style.removeProperty(key);\n }\n}\n"],"names":["bridgeListener","constructor","gesturesApi","this","nativeApi","onTap","event","JSON","stringify","onLinkActivated","href","outerHtml","window","gestures","gesturesListener","tapEvent","x","clientX","visualViewport","offsetLeft","scale","y","clientY","offsetTop","listener","document","addEventListener","onClick","defaultPrevented","selection","getSelection","type","nearestElement","target","HTMLElement","nearestInteractiveElement","HTMLAnchorElement","outerHTML","stopPropagation","preventDefault","element","indexOf","nodeName","toLowerCase","hasAttribute","getAttribute","parentElement","Window","prototype","readiumcss","setProperties","properties","key","value","setProperty","removeProperty","documentElement","style","initialization","onScriptsLoaded","onDocumentLoaded"],"sourceRoot":""} \ No newline at end of file +{"version":3,"file":"reflowable-injectable-script.js","mappings":"yBAWA,MAAMA,EAAiB,ICXhB,MACH,WAAAC,CAAYC,GACRC,KAAKC,UAAYF,CACrB,CACA,KAAAG,CAAMC,GACFH,KAAKC,UAAUC,MAAME,KAAKC,UAAUF,GACxC,CACA,eAAAG,CAAgBC,EAAMC,GAClBR,KAAKC,UAAUK,gBAAgBC,EAAMC,EACzC,GDE6CC,OAAOC,UAClDC,EAAmB,CACrBT,MAAQC,IACJ,MAAMS,EAAW,CACbC,GAAIV,EAAMW,QAAUC,eAAeC,YAAcD,eAAeE,MAChEC,GAAIf,EAAMgB,QAAUJ,eAAeK,WAAaL,eAAeE,OAEnEpB,EAAeK,MAAMU,EAAS,EAElCN,gBAAiB,CAACC,EAAMC,KACpBX,EAAeS,gBAAgBC,EAAMC,EAAU,GAGvD,IExBO,MACH,WAAAV,CAAYW,EAAQY,GAChBrB,KAAKS,OAASA,EACdT,KAAKqB,SAAWA,EAChBC,SAASC,iBAAiB,SAAUpB,IAChCH,KAAKwB,QAAQrB,EAAM,IACpB,EACP,CACA,OAAAqB,CAAQrB,GACJ,GAAIA,EAAMsB,iBACN,OAEJ,MAAMC,EAAY1B,KAAKS,OAAOkB,eAC9B,GAAID,GAA+B,SAAlBA,EAAUE,KAIvB,OAEJ,IAAIC,EAEAA,EADA1B,EAAM2B,kBAAkBC,YACP/B,KAAKgC,0BAA0B7B,EAAM2B,QAGrC,KAEjBD,EACIA,aAA0BI,mBAC1BjC,KAAKqB,SAASf,gBAAgBuB,EAAetB,KAAMsB,EAAeK,WAItElC,KAAKqB,SAASnB,MAAMC,GAExBA,EAAMgC,kBACNhC,EAAMiC,gBACV,CAEA,yBAAAJ,CAA0BK,GACtB,OAAe,MAAXA,EACO,MAgBqD,GAdxC,CACpB,IACA,QACA,SACA,SACA,UACA,QACA,QACA,SACA,SACA,SACA,WACA,SAEgBC,QAAQD,EAAQE,SAASC,gBAIzCH,EAAQI,aAAa,oBACoC,SAAzDJ,EAAQK,aAAa,mBAAmBF,cAJjCH,EAQPA,EAAQM,cACD3C,KAAKgC,0BAA0BK,EAAQM,eAE3C,IACX,GF7CiBlC,OAAQE,GAC7BiC,OAAOC,UAAUC,WAAa,IGzBvB,MACH,WAAAhD,CAAYwB,GACRtB,KAAKsB,SAAWA,CACpB,CACA,aAAAyB,CAAcC,GACV,IAAK,MAAOC,EAAKC,KAAUF,EACvBhD,KAAKmD,YAAYF,EAAKC,EAE9B,CAEA,WAAAC,CAAYF,EAAKC,GACC,OAAVA,GAA4B,KAAVA,EAClBlD,KAAKoD,eAAeH,GAGP3B,SAAS+B,gBAGjBC,MAAMH,YAAYF,EAAKC,EAAO,YAE3C,CAEA,cAAAE,CAAeH,GACE3B,SAAS+B,gBACjBC,MAAMF,eAAeH,EAC9B,GHAwCxC,OAAOa,UACnDb,OAAO8C,eAAeC,kBAEtB/C,OAAOc,iBAAiB,QAASpB,IACZ,IAAIsD,gBAAe,KAChCC,uBAAsB,KAClBjD,OAAO8C,eAAeI,mBAAmB,GAC3C,IAEGC,QAAQtC,SAASuC,MAC1BpD,OAAO8C,eAAeO,kBAAkB,G","sources":["webpack://readium-js/./src/index-reflowable-injectable.ts","webpack://readium-js/./src/bridge/all-gestures-bridge.ts","webpack://readium-js/./src/common/gestures.ts","webpack://readium-js/./src/bridge/reflowable-css-bridge.ts"],"sourcesContent":["//\n// Copyright 2024 Readium Foundation. All rights reserved.\n// Use of this source code is governed by the BSD-style license\n// available in the top-level LICENSE file of the project.\n//\n/**\n * Script loaded by reflowable resources.\n */\nimport { BridgeGesturesAdapter, } from \"./bridge/all-gestures-bridge\";\nimport { CssBridge } from \"./bridge/reflowable-css-bridge\";\nimport { GesturesDetector } from \"./common/gestures\";\nconst bridgeListener = new BridgeGesturesAdapter(window.gestures);\nconst gesturesListener = {\n onTap: (event) => {\n const tapEvent = {\n x: (event.clientX - visualViewport.offsetLeft) * visualViewport.scale,\n y: (event.clientY - visualViewport.offsetTop) * visualViewport.scale,\n };\n bridgeListener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n bridgeListener.onLinkActivated(href, outerHtml);\n },\n};\nnew GesturesDetector(window, gesturesListener);\nWindow.prototype.readiumcss = new CssBridge(window.document);\nwindow.initialization.onScriptsLoaded();\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nwindow.addEventListener(\"load\", (event) => {\n const observer = new ResizeObserver(() => {\n requestAnimationFrame(() => {\n window.initialization.onDocumentResized();\n });\n });\n observer.observe(document.body);\n window.initialization.onDocumentLoaded();\n});\n","export class BridgeGesturesAdapter {\n constructor(gesturesApi) {\n this.nativeApi = gesturesApi;\n }\n onTap(event) {\n this.nativeApi.onTap(JSON.stringify(event));\n }\n onLinkActivated(href, outerHtml) {\n this.nativeApi.onLinkActivated(href, outerHtml);\n }\n}\n","export class GesturesDetector {\n constructor(window, listener) {\n this.window = window;\n this.listener = listener;\n document.addEventListener(\"click\", (event) => {\n this.onClick(event);\n }, false);\n }\n onClick(event) {\n if (event.defaultPrevented) {\n return;\n }\n const selection = this.window.getSelection();\n if (selection && selection.type == \"Range\") {\n // There's an on-going selection, the tap will dismiss it so we don't forward it.\n // selection.type might be None (collapsed) or Caret with a collapsed range\n // when there is not true selection.\n return;\n }\n let nearestElement;\n if (event.target instanceof HTMLElement) {\n nearestElement = this.nearestInteractiveElement(event.target);\n }\n else {\n nearestElement = null;\n }\n if (nearestElement) {\n if (nearestElement instanceof HTMLAnchorElement) {\n this.listener.onLinkActivated(nearestElement.href, nearestElement.outerHTML);\n }\n }\n else {\n this.listener.onTap(event);\n }\n event.stopPropagation();\n event.preventDefault();\n }\n // See. https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling\n nearestInteractiveElement(element) {\n if (element == null) {\n return null;\n }\n const interactiveTags = [\n \"a\",\n \"audio\",\n \"button\",\n \"canvas\",\n \"details\",\n \"input\",\n \"label\",\n \"option\",\n \"select\",\n \"submit\",\n \"textarea\",\n \"video\",\n ];\n if (interactiveTags.indexOf(element.nodeName.toLowerCase()) != -1) {\n return element;\n }\n // Checks whether the element is editable by the user.\n if (element.hasAttribute(\"contenteditable\") &&\n element.getAttribute(\"contenteditable\").toLowerCase() != \"false\") {\n return element;\n }\n // Checks parents recursively because the touch might be for example on an inside a .\n if (element.parentElement) {\n return this.nearestInteractiveElement(element.parentElement);\n }\n return null;\n }\n}\n","export class CssBridge {\n constructor(document) {\n this.document = document;\n }\n setProperties(properties) {\n for (const [key, value] of properties) {\n this.setProperty(key, value);\n }\n }\n // For setting user setting.\n setProperty(key, value) {\n if (value === null || value === \"\") {\n this.removeProperty(key);\n }\n else {\n const root = document.documentElement;\n // The `!important` annotation is added with `setProperty()` because if it's part of the\n // `value`, it will be ignored by the Web View.\n root.style.setProperty(key, value, \"important\");\n }\n }\n // For removing user setting.\n removeProperty(key) {\n const root = document.documentElement;\n root.style.removeProperty(key);\n }\n}\n"],"names":["bridgeListener","constructor","gesturesApi","this","nativeApi","onTap","event","JSON","stringify","onLinkActivated","href","outerHtml","window","gestures","gesturesListener","tapEvent","x","clientX","visualViewport","offsetLeft","scale","y","clientY","offsetTop","listener","document","addEventListener","onClick","defaultPrevented","selection","getSelection","type","nearestElement","target","HTMLElement","nearestInteractiveElement","HTMLAnchorElement","outerHTML","stopPropagation","preventDefault","element","indexOf","nodeName","toLowerCase","hasAttribute","getAttribute","parentElement","Window","prototype","readiumcss","setProperties","properties","key","value","setProperty","removeProperty","documentElement","style","initialization","onScriptsLoaded","ResizeObserver","requestAnimationFrame","onDocumentResized","observe","body","onDocumentLoaded"],"sourceRoot":""} \ No newline at end of file diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt index 58e8595397..ac0cb27704 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt @@ -14,6 +14,8 @@ import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.displayCutout import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Modifier @@ -73,7 +75,7 @@ public fun ReflowableWebRendition( val itemIndex = state.pagerState.currentPage val itemHref = state.readingOrder.items[itemIndex].href - state.updateLocation(ReflowableWebLocation(itemHref)) + state.updateLocation(ReflowableWebLocation(itemHref, state.currentProgression)) val coroutineScope = rememberCoroutineScope() @@ -97,10 +99,18 @@ public fun ReflowableWebRendition( ?: state.layoutDelegate.settings.value.theme.backgroundColor ) + val readyToScrollNext = remember(state.pagerState.currentPage) { + mutableStateOf(itemIndex == state.pagerState.pageCount - 1) + } + + val readyToScrollPrev = remember(state.pagerState.currentPage) { + mutableStateOf(itemIndex == 0) + } + RenditionPager( modifier = modifier, state = state.pagerState, - beyondViewportPageCount = 2, + beyondViewportPageCount = 3, reverseLayout = reverseLayout, orientation = when { state.layoutDelegate.settings.value.verticalText -> Orientation.Horizontal @@ -121,7 +131,13 @@ public fun ReflowableWebRendition( rsProperties = state.readiumCss.value.rsProperties, userProperties = state.readiumCss.value.userProperties, layout = state.readiumCss.value.layout, - initialProgression = if (index <= itemIndex) 0.0 else 100.0, + initialProgression = when { + index < itemIndex -> 1.0 + index > itemIndex -> 0.0 + else -> state.currentProgression + }, + stickToInitialProgression = index != itemIndex, + enableScroll = readyToScrollNext.value && readyToScrollPrev.value, onTap = { tapEvent -> inputListener.onTap(tapEvent, TapContext(viewportSize.value)) }, @@ -129,6 +145,20 @@ public fun ReflowableWebRendition( coroutineScope.launch { onLinkActivated(url, outerHtml, state, hyperlinkListener) } + }, + onScrollChanged = { + if (index == itemIndex) { + val itemIndex = state.pagerState.currentPage + val itemHref = state.readingOrder.items[itemIndex].href + state.updateLocation(ReflowableWebLocation(itemHref, state.currentProgression)) + } + }, + onReadyToScroll = { + when (index) { + itemIndex - 1 -> readyToScrollPrev.value = true + itemIndex + 1 -> readyToScrollNext.value = true + else -> {} + } } ) } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt index a038f3e72a..1084a3eb48 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt @@ -109,7 +109,7 @@ public class ReflowableWebRenditionState internal constructor( ) } - private val webViewServer = + internal val webViewServer = WebViewServer( application = application, container = container, @@ -129,6 +129,11 @@ public class ReflowableWebRenditionState internal constructor( pageCount = { readingOrder.items.size } ) + internal val currentProgression: Double = + controller?.location?.value?.progression + ?: initialLocation.progression + ?: 0.0 + internal suspend fun computeHyperlinkContext(originUrl: Url, outerHtml: String): LinkContext? = hyperlinkProcessor.computeLinkContext(originUrl, outerHtml) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/DoubleViewportSpread.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/DoubleViewportSpread.kt index c190fa7eeb..c5672b7c7c 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/DoubleViewportSpread.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/DoubleViewportSpread.kt @@ -25,6 +25,7 @@ import org.readium.navigator.web.layout.DoubleViewportSpread import org.readium.navigator.web.util.DisplayArea import org.readium.navigator.web.util.WebViewClient import org.readium.navigator.web.webapi.FixedDoubleApi +import org.readium.navigator.web.webview.RelaxedWebView import org.readium.navigator.web.webview.rememberWebViewStateWithHTMLData import org.readium.r2.navigator.preferences.Fit import org.readium.r2.shared.ExperimentalReadiumApi @@ -43,7 +44,7 @@ internal fun DoubleViewportSpread( modifier = Modifier.fillMaxSize(), propagateMinConstraints = true ) { - val webViewState = rememberWebViewStateWithHTMLData( + val webViewState = rememberWebViewStateWithHTMLData( data = state.htmlData, baseUrl = state.publicationBaseUrl.toString() ) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SingleViewportSpread.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SingleViewportSpread.kt index fb051e9b3a..f54a719a4e 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SingleViewportSpread.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SingleViewportSpread.kt @@ -25,6 +25,7 @@ import org.readium.navigator.web.layout.SingleViewportSpread import org.readium.navigator.web.util.DisplayArea import org.readium.navigator.web.util.WebViewClient import org.readium.navigator.web.webapi.FixedSingleApi +import org.readium.navigator.web.webview.RelaxedWebView import org.readium.navigator.web.webview.rememberWebViewStateWithHTMLData import org.readium.r2.navigator.preferences.Fit import org.readium.r2.shared.ExperimentalReadiumApi @@ -43,7 +44,7 @@ internal fun SingleViewportSpread( modifier = Modifier.fillMaxSize(), propagateMinConstraints = true ) { - val webViewState = rememberWebViewStateWithHTMLData( + val webViewState = rememberWebViewStateWithHTMLData( data = state.htmlData, baseUrl = state.publicationBaseUrl.toString() ) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt index 789578be0f..20d28925bc 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt @@ -34,7 +34,7 @@ import org.readium.r2.shared.util.AbsoluteUrl @SuppressLint("SetJavaScriptEnabled") @Composable internal fun SpreadWebView( - state: WebViewState, + state: WebViewState, client: WebViewClient, onScriptsLoaded: () -> Unit, onTap: (TapEvent) -> Unit, @@ -47,7 +47,7 @@ internal fun SpreadWebView( val spreadNestedScrollConnection = SpreadNestedScrollConnection(scrollableState) val initializationApi = remember(onScriptsLoaded) { - InitializationApi(onScriptsLoaded, {}) + InitializationApi(onScriptsLoaded, {}, {}) } val gesturesApi = remember(onTap) { diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/location/LocationTypes.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/location/LocationTypes.kt index 448835d9c3..9e88e206f5 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/location/LocationTypes.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/location/LocationTypes.kt @@ -24,7 +24,7 @@ public data class ReflowableWebGoLocation( @ExperimentalReadiumApi public data class ReflowableWebLocation( override val href: Url, - // val progression: Double, + val progression: Double, // val cssSelector: String?, // val textBefore: String?, // val textAfter: String?, diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt index 73b1fc963d..e5f1b2eee7 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt @@ -9,6 +9,7 @@ package org.readium.navigator.web.reflowable import android.annotation.SuppressLint +import android.os.Build import android.view.MotionEvent import android.view.View import androidx.compose.foundation.background @@ -77,15 +78,25 @@ internal fun ReflowableResource( rsProperties: RsProperties, layout: Layout, initialProgression: Double, + stickToInitialProgression: Boolean, + enableScroll: Boolean, + onReadyToScroll: () -> Unit, onTap: (TapEvent) -> Unit, onLinkActivated: (Url, String) -> Unit, + onScrollChanged: (Double) -> Unit, ) { + val scrollOrientation = when { + verticalText -> Orientation.Horizontal + scroll -> Orientation.Vertical + else -> Orientation.Horizontal + } + Box( modifier = Modifier.fillMaxSize(), propagateMinConstraints = true ) { val webViewState = - rememberWebViewState( + rememberWebViewState( url = publicationBaseUrl.resolve(href).toString() ) @@ -96,7 +107,13 @@ internal fun ReflowableResource( val contentIsLaidOut = remember(webViewState.webView) { mutableStateOf(false) } - val initializationApi = remember(webViewState.webView) { + val readyToScroll = remember(webViewState.webView) { mutableStateOf(false) } + + if (readyToScroll.value) { + onReadyToScroll() + } + + val initializationApi = remember(webViewState.webView, stickToInitialProgression) { InitializationApi( onScriptsLoadedDelegate = { scriptsLoaded.value = true @@ -118,6 +135,12 @@ internal fun ReflowableResource( } } } + }, + onDocumentResizedDelegate = { + readyToScroll.value = true + if (stickToInitialProgression) { + webViewState.webView?.scrollToProgression(initialProgression, scrollOrientation) + } } ) } @@ -160,20 +183,21 @@ internal fun ReflowableResource( val density = LocalDensity.current - val scrollOrientation = when { - verticalText -> Orientation.Horizontal - scroll -> Orientation.Vertical - else -> Orientation.Horizontal - } - LaunchedEffect(contentIsLaidOut, contentIsLaidOut.value, scrollableState.webView) { - scrollableState.webView?.let { webview -> - if (scrollOrientation == Orientation.Horizontal) { - webview.scrollTo(floor(initialProgression * webview.maxScrollX).toInt(), 0) - } else { - webview.scrollTo(0, ceil(initialProgression * webview.maxScrollY).toInt()) + scrollableState.webView + .takeIf { contentIsLaidOut.value } + ?.let { webview -> + webview.scrollToProgression(initialProgression, scrollOrientation) + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + webview.setOnScrollChangeListener { view, scrollX, scrollY, oldScrollX, oldScrollY -> + onScrollChanged(webview.progression(scrollOrientation)) + } + } else { + // Broken + throw IllegalStateException() + } } - } } val webViewViewport = DpSize( @@ -185,7 +209,7 @@ internal fun ReflowableResource( if (scroll) { null } else { - (webViewState.webView as? RelaxedWebView) + webViewState.webView ?.let { pagingFlingBehavior( WebViewLayoutInfoProvider( @@ -216,7 +240,7 @@ internal fun ReflowableResource( ) } .scrollable2D( - enabled = contentIsLaidOut.value, + enabled = enableScroll, state = scrollableState, flingBehavior = flingBehavior, reverseDirection = !reverseLayout, @@ -258,6 +282,19 @@ internal fun ReflowableResource( } } +private fun RelaxedWebView.scrollToProgression(progression: Double, scrollOrientation: Orientation) { + if (scrollOrientation == Orientation.Horizontal) { + scrollTo(floor(progression * maxScrollX).toInt(), 0) + } else { + scrollTo(0, ceil(progression * maxScrollY).toInt()) + } +} + +private fun RelaxedWebView.progression(orientation: Orientation) = when (orientation) { + Orientation.Vertical -> scrollY / maxScrollY.toDouble() + Orientation.Horizontal -> scrollX / maxScrollX.toDouble() +} + private fun FlingBehavior.toFling2DBehavior(orientation: Orientation) = object : Fling2DBehavior { override suspend fun Scroll2DScope.performFling( diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/util/WebViewClient.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/util/WebViewClient.kt index 2b4be265ec..bb64c6e84c 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/util/WebViewClient.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/util/WebViewClient.kt @@ -9,9 +9,12 @@ package org.readium.navigator.web.util import android.webkit.WebResourceRequest import android.webkit.WebResourceResponse import android.webkit.WebView +import androidx.webkit.WebViewCompat +import androidx.webkit.WebViewFeature internal class WebViewClient( private val webViewServer: WebViewServer, + private val onPageFinishedDelegate: (() -> Unit)? = null, ) : android.webkit.WebViewClient() { override fun shouldInterceptRequest( @@ -20,4 +23,12 @@ internal class WebViewClient( ): WebResourceResponse? { return webViewServer.shouldInterceptRequest(request) } + + override fun onPageFinished(view: WebView, url: String?) { + if (WebViewFeature.isFeatureSupported(WebViewFeature.VISUAL_STATE_CALLBACK)) { + WebViewCompat.postVisualStateCallback(view, 0) { + onPageFinishedDelegate?.invoke() + } + } + } } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/webapi/InitializationApi.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/webapi/InitializationApi.kt index d8c5947845..8d5c2de452 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/webapi/InitializationApi.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/webapi/InitializationApi.kt @@ -12,6 +12,7 @@ import android.webkit.WebView internal class InitializationApi( private val onScriptsLoadedDelegate: () -> Unit, private val onDocumentLoadedDelegate: () -> Unit, + private val onDocumentResizedDelegate: () -> Unit, ) { fun registerOnWebView(webView: WebView) { @@ -27,4 +28,9 @@ internal class InitializationApi( fun onDocumentLoaded() { onDocumentLoadedDelegate.invoke() } + + @JavascriptInterface + fun onDocumentResized() { + onDocumentResizedDelegate.invoke() + } } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/ComposableWebView.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/ComposableWebView.kt index f3626b4a9a..67185baeb6 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/ComposableWebView.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/ComposableWebView.kt @@ -48,7 +48,7 @@ import androidx.compose.ui.viewinterop.AndroidView @SuppressLint("UnusedBoxWithConstraintsScope") @Composable internal fun WebView( - state: WebViewState, + state: WebViewState, modifier: Modifier = Modifier, onCreated: (WebView) -> Unit = {}, onDispose: (WebView) -> Unit = {}, @@ -86,7 +86,7 @@ internal fun WebView( @SuppressLint("UnusedBoxWithConstraintsScope") @Composable internal fun WebView( - state: WebViewState, + state: WebViewState, factory: ((Context) -> T), modifier: Modifier = Modifier, onCreated: (T) -> Unit = {}, @@ -161,7 +161,7 @@ internal fun WebView( */ @Composable internal fun WebView( - state: WebViewState, + state: WebViewState, factory: ((Context) -> T), layoutParams: FrameLayout.LayoutParams, modifier: Modifier = Modifier, @@ -232,7 +232,7 @@ internal sealed class WebContent { * using the rememberWebViewState(uri) function. */ @Stable -internal class WebViewState(webContent: WebContent) { +internal class WebViewState(webContent: WebContent) { /** * The content being loaded by the WebView */ @@ -240,7 +240,7 @@ internal class WebViewState(webContent: WebContent) { // An internal DisposableEffect or AndroidView onDestroy is called // after the state saver and so can't be used. - internal var webView by mutableStateOf(null) + internal var webView by mutableStateOf(null) } /** @@ -251,14 +251,14 @@ internal class WebViewState(webContent: WebContent) { * Note that these headers are used for all subsequent requests of the WebView. */ @Composable -internal fun rememberWebViewState( +internal fun rememberWebViewState( url: String, additionalHttpHeaders: Map = emptyMap(), -): WebViewState = +): WebViewState = // Rather than using .apply {} here we will recreate the state, this prevents // a recomposition loop when the webview updates the url itself. remember { - WebViewState( + WebViewState( WebContent.Url( url = url, additionalHttpHeaders = additionalHttpHeaders @@ -277,15 +277,15 @@ internal fun rememberWebViewState( * @param data The uri to load in the WebView */ @Composable -internal fun rememberWebViewStateWithHTMLData( +internal fun rememberWebViewStateWithHTMLData( data: String, baseUrl: String? = null, encoding: String = "utf-8", mimeType: String? = null, historyUrl: String? = null, -): WebViewState = +): WebViewState = remember { - WebViewState(WebContent.Data(data, baseUrl, encoding, mimeType, historyUrl)) + WebViewState(WebContent.Data(data, baseUrl, encoding, mimeType, historyUrl)) }.apply { this.content = WebContent.Data( data, From 33b1e6002ab6cf17dcbb82c6c72b233f5582a842 Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Mon, 6 Jan 2025 11:18:17 +0100 Subject: [PATCH 14/88] Bump minSdk to 23 --- readium/navigators/demo/build.gradle.kts | 2 +- readium/navigators/web/build.gradle.kts | 4 +++ .../web/reflowable/ReflowableResource.kt | 33 ++++++------------- 3 files changed, 15 insertions(+), 24 deletions(-) diff --git a/readium/navigators/demo/build.gradle.kts b/readium/navigators/demo/build.gradle.kts index 26dfc39076..5322e6aece 100644 --- a/readium/navigators/demo/build.gradle.kts +++ b/readium/navigators/demo/build.gradle.kts @@ -10,7 +10,7 @@ android { compileSdk = (property("android.compileSdk") as String).toInt() defaultConfig { - minSdk = (property("android.minSdk") as String).toInt() + minSdk = 23 targetSdk = (property("android.targetSdk") as String).toInt() applicationId = "org.readium.navigator.demo" diff --git a/readium/navigators/web/build.gradle.kts b/readium/navigators/web/build.gradle.kts index f2f9b447ef..2e921781e2 100644 --- a/readium/navigators/web/build.gradle.kts +++ b/readium/navigators/web/build.gradle.kts @@ -16,6 +16,10 @@ android { buildFeatures { compose = true } + + defaultConfig { + minSdk = 23 + } } dependencies { diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt index e5f1b2eee7..671b34c991 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt @@ -9,9 +9,9 @@ package org.readium.navigator.web.reflowable import android.annotation.SuppressLint -import android.os.Build import android.view.MotionEvent import android.view.View +import android.webkit.WebView import androidx.compose.foundation.background import androidx.compose.foundation.gestures.FlingBehavior import androidx.compose.foundation.gestures.Orientation @@ -32,9 +32,6 @@ import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.DpOffset import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.Velocity -import androidx.core.view.postDelayed -import androidx.webkit.WebViewCompat -import androidx.webkit.WebViewFeature import kotlin.Float import kotlin.math.ceil import kotlin.math.floor @@ -121,18 +118,14 @@ internal fun ReflowableResource( onDocumentLoadedDelegate = { webViewState.webView?.apply { post { - if (WebViewFeature.isFeatureSupported(WebViewFeature.VISUAL_STATE_CALLBACK)) { - WebViewCompat.postVisualStateCallback(this, 0) { - contentIsLaidOut.value = true + postVisualStateCallback( + 0, + object : WebView.VisualStateCallback() { + override fun onComplete(requestId: Long) { + contentIsLaidOut.value = true + } } - } else { - // On older devices, there's no reliable way to guarantee the page is fully laid out. - // As a workaround, we run a dummy JavaScript, then wait for a short delay before - // assuming it's ready. - evaluateJavascript("true") { - postDelayed(500) { contentIsLaidOut.value = true } - } - } + ) } } }, @@ -188,14 +181,8 @@ internal fun ReflowableResource( .takeIf { contentIsLaidOut.value } ?.let { webview -> webview.scrollToProgression(initialProgression, scrollOrientation) - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - webview.setOnScrollChangeListener { view, scrollX, scrollY, oldScrollX, oldScrollY -> - onScrollChanged(webview.progression(scrollOrientation)) - } - } else { - // Broken - throw IllegalStateException() + webview.setOnScrollChangeListener { view, scrollX, scrollY, oldScrollX, oldScrollY -> + onScrollChanged(webview.progression(scrollOrientation)) } } } From 0e6c6f8d34826b5e09e6a0249f0fe49e377be253 Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Fri, 28 Mar 2025 11:31:44 +0100 Subject: [PATCH 15/88] Restore default behavior in Scrollable2D: pre/postScroll are called when flinging --- .../web/fixed/SpreadNestedScrollConnection.kt | 4 ++++ .../navigator/web/gestures/Scrollable2D.kt | 22 +++++++++++++------ .../web/pager/PagerNestedScrollConnection.kt | 8 +++++++ 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadNestedScrollConnection.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadNestedScrollConnection.kt index eef936546d..5c22e463a8 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadNestedScrollConnection.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadNestedScrollConnection.kt @@ -19,6 +19,10 @@ internal class SpreadNestedScrollConnection( ) : NestedScrollConnection { override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { + if (source != NestedScrollSource.UserInput) { + return Offset.Zero + } + val webViewNow = webviewState.webView ?: return Offset.Zero // For some reason, scrollX can vary by 1 or 2 pixels without any call to scrollTo. diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/gestures/Scrollable2D.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/gestures/Scrollable2D.kt index 7a9234def9..aadc8aa4ee 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/gestures/Scrollable2D.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/gestures/Scrollable2D.kt @@ -51,6 +51,7 @@ import androidx.compose.ui.geometry.Offset import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.NestedScrollDispatcher import androidx.compose.ui.input.nestedscroll.NestedScrollSource +import androidx.compose.ui.input.nestedscroll.NestedScrollSource.Companion.SideEffect import androidx.compose.ui.input.nestedscroll.nestedScrollModifierNode import androidx.compose.ui.input.pointer.PointerEvent import androidx.compose.ui.input.pointer.PointerEventPass @@ -656,15 +657,22 @@ internal class ScrollingLogic( suspend fun doFlingAnimation(available: Velocity): Velocity { var result: Velocity = available - // Unlike the scrollable modifier, we bypass nested scroll while performing fling - // so that nested scroll is more predictable : ancestors do not get called while - // this is performing fling, only preFling beforehand and postFling afterwards. - scrollableState.scroll(scrollPriority = MutatePriority.Default) { - with(flingBehavior) { - result = performFling(available.reverseIfNeeded()).reverseIfNeeded() + scroll(scrollPriority = MutatePriority.Default) { + val nestedScrollScope = this + val reverseScope = object : Scroll2DScope { + override fun scrollBy(pixels: Offset): Offset { + return nestedScrollScope.scrollByWithOverscroll( + offset = pixels.reverseIfNeeded(), + source = SideEffect + ).reverseIfNeeded() + } + } + with(reverseScope) { + with(flingBehavior) { + result = performFling(available.reverseIfNeeded()).reverseIfNeeded() + } } } - return result } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/PagerNestedScrollConnection.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/PagerNestedScrollConnection.kt index d1722adfa1..71cd63b96f 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/PagerNestedScrollConnection.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/PagerNestedScrollConnection.kt @@ -31,6 +31,10 @@ internal class PagerNestedScrollConnection( layoutInfo.visiblePagesInfo.last().offset override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { + if (source != NestedScrollSource.UserInput) { + return Offset.Zero + } + if (state.layoutInfo.visiblePagesInfo.size <= 1) { return Offset.Zero } @@ -88,6 +92,10 @@ internal class PagerNestedScrollConnection( available: Offset, source: NestedScrollSource, ): Offset { + if (source != NestedScrollSource.UserInput) { + return Offset.Zero + } + if (orientation == Orientation.Horizontal && abs(consumed.y) > 0 || orientation == Orientation.Vertical && abs(consumed.x) > 0 ) { From c60089dbc153b2b01ea30d15738077b40c74f4d7 Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Fri, 28 Mar 2025 14:51:35 +0100 Subject: [PATCH 16/88] Implement a different nested scroll strategy --- .idea/inspectionProfiles/Project_Default.xml | 3 + .../navigator/web/ReflowableWebRendition.kt | 2 + .../web/pager/PageNestedScrollConnection.kt | 38 ++ .../web/pager/PagerNestedScrollConnection.kt | 24 +- .../navigator/web/pager/RenditionPager.kt | 15 +- .../web/reflowable/ReflowableResource.kt | 12 +- .../ResourceNestedScrollConnection.kt | 80 +++ .../LazyListSnapLayoutInfoProvider.kt | 3 - .../web/snapping/PagingFlingBehavior.kt | 2 +- .../web/snapping/SnapFlingBehavior.kt | 516 ++++++++++++++++++ .../web/webview/WebViewScrollable2DState.kt | 8 +- settings.gradle.kts | 2 +- 12 files changed, 685 insertions(+), 20 deletions(-) create mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/pager/PageNestedScrollConnection.kt create mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ResourceNestedScrollConnection.kt create mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/SnapFlingBehavior.kt diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml index 31a91a0896..c525a128f2 100644 --- a/.idea/inspectionProfiles/Project_Default.xml +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -65,6 +65,9 @@ .\n if (element.parentElement) {\n return this.nearestInteractiveElement(element.parentElement);\n }\n return null;\n }\n}\n","import { computeScale } from \"../util/fit\";\nimport { PageManager } from \"./page-manager\";\nimport { ViewportStringBuilder } from \"../util/viewport\";\nimport { GesturesDetector } from \"../common/gestures\";\nexport class DoubleAreaManager {\n constructor(window, leftIframe, rightIframe, metaViewport, listener) {\n this.fit = \"contain\" /* Fit.Contain */;\n this.insets = { top: 0, right: 0, bottom: 0, left: 0 };\n window.addEventListener(\"message\", (event) => {\n if (!event.ports[0]) {\n return;\n }\n if (event.source === leftIframe.contentWindow) {\n this.leftPage.setMessagePort(event.ports[0]);\n }\n else if (event.source == rightIframe.contentWindow) {\n this.rightPage.setMessagePort(event.ports[0]);\n }\n });\n const wrapperGesturesListener = {\n onTap: (event) => {\n const tapEvent = {\n x: (event.clientX - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.clientY - visualViewport.offsetTop) * visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onLinkActivated: (_) => {\n throw Error(\"No interactive element in the root document.\");\n },\n };\n new GesturesDetector(window, wrapperGesturesListener);\n const leftPageListener = {\n onIframeLoaded: () => {\n this.layout();\n },\n onTap: (event) => {\n const boundingRect = leftIframe.getBoundingClientRect();\n const tapEvent = {\n x: (event.x + boundingRect.left - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.y + boundingRect.top - visualViewport.offsetTop) *\n visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n listener.onLinkActivated(href, outerHtml);\n },\n };\n const rightPageListener = {\n onIframeLoaded: () => {\n this.layout();\n },\n onTap: (event) => {\n const boundingRect = rightIframe.getBoundingClientRect();\n const tapEvent = {\n x: (event.x + boundingRect.left - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.y + boundingRect.top - visualViewport.offsetTop) *\n visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n listener.onLinkActivated(href, outerHtml);\n },\n };\n this.leftPage = new PageManager(window, leftIframe, leftPageListener);\n this.rightPage = new PageManager(window, rightIframe, rightPageListener);\n this.metaViewport = metaViewport;\n }\n loadSpread(spread) {\n this.leftPage.hide();\n this.rightPage.hide();\n this.spread = spread;\n if (spread.left) {\n this.leftPage.loadPage(spread.left);\n }\n if (spread.right) {\n this.rightPage.loadPage(spread.right);\n }\n }\n setViewport(size, insets) {\n if (this.viewport == size && this.insets == insets) {\n return;\n }\n this.viewport = size;\n this.insets = insets;\n this.layout();\n }\n setFit(fit) {\n if (this.fit == fit) {\n return;\n }\n this.fit = fit;\n this.layout();\n }\n layout() {\n if (!this.viewport ||\n (!this.leftPage.size && this.spread.left) ||\n (!this.rightPage.size && this.spread.right)) {\n return;\n }\n const leftMargins = {\n top: this.insets.top,\n right: 0,\n bottom: this.insets.bottom,\n left: this.insets.left,\n };\n this.leftPage.setMargins(leftMargins);\n const rightMargins = {\n top: this.insets.top,\n right: this.insets.right,\n bottom: this.insets.bottom,\n left: 0,\n };\n this.rightPage.setMargins(rightMargins);\n if (!this.spread.right) {\n this.rightPage.setPlaceholder(this.leftPage.size);\n }\n else if (!this.spread.left) {\n this.leftPage.setPlaceholder(this.rightPage.size);\n }\n const contentWidth = this.leftPage.size.width + this.rightPage.size.width;\n const contentHeight = Math.max(this.leftPage.size.height, this.rightPage.size.height);\n const contentSize = { width: contentWidth, height: contentHeight };\n const safeDrawingSize = {\n width: this.viewport.width - this.insets.left - this.insets.right,\n height: this.viewport.height - this.insets.top - this.insets.bottom,\n };\n const scale = computeScale(this.fit, contentSize, safeDrawingSize);\n this.metaViewport.content = new ViewportStringBuilder()\n .setInitialScale(scale)\n .setMinimumScale(scale)\n .setWidth(contentWidth)\n .setHeight(contentHeight)\n .build();\n this.leftPage.show();\n this.rightPage.show();\n }\n}\n","export function computeScale(fit, content, container) {\n switch (fit) {\n case \"contain\" /* Fit.Contain */:\n return fitContain(content, container);\n case \"width\" /* Fit.Width */:\n return fitWidth(content, container);\n case \"height\" /* Fit.Height */:\n return fitHeight(content, container);\n }\n}\nfunction fitContain(content, container) {\n const widthRatio = container.width / content.width;\n const heightRatio = container.height / content.height;\n return Math.min(widthRatio, heightRatio);\n}\nfunction fitWidth(content, container) {\n return container.width / content.width;\n}\nfunction fitHeight(content, container) {\n return container.height / content.height;\n}\n","export class BridgeGesturesAdapter {\n constructor(gesturesApi) {\n this.nativeApi = gesturesApi;\n }\n onTap(event) {\n this.nativeApi.onTap(JSON.stringify(event));\n }\n onLinkActivated(href, outerHtml) {\n this.nativeApi.onLinkActivated(href, outerHtml);\n }\n}\n","//\n// Copyright 2024 Readium Foundation. All rights reserved.\n// Use of this source code is governed by the BSD-style license\n// available in the top-level LICENSE file of the project.\n//\nimport { FixedDoubleBridge } from \"./bridge/fixed-double-bridge\";\nconst leftIframe = document.getElementById(\"page-left\");\nconst rightIframe = document.getElementById(\"page-right\");\nconst metaViewport = document.querySelector(\"meta[name=viewport]\");\nWindow.prototype.doubleArea = new FixedDoubleBridge(window, leftIframe, rightIframe, metaViewport, window.gestures);\nwindow.initialization.onScriptsLoaded();\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nwindow.addEventListener(\"load\", (event) => {\n window.initialization.onDocumentLoaded();\n});\n","import { DoubleAreaManager } from \"../fixed/double-area-manager\";\nimport { BridgeGesturesAdapter } from \"./all-gestures-bridge\";\nexport class FixedDoubleBridge {\n constructor(window, leftIframe, rightIframe, metaViewport, gestures) {\n const listener = new BridgeGesturesAdapter(gestures);\n this.manager = new DoubleAreaManager(window, leftIframe, rightIframe, metaViewport, listener);\n }\n loadSpread(spread) {\n this.manager.loadSpread(spread);\n }\n setViewport(viewporttWidth, viewportHeight, insetTop, insetRight, insetBottom, insetLeft) {\n const viewport = { width: viewporttWidth, height: viewportHeight };\n const insets = {\n top: insetTop,\n left: insetLeft,\n bottom: insetBottom,\n right: insetRight,\n };\n this.manager.setViewport(viewport, insets);\n }\n setFit(fit) {\n if (fit != \"contain\" && fit != \"width\" && fit != \"height\") {\n throw Error(`Invalid fit value: ${fit}`);\n }\n this.manager.setFit(fit);\n }\n}\n"],"names":["PageManager","constructor","window","iframe","listener","this","margins","top","right","bottom","left","contentWindow","Error","setMessagePort","messagePort","onmessage","message","onMessageFromIframe","show","style","display","hide","setMargins","marginTop","marginLeft","marginBottom","marginRight","loadPage","url","src","setPlaceholder","size","visibility","width","height","event","data","kind","onContentSizeAvailable","onTap","x","y","onLinkActivated","URL","href","toString","outerHtml","_a","onIframeLoaded","ViewportStringBuilder","setInitialScale","scale","initialScale","setMinimumScale","minimumScale","setWidth","setHeight","build","components","push","join","GesturesDetector","document","addEventListener","onClick","defaultPrevented","selection","getSelection","type","nearestElement","target","HTMLElement","nearestInteractiveElement","HTMLAnchorElement","outerHTML","stopPropagation","preventDefault","element","indexOf","nodeName","toLowerCase","hasAttribute","getAttribute","parentElement","DoubleAreaManager","leftIframe","rightIframe","metaViewport","fit","insets","ports","source","leftPage","rightPage","tapEvent","clientX","visualViewport","offsetLeft","clientY","offsetTop","_","leftPageListener","layout","boundingRect","getBoundingClientRect","rightPageListener","loadSpread","spread","setViewport","viewport","setFit","leftMargins","rightMargins","contentWidth","contentHeight","Math","max","contentSize","safeDrawingSize","content","container","widthRatio","heightRatio","min","fitContain","fitWidth","fitHeight","computeScale","BridgeGesturesAdapter","gesturesApi","nativeApi","JSON","stringify","getElementById","querySelector","Window","prototype","doubleArea","gestures","manager","viewporttWidth","viewportHeight","insetTop","insetRight","insetBottom","insetLeft","initialization","onScriptsLoaded","onDocumentLoaded"],"sourceRoot":""} \ No newline at end of file +{"version":3,"file":"fixed-double-script.js","mappings":"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","sources":["webpack://readium-js/./src/fixed/page-manager.ts","webpack://readium-js/./src/util/viewport.ts","webpack://readium-js/./src/common/gestures.ts","webpack://readium-js/./src/fixed/double-area-manager.ts","webpack://readium-js/./src/util/fit.ts","webpack://readium-js/./src/bridge/all-gestures-bridge.ts","webpack://readium-js/./src/index-fixed-double.ts","webpack://readium-js/./src/bridge/fixed-double-bridge.ts"],"sourcesContent":["/** Manages a fixed layout resource embedded in an iframe. */\nexport class PageManager {\n constructor(window, iframe, listener) {\n this.margins = { top: 0, right: 0, bottom: 0, left: 0 };\n if (!iframe.contentWindow) {\n throw Error(\"Iframe argument must have been attached to DOM.\");\n }\n this.listener = listener;\n this.iframe = iframe;\n }\n setMessagePort(messagePort) {\n messagePort.onmessage = (message) => {\n this.onMessageFromIframe(message);\n };\n }\n show() {\n this.iframe.style.display = \"unset\";\n }\n hide() {\n this.iframe.style.display = \"none\";\n }\n /** Sets page margins. */\n setMargins(margins) {\n if (this.margins == margins) {\n return;\n }\n this.iframe.style.marginTop = this.margins.top + \"px\";\n this.iframe.style.marginLeft = this.margins.left + \"px\";\n this.iframe.style.marginBottom = this.margins.bottom + \"px\";\n this.iframe.style.marginRight = this.margins.right + \"px\";\n }\n /** Loads page content. */\n loadPage(url) {\n this.iframe.src = url;\n }\n /** Sets the size of this page without content. */\n setPlaceholder(size) {\n this.iframe.style.visibility = \"hidden\";\n this.iframe.style.width = size.width + \"px\";\n this.iframe.style.height = size.height + \"px\";\n this.size = size;\n }\n onMessageFromIframe(event) {\n const message = event.data;\n switch (message.kind) {\n case \"contentSize\":\n return this.onContentSizeAvailable(message.size);\n case \"tap\":\n return this.listener.onTap({ x: message.x, y: message.y });\n case \"linkActivated\":\n return this.onLinkActivated(message);\n }\n }\n onLinkActivated(message) {\n try {\n const url = new URL(message.href, this.iframe.src);\n this.listener.onLinkActivated(url.toString(), message.outerHtml);\n }\n catch (_a) {\n // Do nothing if url is not valid.\n }\n }\n onContentSizeAvailable(size) {\n if (!size) {\n //FIXME: handle edge case\n return;\n }\n this.iframe.style.width = size.width + \"px\";\n this.iframe.style.height = size.height + \"px\";\n this.size = size;\n this.listener.onIframeLoaded();\n }\n}\n","export class ViewportStringBuilder {\n setInitialScale(scale) {\n this.initialScale = scale;\n return this;\n }\n setMinimumScale(scale) {\n this.minimumScale = scale;\n return this;\n }\n setWidth(width) {\n this.width = width;\n return this;\n }\n setHeight(height) {\n this.height = height;\n return this;\n }\n build() {\n const components = [];\n if (this.initialScale) {\n components.push(\"initial-scale=\" + this.initialScale);\n }\n if (this.minimumScale) {\n components.push(\"minimum-scale=\" + this.minimumScale);\n }\n if (this.width) {\n components.push(\"width=\" + this.width);\n }\n if (this.height) {\n components.push(\"height=\" + this.height);\n }\n return components.join(\", \");\n }\n}\nexport function parseViewportString(viewportString) {\n const regex = /(\\w+) *= *([^\\s,]+)/g;\n const properties = new Map();\n let match;\n while ((match = regex.exec(viewportString))) {\n if (match != null) {\n properties.set(match[1], match[2]);\n }\n }\n const width = parseFloat(properties.get(\"width\"));\n const height = parseFloat(properties.get(\"height\"));\n if (width && height) {\n return { width, height };\n }\n else {\n return undefined;\n }\n}\n","export class GesturesDetector {\n constructor(window, listener) {\n this.window = window;\n this.listener = listener;\n document.addEventListener(\"click\", (event) => {\n this.onClick(event);\n }, false);\n }\n onClick(event) {\n if (event.defaultPrevented) {\n return;\n }\n const selection = this.window.getSelection();\n if (selection && selection.type == \"Range\") {\n // There's an on-going selection, the tap will dismiss it so we don't forward it.\n // selection.type might be None (collapsed) or Caret with a collapsed range\n // when there is not true selection.\n return;\n }\n let nearestElement;\n if (event.target instanceof HTMLElement) {\n nearestElement = this.nearestInteractiveElement(event.target);\n }\n else {\n nearestElement = null;\n }\n if (nearestElement) {\n if (nearestElement instanceof HTMLAnchorElement) {\n this.listener.onLinkActivated(nearestElement.href, nearestElement.outerHTML);\n }\n }\n else {\n this.listener.onTap(event);\n }\n event.stopPropagation();\n event.preventDefault();\n }\n // See. https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling\n nearestInteractiveElement(element) {\n if (element == null) {\n return null;\n }\n const interactiveTags = [\n \"a\",\n \"audio\",\n \"button\",\n \"canvas\",\n \"details\",\n \"input\",\n \"label\",\n \"option\",\n \"select\",\n \"submit\",\n \"textarea\",\n \"video\",\n ];\n if (interactiveTags.indexOf(element.nodeName.toLowerCase()) != -1) {\n return element;\n }\n // Checks whether the element is editable by the user.\n if (element.hasAttribute(\"contenteditable\") &&\n element.getAttribute(\"contenteditable\").toLowerCase() != \"false\") {\n return element;\n }\n // Checks parents recursively because the touch might be for example on an inside a .\n if (element.parentElement) {\n return this.nearestInteractiveElement(element.parentElement);\n }\n return null;\n }\n}\n","import { computeScale } from \"../util/fit\";\nimport { PageManager } from \"./page-manager\";\nimport { ViewportStringBuilder } from \"../util/viewport\";\nimport { GesturesDetector } from \"../common/gestures\";\nexport class DoubleAreaManager {\n constructor(window, leftIframe, rightIframe, metaViewport, listener) {\n this.fit = \"contain\" /* Fit.Contain */;\n this.insets = { top: 0, right: 0, bottom: 0, left: 0 };\n window.addEventListener(\"message\", (event) => {\n if (!event.ports[0]) {\n return;\n }\n if (event.source === leftIframe.contentWindow) {\n this.leftPage.setMessagePort(event.ports[0]);\n }\n else if (event.source == rightIframe.contentWindow) {\n this.rightPage.setMessagePort(event.ports[0]);\n }\n });\n const wrapperGesturesListener = {\n onTap: (event) => {\n const tapEvent = {\n x: (event.clientX - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.clientY - visualViewport.offsetTop) * visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onLinkActivated: (_) => {\n throw Error(\"No interactive element in the root document.\");\n },\n };\n new GesturesDetector(window, wrapperGesturesListener);\n const leftPageListener = {\n onIframeLoaded: () => {\n this.layout();\n },\n onTap: (event) => {\n const boundingRect = leftIframe.getBoundingClientRect();\n const tapEvent = {\n x: (event.x + boundingRect.left - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.y + boundingRect.top - visualViewport.offsetTop) *\n visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n listener.onLinkActivated(href, outerHtml);\n },\n };\n const rightPageListener = {\n onIframeLoaded: () => {\n this.layout();\n },\n onTap: (event) => {\n const boundingRect = rightIframe.getBoundingClientRect();\n const tapEvent = {\n x: (event.x + boundingRect.left - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.y + boundingRect.top - visualViewport.offsetTop) *\n visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n listener.onLinkActivated(href, outerHtml);\n },\n };\n this.leftPage = new PageManager(window, leftIframe, leftPageListener);\n this.rightPage = new PageManager(window, rightIframe, rightPageListener);\n this.metaViewport = metaViewport;\n }\n loadSpread(spread) {\n this.leftPage.hide();\n this.rightPage.hide();\n this.spread = spread;\n if (spread.left) {\n this.leftPage.loadPage(spread.left);\n }\n if (spread.right) {\n this.rightPage.loadPage(spread.right);\n }\n }\n setViewport(size, insets) {\n if (this.viewport == size && this.insets == insets) {\n return;\n }\n this.viewport = size;\n this.insets = insets;\n this.layout();\n }\n setFit(fit) {\n if (this.fit == fit) {\n return;\n }\n this.fit = fit;\n this.layout();\n }\n layout() {\n if (!this.viewport ||\n (!this.leftPage.size && this.spread.left) ||\n (!this.rightPage.size && this.spread.right)) {\n return;\n }\n const leftMargins = {\n top: this.insets.top,\n right: 0,\n bottom: this.insets.bottom,\n left: this.insets.left,\n };\n this.leftPage.setMargins(leftMargins);\n const rightMargins = {\n top: this.insets.top,\n right: this.insets.right,\n bottom: this.insets.bottom,\n left: 0,\n };\n this.rightPage.setMargins(rightMargins);\n if (!this.spread.right) {\n this.rightPage.setPlaceholder(this.leftPage.size);\n }\n else if (!this.spread.left) {\n this.leftPage.setPlaceholder(this.rightPage.size);\n }\n const contentWidth = this.leftPage.size.width + this.rightPage.size.width;\n const contentHeight = Math.max(this.leftPage.size.height, this.rightPage.size.height);\n const contentSize = { width: contentWidth, height: contentHeight };\n const safeDrawingSize = {\n width: this.viewport.width - this.insets.left - this.insets.right,\n height: this.viewport.height - this.insets.top - this.insets.bottom,\n };\n const scale = computeScale(this.fit, contentSize, safeDrawingSize);\n this.metaViewport.content = new ViewportStringBuilder()\n .setInitialScale(scale)\n .setMinimumScale(scale)\n .setWidth(contentWidth)\n .setHeight(contentHeight)\n .build();\n this.leftPage.show();\n this.rightPage.show();\n }\n}\n","export function computeScale(fit, content, container) {\n switch (fit) {\n case \"contain\" /* Fit.Contain */:\n return fitContain(content, container);\n case \"width\" /* Fit.Width */:\n return fitWidth(content, container);\n case \"height\" /* Fit.Height */:\n return fitHeight(content, container);\n }\n}\nfunction fitContain(content, container) {\n const widthRatio = container.width / content.width;\n const heightRatio = container.height / content.height;\n return Math.min(widthRatio, heightRatio);\n}\nfunction fitWidth(content, container) {\n return container.width / content.width;\n}\nfunction fitHeight(content, container) {\n return container.height / content.height;\n}\n","export class BridgeGesturesAdapter {\n constructor(gesturesApi) {\n this.nativeApi = gesturesApi;\n }\n onTap(event) {\n this.nativeApi.onTap(JSON.stringify(event));\n }\n onLinkActivated(href, outerHtml) {\n this.nativeApi.onLinkActivated(href, outerHtml);\n }\n}\n","//\n// Copyright 2024 Readium Foundation. All rights reserved.\n// Use of this source code is governed by the BSD-style license\n// available in the top-level LICENSE file of the project.\n//\nimport { FixedDoubleBridge } from \"./bridge/fixed-double-bridge\";\nconst leftIframe = document.getElementById(\"page-left\");\nconst rightIframe = document.getElementById(\"page-right\");\nconst metaViewport = document.querySelector(\"meta[name=viewport]\");\nWindow.prototype.doubleArea = new FixedDoubleBridge(window, leftIframe, rightIframe, metaViewport, window.gestures);\nwindow.documentState.onScriptsLoaded();\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nwindow.addEventListener(\"load\", (event) => {\n window.documentState.onDocumentLoaded();\n});\n","import { DoubleAreaManager } from \"../fixed/double-area-manager\";\nimport { BridgeGesturesAdapter } from \"./all-gestures-bridge\";\nexport class FixedDoubleBridge {\n constructor(window, leftIframe, rightIframe, metaViewport, gestures) {\n const listener = new BridgeGesturesAdapter(gestures);\n this.manager = new DoubleAreaManager(window, leftIframe, rightIframe, metaViewport, listener);\n }\n loadSpread(spread) {\n this.manager.loadSpread(spread);\n }\n setViewport(viewporttWidth, viewportHeight, insetTop, insetRight, insetBottom, insetLeft) {\n const viewport = { width: viewporttWidth, height: viewportHeight };\n const insets = {\n top: insetTop,\n left: insetLeft,\n bottom: insetBottom,\n right: insetRight,\n };\n this.manager.setViewport(viewport, insets);\n }\n setFit(fit) {\n if (fit != \"contain\" && fit != \"width\" && fit != \"height\") {\n throw Error(`Invalid fit value: ${fit}`);\n }\n this.manager.setFit(fit);\n }\n}\n"],"names":["PageManager","constructor","window","iframe","listener","this","margins","top","right","bottom","left","contentWindow","Error","setMessagePort","messagePort","onmessage","message","onMessageFromIframe","show","style","display","hide","setMargins","marginTop","marginLeft","marginBottom","marginRight","loadPage","url","src","setPlaceholder","size","visibility","width","height","event","data","kind","onContentSizeAvailable","onTap","x","y","onLinkActivated","URL","href","toString","outerHtml","_a","onIframeLoaded","ViewportStringBuilder","setInitialScale","scale","initialScale","setMinimumScale","minimumScale","setWidth","setHeight","build","components","push","join","GesturesDetector","document","addEventListener","onClick","defaultPrevented","selection","getSelection","type","nearestElement","target","HTMLElement","nearestInteractiveElement","HTMLAnchorElement","outerHTML","stopPropagation","preventDefault","element","indexOf","nodeName","toLowerCase","hasAttribute","getAttribute","parentElement","DoubleAreaManager","leftIframe","rightIframe","metaViewport","fit","insets","ports","source","leftPage","rightPage","tapEvent","clientX","visualViewport","offsetLeft","clientY","offsetTop","_","leftPageListener","layout","boundingRect","getBoundingClientRect","rightPageListener","loadSpread","spread","setViewport","viewport","setFit","leftMargins","rightMargins","contentWidth","contentHeight","Math","max","contentSize","safeDrawingSize","content","container","widthRatio","heightRatio","min","fitContain","fitWidth","fitHeight","computeScale","BridgeGesturesAdapter","gesturesApi","nativeApi","JSON","stringify","getElementById","querySelector","Window","prototype","doubleArea","gestures","manager","viewporttWidth","viewportHeight","insetTop","insetRight","insetBottom","insetLeft","documentState","onScriptsLoaded","onDocumentLoaded"],"sourceRoot":""} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-single-script.js b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-single-script.js index bf256593b4..c20c12c289 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-single-script.js +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-single-script.js @@ -1,2 +1,2 @@ -!function(){"use strict";class t{constructor(t,e,i){if(this.margins={top:0,right:0,bottom:0,left:0},!e.contentWindow)throw Error("Iframe argument must have been attached to DOM.");this.listener=i,this.iframe=e}setMessagePort(t){t.onmessage=t=>{this.onMessageFromIframe(t)}}show(){this.iframe.style.display="unset"}hide(){this.iframe.style.display="none"}setMargins(t){this.margins!=t&&(this.iframe.style.marginTop=this.margins.top+"px",this.iframe.style.marginLeft=this.margins.left+"px",this.iframe.style.marginBottom=this.margins.bottom+"px",this.iframe.style.marginRight=this.margins.right+"px")}loadPage(t){this.iframe.src=t}setPlaceholder(t){this.iframe.style.visibility="hidden",this.iframe.style.width=t.width+"px",this.iframe.style.height=t.height+"px",this.size=t}onMessageFromIframe(t){const e=t.data;switch(e.kind){case"contentSize":return this.onContentSizeAvailable(e.size);case"tap":return this.listener.onTap({x:e.x,y:e.y});case"linkActivated":return this.onLinkActivated(e)}}onLinkActivated(t){try{const e=new URL(t.href,this.iframe.src);this.listener.onLinkActivated(e.toString(),t.outerHtml)}catch(t){}}onContentSizeAvailable(t){t&&(this.iframe.style.width=t.width+"px",this.iframe.style.height=t.height+"px",this.size=t,this.listener.onIframeLoaded())}}class e{setInitialScale(t){return this.initialScale=t,this}setMinimumScale(t){return this.minimumScale=t,this}setWidth(t){return this.width=t,this}setHeight(t){return this.height=t,this}build(){const t=[];return this.initialScale&&t.push("initial-scale="+this.initialScale),this.minimumScale&&t.push("minimum-scale="+this.minimumScale),this.width&&t.push("width="+this.width),this.height&&t.push("height="+this.height),t.join(", ")}}class i{constructor(t,e){this.window=t,this.listener=e,document.addEventListener("click",(t=>{this.onClick(t)}),!1)}onClick(t){if(t.defaultPrevented)return;const e=this.window.getSelection();if(e&&"Range"==e.type)return;let i;i=t.target instanceof HTMLElement?this.nearestInteractiveElement(t.target):null,i?i instanceof HTMLAnchorElement&&this.listener.onLinkActivated(i.href,i.outerHTML):this.listener.onTap(t),t.stopPropagation(),t.preventDefault()}nearestInteractiveElement(t){return null==t?null:-1!=["a","audio","button","canvas","details","input","label","option","select","submit","textarea","video"].indexOf(t.nodeName.toLowerCase())||t.hasAttribute("contenteditable")&&"false"!=t.getAttribute("contenteditable").toLowerCase()?t:t.parentElement?this.nearestInteractiveElement(t.parentElement):null}}class s{constructor(e,s,n,a){this.fit="contain",this.insets={top:0,right:0,bottom:0,left:0},this.scale=1,e.addEventListener("message",(t=>{t.source===s.contentWindow&&t.ports[0]&&this.page.setMessagePort(t.ports[0])})),new i(e,{onTap:t=>{const e={x:(t.clientX-visualViewport.offsetLeft)*visualViewport.scale,y:(t.clientY-visualViewport.offsetTop)*visualViewport.scale};a.onTap(e)},onLinkActivated:t=>{throw Error("No interactive element in the root document.")}}),this.metaViewport=n;const o={onIframeLoaded:()=>{this.onIframeLoaded()},onTap:t=>{const e=s.getBoundingClientRect(),i={x:(t.x+e.left-visualViewport.offsetLeft)*visualViewport.scale,y:(t.y+e.top-visualViewport.offsetTop)*visualViewport.scale};a.onTap(i)},onLinkActivated:(t,e)=>{a.onLinkActivated(t,e)}};this.page=new t(e,s,o)}setViewport(t,e){this.viewport==t&&this.insets==e||(this.viewport=t,this.insets=e,this.layout())}setFit(t){this.fit!=t&&(this.fit=t,this.layout())}loadResource(t){this.page.hide(),this.page.loadPage(t)}onIframeLoaded(){this.page.size&&this.layout()}layout(){if(!this.page.size||!this.viewport)return;const t={top:this.insets.top,right:this.insets.right,bottom:this.insets.bottom,left:this.insets.left};this.page.setMargins(t);const i={width:this.viewport.width-this.insets.left-this.insets.right,height:this.viewport.height-this.insets.top-this.insets.bottom},s=function(t,e,i){switch(t){case"contain":return function(t,e){const i=e.width/t.width,s=e.height/t.height;return Math.min(i,s)}(e,i);case"width":return function(t,e){return e.width/t.width}(e,i);case"height":return function(t,e){return e.height/t.height}(e,i)}}(this.fit,this.page.size,i);this.metaViewport.content=(new e).setInitialScale(s).setMinimumScale(s).setWidth(this.page.size.width).setHeight(this.page.size.height).build(),this.scale=s,this.page.show()}}class n{constructor(t){this.nativeApi=t}onTap(t){this.nativeApi.onTap(JSON.stringify(t))}onLinkActivated(t,e){this.nativeApi.onLinkActivated(t,e)}}const a=document.getElementById("page"),o=document.querySelector("meta[name=viewport]");window.singleArea=new class{constructor(t,e,i,a){const o=new n(a);this.manager=new s(t,e,i,o)}loadResource(t){this.manager.loadResource(t)}setViewport(t,e,i,s,n,a){const o={width:t,height:e},h={top:i,left:a,bottom:n,right:s};this.manager.setViewport(o,h)}setFit(t){if("contain"!=t&&"width"!=t&&"height"!=t)throw Error(`Invalid fit value: ${t}`);this.manager.setFit(t)}}(window,a,o,window.gestures),window.initialization.onScriptsLoaded(),window.addEventListener("load",(t=>{window.initialization.onDocumentLoaded()}))}(); +!function(){"use strict";class t{constructor(t,e,i){if(this.margins={top:0,right:0,bottom:0,left:0},!e.contentWindow)throw Error("Iframe argument must have been attached to DOM.");this.listener=i,this.iframe=e}setMessagePort(t){t.onmessage=t=>{this.onMessageFromIframe(t)}}show(){this.iframe.style.display="unset"}hide(){this.iframe.style.display="none"}setMargins(t){this.margins!=t&&(this.iframe.style.marginTop=this.margins.top+"px",this.iframe.style.marginLeft=this.margins.left+"px",this.iframe.style.marginBottom=this.margins.bottom+"px",this.iframe.style.marginRight=this.margins.right+"px")}loadPage(t){this.iframe.src=t}setPlaceholder(t){this.iframe.style.visibility="hidden",this.iframe.style.width=t.width+"px",this.iframe.style.height=t.height+"px",this.size=t}onMessageFromIframe(t){const e=t.data;switch(e.kind){case"contentSize":return this.onContentSizeAvailable(e.size);case"tap":return this.listener.onTap({x:e.x,y:e.y});case"linkActivated":return this.onLinkActivated(e)}}onLinkActivated(t){try{const e=new URL(t.href,this.iframe.src);this.listener.onLinkActivated(e.toString(),t.outerHtml)}catch(t){}}onContentSizeAvailable(t){t&&(this.iframe.style.width=t.width+"px",this.iframe.style.height=t.height+"px",this.size=t,this.listener.onIframeLoaded())}}class e{setInitialScale(t){return this.initialScale=t,this}setMinimumScale(t){return this.minimumScale=t,this}setWidth(t){return this.width=t,this}setHeight(t){return this.height=t,this}build(){const t=[];return this.initialScale&&t.push("initial-scale="+this.initialScale),this.minimumScale&&t.push("minimum-scale="+this.minimumScale),this.width&&t.push("width="+this.width),this.height&&t.push("height="+this.height),t.join(", ")}}class i{constructor(t,e){this.window=t,this.listener=e,document.addEventListener("click",(t=>{this.onClick(t)}),!1)}onClick(t){if(t.defaultPrevented)return;const e=this.window.getSelection();if(e&&"Range"==e.type)return;let i;i=t.target instanceof HTMLElement?this.nearestInteractiveElement(t.target):null,i?i instanceof HTMLAnchorElement&&this.listener.onLinkActivated(i.href,i.outerHTML):this.listener.onTap(t),t.stopPropagation(),t.preventDefault()}nearestInteractiveElement(t){return null==t?null:-1!=["a","audio","button","canvas","details","input","label","option","select","submit","textarea","video"].indexOf(t.nodeName.toLowerCase())||t.hasAttribute("contenteditable")&&"false"!=t.getAttribute("contenteditable").toLowerCase()?t:t.parentElement?this.nearestInteractiveElement(t.parentElement):null}}class s{constructor(e,s,n,a){this.fit="contain",this.insets={top:0,right:0,bottom:0,left:0},this.scale=1,e.addEventListener("message",(t=>{t.source===s.contentWindow&&t.ports[0]&&this.page.setMessagePort(t.ports[0])})),new i(e,{onTap:t=>{const e={x:(t.clientX-visualViewport.offsetLeft)*visualViewport.scale,y:(t.clientY-visualViewport.offsetTop)*visualViewport.scale};a.onTap(e)},onLinkActivated:t=>{throw Error("No interactive element in the root document.")}}),this.metaViewport=n;const o={onIframeLoaded:()=>{this.onIframeLoaded()},onTap:t=>{const e=s.getBoundingClientRect(),i={x:(t.x+e.left-visualViewport.offsetLeft)*visualViewport.scale,y:(t.y+e.top-visualViewport.offsetTop)*visualViewport.scale};a.onTap(i)},onLinkActivated:(t,e)=>{a.onLinkActivated(t,e)}};this.page=new t(e,s,o)}setViewport(t,e){this.viewport==t&&this.insets==e||(this.viewport=t,this.insets=e,this.layout())}setFit(t){this.fit!=t&&(this.fit=t,this.layout())}loadResource(t){this.page.hide(),this.page.loadPage(t)}onIframeLoaded(){this.page.size&&this.layout()}layout(){if(!this.page.size||!this.viewport)return;const t={top:this.insets.top,right:this.insets.right,bottom:this.insets.bottom,left:this.insets.left};this.page.setMargins(t);const i={width:this.viewport.width-this.insets.left-this.insets.right,height:this.viewport.height-this.insets.top-this.insets.bottom},s=function(t,e,i){switch(t){case"contain":return function(t,e){const i=e.width/t.width,s=e.height/t.height;return Math.min(i,s)}(e,i);case"width":return function(t,e){return e.width/t.width}(e,i);case"height":return function(t,e){return e.height/t.height}(e,i)}}(this.fit,this.page.size,i);this.metaViewport.content=(new e).setInitialScale(s).setMinimumScale(s).setWidth(this.page.size.width).setHeight(this.page.size.height).build(),this.scale=s,this.page.show()}}class n{constructor(t){this.nativeApi=t}onTap(t){this.nativeApi.onTap(JSON.stringify(t))}onLinkActivated(t,e){this.nativeApi.onLinkActivated(t,e)}}const a=document.getElementById("page"),o=document.querySelector("meta[name=viewport]");window.singleArea=new class{constructor(t,e,i,a){const o=new n(a);this.manager=new s(t,e,i,o)}loadResource(t){this.manager.loadResource(t)}setViewport(t,e,i,s,n,a){const o={width:t,height:e},h={top:i,left:a,bottom:n,right:s};this.manager.setViewport(o,h)}setFit(t){if("contain"!=t&&"width"!=t&&"height"!=t)throw Error(`Invalid fit value: ${t}`);this.manager.setFit(t)}}(window,a,o,window.gestures),window.documentState.onScriptsLoaded(),window.addEventListener("load",(t=>{window.documentState.onDocumentLoaded()}))}(); //# sourceMappingURL=fixed-single-script.js.map \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-single-script.js.map b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-single-script.js.map index a05d3d5ee3..e94b47e25a 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-single-script.js.map +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-single-script.js.map @@ -1 +1 @@ -{"version":3,"file":"fixed-single-script.js","mappings":"yBACO,MAAMA,EACT,WAAAC,CAAYC,EAAQC,EAAQC,GAExB,GADAC,KAAKC,QAAU,CAAEC,IAAK,EAAGC,MAAO,EAAGC,OAAQ,EAAGC,KAAM,IAC/CP,EAAOQ,cACR,MAAMC,MAAM,mDAEhBP,KAAKD,SAAWA,EAChBC,KAAKF,OAASA,CAClB,CACA,cAAAU,CAAeC,GACXA,EAAYC,UAAaC,IACrBX,KAAKY,oBAAoBD,EAAQ,CAEzC,CACA,IAAAE,GACIb,KAAKF,OAAOgB,MAAMC,QAAU,OAChC,CACA,IAAAC,GACIhB,KAAKF,OAAOgB,MAAMC,QAAU,MAChC,CAEA,UAAAE,CAAWhB,GACHD,KAAKC,SAAWA,IAGpBD,KAAKF,OAAOgB,MAAMI,UAAYlB,KAAKC,QAAQC,IAAM,KACjDF,KAAKF,OAAOgB,MAAMK,WAAanB,KAAKC,QAAQI,KAAO,KACnDL,KAAKF,OAAOgB,MAAMM,aAAepB,KAAKC,QAAQG,OAAS,KACvDJ,KAAKF,OAAOgB,MAAMO,YAAcrB,KAAKC,QAAQE,MAAQ,KACzD,CAEA,QAAAmB,CAASC,GACLvB,KAAKF,OAAO0B,IAAMD,CACtB,CAEA,cAAAE,CAAeC,GACX1B,KAAKF,OAAOgB,MAAMa,WAAa,SAC/B3B,KAAKF,OAAOgB,MAAMc,MAAQF,EAAKE,MAAQ,KACvC5B,KAAKF,OAAOgB,MAAMe,OAASH,EAAKG,OAAS,KACzC7B,KAAK0B,KAAOA,CAChB,CACA,mBAAAd,CAAoBkB,GAChB,MAAMnB,EAAUmB,EAAMC,KACtB,OAAQpB,EAAQqB,MACZ,IAAK,cACD,OAAOhC,KAAKiC,uBAAuBtB,EAAQe,MAC/C,IAAK,MACD,OAAO1B,KAAKD,SAASmC,MAAM,CAAEC,EAAGxB,EAAQwB,EAAGC,EAAGzB,EAAQyB,IAC1D,IAAK,gBACD,OAAOpC,KAAKqC,gBAAgB1B,GAExC,CACA,eAAA0B,CAAgB1B,GACZ,IACI,MAAMY,EAAM,IAAIe,IAAI3B,EAAQ4B,KAAMvC,KAAKF,OAAO0B,KAC9CxB,KAAKD,SAASsC,gBAAgBd,EAAIiB,WAAY7B,EAAQ8B,UAC1D,CACA,MAAOC,GAEP,CACJ,CACA,sBAAAT,CAAuBP,GACdA,IAIL1B,KAAKF,OAAOgB,MAAMc,MAAQF,EAAKE,MAAQ,KACvC5B,KAAKF,OAAOgB,MAAMe,OAASH,EAAKG,OAAS,KACzC7B,KAAK0B,KAAOA,EACZ1B,KAAKD,SAAS4C,iBAClB,ECvEG,MAAMC,EACT,eAAAC,CAAgBC,GAEZ,OADA9C,KAAK+C,aAAeD,EACb9C,IACX,CACA,eAAAgD,CAAgBF,GAEZ,OADA9C,KAAKiD,aAAeH,EACb9C,IACX,CACA,QAAAkD,CAAStB,GAEL,OADA5B,KAAK4B,MAAQA,EACN5B,IACX,CACA,SAAAmD,CAAUtB,GAEN,OADA7B,KAAK6B,OAASA,EACP7B,IACX,CACA,KAAAoD,GACI,MAAMC,EAAa,GAanB,OAZIrD,KAAK+C,cACLM,EAAWC,KAAK,iBAAmBtD,KAAK+C,cAExC/C,KAAKiD,cACLI,EAAWC,KAAK,iBAAmBtD,KAAKiD,cAExCjD,KAAK4B,OACLyB,EAAWC,KAAK,SAAWtD,KAAK4B,OAEhC5B,KAAK6B,QACLwB,EAAWC,KAAK,UAAYtD,KAAK6B,QAE9BwB,EAAWE,KAAK,KAC3B,EChCG,MAAMC,EACT,WAAA5D,CAAYC,EAAQE,GAChBC,KAAKH,OAASA,EACdG,KAAKD,SAAWA,EAChB0D,SAASC,iBAAiB,SAAU5B,IAChC9B,KAAK2D,QAAQ7B,EAAM,IACpB,EACP,CACA,OAAA6B,CAAQ7B,GACJ,GAAIA,EAAM8B,iBACN,OAEJ,MAAMC,EAAY7D,KAAKH,OAAOiE,eAC9B,GAAID,GAA+B,SAAlBA,EAAUE,KAIvB,OAEJ,IAAIC,EAEAA,EADAlC,EAAMmC,kBAAkBC,YACPlE,KAAKmE,0BAA0BrC,EAAMmC,QAGrC,KAEjBD,EACIA,aAA0BI,mBAC1BpE,KAAKD,SAASsC,gBAAgB2B,EAAezB,KAAMyB,EAAeK,WAItErE,KAAKD,SAASmC,MAAMJ,GAExBA,EAAMwC,kBACNxC,EAAMyC,gBACV,CAEA,yBAAAJ,CAA0BK,GACtB,OAAe,MAAXA,EACO,MAgBqD,GAdxC,CACpB,IACA,QACA,SACA,SACA,UACA,QACA,QACA,SACA,SACA,SACA,WACA,SAEgBC,QAAQD,EAAQE,SAASC,gBAIzCH,EAAQI,aAAa,oBACoC,SAAzDJ,EAAQK,aAAa,mBAAmBF,cAJjCH,EAQPA,EAAQM,cACD9E,KAAKmE,0BAA0BK,EAAQM,eAE3C,IACX,ECjEG,MAAMC,EACT,WAAAnF,CAAYC,EAAQC,EAAQkF,EAAcjF,GACtCC,KAAKiF,IAAM,UACXjF,KAAKkF,OAAS,CAAEhF,IAAK,EAAGC,MAAO,EAAGC,OAAQ,EAAGC,KAAM,GACnDL,KAAK8C,MAAQ,EACbjD,EAAO6D,iBAAiB,WAAY5B,IAC5BA,EAAMqD,SAAWrF,EAAOQ,eAAiBwB,EAAMsD,MAAM,IACrDpF,KAAKqF,KAAK7E,eAAesB,EAAMsD,MAAM,GACzC,IAgBJ,IAAI5B,EAAiB3D,EAdW,CAC5BqC,MAAQJ,IACJ,MAAMwD,EAAW,CACbnD,GAAIL,EAAMyD,QAAUC,eAAeC,YAC/BD,eAAe1C,MACnBV,GAAIN,EAAM4D,QAAUF,eAAeG,WAAaH,eAAe1C,OAEnE/C,EAASmC,MAAMoD,EAAS,EAG5BjD,gBAAkBuD,IACd,MAAMrF,MAAM,+CAA+C,IAInEP,KAAKgF,aAAeA,EACpB,MAAMa,EAAe,CACjBlD,eAAgB,KACZ3C,KAAK2C,gBAAgB,EAEzBT,MAAQJ,IACJ,MAAMgE,EAAehG,EAAOiG,wBACtBT,EAAW,CACbnD,GAAIL,EAAMK,EAAI2D,EAAazF,KAAOmF,eAAeC,YAC7CD,eAAe1C,MACnBV,GAAIN,EAAMM,EAAI0D,EAAa5F,IAAMsF,eAAeG,WAC5CH,eAAe1C,OAEvB/C,EAASmC,MAAMoD,EAAS,EAE5BjD,gBAAiB,CAACE,EAAME,KACpB1C,EAASsC,gBAAgBE,EAAME,EAAU,GAGjDzC,KAAKqF,KAAO,IAAI1F,EAAYE,EAAQC,EAAQ+F,EAChD,CACA,WAAAG,CAAYC,EAAUf,GACdlF,KAAKiG,UAAYA,GAAYjG,KAAKkF,QAAUA,IAGhDlF,KAAKiG,SAAWA,EAChBjG,KAAKkF,OAASA,EACdlF,KAAKkG,SACT,CACA,MAAAC,CAAOlB,GACCjF,KAAKiF,KAAOA,IAGhBjF,KAAKiF,IAAMA,EACXjF,KAAKkG,SACT,CACA,YAAAE,CAAa7E,GACTvB,KAAKqF,KAAKrE,OACVhB,KAAKqF,KAAK/D,SAASC,EACvB,CACA,cAAAoB,GACS3C,KAAKqF,KAAK3D,MAIX1B,KAAKkG,QAEb,CACA,MAAAA,GACI,IAAKlG,KAAKqF,KAAK3D,OAAS1B,KAAKiG,SACzB,OAEJ,MAAMhG,EAAU,CACZC,IAAKF,KAAKkF,OAAOhF,IACjBC,MAAOH,KAAKkF,OAAO/E,MACnBC,OAAQJ,KAAKkF,OAAO9E,OACpBC,KAAML,KAAKkF,OAAO7E,MAEtBL,KAAKqF,KAAKpE,WAAWhB,GACrB,MAAMoG,EAAkB,CACpBzE,MAAO5B,KAAKiG,SAASrE,MAAQ5B,KAAKkF,OAAO7E,KAAOL,KAAKkF,OAAO/E,MAC5D0B,OAAQ7B,KAAKiG,SAASpE,OAAS7B,KAAKkF,OAAOhF,IAAMF,KAAKkF,OAAO9E,QAE3D0C,EC5FP,SAAsBmC,EAAKqB,EAASC,GACvC,OAAQtB,GACJ,IAAK,UACD,OAOZ,SAAoBqB,EAASC,GACzB,MAAMC,EAAaD,EAAU3E,MAAQ0E,EAAQ1E,MACvC6E,EAAcF,EAAU1E,OAASyE,EAAQzE,OAC/C,OAAO6E,KAAKC,IAAIH,EAAYC,EAChC,CAXmBG,CAAWN,EAASC,GAC/B,IAAK,QACD,OAUZ,SAAkBD,EAASC,GACvB,OAAOA,EAAU3E,MAAQ0E,EAAQ1E,KACrC,CAZmBiF,CAASP,EAASC,GAC7B,IAAK,SACD,OAWZ,SAAmBD,EAASC,GACxB,OAAOA,EAAU1E,OAASyE,EAAQzE,MACtC,CAbmBiF,CAAUR,EAASC,GAEtC,CDmFsBQ,CAAa/G,KAAKiF,IAAKjF,KAAKqF,KAAK3D,KAAM2E,GACrDrG,KAAKgF,aAAasB,SAAU,IAAI1D,GAC3BC,gBAAgBC,GAChBE,gBAAgBF,GAChBI,SAASlD,KAAKqF,KAAK3D,KAAKE,OACxBuB,UAAUnD,KAAKqF,KAAK3D,KAAKG,QACzBuB,QACLpD,KAAK8C,MAAQA,EACb9C,KAAKqF,KAAKxE,MACd,EErGG,MAAMmG,EACT,WAAApH,CAAYqH,GACRjH,KAAKkH,UAAYD,CACrB,CACA,KAAA/E,CAAMJ,GACF9B,KAAKkH,UAAUhF,MAAMiF,KAAKC,UAAUtF,GACxC,CACA,eAAAO,CAAgBE,EAAME,GAClBzC,KAAKkH,UAAU7E,gBAAgBE,EAAME,EACzC,ECHJ,MAAM3C,EAAS2D,SAAS4D,eAAe,QACjCrC,EAAevB,SAAS6D,cAAc,uBAC5CzH,OAAO0H,WAAa,ICNb,MACH,WAAA3H,CAAYC,EAAQC,EAAQkF,EAAcwC,GACtC,MAAMzH,EAAW,IAAIiH,EAAsBQ,GAC3CxH,KAAKyH,QAAU,IAAI1C,EAAkBlF,EAAQC,EAAQkF,EAAcjF,EACvE,CACA,YAAAqG,CAAa7E,GACTvB,KAAKyH,QAAQrB,aAAa7E,EAC9B,CACA,WAAAyE,CAAY0B,EAAgBC,EAAgBC,EAAUC,EAAYC,EAAaC,GAC3E,MAAM9B,EAAW,CAAErE,MAAO8F,EAAgB7F,OAAQ8F,GAC5CzC,EAAS,CACXhF,IAAK0H,EACLvH,KAAM0H,EACN3H,OAAQ0H,EACR3H,MAAO0H,GAEX7H,KAAKyH,QAAQzB,YAAYC,EAAUf,EACvC,CACA,MAAAiB,CAAOlB,GACH,GAAW,WAAPA,GAA2B,SAAPA,GAAyB,UAAPA,EACtC,MAAM1E,MAAM,sBAAsB0E,KAEtCjF,KAAKyH,QAAQtB,OAAOlB,EACxB,GDjBsCpF,OAAQC,EAAQkF,EAAcnF,OAAO2H,UAC/E3H,OAAOmI,eAAeC,kBAEtBpI,OAAO6D,iBAAiB,QAAS5B,IAC7BjC,OAAOmI,eAAeE,kBAAkB,G","sources":["webpack://readium-js/./src/fixed/page-manager.ts","webpack://readium-js/./src/util/viewport.ts","webpack://readium-js/./src/common/gestures.ts","webpack://readium-js/./src/fixed/single-area-manager.ts","webpack://readium-js/./src/util/fit.ts","webpack://readium-js/./src/bridge/all-gestures-bridge.ts","webpack://readium-js/./src/index-fixed-single.ts","webpack://readium-js/./src/bridge/fixed-single-bridge.ts"],"sourcesContent":["/** Manages a fixed layout resource embedded in an iframe. */\nexport class PageManager {\n constructor(window, iframe, listener) {\n this.margins = { top: 0, right: 0, bottom: 0, left: 0 };\n if (!iframe.contentWindow) {\n throw Error(\"Iframe argument must have been attached to DOM.\");\n }\n this.listener = listener;\n this.iframe = iframe;\n }\n setMessagePort(messagePort) {\n messagePort.onmessage = (message) => {\n this.onMessageFromIframe(message);\n };\n }\n show() {\n this.iframe.style.display = \"unset\";\n }\n hide() {\n this.iframe.style.display = \"none\";\n }\n /** Sets page margins. */\n setMargins(margins) {\n if (this.margins == margins) {\n return;\n }\n this.iframe.style.marginTop = this.margins.top + \"px\";\n this.iframe.style.marginLeft = this.margins.left + \"px\";\n this.iframe.style.marginBottom = this.margins.bottom + \"px\";\n this.iframe.style.marginRight = this.margins.right + \"px\";\n }\n /** Loads page content. */\n loadPage(url) {\n this.iframe.src = url;\n }\n /** Sets the size of this page without content. */\n setPlaceholder(size) {\n this.iframe.style.visibility = \"hidden\";\n this.iframe.style.width = size.width + \"px\";\n this.iframe.style.height = size.height + \"px\";\n this.size = size;\n }\n onMessageFromIframe(event) {\n const message = event.data;\n switch (message.kind) {\n case \"contentSize\":\n return this.onContentSizeAvailable(message.size);\n case \"tap\":\n return this.listener.onTap({ x: message.x, y: message.y });\n case \"linkActivated\":\n return this.onLinkActivated(message);\n }\n }\n onLinkActivated(message) {\n try {\n const url = new URL(message.href, this.iframe.src);\n this.listener.onLinkActivated(url.toString(), message.outerHtml);\n }\n catch (_a) {\n // Do nothing if url is not valid.\n }\n }\n onContentSizeAvailable(size) {\n if (!size) {\n //FIXME: handle edge case\n return;\n }\n this.iframe.style.width = size.width + \"px\";\n this.iframe.style.height = size.height + \"px\";\n this.size = size;\n this.listener.onIframeLoaded();\n }\n}\n","export class ViewportStringBuilder {\n setInitialScale(scale) {\n this.initialScale = scale;\n return this;\n }\n setMinimumScale(scale) {\n this.minimumScale = scale;\n return this;\n }\n setWidth(width) {\n this.width = width;\n return this;\n }\n setHeight(height) {\n this.height = height;\n return this;\n }\n build() {\n const components = [];\n if (this.initialScale) {\n components.push(\"initial-scale=\" + this.initialScale);\n }\n if (this.minimumScale) {\n components.push(\"minimum-scale=\" + this.minimumScale);\n }\n if (this.width) {\n components.push(\"width=\" + this.width);\n }\n if (this.height) {\n components.push(\"height=\" + this.height);\n }\n return components.join(\", \");\n }\n}\nexport function parseViewportString(viewportString) {\n const regex = /(\\w+) *= *([^\\s,]+)/g;\n const properties = new Map();\n let match;\n while ((match = regex.exec(viewportString))) {\n if (match != null) {\n properties.set(match[1], match[2]);\n }\n }\n const width = parseFloat(properties.get(\"width\"));\n const height = parseFloat(properties.get(\"height\"));\n if (width && height) {\n return { width, height };\n }\n else {\n return undefined;\n }\n}\n","export class GesturesDetector {\n constructor(window, listener) {\n this.window = window;\n this.listener = listener;\n document.addEventListener(\"click\", (event) => {\n this.onClick(event);\n }, false);\n }\n onClick(event) {\n if (event.defaultPrevented) {\n return;\n }\n const selection = this.window.getSelection();\n if (selection && selection.type == \"Range\") {\n // There's an on-going selection, the tap will dismiss it so we don't forward it.\n // selection.type might be None (collapsed) or Caret with a collapsed range\n // when there is not true selection.\n return;\n }\n let nearestElement;\n if (event.target instanceof HTMLElement) {\n nearestElement = this.nearestInteractiveElement(event.target);\n }\n else {\n nearestElement = null;\n }\n if (nearestElement) {\n if (nearestElement instanceof HTMLAnchorElement) {\n this.listener.onLinkActivated(nearestElement.href, nearestElement.outerHTML);\n }\n }\n else {\n this.listener.onTap(event);\n }\n event.stopPropagation();\n event.preventDefault();\n }\n // See. https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling\n nearestInteractiveElement(element) {\n if (element == null) {\n return null;\n }\n const interactiveTags = [\n \"a\",\n \"audio\",\n \"button\",\n \"canvas\",\n \"details\",\n \"input\",\n \"label\",\n \"option\",\n \"select\",\n \"submit\",\n \"textarea\",\n \"video\",\n ];\n if (interactiveTags.indexOf(element.nodeName.toLowerCase()) != -1) {\n return element;\n }\n // Checks whether the element is editable by the user.\n if (element.hasAttribute(\"contenteditable\") &&\n element.getAttribute(\"contenteditable\").toLowerCase() != \"false\") {\n return element;\n }\n // Checks parents recursively because the touch might be for example on an inside a .\n if (element.parentElement) {\n return this.nearestInteractiveElement(element.parentElement);\n }\n return null;\n }\n}\n","import { computeScale } from \"../util/fit\";\nimport { PageManager } from \"./page-manager\";\nimport { ViewportStringBuilder } from \"../util/viewport\";\nimport { GesturesDetector } from \"../common/gestures\";\nexport class SingleAreaManager {\n constructor(window, iframe, metaViewport, listener) {\n this.fit = \"contain\" /* Fit.Contain */;\n this.insets = { top: 0, right: 0, bottom: 0, left: 0 };\n this.scale = 1;\n window.addEventListener(\"message\", (event) => {\n if (event.source === iframe.contentWindow && event.ports[0]) {\n this.page.setMessagePort(event.ports[0]);\n }\n });\n const wrapperGesturesListener = {\n onTap: (event) => {\n const tapEvent = {\n x: (event.clientX - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.clientY - visualViewport.offsetTop) * visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onLinkActivated: (_) => {\n throw Error(\"No interactive element in the root document.\");\n },\n };\n new GesturesDetector(window, wrapperGesturesListener);\n this.metaViewport = metaViewport;\n const pageListener = {\n onIframeLoaded: () => {\n this.onIframeLoaded();\n },\n onTap: (event) => {\n const boundingRect = iframe.getBoundingClientRect();\n const tapEvent = {\n x: (event.x + boundingRect.left - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.y + boundingRect.top - visualViewport.offsetTop) *\n visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n listener.onLinkActivated(href, outerHtml);\n },\n };\n this.page = new PageManager(window, iframe, pageListener);\n }\n setViewport(viewport, insets) {\n if (this.viewport == viewport && this.insets == insets) {\n return;\n }\n this.viewport = viewport;\n this.insets = insets;\n this.layout();\n }\n setFit(fit) {\n if (this.fit == fit) {\n return;\n }\n this.fit = fit;\n this.layout();\n }\n loadResource(url) {\n this.page.hide();\n this.page.loadPage(url);\n }\n onIframeLoaded() {\n if (!this.page.size) {\n // FIXME: raise error\n }\n else {\n this.layout();\n }\n }\n layout() {\n if (!this.page.size || !this.viewport) {\n return;\n }\n const margins = {\n top: this.insets.top,\n right: this.insets.right,\n bottom: this.insets.bottom,\n left: this.insets.left,\n };\n this.page.setMargins(margins);\n const safeDrawingSize = {\n width: this.viewport.width - this.insets.left - this.insets.right,\n height: this.viewport.height - this.insets.top - this.insets.bottom,\n };\n const scale = computeScale(this.fit, this.page.size, safeDrawingSize);\n this.metaViewport.content = new ViewportStringBuilder()\n .setInitialScale(scale)\n .setMinimumScale(scale)\n .setWidth(this.page.size.width)\n .setHeight(this.page.size.height)\n .build();\n this.scale = scale;\n this.page.show();\n }\n}\n","export function computeScale(fit, content, container) {\n switch (fit) {\n case \"contain\" /* Fit.Contain */:\n return fitContain(content, container);\n case \"width\" /* Fit.Width */:\n return fitWidth(content, container);\n case \"height\" /* Fit.Height */:\n return fitHeight(content, container);\n }\n}\nfunction fitContain(content, container) {\n const widthRatio = container.width / content.width;\n const heightRatio = container.height / content.height;\n return Math.min(widthRatio, heightRatio);\n}\nfunction fitWidth(content, container) {\n return container.width / content.width;\n}\nfunction fitHeight(content, container) {\n return container.height / content.height;\n}\n","export class BridgeGesturesAdapter {\n constructor(gesturesApi) {\n this.nativeApi = gesturesApi;\n }\n onTap(event) {\n this.nativeApi.onTap(JSON.stringify(event));\n }\n onLinkActivated(href, outerHtml) {\n this.nativeApi.onLinkActivated(href, outerHtml);\n }\n}\n","//\n// Copyright 2024 Readium Foundation. All rights reserved.\n// Use of this source code is governed by the BSD-style license\n// available in the top-level LICENSE file of the project.\n//\nimport { FixedSingleBridge } from \"./bridge/fixed-single-bridge\";\nconst iframe = document.getElementById(\"page\");\nconst metaViewport = document.querySelector(\"meta[name=viewport]\");\nwindow.singleArea = new FixedSingleBridge(window, iframe, metaViewport, window.gestures);\nwindow.initialization.onScriptsLoaded();\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nwindow.addEventListener(\"load\", (event) => {\n window.initialization.onDocumentLoaded();\n});\n","import { SingleAreaManager } from \"../fixed/single-area-manager\";\nimport { BridgeGesturesAdapter } from \"./all-gestures-bridge\";\nexport class FixedSingleBridge {\n constructor(window, iframe, metaViewport, gestures) {\n const listener = new BridgeGesturesAdapter(gestures);\n this.manager = new SingleAreaManager(window, iframe, metaViewport, listener);\n }\n loadResource(url) {\n this.manager.loadResource(url);\n }\n setViewport(viewporttWidth, viewportHeight, insetTop, insetRight, insetBottom, insetLeft) {\n const viewport = { width: viewporttWidth, height: viewportHeight };\n const insets = {\n top: insetTop,\n left: insetLeft,\n bottom: insetBottom,\n right: insetRight,\n };\n this.manager.setViewport(viewport, insets);\n }\n setFit(fit) {\n if (fit != \"contain\" && fit != \"width\" && fit != \"height\") {\n throw Error(`Invalid fit value: ${fit}`);\n }\n this.manager.setFit(fit);\n }\n}\n"],"names":["PageManager","constructor","window","iframe","listener","this","margins","top","right","bottom","left","contentWindow","Error","setMessagePort","messagePort","onmessage","message","onMessageFromIframe","show","style","display","hide","setMargins","marginTop","marginLeft","marginBottom","marginRight","loadPage","url","src","setPlaceholder","size","visibility","width","height","event","data","kind","onContentSizeAvailable","onTap","x","y","onLinkActivated","URL","href","toString","outerHtml","_a","onIframeLoaded","ViewportStringBuilder","setInitialScale","scale","initialScale","setMinimumScale","minimumScale","setWidth","setHeight","build","components","push","join","GesturesDetector","document","addEventListener","onClick","defaultPrevented","selection","getSelection","type","nearestElement","target","HTMLElement","nearestInteractiveElement","HTMLAnchorElement","outerHTML","stopPropagation","preventDefault","element","indexOf","nodeName","toLowerCase","hasAttribute","getAttribute","parentElement","SingleAreaManager","metaViewport","fit","insets","source","ports","page","tapEvent","clientX","visualViewport","offsetLeft","clientY","offsetTop","_","pageListener","boundingRect","getBoundingClientRect","setViewport","viewport","layout","setFit","loadResource","safeDrawingSize","content","container","widthRatio","heightRatio","Math","min","fitContain","fitWidth","fitHeight","computeScale","BridgeGesturesAdapter","gesturesApi","nativeApi","JSON","stringify","getElementById","querySelector","singleArea","gestures","manager","viewporttWidth","viewportHeight","insetTop","insetRight","insetBottom","insetLeft","initialization","onScriptsLoaded","onDocumentLoaded"],"sourceRoot":""} \ No newline at end of file +{"version":3,"file":"fixed-single-script.js","mappings":"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","sources":["webpack://readium-js/./src/fixed/page-manager.ts","webpack://readium-js/./src/util/viewport.ts","webpack://readium-js/./src/common/gestures.ts","webpack://readium-js/./src/fixed/single-area-manager.ts","webpack://readium-js/./src/util/fit.ts","webpack://readium-js/./src/bridge/all-gestures-bridge.ts","webpack://readium-js/./src/index-fixed-single.ts","webpack://readium-js/./src/bridge/fixed-single-bridge.ts"],"sourcesContent":["/** Manages a fixed layout resource embedded in an iframe. */\nexport class PageManager {\n constructor(window, iframe, listener) {\n this.margins = { top: 0, right: 0, bottom: 0, left: 0 };\n if (!iframe.contentWindow) {\n throw Error(\"Iframe argument must have been attached to DOM.\");\n }\n this.listener = listener;\n this.iframe = iframe;\n }\n setMessagePort(messagePort) {\n messagePort.onmessage = (message) => {\n this.onMessageFromIframe(message);\n };\n }\n show() {\n this.iframe.style.display = \"unset\";\n }\n hide() {\n this.iframe.style.display = \"none\";\n }\n /** Sets page margins. */\n setMargins(margins) {\n if (this.margins == margins) {\n return;\n }\n this.iframe.style.marginTop = this.margins.top + \"px\";\n this.iframe.style.marginLeft = this.margins.left + \"px\";\n this.iframe.style.marginBottom = this.margins.bottom + \"px\";\n this.iframe.style.marginRight = this.margins.right + \"px\";\n }\n /** Loads page content. */\n loadPage(url) {\n this.iframe.src = url;\n }\n /** Sets the size of this page without content. */\n setPlaceholder(size) {\n this.iframe.style.visibility = \"hidden\";\n this.iframe.style.width = size.width + \"px\";\n this.iframe.style.height = size.height + \"px\";\n this.size = size;\n }\n onMessageFromIframe(event) {\n const message = event.data;\n switch (message.kind) {\n case \"contentSize\":\n return this.onContentSizeAvailable(message.size);\n case \"tap\":\n return this.listener.onTap({ x: message.x, y: message.y });\n case \"linkActivated\":\n return this.onLinkActivated(message);\n }\n }\n onLinkActivated(message) {\n try {\n const url = new URL(message.href, this.iframe.src);\n this.listener.onLinkActivated(url.toString(), message.outerHtml);\n }\n catch (_a) {\n // Do nothing if url is not valid.\n }\n }\n onContentSizeAvailable(size) {\n if (!size) {\n //FIXME: handle edge case\n return;\n }\n this.iframe.style.width = size.width + \"px\";\n this.iframe.style.height = size.height + \"px\";\n this.size = size;\n this.listener.onIframeLoaded();\n }\n}\n","export class ViewportStringBuilder {\n setInitialScale(scale) {\n this.initialScale = scale;\n return this;\n }\n setMinimumScale(scale) {\n this.minimumScale = scale;\n return this;\n }\n setWidth(width) {\n this.width = width;\n return this;\n }\n setHeight(height) {\n this.height = height;\n return this;\n }\n build() {\n const components = [];\n if (this.initialScale) {\n components.push(\"initial-scale=\" + this.initialScale);\n }\n if (this.minimumScale) {\n components.push(\"minimum-scale=\" + this.minimumScale);\n }\n if (this.width) {\n components.push(\"width=\" + this.width);\n }\n if (this.height) {\n components.push(\"height=\" + this.height);\n }\n return components.join(\", \");\n }\n}\nexport function parseViewportString(viewportString) {\n const regex = /(\\w+) *= *([^\\s,]+)/g;\n const properties = new Map();\n let match;\n while ((match = regex.exec(viewportString))) {\n if (match != null) {\n properties.set(match[1], match[2]);\n }\n }\n const width = parseFloat(properties.get(\"width\"));\n const height = parseFloat(properties.get(\"height\"));\n if (width && height) {\n return { width, height };\n }\n else {\n return undefined;\n }\n}\n","export class GesturesDetector {\n constructor(window, listener) {\n this.window = window;\n this.listener = listener;\n document.addEventListener(\"click\", (event) => {\n this.onClick(event);\n }, false);\n }\n onClick(event) {\n if (event.defaultPrevented) {\n return;\n }\n const selection = this.window.getSelection();\n if (selection && selection.type == \"Range\") {\n // There's an on-going selection, the tap will dismiss it so we don't forward it.\n // selection.type might be None (collapsed) or Caret with a collapsed range\n // when there is not true selection.\n return;\n }\n let nearestElement;\n if (event.target instanceof HTMLElement) {\n nearestElement = this.nearestInteractiveElement(event.target);\n }\n else {\n nearestElement = null;\n }\n if (nearestElement) {\n if (nearestElement instanceof HTMLAnchorElement) {\n this.listener.onLinkActivated(nearestElement.href, nearestElement.outerHTML);\n }\n }\n else {\n this.listener.onTap(event);\n }\n event.stopPropagation();\n event.preventDefault();\n }\n // See. https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling\n nearestInteractiveElement(element) {\n if (element == null) {\n return null;\n }\n const interactiveTags = [\n \"a\",\n \"audio\",\n \"button\",\n \"canvas\",\n \"details\",\n \"input\",\n \"label\",\n \"option\",\n \"select\",\n \"submit\",\n \"textarea\",\n \"video\",\n ];\n if (interactiveTags.indexOf(element.nodeName.toLowerCase()) != -1) {\n return element;\n }\n // Checks whether the element is editable by the user.\n if (element.hasAttribute(\"contenteditable\") &&\n element.getAttribute(\"contenteditable\").toLowerCase() != \"false\") {\n return element;\n }\n // Checks parents recursively because the touch might be for example on an inside a .\n if (element.parentElement) {\n return this.nearestInteractiveElement(element.parentElement);\n }\n return null;\n }\n}\n","import { computeScale } from \"../util/fit\";\nimport { PageManager } from \"./page-manager\";\nimport { ViewportStringBuilder } from \"../util/viewport\";\nimport { GesturesDetector } from \"../common/gestures\";\nexport class SingleAreaManager {\n constructor(window, iframe, metaViewport, listener) {\n this.fit = \"contain\" /* Fit.Contain */;\n this.insets = { top: 0, right: 0, bottom: 0, left: 0 };\n this.scale = 1;\n window.addEventListener(\"message\", (event) => {\n if (event.source === iframe.contentWindow && event.ports[0]) {\n this.page.setMessagePort(event.ports[0]);\n }\n });\n const wrapperGesturesListener = {\n onTap: (event) => {\n const tapEvent = {\n x: (event.clientX - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.clientY - visualViewport.offsetTop) * visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onLinkActivated: (_) => {\n throw Error(\"No interactive element in the root document.\");\n },\n };\n new GesturesDetector(window, wrapperGesturesListener);\n this.metaViewport = metaViewport;\n const pageListener = {\n onIframeLoaded: () => {\n this.onIframeLoaded();\n },\n onTap: (event) => {\n const boundingRect = iframe.getBoundingClientRect();\n const tapEvent = {\n x: (event.x + boundingRect.left - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.y + boundingRect.top - visualViewport.offsetTop) *\n visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n listener.onLinkActivated(href, outerHtml);\n },\n };\n this.page = new PageManager(window, iframe, pageListener);\n }\n setViewport(viewport, insets) {\n if (this.viewport == viewport && this.insets == insets) {\n return;\n }\n this.viewport = viewport;\n this.insets = insets;\n this.layout();\n }\n setFit(fit) {\n if (this.fit == fit) {\n return;\n }\n this.fit = fit;\n this.layout();\n }\n loadResource(url) {\n this.page.hide();\n this.page.loadPage(url);\n }\n onIframeLoaded() {\n if (!this.page.size) {\n // FIXME: raise error\n }\n else {\n this.layout();\n }\n }\n layout() {\n if (!this.page.size || !this.viewport) {\n return;\n }\n const margins = {\n top: this.insets.top,\n right: this.insets.right,\n bottom: this.insets.bottom,\n left: this.insets.left,\n };\n this.page.setMargins(margins);\n const safeDrawingSize = {\n width: this.viewport.width - this.insets.left - this.insets.right,\n height: this.viewport.height - this.insets.top - this.insets.bottom,\n };\n const scale = computeScale(this.fit, this.page.size, safeDrawingSize);\n this.metaViewport.content = new ViewportStringBuilder()\n .setInitialScale(scale)\n .setMinimumScale(scale)\n .setWidth(this.page.size.width)\n .setHeight(this.page.size.height)\n .build();\n this.scale = scale;\n this.page.show();\n }\n}\n","export function computeScale(fit, content, container) {\n switch (fit) {\n case \"contain\" /* Fit.Contain */:\n return fitContain(content, container);\n case \"width\" /* Fit.Width */:\n return fitWidth(content, container);\n case \"height\" /* Fit.Height */:\n return fitHeight(content, container);\n }\n}\nfunction fitContain(content, container) {\n const widthRatio = container.width / content.width;\n const heightRatio = container.height / content.height;\n return Math.min(widthRatio, heightRatio);\n}\nfunction fitWidth(content, container) {\n return container.width / content.width;\n}\nfunction fitHeight(content, container) {\n return container.height / content.height;\n}\n","export class BridgeGesturesAdapter {\n constructor(gesturesApi) {\n this.nativeApi = gesturesApi;\n }\n onTap(event) {\n this.nativeApi.onTap(JSON.stringify(event));\n }\n onLinkActivated(href, outerHtml) {\n this.nativeApi.onLinkActivated(href, outerHtml);\n }\n}\n","//\n// Copyright 2024 Readium Foundation. All rights reserved.\n// Use of this source code is governed by the BSD-style license\n// available in the top-level LICENSE file of the project.\n//\nimport { FixedSingleBridge } from \"./bridge/fixed-single-bridge\";\nconst iframe = document.getElementById(\"page\");\nconst metaViewport = document.querySelector(\"meta[name=viewport]\");\nwindow.singleArea = new FixedSingleBridge(window, iframe, metaViewport, window.gestures);\nwindow.documentState.onScriptsLoaded();\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nwindow.addEventListener(\"load\", (event) => {\n window.documentState.onDocumentLoaded();\n});\n","import { SingleAreaManager } from \"../fixed/single-area-manager\";\nimport { BridgeGesturesAdapter } from \"./all-gestures-bridge\";\nexport class FixedSingleBridge {\n constructor(window, iframe, metaViewport, gestures) {\n const listener = new BridgeGesturesAdapter(gestures);\n this.manager = new SingleAreaManager(window, iframe, metaViewport, listener);\n }\n loadResource(url) {\n this.manager.loadResource(url);\n }\n setViewport(viewporttWidth, viewportHeight, insetTop, insetRight, insetBottom, insetLeft) {\n const viewport = { width: viewporttWidth, height: viewportHeight };\n const insets = {\n top: insetTop,\n left: insetLeft,\n bottom: insetBottom,\n right: insetRight,\n };\n this.manager.setViewport(viewport, insets);\n }\n setFit(fit) {\n if (fit != \"contain\" && fit != \"width\" && fit != \"height\") {\n throw Error(`Invalid fit value: ${fit}`);\n }\n this.manager.setFit(fit);\n }\n}\n"],"names":["PageManager","constructor","window","iframe","listener","this","margins","top","right","bottom","left","contentWindow","Error","setMessagePort","messagePort","onmessage","message","onMessageFromIframe","show","style","display","hide","setMargins","marginTop","marginLeft","marginBottom","marginRight","loadPage","url","src","setPlaceholder","size","visibility","width","height","event","data","kind","onContentSizeAvailable","onTap","x","y","onLinkActivated","URL","href","toString","outerHtml","_a","onIframeLoaded","ViewportStringBuilder","setInitialScale","scale","initialScale","setMinimumScale","minimumScale","setWidth","setHeight","build","components","push","join","GesturesDetector","document","addEventListener","onClick","defaultPrevented","selection","getSelection","type","nearestElement","target","HTMLElement","nearestInteractiveElement","HTMLAnchorElement","outerHTML","stopPropagation","preventDefault","element","indexOf","nodeName","toLowerCase","hasAttribute","getAttribute","parentElement","SingleAreaManager","metaViewport","fit","insets","source","ports","page","tapEvent","clientX","visualViewport","offsetLeft","clientY","offsetTop","_","pageListener","boundingRect","getBoundingClientRect","setViewport","viewport","layout","setFit","loadResource","safeDrawingSize","content","container","widthRatio","heightRatio","Math","min","fitContain","fitWidth","fitHeight","computeScale","BridgeGesturesAdapter","gesturesApi","nativeApi","JSON","stringify","getElementById","querySelector","singleArea","gestures","manager","viewporttWidth","viewportHeight","insetTop","insetRight","insetBottom","insetLeft","documentState","onScriptsLoaded","onDocumentLoaded"],"sourceRoot":""} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js index 7de859a679..008f954fdc 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js @@ -1,2 +1,2 @@ -!function(){"use strict";const e=new class{constructor(e){this.nativeApi=e}onTap(e){this.nativeApi.onTap(JSON.stringify(e))}onLinkActivated(e,t){this.nativeApi.onLinkActivated(e,t)}}(window.gestures),t={onTap:t=>{const n={x:(t.clientX-visualViewport.offsetLeft)*visualViewport.scale,y:(t.clientY-visualViewport.offsetTop)*visualViewport.scale};e.onTap(n)},onLinkActivated:(t,n)=>{e.onLinkActivated(t,n)}};new class{constructor(e,t){this.window=e,this.listener=t,document.addEventListener("click",(e=>{this.onClick(e)}),!1)}onClick(e){if(e.defaultPrevented)return;const t=this.window.getSelection();if(t&&"Range"==t.type)return;let n;n=e.target instanceof HTMLElement?this.nearestInteractiveElement(e.target):null,n?n instanceof HTMLAnchorElement&&this.listener.onLinkActivated(n.href,n.outerHTML):this.listener.onTap(e),e.stopPropagation(),e.preventDefault()}nearestInteractiveElement(e){return null==e?null:-1!=["a","audio","button","canvas","details","input","label","option","select","submit","textarea","video"].indexOf(e.nodeName.toLowerCase())||e.hasAttribute("contenteditable")&&"false"!=e.getAttribute("contenteditable").toLowerCase()?e:e.parentElement?this.nearestInteractiveElement(e.parentElement):null}}(window,t),Window.prototype.readiumcss=new class{constructor(e){this.document=e}setProperties(e){for(const[t,n]of e)this.setProperty(t,n)}setProperty(e,t){null===t||""===t?this.removeProperty(e):document.documentElement.style.setProperty(e,t,"important")}removeProperty(e){document.documentElement.style.removeProperty(e)}}(window.document),window.initialization.onScriptsLoaded(),window.addEventListener("load",(e=>{new ResizeObserver((()=>{requestAnimationFrame((()=>{window.initialization.onDocumentResized()}))})).observe(document.body),window.initialization.onDocumentLoaded()}))}(); +!function(){"use strict";const e=new class{constructor(e){this.nativeApi=e}onTap(e){this.nativeApi.onTap(JSON.stringify(e))}onLinkActivated(e,t){this.nativeApi.onLinkActivated(e,t)}}(window.gestures),t={onTap:t=>{const n={x:(t.clientX-visualViewport.offsetLeft)*visualViewport.scale,y:(t.clientY-visualViewport.offsetTop)*visualViewport.scale};e.onTap(n)},onLinkActivated:(t,n)=>{e.onLinkActivated(t,n)}};new class{constructor(e,t){this.window=e,this.listener=t,document.addEventListener("click",(e=>{this.onClick(e)}),!1)}onClick(e){if(e.defaultPrevented)return;const t=this.window.getSelection();if(t&&"Range"==t.type)return;let n;n=e.target instanceof HTMLElement?this.nearestInteractiveElement(e.target):null,n?n instanceof HTMLAnchorElement&&this.listener.onLinkActivated(n.href,n.outerHTML):this.listener.onTap(e),e.stopPropagation(),e.preventDefault()}nearestInteractiveElement(e){return null==e?null:-1!=["a","audio","button","canvas","details","input","label","option","select","submit","textarea","video"].indexOf(e.nodeName.toLowerCase())||e.hasAttribute("contenteditable")&&"false"!=e.getAttribute("contenteditable").toLowerCase()?e:e.parentElement?this.nearestInteractiveElement(e.parentElement):null}}(window,t),Window.prototype.readiumcss=new class{constructor(e){this.document=e}setProperties(e){for(const[t,n]of e)this.setProperty(t,n)}setProperty(e,t){null===t||""===t?this.removeProperty(e):document.documentElement.style.setProperty(e,t,"important")}removeProperty(e){document.documentElement.style.removeProperty(e)}}(window.document),window.documentState.onScriptsLoaded(),window.addEventListener("load",(e=>{new ResizeObserver((()=>{requestAnimationFrame((()=>{window.documentState.onDocumentResized()}))})).observe(document.body),window.documentState.onDocumentLoaded()}))}(); //# sourceMappingURL=reflowable-injectable-script.js.map \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map index 389107393a..ed71e88c52 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map @@ -1 +1 @@ -{"version":3,"file":"reflowable-injectable-script.js","mappings":"yBAWA,MAAMA,EAAiB,ICXhB,MACH,WAAAC,CAAYC,GACRC,KAAKC,UAAYF,CACrB,CACA,KAAAG,CAAMC,GACFH,KAAKC,UAAUC,MAAME,KAAKC,UAAUF,GACxC,CACA,eAAAG,CAAgBC,EAAMC,GAClBR,KAAKC,UAAUK,gBAAgBC,EAAMC,EACzC,GDE6CC,OAAOC,UAClDC,EAAmB,CACrBT,MAAQC,IACJ,MAAMS,EAAW,CACbC,GAAIV,EAAMW,QAAUC,eAAeC,YAAcD,eAAeE,MAChEC,GAAIf,EAAMgB,QAAUJ,eAAeK,WAAaL,eAAeE,OAEnEpB,EAAeK,MAAMU,EAAS,EAElCN,gBAAiB,CAACC,EAAMC,KACpBX,EAAeS,gBAAgBC,EAAMC,EAAU,GAGvD,IExBO,MACH,WAAAV,CAAYW,EAAQY,GAChBrB,KAAKS,OAASA,EACdT,KAAKqB,SAAWA,EAChBC,SAASC,iBAAiB,SAAUpB,IAChCH,KAAKwB,QAAQrB,EAAM,IACpB,EACP,CACA,OAAAqB,CAAQrB,GACJ,GAAIA,EAAMsB,iBACN,OAEJ,MAAMC,EAAY1B,KAAKS,OAAOkB,eAC9B,GAAID,GAA+B,SAAlBA,EAAUE,KAIvB,OAEJ,IAAIC,EAEAA,EADA1B,EAAM2B,kBAAkBC,YACP/B,KAAKgC,0BAA0B7B,EAAM2B,QAGrC,KAEjBD,EACIA,aAA0BI,mBAC1BjC,KAAKqB,SAASf,gBAAgBuB,EAAetB,KAAMsB,EAAeK,WAItElC,KAAKqB,SAASnB,MAAMC,GAExBA,EAAMgC,kBACNhC,EAAMiC,gBACV,CAEA,yBAAAJ,CAA0BK,GACtB,OAAe,MAAXA,EACO,MAgBqD,GAdxC,CACpB,IACA,QACA,SACA,SACA,UACA,QACA,QACA,SACA,SACA,SACA,WACA,SAEgBC,QAAQD,EAAQE,SAASC,gBAIzCH,EAAQI,aAAa,oBACoC,SAAzDJ,EAAQK,aAAa,mBAAmBF,cAJjCH,EAQPA,EAAQM,cACD3C,KAAKgC,0BAA0BK,EAAQM,eAE3C,IACX,GF7CiBlC,OAAQE,GAC7BiC,OAAOC,UAAUC,WAAa,IGzBvB,MACH,WAAAhD,CAAYwB,GACRtB,KAAKsB,SAAWA,CACpB,CACA,aAAAyB,CAAcC,GACV,IAAK,MAAOC,EAAKC,KAAUF,EACvBhD,KAAKmD,YAAYF,EAAKC,EAE9B,CAEA,WAAAC,CAAYF,EAAKC,GACC,OAAVA,GAA4B,KAAVA,EAClBlD,KAAKoD,eAAeH,GAGP3B,SAAS+B,gBAGjBC,MAAMH,YAAYF,EAAKC,EAAO,YAE3C,CAEA,cAAAE,CAAeH,GACE3B,SAAS+B,gBACjBC,MAAMF,eAAeH,EAC9B,GHAwCxC,OAAOa,UACnDb,OAAO8C,eAAeC,kBAEtB/C,OAAOc,iBAAiB,QAASpB,IACZ,IAAIsD,gBAAe,KAChCC,uBAAsB,KAClBjD,OAAO8C,eAAeI,mBAAmB,GAC3C,IAEGC,QAAQtC,SAASuC,MAC1BpD,OAAO8C,eAAeO,kBAAkB,G","sources":["webpack://readium-js/./src/index-reflowable-injectable.ts","webpack://readium-js/./src/bridge/all-gestures-bridge.ts","webpack://readium-js/./src/common/gestures.ts","webpack://readium-js/./src/bridge/reflowable-css-bridge.ts"],"sourcesContent":["//\n// Copyright 2024 Readium Foundation. All rights reserved.\n// Use of this source code is governed by the BSD-style license\n// available in the top-level LICENSE file of the project.\n//\n/**\n * Script loaded by reflowable resources.\n */\nimport { BridgeGesturesAdapter, } from \"./bridge/all-gestures-bridge\";\nimport { CssBridge } from \"./bridge/reflowable-css-bridge\";\nimport { GesturesDetector } from \"./common/gestures\";\nconst bridgeListener = new BridgeGesturesAdapter(window.gestures);\nconst gesturesListener = {\n onTap: (event) => {\n const tapEvent = {\n x: (event.clientX - visualViewport.offsetLeft) * visualViewport.scale,\n y: (event.clientY - visualViewport.offsetTop) * visualViewport.scale,\n };\n bridgeListener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n bridgeListener.onLinkActivated(href, outerHtml);\n },\n};\nnew GesturesDetector(window, gesturesListener);\nWindow.prototype.readiumcss = new CssBridge(window.document);\nwindow.initialization.onScriptsLoaded();\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nwindow.addEventListener(\"load\", (event) => {\n const observer = new ResizeObserver(() => {\n requestAnimationFrame(() => {\n window.initialization.onDocumentResized();\n });\n });\n observer.observe(document.body);\n window.initialization.onDocumentLoaded();\n});\n","export class BridgeGesturesAdapter {\n constructor(gesturesApi) {\n this.nativeApi = gesturesApi;\n }\n onTap(event) {\n this.nativeApi.onTap(JSON.stringify(event));\n }\n onLinkActivated(href, outerHtml) {\n this.nativeApi.onLinkActivated(href, outerHtml);\n }\n}\n","export class GesturesDetector {\n constructor(window, listener) {\n this.window = window;\n this.listener = listener;\n document.addEventListener(\"click\", (event) => {\n this.onClick(event);\n }, false);\n }\n onClick(event) {\n if (event.defaultPrevented) {\n return;\n }\n const selection = this.window.getSelection();\n if (selection && selection.type == \"Range\") {\n // There's an on-going selection, the tap will dismiss it so we don't forward it.\n // selection.type might be None (collapsed) or Caret with a collapsed range\n // when there is not true selection.\n return;\n }\n let nearestElement;\n if (event.target instanceof HTMLElement) {\n nearestElement = this.nearestInteractiveElement(event.target);\n }\n else {\n nearestElement = null;\n }\n if (nearestElement) {\n if (nearestElement instanceof HTMLAnchorElement) {\n this.listener.onLinkActivated(nearestElement.href, nearestElement.outerHTML);\n }\n }\n else {\n this.listener.onTap(event);\n }\n event.stopPropagation();\n event.preventDefault();\n }\n // See. https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling\n nearestInteractiveElement(element) {\n if (element == null) {\n return null;\n }\n const interactiveTags = [\n \"a\",\n \"audio\",\n \"button\",\n \"canvas\",\n \"details\",\n \"input\",\n \"label\",\n \"option\",\n \"select\",\n \"submit\",\n \"textarea\",\n \"video\",\n ];\n if (interactiveTags.indexOf(element.nodeName.toLowerCase()) != -1) {\n return element;\n }\n // Checks whether the element is editable by the user.\n if (element.hasAttribute(\"contenteditable\") &&\n element.getAttribute(\"contenteditable\").toLowerCase() != \"false\") {\n return element;\n }\n // Checks parents recursively because the touch might be for example on an inside a .\n if (element.parentElement) {\n return this.nearestInteractiveElement(element.parentElement);\n }\n return null;\n }\n}\n","export class CssBridge {\n constructor(document) {\n this.document = document;\n }\n setProperties(properties) {\n for (const [key, value] of properties) {\n this.setProperty(key, value);\n }\n }\n // For setting user setting.\n setProperty(key, value) {\n if (value === null || value === \"\") {\n this.removeProperty(key);\n }\n else {\n const root = document.documentElement;\n // The `!important` annotation is added with `setProperty()` because if it's part of the\n // `value`, it will be ignored by the Web View.\n root.style.setProperty(key, value, \"important\");\n }\n }\n // For removing user setting.\n removeProperty(key) {\n const root = document.documentElement;\n root.style.removeProperty(key);\n }\n}\n"],"names":["bridgeListener","constructor","gesturesApi","this","nativeApi","onTap","event","JSON","stringify","onLinkActivated","href","outerHtml","window","gestures","gesturesListener","tapEvent","x","clientX","visualViewport","offsetLeft","scale","y","clientY","offsetTop","listener","document","addEventListener","onClick","defaultPrevented","selection","getSelection","type","nearestElement","target","HTMLElement","nearestInteractiveElement","HTMLAnchorElement","outerHTML","stopPropagation","preventDefault","element","indexOf","nodeName","toLowerCase","hasAttribute","getAttribute","parentElement","Window","prototype","readiumcss","setProperties","properties","key","value","setProperty","removeProperty","documentElement","style","initialization","onScriptsLoaded","ResizeObserver","requestAnimationFrame","onDocumentResized","observe","body","onDocumentLoaded"],"sourceRoot":""} \ No newline at end of file +{"version":3,"file":"reflowable-injectable-script.js","mappings":"yBAWA,MAAMA,EAAiB,ICXhB,MACH,WAAAC,CAAYC,GACRC,KAAKC,UAAYF,CACrB,CACA,KAAAG,CAAMC,GACFH,KAAKC,UAAUC,MAAME,KAAKC,UAAUF,GACxC,CACA,eAAAG,CAAgBC,EAAMC,GAClBR,KAAKC,UAAUK,gBAAgBC,EAAMC,EACzC,GDE6CC,OAAOC,UAClDC,EAAmB,CACrBT,MAAQC,IACJ,MAAMS,EAAW,CACbC,GAAIV,EAAMW,QAAUC,eAAeC,YAAcD,eAAeE,MAChEC,GAAIf,EAAMgB,QAAUJ,eAAeK,WAAaL,eAAeE,OAEnEpB,EAAeK,MAAMU,EAAS,EAElCN,gBAAiB,CAACC,EAAMC,KACpBX,EAAeS,gBAAgBC,EAAMC,EAAU,GAGvD,IExBO,MACH,WAAAV,CAAYW,EAAQY,GAChBrB,KAAKS,OAASA,EACdT,KAAKqB,SAAWA,EAChBC,SAASC,iBAAiB,SAAUpB,IAChCH,KAAKwB,QAAQrB,EAAM,IACpB,EACP,CACA,OAAAqB,CAAQrB,GACJ,GAAIA,EAAMsB,iBACN,OAEJ,MAAMC,EAAY1B,KAAKS,OAAOkB,eAC9B,GAAID,GAA+B,SAAlBA,EAAUE,KAIvB,OAEJ,IAAIC,EAEAA,EADA1B,EAAM2B,kBAAkBC,YACP/B,KAAKgC,0BAA0B7B,EAAM2B,QAGrC,KAEjBD,EACIA,aAA0BI,mBAC1BjC,KAAKqB,SAASf,gBAAgBuB,EAAetB,KAAMsB,EAAeK,WAItElC,KAAKqB,SAASnB,MAAMC,GAExBA,EAAMgC,kBACNhC,EAAMiC,gBACV,CAEA,yBAAAJ,CAA0BK,GACtB,OAAe,MAAXA,EACO,MAgBqD,GAdxC,CACpB,IACA,QACA,SACA,SACA,UACA,QACA,QACA,SACA,SACA,SACA,WACA,SAEgBC,QAAQD,EAAQE,SAASC,gBAIzCH,EAAQI,aAAa,oBACoC,SAAzDJ,EAAQK,aAAa,mBAAmBF,cAJjCH,EAQPA,EAAQM,cACD3C,KAAKgC,0BAA0BK,EAAQM,eAE3C,IACX,GF7CiBlC,OAAQE,GAC7BiC,OAAOC,UAAUC,WAAa,IGzBvB,MACH,WAAAhD,CAAYwB,GACRtB,KAAKsB,SAAWA,CACpB,CACA,aAAAyB,CAAcC,GACV,IAAK,MAAOC,EAAKC,KAAUF,EACvBhD,KAAKmD,YAAYF,EAAKC,EAE9B,CAEA,WAAAC,CAAYF,EAAKC,GACC,OAAVA,GAA4B,KAAVA,EAClBlD,KAAKoD,eAAeH,GAGP3B,SAAS+B,gBAGjBC,MAAMH,YAAYF,EAAKC,EAAO,YAE3C,CAEA,cAAAE,CAAeH,GACE3B,SAAS+B,gBACjBC,MAAMF,eAAeH,EAC9B,GHAwCxC,OAAOa,UACnDb,OAAO8C,cAAcC,kBAErB/C,OAAOc,iBAAiB,QAASpB,IACZ,IAAIsD,gBAAe,KAChCC,uBAAsB,KAClBjD,OAAO8C,cAAcI,mBAAmB,GAC1C,IAEGC,QAAQtC,SAASuC,MAC1BpD,OAAO8C,cAAcO,kBAAkB,G","sources":["webpack://readium-js/./src/index-reflowable-injectable.ts","webpack://readium-js/./src/bridge/all-gestures-bridge.ts","webpack://readium-js/./src/common/gestures.ts","webpack://readium-js/./src/bridge/reflowable-css-bridge.ts"],"sourcesContent":["//\n// Copyright 2024 Readium Foundation. All rights reserved.\n// Use of this source code is governed by the BSD-style license\n// available in the top-level LICENSE file of the project.\n//\n/**\n * Script loaded by reflowable resources.\n */\nimport { BridgeGesturesAdapter, } from \"./bridge/all-gestures-bridge\";\nimport { CssBridge } from \"./bridge/reflowable-css-bridge\";\nimport { GesturesDetector } from \"./common/gestures\";\nconst bridgeListener = new BridgeGesturesAdapter(window.gestures);\nconst gesturesListener = {\n onTap: (event) => {\n const tapEvent = {\n x: (event.clientX - visualViewport.offsetLeft) * visualViewport.scale,\n y: (event.clientY - visualViewport.offsetTop) * visualViewport.scale,\n };\n bridgeListener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n bridgeListener.onLinkActivated(href, outerHtml);\n },\n};\nnew GesturesDetector(window, gesturesListener);\nWindow.prototype.readiumcss = new CssBridge(window.document);\nwindow.documentState.onScriptsLoaded();\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nwindow.addEventListener(\"load\", (event) => {\n const observer = new ResizeObserver(() => {\n requestAnimationFrame(() => {\n window.documentState.onDocumentResized();\n });\n });\n observer.observe(document.body);\n window.documentState.onDocumentLoaded();\n});\n","export class BridgeGesturesAdapter {\n constructor(gesturesApi) {\n this.nativeApi = gesturesApi;\n }\n onTap(event) {\n this.nativeApi.onTap(JSON.stringify(event));\n }\n onLinkActivated(href, outerHtml) {\n this.nativeApi.onLinkActivated(href, outerHtml);\n }\n}\n","export class GesturesDetector {\n constructor(window, listener) {\n this.window = window;\n this.listener = listener;\n document.addEventListener(\"click\", (event) => {\n this.onClick(event);\n }, false);\n }\n onClick(event) {\n if (event.defaultPrevented) {\n return;\n }\n const selection = this.window.getSelection();\n if (selection && selection.type == \"Range\") {\n // There's an on-going selection, the tap will dismiss it so we don't forward it.\n // selection.type might be None (collapsed) or Caret with a collapsed range\n // when there is not true selection.\n return;\n }\n let nearestElement;\n if (event.target instanceof HTMLElement) {\n nearestElement = this.nearestInteractiveElement(event.target);\n }\n else {\n nearestElement = null;\n }\n if (nearestElement) {\n if (nearestElement instanceof HTMLAnchorElement) {\n this.listener.onLinkActivated(nearestElement.href, nearestElement.outerHTML);\n }\n }\n else {\n this.listener.onTap(event);\n }\n event.stopPropagation();\n event.preventDefault();\n }\n // See. https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling\n nearestInteractiveElement(element) {\n if (element == null) {\n return null;\n }\n const interactiveTags = [\n \"a\",\n \"audio\",\n \"button\",\n \"canvas\",\n \"details\",\n \"input\",\n \"label\",\n \"option\",\n \"select\",\n \"submit\",\n \"textarea\",\n \"video\",\n ];\n if (interactiveTags.indexOf(element.nodeName.toLowerCase()) != -1) {\n return element;\n }\n // Checks whether the element is editable by the user.\n if (element.hasAttribute(\"contenteditable\") &&\n element.getAttribute(\"contenteditable\").toLowerCase() != \"false\") {\n return element;\n }\n // Checks parents recursively because the touch might be for example on an inside a .\n if (element.parentElement) {\n return this.nearestInteractiveElement(element.parentElement);\n }\n return null;\n }\n}\n","export class CssBridge {\n constructor(document) {\n this.document = document;\n }\n setProperties(properties) {\n for (const [key, value] of properties) {\n this.setProperty(key, value);\n }\n }\n // For setting user setting.\n setProperty(key, value) {\n if (value === null || value === \"\") {\n this.removeProperty(key);\n }\n else {\n const root = document.documentElement;\n // The `!important` annotation is added with `setProperty()` because if it's part of the\n // `value`, it will be ignored by the Web View.\n root.style.setProperty(key, value, \"important\");\n }\n }\n // For removing user setting.\n removeProperty(key) {\n const root = document.documentElement;\n root.style.removeProperty(key);\n }\n}\n"],"names":["bridgeListener","constructor","gesturesApi","this","nativeApi","onTap","event","JSON","stringify","onLinkActivated","href","outerHtml","window","gestures","gesturesListener","tapEvent","x","clientX","visualViewport","offsetLeft","scale","y","clientY","offsetTop","listener","document","addEventListener","onClick","defaultPrevented","selection","getSelection","type","nearestElement","target","HTMLElement","nearestInteractiveElement","HTMLAnchorElement","outerHTML","stopPropagation","preventDefault","element","indexOf","nodeName","toLowerCase","hasAttribute","getAttribute","parentElement","Window","prototype","readiumcss","setProperties","properties","key","value","setProperty","removeProperty","documentElement","style","documentState","onScriptsLoaded","ResizeObserver","requestAnimationFrame","onDocumentResized","observe","body","onDocumentLoaded"],"sourceRoot":""} \ No newline at end of file diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt index e4e6864ca2..8e1dc7d91f 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt @@ -99,12 +99,12 @@ public fun ReflowableWebRendition( val inputListenerState = rememberUpdatedState(inputListener) - // First location update to enable controller creation. + // First location update to trigger controller creation. // In the future, that should require access to the WebView. state.updateLocation( ReflowableWebLocation( href = state.publication.readingOrder.items[currentItemIndexState.value].href, - progression = state.currentProgression + progression = state.resourceStates[currentItemIndexState.value].progression.ratio ) ) @@ -119,11 +119,9 @@ public fun ReflowableWebRendition( else -> Orientation.Horizontal } ) { index -> - val prevReadyToScroll = index == 0 || - state.resourceStates[index - 1].scrollController.value != null - - val nextReadyToScroll = index == state.resourceStates.size - 1 || - state.resourceStates[index + 1].scrollController.value != null + val readyToScroll = ((index - 1)..(index + 1)).toList() + .mapNotNull { state.resourceStates.getOrNull(it) } + .all { it.scrollController.value != null } ReflowableResource( resourceState = state.resourceStates[index], @@ -139,13 +137,7 @@ public fun ReflowableWebRendition( rsProperties = state.readiumCss.value.rsProperties, userProperties = state.readiumCss.value.userProperties, layout = state.readiumCss.value.layout, - initialProgression = when { - index < currentItemIndexState.value -> 1.0 - index > currentItemIndexState.value -> 0.0 - else -> state.currentProgression - }, - stickToInitialProgression = index != currentItemIndexState.value, - enableScroll = prevReadyToScroll && nextReadyToScroll, + enableScroll = readyToScroll, onTap = { tapEvent -> inputListenerState.value.onTap(tapEvent, TapContext(viewportSize.value)) }, diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt index 508fb12f39..ac2c6c4602 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt @@ -28,6 +28,8 @@ import org.readium.navigator.web.css.update import org.readium.navigator.web.location.ReflowableWebGoLocation import org.readium.navigator.web.location.ReflowableWebLocation import org.readium.navigator.web.preferences.ReflowableWebSettings +import org.readium.navigator.web.reflowable.EndProgression +import org.readium.navigator.web.reflowable.RatioProgression import org.readium.navigator.web.reflowable.ReflowableResourceState import org.readium.navigator.web.reflowable.ReflowableWebPublication import org.readium.navigator.web.util.HyperlinkProcessor @@ -59,11 +61,18 @@ public class ReflowableWebRenditionState internal constructor( fontFamilyDeclarations: List, ) : RenditionState { + private val initialIndex = publication.readingOrder.indexOfHref(initialLocation.href) ?: 0 + internal val resourceStates: List = publication.readingOrder.items.mapIndexed { index, item -> ReflowableResourceState( index = index, - href = item.href + href = item.href, + initialProgression = when { + index < initialIndex -> EndProgression + index > initialIndex -> RatioProgression(0.0) + else -> RatioProgression(initialLocation.progression ?: 0.0) + } ) } @@ -133,15 +142,10 @@ public class ReflowableWebRenditionState internal constructor( internal val pagerState: PagerState = PagerState( - currentPage = publication.readingOrder.indexOfHref(initialLocation.href) ?: 0, + currentPage = initialIndex, pageCount = { publication.readingOrder.size } ) - internal val currentProgression: Double get() = - controller?.location?.value?.progression - ?: initialLocation.progression - ?: 0.0 - internal suspend fun computeHyperlinkContext(originUrl: Url, outerHtml: String): LinkContext? = hyperlinkProcessor.computeLinkContext(originUrl, outerHtml) @@ -204,6 +208,8 @@ internal class ReflowableNavigationDelegate( mutableStateOf(initialLocation) internal fun updateLocation(location: ReflowableWebLocation) { + val index = checkNotNull(readingOrder.indexOfHref(location.href)) + resourceStates[index].progression = RatioProgression(location.progression) locationMutable.value = location } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt index 20d28925bc..6b97f0d1d5 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt @@ -20,9 +20,9 @@ import androidx.compose.ui.unit.DpOffset import org.readium.navigator.common.TapEvent import org.readium.navigator.web.gestures.scrollable2D import org.readium.navigator.web.util.WebViewClient +import org.readium.navigator.web.webapi.DocumentStateApi import org.readium.navigator.web.webapi.GesturesApi import org.readium.navigator.web.webapi.GesturesListener -import org.readium.navigator.web.webapi.InitializationApi import org.readium.navigator.web.webview.RelaxedWebView import org.readium.navigator.web.webview.WebView import org.readium.navigator.web.webview.WebViewScrollable2DState @@ -46,8 +46,8 @@ internal fun SpreadWebView( val spreadNestedScrollConnection = SpreadNestedScrollConnection(scrollableState) - val initializationApi = remember(onScriptsLoaded) { - InitializationApi(onScriptsLoaded, {}, {}) + val documentStateApi = remember(onScriptsLoaded) { + DocumentStateApi(onScriptsLoaded, {}, {}) } val gesturesApi = remember(onTap) { @@ -64,7 +64,7 @@ internal fun SpreadWebView( } LaunchedEffect(state.webView) { - state.webView?.let { initializationApi.registerOnWebView(it) } + state.webView?.let { documentStateApi.registerOnWebView(it) } state.webView?.let { gesturesApi.registerOnWebView(it) } } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesEditor.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesEditor.kt index 45e6b547a9..61a5d0aabb 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesEditor.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesEditor.kt @@ -349,7 +349,7 @@ public class ReflowableWebPreferencesEditor internal constructor( * Indicates if the overflow of resources should be handled using scrolling instead of synthetic * pagination. * - * Only effective with reflowable publications. + * Only effective with reflowable publications and if [verticalText] is false. */ public val scroll: Preference = PreferenceDelegate( diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt index c495872362..a3b689c829 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt @@ -25,6 +25,7 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.key import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color @@ -35,8 +36,6 @@ import androidx.compose.ui.unit.DpOffset import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.Velocity import androidx.compose.ui.zIndex -import kotlin.math.ceil -import kotlin.math.floor import org.readium.navigator.common.TapEvent import org.readium.navigator.web.css.Layout import org.readium.navigator.web.css.RsProperties @@ -48,9 +47,9 @@ import org.readium.navigator.web.util.AbsolutePaddingValues import org.readium.navigator.web.util.WebViewClient import org.readium.navigator.web.util.absolutePadding import org.readium.navigator.web.webapi.CssApi +import org.readium.navigator.web.webapi.DelegatingGesturesListener +import org.readium.navigator.web.webapi.DocumentStateApi import org.readium.navigator.web.webapi.GesturesApi -import org.readium.navigator.web.webapi.GesturesListener -import org.readium.navigator.web.webapi.InitializationApi import org.readium.navigator.web.webview.RelaxedWebView import org.readium.navigator.web.webview.WebView import org.readium.navigator.web.webview.WebViewLayoutInfoProvider @@ -78,19 +77,11 @@ internal fun ReflowableResource( userProperties: UserProperties, rsProperties: RsProperties, layout: Layout, - initialProgression: Double, - stickToInitialProgression: Boolean, enableScroll: Boolean, onTap: (TapEvent) -> Unit, onLinkActivated: (Url, String) -> Unit, onScrollChanged: (Double) -> Unit, ) { - val scrollOrientation = when { - verticalText -> Orientation.Horizontal - scroll -> Orientation.Vertical - else -> Orientation.Horizontal - } - Box( modifier = Modifier.fillMaxSize(), propagateMinConstraints = true @@ -100,15 +91,23 @@ internal fun ReflowableResource( url = publicationBaseUrl.resolve(resourceState.href).toString() ) - val scriptsLoaded = remember(webViewState.webView) { - mutableStateOf(false) - } + val scrollOrientation = + rememberUpdatedState( + when { + verticalText -> Orientation.Horizontal + scroll -> Orientation.Vertical + else -> Orientation.Horizontal + } + ) + + val scriptsLoaded = + remember(webViewState.webView) { mutableStateOf(false) } val contentIsLaidOut = remember(webViewState.webView) { mutableStateOf(false) } - val initializationApi = remember(webViewState.webView, stickToInitialProgression) { - InitializationApi( + val documentStateApi = remember(webViewState.webView) { + DocumentStateApi( onScriptsLoadedDelegate = { scriptsLoaded.value = true }, @@ -119,7 +118,14 @@ internal fun ReflowableResource( 0, object : WebView.VisualStateCallback() { override fun onComplete(requestId: Long) { - scrollToProgression(initialProgression, scrollOrientation) + with(this@apply) { + val scrollController = WebViewScrollController(this) + scrollController.scrollToProgression(resourceState.progression.ratio, scrollOrientation.value) + resourceState.scrollController.value = scrollController + setOnScrollChangeListener { view, scrollX, scrollY, oldScrollX, oldScrollY -> + onScrollChanged(scrollController.progression(scrollOrientation.value)) + } + } contentIsLaidOut.value = true } } @@ -128,45 +134,47 @@ internal fun ReflowableResource( } }, onDocumentResizedDelegate = { - resourceState.scrollController.value = webViewState.webView?.let { WebViewScrollController(it) } - if (stickToInitialProgression) { - webViewState.webView?.scrollToProgression(initialProgression, scrollOrientation) + // If a previous resource is resized, we might need to scroll it again to the end + if (resourceState.progression is EndProgression) { + val scrollControllerNow = resourceState.scrollController.value + scrollControllerNow?.scrollToProgression(1.0, scrollOrientation.value) } } ) } + LaunchedEffect(webViewState.webView, documentStateApi) { + webViewState.webView?.let { documentStateApi.registerOnWebView(it) } + } + val cssApi = remember(webViewState.webView, scriptsLoaded.value) { webViewState.webView .takeIf { scriptsLoaded.value } ?.let { CssApi(it) } } - cssApi?.let { api -> - LaunchedEffect(rsProperties, userProperties) { - api.setProperties(userProperties, rsProperties) - } + LaunchedEffect(cssApi, rsProperties, userProperties) { + cssApi?.setProperties(userProperties, rsProperties) } - val gesturesApi = remember(onTap) { - val listener = object : GesturesListener { - override fun onTap(offset: DpOffset) { - val shiftedOffset = DpOffset( - x = offset.x + padding.left, - y = offset.y + padding.top - ) - onTap(TapEvent(shiftedOffset)) - } - - override fun onLinkActivated(href: AbsoluteUrl, outerHtml: String) { - onLinkActivated(publicationBaseUrl.relativize(href), outerHtml) - } - } - GesturesApi(listener) + val gesturesApi = remember(onTap, onLinkActivated) { + GesturesApi( + DelegatingGesturesListener( + onTapDelegate = { offset -> + val shiftedOffset = DpOffset( + x = offset.x + padding.left, + y = offset.y + padding.top + ) + onTap(TapEvent(shiftedOffset)) + }, + onLinkActivatedDelegate = { href, outerHtml -> + onLinkActivated(publicationBaseUrl.relativize(href), outerHtml) + } + ) + ) } - LaunchedEffect(webViewState.webView) { - webViewState.webView?.let { initializationApi.registerOnWebView(it) } + LaunchedEffect(webViewState.webView, gesturesApi) { webViewState.webView?.let { gesturesApi.registerOnWebView(it) } } @@ -174,16 +182,6 @@ internal fun ReflowableResource( val density = LocalDensity.current - LaunchedEffect(contentIsLaidOut, contentIsLaidOut.value, scrollableState.webView) { - scrollableState.webView - .takeIf { contentIsLaidOut.value } - ?.let { webview -> - webview.setOnScrollChangeListener { view, scrollX, scrollY, oldScrollX, oldScrollY -> - onScrollChanged(webview.progression(scrollOrientation)) - } - } - } - val webViewViewport = DpSize( width = viewportSize.width - padding.left - padding.right, height = viewportSize.height - padding.top - padding.bottom @@ -198,18 +196,18 @@ internal fun ReflowableResource( pagingFlingBehavior( WebViewLayoutInfoProvider( density, - scrollOrientation, + scrollOrientation.value, reverseLayout, webViewViewport, it ) ) } - ?.toFling2DBehavior(orientation = scrollOrientation) + ?.toFling2DBehavior(orientation = scrollOrientation.value) } val resourceScrollConnection = - ResourceNestedScrollConnection(pagerState, scrollableState, scrollOrientation) + ResourceNestedScrollConnection(pagerState, scrollableState, scrollOrientation.value) // Hide content before initial position is settled if (!contentIsLaidOut.value) { @@ -222,7 +220,7 @@ internal fun ReflowableResource( ) } - key(layout) { + key(layout, scrollOrientation.value) { WebView( modifier = Modifier // Detect taps on padding @@ -242,7 +240,7 @@ internal fun ReflowableResource( state = scrollableState, flingBehavior = flingBehavior, reverseDirection = !reverseLayout, - orientation = scrollOrientation + orientation = scrollOrientation.value ) .fillMaxSize() .background(backgroundColor) @@ -261,7 +259,7 @@ internal fun ReflowableResource( webview.isVerticalScrollBarEnabled = false webview.isHorizontalScrollBarEnabled = false webview.setLayerType(View.LAYER_TYPE_HARDWARE, null) - if (verticalText || !scroll) { + if (scrollOrientation.value == Orientation.Horizontal) { // Prevents vertical scrolling towards blank space. // See https://github.com/readium/readium-css/issues/158 webview.setOnTouchListener(object : View.OnTouchListener { @@ -281,19 +279,6 @@ internal fun ReflowableResource( } } -private fun RelaxedWebView.scrollToProgression(progression: Double, scrollOrientation: Orientation) { - if (scrollOrientation == Orientation.Horizontal) { - scrollTo(floor(progression * maxScrollX).toInt(), 0) - } else { - scrollTo(0, ceil(progression * maxScrollY).toInt()) - } -} - -private fun RelaxedWebView.progression(orientation: Orientation) = when (orientation) { - Orientation.Vertical -> scrollY / maxScrollY.toDouble() - Orientation.Horizontal -> scrollX / maxScrollX.toDouble() -} - private fun FlingBehavior.toFling2DBehavior(orientation: Orientation) = object : Fling2DBehavior { override suspend fun Scroll2DScope.performFling( diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResourceState.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResourceState.kt index 2d69a4b711..25caecef07 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResourceState.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResourceState.kt @@ -16,7 +16,22 @@ import org.readium.r2.shared.util.Url internal class ReflowableResourceState( val index: Int, val href: Url, + initialProgression: Progression, ) { + var progression: Progression = initialProgression + val scrollController: MutableState = mutableStateOf(null) } + +internal sealed interface Progression { + + val ratio: Double +} + +internal data class RatioProgression(override val ratio: Double) : Progression + +internal data object EndProgression : Progression { + + override val ratio: Double = 1.0 +} diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/webapi/InitializationApi.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/webapi/DocumentStateApi.kt similarity index 89% rename from readium/navigators/web/src/main/java/org/readium/navigator/web/webapi/InitializationApi.kt rename to readium/navigators/web/src/main/java/org/readium/navigator/web/webapi/DocumentStateApi.kt index 8d5c2de452..4191e39f2b 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/webapi/InitializationApi.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/webapi/DocumentStateApi.kt @@ -9,14 +9,14 @@ package org.readium.navigator.web.webapi import android.webkit.JavascriptInterface import android.webkit.WebView -internal class InitializationApi( +internal class DocumentStateApi( private val onScriptsLoadedDelegate: () -> Unit, private val onDocumentLoadedDelegate: () -> Unit, private val onDocumentResizedDelegate: () -> Unit, ) { fun registerOnWebView(webView: WebView) { - webView.addJavascriptInterface(this, "initialization") + webView.addJavascriptInterface(this, "documentState") } @JavascriptInterface diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/webapi/GesturesApi.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/webapi/GesturesApi.kt index 5672dfed68..9e7ab2e0d9 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/webapi/GesturesApi.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/webapi/GesturesApi.kt @@ -13,9 +13,27 @@ import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json import org.readium.r2.shared.util.AbsoluteUrl +internal class DelegatingGesturesListener( + private val onTapDelegate: (DpOffset) -> Unit, + private val onLinkActivatedDelegate: (AbsoluteUrl, String) -> Unit, +) : GesturesListener { + + override fun onTap(offset: DpOffset) { + onTapDelegate(offset) + } + + override fun onLinkActivated( + href: AbsoluteUrl, + outerHtml: String, + ) { + onLinkActivatedDelegate(href, outerHtml) + } +} + internal interface GesturesListener { fun onTap(offset: DpOffset) + fun onLinkActivated(href: AbsoluteUrl, outerHtml: String) } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollController.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollController.kt index 20536705ac..c0ea8c4562 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollController.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollController.kt @@ -1,38 +1,58 @@ package org.readium.navigator.web.webview +import androidx.compose.foundation.gestures.Orientation +import kotlin.math.ceil +import kotlin.math.floor + internal class WebViewScrollController( private val webView: RelaxedWebView, ) { val canMoveLeft: Boolean - get() = - webView?.let { it.scrollX > it.width / 2 } == true + get() = webView.scrollX > webView.width / 2 == true val canMoveRight: Boolean - get() = - webView?.let { (it.maxScrollX - it.scrollX) > it.width / 2 } == true + get() = webView.maxScrollX - webView.scrollX > webView.width / 2 == true val canMoveTop: Boolean - get() = - webView?.let { it.scrollY > it.width / 2 } == true + get() = webView.scrollY > webView.width / 2 == true val canMoveBottom: Boolean - get() = - webView?.let { (it.maxScrollY - it.scrollY) > it.width / 2 } == true + get() = webView.maxScrollY - webView.scrollY > webView.width / 2 == true fun moveLeft() { - webView?.let { it.scrollBy(-it.width, 0) } + webView.scrollBy(-webView.width, 0) } fun moveRight() { - webView?.let { it.scrollBy(it.width, 0) } + webView.scrollBy(webView.width, 0) } fun moveTop() { - webView?.let { it.scrollBy(0, -it.width) } + webView.scrollBy(0, -webView.width) } fun moveBottom() { - webView?.let { it.scrollBy(0, it.width) } + webView.scrollBy(0, webView.width) + } + + fun scrollToProgression(progression: Double, scrollOrientation: Orientation) { + webView.scrollToProgression(progression, scrollOrientation) } + + fun progression(scrollOrientation: Orientation) = + webView.progression(scrollOrientation) +} + +private fun RelaxedWebView.scrollToProgression(progression: Double, scrollOrientation: Orientation) { + if (scrollOrientation == Orientation.Horizontal) { + scrollTo(floor(progression * maxScrollX).toInt(), 0) + } else { + scrollTo(0, ceil(progression * maxScrollY).toInt()) + } +} + +private fun RelaxedWebView.progression(orientation: Orientation) = when (orientation) { + Orientation.Vertical -> scrollY / maxScrollY.toDouble() + Orientation.Horizontal -> scrollX / maxScrollX.toDouble() } From 354de42e73944e255361ed5c211ab2d331f79ce7 Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Mon, 31 Mar 2025 12:23:22 +0200 Subject: [PATCH 27/88] Various changes in reflowable preferences and preference editor --- .../demo/preferences/UserPreferences.kt | 12 ++-- .../navigator/web/ReflowableWebRendition.kt | 2 +- .../readium/navigator/web/css/ReadiumCss.kt | 3 +- .../preferences/ReflowableWebPreferences.kt | 8 +-- .../ReflowableWebPreferencesEditor.kt | 71 +++++-------------- .../web/preferences/ReflowableWebSettings.kt | 2 +- .../ReflowableWebSettingsResolver.kt | 2 +- 7 files changed, 31 insertions(+), 69 deletions(-) diff --git a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/preferences/UserPreferences.kt b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/preferences/UserPreferences.kt index 506671b1f1..2ad60e56cb 100644 --- a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/preferences/UserPreferences.kt +++ b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/preferences/UserPreferences.kt @@ -104,7 +104,7 @@ fun

, S : Settings, E : PreferencesEditor> UserPreferen letterSpacing = editor.letterSpacing, ligatures = editor.ligatures, lineHeight = editor.lineHeight, - pageMargins = editor.pageMargins, + horizontalMargins = editor.horizontalMargins, paragraphIndent = editor.paragraphIndent, paragraphSpacing = editor.paragraphSpacing, publisherStyles = editor.publisherStyles, @@ -208,7 +208,7 @@ private fun ReflowableUserPreferences( letterSpacing: RangePreference? = null, ligatures: Preference? = null, lineHeight: RangePreference? = null, - pageMargins: RangePreference? = null, + horizontalMargins: RangePreference? = null, paragraphIndent: RangePreference? = null, paragraphSpacing: RangePreference? = null, publisherStyles: Preference? = null, @@ -247,7 +247,7 @@ private fun ReflowableUserPreferences( Divider() } - if (scroll != null || columnCount != null || pageMargins != null) { + if (scroll != null || columnCount != null || horizontalMargins != null) { if (scroll != null) { SwitchItem( title = "Scroll", @@ -263,10 +263,10 @@ private fun ReflowableUserPreferences( ) } - if (pageMargins != null) { + if (horizontalMargins != null) { StepperItem( - title = "Page margins", - preference = pageMargins + title = "Horizontal margins", + preference = horizontalMargins ) } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt index 8e1dc7d91f..bb2e4671e2 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt @@ -119,7 +119,7 @@ public fun ReflowableWebRendition( else -> Orientation.Horizontal } ) { index -> - val readyToScroll = ((index - 1)..(index + 1)).toList() + val readyToScroll = ((index - 2)..(index + 2)).toList() .mapNotNull { state.resourceStates.getOrNull(it) } .all { it.scrollController.value != null } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCss.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCss.kt index a90db9c7f1..0536ba9093 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCss.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCss.kt @@ -22,7 +22,6 @@ import org.readium.r2.navigator.preferences.Theme import org.readium.r2.shared.ExperimentalReadiumApi import org.readium.r2.shared.util.AbsoluteUrl import org.readium.r2.shared.util.Either -import org.readium.r2.shared.util.Either.Companion.invoke import org.readium.r2.shared.util.RelativeUrl import org.readium.r2.shared.util.Url @@ -299,7 +298,7 @@ internal fun ReadiumCss.update(settings: ReflowableWebSettings, useReadiumCssFon copy( layout = Layout.from(settings), rsProperties = rsProperties.copy( - pageGutter = Length.Px((rsProperties.pageGutter?.value ?: 20.0) * pageMargins) + pageGutter = Length.Px((rsProperties.pageGutter?.value ?: 20.0) * horizontalMargins) ), userProperties = userProperties.copy( view = when (scroll) { diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferences.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferences.kt index 41b0effe8e..c9a4a4d7c2 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferences.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferences.kt @@ -26,7 +26,7 @@ import org.readium.r2.shared.util.Language * @param letterSpacing Space between letters. * @param ligatures Enable ligatures in Arabic. * @param lineHeight Leading line height. - * @param pageMargins Factor applied to horizontal margins. + * @param horizontalMargins Factor applied to horizontal margins. * @param paragraphIndent Text indentation for paragraphs. * @param paragraphSpacing Vertical margins for paragraphs. * @param publisherStyles Indicates whether the original publisher styles should be observed. @@ -59,7 +59,7 @@ public data class ReflowableWebPreferences( val letterSpacing: Double? = null, val ligatures: Boolean? = null, val lineHeight: Double? = null, - val pageMargins: Double? = null, + val horizontalMargins: Double? = null, val paragraphIndent: Double? = null, val paragraphSpacing: Double? = null, val publisherStyles: Boolean? = null, @@ -79,7 +79,7 @@ public data class ReflowableWebPreferences( require(fontSize == null || fontSize >= 0) require(fontWeight == null || fontWeight in 0.0..2.5) require(letterSpacing == null || letterSpacing >= 0) - require(pageMargins == null || pageMargins >= 0) + require(horizontalMargins == null || horizontalMargins >= 0) require(paragraphSpacing == null || paragraphSpacing >= 0) require(spread in listOf(null, Spread.NEVER, Spread.ALWAYS)) require(wordSpacing == null || wordSpacing >= 0) @@ -99,7 +99,7 @@ public data class ReflowableWebPreferences( letterSpacing = other.letterSpacing ?: letterSpacing, ligatures = other.ligatures ?: ligatures, lineHeight = other.lineHeight ?: lineHeight, - pageMargins = other.pageMargins ?: pageMargins, + horizontalMargins = other.horizontalMargins ?: horizontalMargins, paragraphIndent = other.paragraphIndent ?: paragraphIndent, paragraphSpacing = other.paragraphSpacing ?: paragraphSpacing, publisherStyles = other.publisherStyles ?: publisherStyles, diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesEditor.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesEditor.kt index 61a5d0aabb..5d8318f79d 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesEditor.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesEditor.kt @@ -78,9 +78,6 @@ public class ReflowableWebPreferencesEditor internal constructor( /** * Default background color. * - * For fixed-layout publications, it applies to the navigator background but not the publication - * pages. - * * When unset, the current [theme] background color is effective. */ public val backgroundColor: Preference = @@ -91,7 +88,7 @@ public class ReflowableWebPreferencesEditor internal constructor( (theme.value ?: theme.effectiveValue).backgroundColor ) }, - getIsEffective = { preferences.backgroundColor != null }, + getIsEffective = { true }, updateValue = { value -> updateValues { it.copy(backgroundColor = value) } } ) @@ -99,10 +96,8 @@ public class ReflowableWebPreferencesEditor internal constructor( * Number of reflowable columns to display (one-page view or two-page spread). * * Only effective when: - * - the publication is reflowable * - [scroll] is off */ - @ExperimentalReadiumApi public val columnCount: EnumPreference = EnumPreferenceDelegate( getValue = { preferences.columnCount }, @@ -114,8 +109,6 @@ public class ReflowableWebPreferencesEditor internal constructor( /** * Default typeface for the text. - * - * Only effective with reflowable publications. */ public val fontFamily: Preference = PreferenceDelegate( @@ -129,8 +122,6 @@ public class ReflowableWebPreferencesEditor internal constructor( * Base text font size as a percentage. Default to 100%. * * Note that allowing a font size that is too large could break the pagination. - * - * Only effective with reflowable publications. */ public val fontSize: RangePreference = RangePreferenceDelegate( @@ -148,14 +139,12 @@ public class ReflowableWebPreferencesEditor internal constructor( * * If you want to change the boldness of all text, including headers, you can use this with * [textNormalization]. - * - * Only effective with reflowable publications. */ public val fontWeight: RangePreference = RangePreferenceDelegate( getValue = { preferences.fontWeight }, getEffectiveValue = { state.settings.fontWeight ?: 1.0 }, - getIsEffective = { preferences.fontWeight != null }, + getIsEffective = { true }, updateValue = { value -> updateValues { it.copy(fontWeight = value) } }, valueFormatter = percentFormatter(), supportedRange = 0.0..2.5, @@ -166,7 +155,6 @@ public class ReflowableWebPreferencesEditor internal constructor( * Enable hyphenation for latin languages. * * Only effective when: - * - the publication is reflowable * - [publisherStyles] is off * - the layout is LTR */ @@ -185,7 +173,6 @@ public class ReflowableWebPreferencesEditor internal constructor( * Filter applied to images in dark theme. * * Only effective when: - * - the publication is reflowable * - the [theme] is set to [Theme.DARK] */ public val imageFilter: EnumPreference = @@ -214,7 +201,6 @@ public class ReflowableWebPreferencesEditor internal constructor( * Space between letters. * * Only effective when: - * - the publication is reflowable * - [publisherStyles] is off * - the layout is LTR */ @@ -233,7 +219,6 @@ public class ReflowableWebPreferencesEditor internal constructor( * Enable ligatures in Arabic. * * Only effective when: - * - the publication is reflowable * - [publisherStyles] is off * - the layout is RTL */ @@ -249,14 +234,13 @@ public class ReflowableWebPreferencesEditor internal constructor( * Leading line height. * * Only effective when: - * - the publication is reflowable * - [publisherStyles] is off */ public val lineHeight: RangePreference = RangePreferenceDelegate( getValue = { preferences.lineHeight }, getEffectiveValue = { state.settings.lineHeight ?: 1.2 }, - getIsEffective = { !state.settings.publisherStyles && preferences.lineHeight != null }, + getIsEffective = { !state.settings.publisherStyles }, updateValue = { value -> updateValues { it.copy(lineHeight = value) } }, supportedRange = 1.0..2.0, progressionStrategy = DoubleIncrement(0.1), @@ -265,16 +249,13 @@ public class ReflowableWebPreferencesEditor internal constructor( /** * Factor applied to horizontal margins. Default to 1. - * - * Only effective with reflowable publications. */ - @ExperimentalReadiumApi - public val pageMargins: RangePreference = + public val horizontalMargins: RangePreference = RangePreferenceDelegate( - getValue = { preferences.pageMargins }, - getEffectiveValue = { state.settings.pageMargins }, + getValue = { preferences.horizontalMargins }, + getEffectiveValue = { state.settings.horizontalMargins }, getIsEffective = { true }, - updateValue = { value -> updateValues { it.copy(pageMargins = value) } }, + updateValue = { value -> updateValues { it.copy(horizontalMargins = value) } }, supportedRange = 0.0..4.0, progressionStrategy = DoubleIncrement(0.3), valueFormatter = { it.format(5) } @@ -284,7 +265,6 @@ public class ReflowableWebPreferencesEditor internal constructor( * Text indentation for paragraphs. * * Only effective when: - * - the publication is reflowable * - [publisherStyles] is off * - the layout is LTR or RTL */ @@ -303,14 +283,13 @@ public class ReflowableWebPreferencesEditor internal constructor( * Vertical margins for paragraphs. * * Only effective when: - * - the publication is reflowable * - [publisherStyles] is off */ public val paragraphSpacing: RangePreference = RangePreferenceDelegate( getValue = { preferences.paragraphSpacing }, getEffectiveValue = { state.settings.paragraphSpacing ?: 0.0 }, - getIsEffective = { !state.settings.publisherStyles && preferences.paragraphSpacing != null }, + getIsEffective = { !state.settings.publisherStyles }, updateValue = { value -> updateValues { it.copy(paragraphSpacing = value) } }, supportedRange = 0.0..2.0, progressionStrategy = DoubleIncrement(0.1), @@ -320,8 +299,6 @@ public class ReflowableWebPreferencesEditor internal constructor( /** * Indicates whether the original publisher styles should be observed. Many advanced settings * require this to be off. - * - * Only effective with reflowable publications. */ public val publisherStyles: Preference = PreferenceDelegate( @@ -349,7 +326,8 @@ public class ReflowableWebPreferencesEditor internal constructor( * Indicates if the overflow of resources should be handled using scrolling instead of synthetic * pagination. * - * Only effective with reflowable publications and if [verticalText] is false. + * Only effective when: + * - [verticalText] is off */ public val scroll: Preference = PreferenceDelegate( @@ -363,7 +341,6 @@ public class ReflowableWebPreferencesEditor internal constructor( * Page text alignment. * * Only effective when: - * - the publication is reflowable * - [publisherStyles] is off * - the layout is LTR or RTL */ @@ -385,7 +362,6 @@ public class ReflowableWebPreferencesEditor internal constructor( * Default page text color. * * When unset, the current [theme] text color is effective. - * Only effective with reflowable publications. */ public val textColor: Preference = PreferenceDelegate( @@ -395,14 +371,12 @@ public class ReflowableWebPreferencesEditor internal constructor( (theme.value ?: theme.effectiveValue).contentColor ) }, - getIsEffective = { preferences.textColor != null }, + getIsEffective = { true }, updateValue = { value -> updateValues { it.copy(textColor = value) } } ) /** * Normalize text styles to increase accessibility. - * - * Only effective with reflowable publications. */ public val textNormalization: Preference = PreferenceDelegate( @@ -414,8 +388,6 @@ public class ReflowableWebPreferencesEditor internal constructor( /** * Reader theme (light, dark, sepia). - * - * Only effective with reflowable publications. */ public val theme: EnumPreference = EnumPreferenceDelegate( @@ -429,8 +401,6 @@ public class ReflowableWebPreferencesEditor internal constructor( /** * Indicates whether the text should be laid out vertically. This is used for example with CJK * languages. This setting is automatically derived from the language if no preference is given. - * - * Only effective with reflowable publications. */ public val verticalText: Preference = PreferenceDelegate( @@ -444,7 +414,6 @@ public class ReflowableWebPreferencesEditor internal constructor( * Space between words. * * Only effective when: - * - the publication is reflowable * - the layout is LTR */ public val wordSpacing: RangePreference = @@ -479,31 +448,25 @@ public class ReflowableWebPreferencesEditor internal constructor( private fun isHyphensEffective() = state.layout.stylesheets == Layout.Stylesheets.Default && - !state.settings.publisherStyles && - (preferences.hyphens != null || state.settings.textAlign == TextAlign.JUSTIFY) + !state.settings.publisherStyles private fun isLetterSpacingEffective() = state.layout.stylesheets == Layout.Stylesheets.Default && - !state.settings.publisherStyles && - preferences.letterSpacing != null + !state.settings.publisherStyles private fun isLigaturesEffective() = state.layout.stylesheets == Layout.Stylesheets.Rtl && - !state.settings.publisherStyles && - preferences.ligatures != null + !state.settings.publisherStyles private fun isParagraphIndentEffective() = state.layout.stylesheets in listOf(Layout.Stylesheets.Default, Layout.Stylesheets.Rtl) && - !state.settings.publisherStyles && - preferences.paragraphIndent != null + !state.settings.publisherStyles private fun isTextAlignEffective() = state.layout.stylesheets in listOf(Layout.Stylesheets.Default, Layout.Stylesheets.Rtl) && - !state.settings.publisherStyles && - preferences.textAlign != null + !state.settings.publisherStyles private fun isWordSpacingEffective(): Boolean = state.layout.stylesheets == Layout.Stylesheets.Default && - !state.settings.publisherStyles && - preferences.wordSpacing != null + !state.settings.publisherStyles } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettings.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettings.kt index f67babf567..22899d020a 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettings.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettings.kt @@ -30,7 +30,7 @@ public data class ReflowableWebSettings( val letterSpacing: Double?, val ligatures: Boolean?, val lineHeight: Double?, - val pageMargins: Double, + val horizontalMargins: Double, val paragraphIndent: Double?, val paragraphSpacing: Double?, val publisherStyles: Boolean, diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettingsResolver.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettingsResolver.kt index 06a4859d09..689fc1b729 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettingsResolver.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettingsResolver.kt @@ -50,7 +50,7 @@ internal class ReflowableWebSettingsResolver( letterSpacing = preferences.letterSpacing ?: defaults.letterSpacing, ligatures = preferences.ligatures ?: defaults.ligatures, lineHeight = preferences.lineHeight ?: defaults.lineHeight, - pageMargins = preferences.pageMargins ?: defaults.pageMargins ?: 1.0, + horizontalMargins = preferences.horizontalMargins ?: defaults.pageMargins ?: 1.0, paragraphIndent = preferences.paragraphIndent ?: defaults.paragraphIndent, paragraphSpacing = preferences.paragraphSpacing ?: defaults.paragraphSpacing, publisherStyles = preferences.publisherStyles ?: defaults.publisherStyles ?: true, From 87449da7cc355a4aaeafbbbdc2dfedb3c9d7a6c7 Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Wed, 9 Apr 2025 11:48:17 +0200 Subject: [PATCH 28/88] Redesign reflowable scroll. Breaks FXL --- .../navigator/web/ReflowableWebRendition.kt | 45 +++++- .../navigator/web/pager/RenditionPager.kt | 31 ++-- .../navigator/web/pager/ScrollDispatcher.kt | 37 +++++ .../reflowable/ReflowablePagingLayoutInfo.kt | 72 +++++++++ .../web/reflowable/ReflowableResource.kt | 81 +++++----- .../web/reflowable/ReflowableResourceState.kt | 3 + .../reflowable/ReflowableScrollDispatcher.kt | 143 +++++++++++++++++ .../snapping/PagerSnapLayoutInfoProvider.kt | 26 ++- .../web/snapping/PagingFlingBehavior.kt | 149 ++++++++++++++++++ .../web/webview/WebViewLayoutInfoProvider.kt | 32 ++-- .../web/webview/WebViewScrollController.kt | 48 ++++++ 11 files changed, 594 insertions(+), 73 deletions(-) create mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollDispatcher.kt create mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowablePagingLayoutInfo.kt create mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableScrollDispatcher.kt diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt index bb2e4671e2..1212a01289 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt @@ -9,6 +9,7 @@ package org.readium.navigator.web import android.annotation.SuppressLint import android.content.res.Configuration import androidx.compose.foundation.gestures.Orientation +import androidx.compose.foundation.gestures.ScrollableDefaults import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.displayCutout @@ -37,7 +38,9 @@ import org.readium.navigator.common.defaultHyperlinkListener import org.readium.navigator.common.defaultInputListener import org.readium.navigator.web.location.ReflowableWebLocation import org.readium.navigator.web.pager.RenditionPager +import org.readium.navigator.web.reflowable.ReflowablePagingLayoutInfo import org.readium.navigator.web.reflowable.ReflowableResource +import org.readium.navigator.web.reflowable.ReflowableScrollDispatcher import org.readium.navigator.web.util.AbsolutePaddingValues import org.readium.navigator.web.util.WebViewServer import org.readium.r2.navigator.preferences.ReadingProgression @@ -45,6 +48,7 @@ import org.readium.r2.shared.ExperimentalReadiumApi import org.readium.r2.shared.util.AbsoluteUrl import org.readium.r2.shared.util.RelativeUrl import org.readium.r2.shared.util.Url +import pagingFlingBehavior @SuppressLint("UnusedBoxWithConstraintsScope") @ExperimentalReadiumApi @@ -108,16 +112,47 @@ public fun ReflowableWebRendition( ) ) + val orientation = when { + state.layoutDelegate.settings.value.verticalText -> Orientation.Horizontal + state.layoutDelegate.settings.value.scroll -> Orientation.Vertical + else -> Orientation.Horizontal + } + + val density = LocalDensity.current + + val flingBehavior = if (state.layoutDelegate.settings.value.scroll) { + ScrollableDefaults.flingBehavior() + } else { + val pagingLayoutInfo = remember(state) { + ReflowablePagingLayoutInfo( + pagerState = state.pagerState, + resourceStates = state.resourceStates, + orientation = orientation, + density = density + ) + } + pagingFlingBehavior(pagingLayoutInfo) + } + + val scrollDispatcher = remember(state) { + ReflowableScrollDispatcher( + pagerState = state.pagerState, + resourceStates = state.resourceStates, + flingBehavior = flingBehavior, + pagerOrientation = orientation, + ) + } + + scrollDispatcher.flingBehavior = flingBehavior + scrollDispatcher.pagerOrientation = orientation + RenditionPager( modifier = Modifier, state = state.pagerState, + scrollDispatcher = scrollDispatcher, beyondViewportPageCount = 3, reverseLayout = reverseLayout, - orientation = when { - state.layoutDelegate.settings.value.verticalText -> Orientation.Horizontal - state.layoutDelegate.settings.value.scroll -> Orientation.Vertical - else -> Orientation.Horizontal - } + orientation = orientation ) { index -> val readyToScroll = ((index - 2)..(index + 2)).toList() .mapNotNull { state.resourceStates.getOrNull(it) } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/RenditionPager.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/RenditionPager.kt index 68dbf810fb..5388559b06 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/RenditionPager.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/RenditionPager.kt @@ -7,50 +7,63 @@ package org.readium.navigator.web.pager import androidx.compose.foundation.gestures.Orientation +import androidx.compose.foundation.gestures.ScrollScope +import androidx.compose.foundation.gestures.TargetedFlingBehavior import androidx.compose.foundation.layout.Box import androidx.compose.foundation.pager.HorizontalPager -import androidx.compose.foundation.pager.PagerDefaults import androidx.compose.foundation.pager.PagerScope -import androidx.compose.foundation.pager.PagerSnapDistance import androidx.compose.foundation.pager.PagerState import androidx.compose.foundation.pager.VerticalPager import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.nestedScroll @Composable internal fun RenditionPager( modifier: Modifier = Modifier, state: PagerState, + scrollDispatcher: ScrollDispatcher? = null, orientation: Orientation, reverseLayout: Boolean, beyondViewportPageCount: Int = 2, key: ((index: Int) -> Any)? = null, pageContent: @Composable PagerScope.(Int) -> Unit, ) { - val flingBehavior = PagerDefaults.flingBehavior( + val flingBehavior = /*PagerDefaults.flingBehavior( state = state, pagerSnapDistance = PagerSnapDistance.atMost(0) - ) + ) */ object : TargetedFlingBehavior { + override suspend fun ScrollScope.performFling( + initialVelocity: Float, + onRemainingDistanceUpdated: (Float) -> Unit, + ): Float { + return initialVelocity + } + } - val nestedScrollConnection = PagerNestedScrollConnection( + val nestedScrollConnection = object : NestedScrollConnection { + } /*PagerNestedScrollConnection( state, flingBehavior, orientation - ) + )*/ val updatedPageContent: @Composable PagerScope.(Int) -> Unit = { index -> Box( - modifier = Modifier.nestedScroll(PageNestedScrollConnection(index, state)), + modifier = Modifier, // .nestedScroll(PageNestedScrollConnection(index, state)), propagateMinConstraints = true ) { pageContent(index) } } + val delegatingNestedScrollConnection = + scrollDispatcher?.let { DelegatingNestedScrollConnection(it) } + if (orientation == Orientation.Horizontal) { HorizontalPager( - modifier = modifier, + modifier = modifier.let { modifier -> delegatingNestedScrollConnection?.let { modifier.nestedScroll(it) } ?: modifier }, // Pages must intercept all scroll gestures so the pager moves // only through the PagerNestedScrollConnection. userScrollEnabled = false, @@ -64,7 +77,7 @@ internal fun RenditionPager( ) } else { VerticalPager( - modifier = modifier, + modifier = modifier.let { modifier -> delegatingNestedScrollConnection?.let { modifier.nestedScroll(it) } ?: modifier }, // Pages must intercept all scroll gestures so the pager moves // only through the PagerNestedScrollConnection. userScrollEnabled = false, diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollDispatcher.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollDispatcher.kt new file mode 100644 index 0000000000..8b6d63031b --- /dev/null +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollDispatcher.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2024 Readium Foundation. All rights reserved. + * Use of this source code is governed by the BSD-style license + * available in the top-level LICENSE file of the project. + */ + +package org.readium.navigator.web.pager + +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.input.nestedscroll.NestedScrollConnection +import androidx.compose.ui.input.nestedscroll.NestedScrollSource +import androidx.compose.ui.unit.Velocity + +internal interface ScrollDispatcher { + + fun onScroll(available: Offset): Offset + + suspend fun onFling(available: Velocity): Velocity +} + +internal class DelegatingNestedScrollConnection( + private val scrollDispatcher: ScrollDispatcher, +) : NestedScrollConnection { + + override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { + if (source == NestedScrollSource.UserInput) { + scrollDispatcher.onScroll(available) + } + + return available + } + + override suspend fun onPreFling(available: Velocity): Velocity { + scrollDispatcher.onFling(available) + return available + } +} diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowablePagingLayoutInfo.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowablePagingLayoutInfo.kt new file mode 100644 index 0000000000..b66910711a --- /dev/null +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowablePagingLayoutInfo.kt @@ -0,0 +1,72 @@ +package org.readium.navigator.web.reflowable + +import androidx.compose.foundation.gestures.Orientation +import androidx.compose.foundation.pager.PagerState +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.unit.Density +import org.readium.navigator.web.snapping.PagingLayoutInfo +import timber.log.Timber + +internal class ReflowablePagingLayoutInfo( + private val pagerState: PagerState, + private val resourceStates: List, + override val orientation: Orientation, + override val density: Density, +) : PagingLayoutInfo { + + override val pageSize: Int get() = + pagerState.layoutInfo.pageSize + + override val pageSpacing: Int get() = + 0 + + override val upDownDifference: Offset + get() = Offset.Zero + + override val reverseLayout: Boolean get() = + false + + override val canScrollForward: Boolean + get() = pagerState.layoutInfo.visiblePagesInfo.last() + .let { pageInfo -> pageInfo.index < pagerState.pageCount - 1 || pageInfo.offset > 0 } || run { + val lastResourceState = resourceStates[pagerState.pageCount - 1] + val scrollController = lastResourceState.scrollController.value ?: return false + return scrollController.canMoveRight + } + + override val canScrollBackward: Boolean + get() = pagerState.layoutInfo.visiblePagesInfo.first() + .let { pageInfo -> pageInfo.index > 0 || pageInfo.offset < 0 } || run { + val scrollController = resourceStates[0].scrollController.value ?: return false + return scrollController.canMoveLeft + } + + override val visiblePageOffsets: List + get() = buildList { + val pagerVisible = pagerState.layoutInfo.visiblePagesInfo + .map { it.index to it.offset } + val webViewVisible = pagerVisible.map { + resourceStates[it.first].scrollController.value?.scrollX to + resourceStates[it.first].scrollController.value?.maxScrollX + } + Timber.d("pager $pagerVisible webview $webViewVisible") + + val pageSize = pageSize + + val firstPage = pagerState.layoutInfo.visiblePagesInfo.first() + val lastPage = pagerState.layoutInfo.visiblePagesInfo.last() + + if (firstPage.index == lastPage.index) { + val index = firstPage.index + val scrollController = resourceStates[index].scrollController.value!! + add(-scrollController.scrollX % pageSize) + add(-scrollController.scrollX % pageSize + pageSize) + Timber.d("visiblePageOffsets if $this") + } else { + val firstScrollController = resourceStates[firstPage.index].scrollController.value!! + add(lastPage.offset - pageSize) + add(lastPage.offset + firstScrollController.maxScrollX - firstScrollController.scrollX) + Timber.d("visiblePageOffsets else $this") + } + } +} diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt index a3b689c829..4f2cf5c8d4 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt @@ -29,7 +29,6 @@ import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color -import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.DpOffset @@ -52,14 +51,12 @@ import org.readium.navigator.web.webapi.DocumentStateApi import org.readium.navigator.web.webapi.GesturesApi import org.readium.navigator.web.webview.RelaxedWebView import org.readium.navigator.web.webview.WebView -import org.readium.navigator.web.webview.WebViewLayoutInfoProvider import org.readium.navigator.web.webview.WebViewScrollController import org.readium.navigator.web.webview.WebViewScrollable2DState import org.readium.navigator.web.webview.rememberWebViewState import org.readium.r2.shared.ExperimentalReadiumApi import org.readium.r2.shared.util.AbsoluteUrl import org.readium.r2.shared.util.Url -import pagingFlingBehavior @SuppressLint("SetJavaScriptEnabled", "ClickableViewAccessibility") @Composable @@ -106,7 +103,45 @@ internal fun ReflowableResource( val contentIsLaidOut = remember(webViewState.webView) { mutableStateOf(false) } - val documentStateApi = remember(webViewState.webView) { + val density = LocalDensity.current + + val webViewViewport = DpSize( + width = viewportSize.width - padding.left - padding.right, + height = viewportSize.height - padding.top - padding.bottom + ) + + val scrollableState = remember(resourceState) { WebViewScrollable2DState(resourceState.href) } + + val flingBehavior = + object : Fling2DBehavior { + override suspend fun Scroll2DScope.performFling( + initialVelocity: Velocity, + ): Velocity { + return initialVelocity + } + } + + /*if (scroll) { + null + } else { + webViewState.webView + ?.let { + pagingFlingBehavior( + WebViewLayoutInfoProvider( + density, + scrollOrientation.value, + reverseLayout, + webViewViewport, + it + ) + ) + } + } + ?.toFling2DBehavior(orientation = scrollOrientation.value) */ + + resourceState.scrollableState = scrollableState + + val documentStateApi = remember(webViewState.webView,) { DocumentStateApi( onScriptsLoadedDelegate = { scriptsLoaded.value = true @@ -178,37 +213,9 @@ internal fun ReflowableResource( webViewState.webView?.let { gesturesApi.registerOnWebView(it) } } - val scrollableState = remember { WebViewScrollable2DState(resourceState.href) } - - val density = LocalDensity.current - - val webViewViewport = DpSize( - width = viewportSize.width - padding.left - padding.right, - height = viewportSize.height - padding.top - padding.bottom - ) - - val flingBehavior = - if (scroll) { - null - } else { - webViewState.webView - ?.let { - pagingFlingBehavior( - WebViewLayoutInfoProvider( - density, - scrollOrientation.value, - reverseLayout, - webViewViewport, - it - ) - ) - } - ?.toFling2DBehavior(orientation = scrollOrientation.value) - } - - val resourceScrollConnection = + /*val resourceScrollConnection = ResourceNestedScrollConnection(pagerState, scrollableState, scrollOrientation.value) - +*/ // Hide content before initial position is settled if (!contentIsLaidOut.value) { Box( @@ -219,8 +226,8 @@ internal fun ReflowableResource( content = {} ) } - - key(layout, scrollOrientation.value) { + // Changing font size invalidates the scroll position of the Webview + key(layout, scrollOrientation.value, userProperties) { WebView( modifier = Modifier // Detect taps on padding @@ -234,7 +241,7 @@ internal fun ReflowableResource( } } ) - }.nestedScroll(resourceScrollConnection) + } // .nestedScroll(resourceScrollConnection) .scrollable2D( enabled = enableScroll, state = scrollableState, diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResourceState.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResourceState.kt index 25caecef07..d56aab5693 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResourceState.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResourceState.kt @@ -10,6 +10,7 @@ import androidx.compose.runtime.MutableState import androidx.compose.runtime.Stable import androidx.compose.runtime.mutableStateOf import org.readium.navigator.web.webview.WebViewScrollController +import org.readium.navigator.web.webview.WebViewScrollable2DState import org.readium.r2.shared.util.Url @Stable @@ -22,6 +23,8 @@ internal class ReflowableResourceState( var progression: Progression = initialProgression val scrollController: MutableState = mutableStateOf(null) + + var scrollableState: WebViewScrollable2DState? = null } internal sealed interface Progression { diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableScrollDispatcher.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableScrollDispatcher.kt new file mode 100644 index 0000000000..e8af5cf232 --- /dev/null +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableScrollDispatcher.kt @@ -0,0 +1,143 @@ +/* + * Copyright 2024 Readium Foundation. All rights reserved. + * Use of this source code is governed by the BSD-style license + * available in the top-level LICENSE file of the project. + */ + +package org.readium.navigator.web.reflowable + +import androidx.compose.foundation.gestures.FlingBehavior +import androidx.compose.foundation.gestures.Orientation +import androidx.compose.foundation.gestures.ScrollScope +import androidx.compose.foundation.pager.PagerState +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.unit.Velocity +import androidx.compose.ui.util.fastCoerceAtLeast +import androidx.compose.ui.util.fastCoerceAtMost +import org.readium.navigator.web.pager.ScrollDispatcher +import timber.log.Timber + +internal class ReflowableScrollDispatcher( + private val pagerState: PagerState, + private val resourceStates: List, + internal var pagerOrientation: Orientation, + internal var flingBehavior: FlingBehavior, +) : ScrollDispatcher, ScrollScope { + + override fun scrollBy(available: Float): Float { + return -rawScrollBy(-available) + } + + private fun rawScrollBy(available: Float): Float { + Timber.d("scrollBy available $available") + var deltaLeft = available + + val firstPage = pagerState.layoutInfo.visiblePagesInfo.first() + + val lastPage = pagerState.layoutInfo.visiblePagesInfo.last() + + val firstTargetPage = when { + available >= 0 -> lastPage + else -> firstPage + } + + val secondTargetPage = when { + available >= 0 -> firstPage + else -> lastPage + } + + val consumedInFirst = consumeInWebview(firstTargetPage.index, deltaLeft) + deltaLeft -= consumedInFirst + Timber.d("consumed $consumedInFirst in ${firstTargetPage.index}") + + val availableForPager = + if (firstPage.index == lastPage.index) { + when { + deltaLeft > 0 -> + deltaLeft.fastCoerceAtMost(pagerState.layoutInfo.pageSize.toFloat()) + deltaLeft < 0 -> + deltaLeft.coerceAtLeast(-pagerState.layoutInfo.pageSize.toFloat()) + else -> + 0f + } + } else { + when { + deltaLeft > 0 -> { + deltaLeft.fastCoerceAtMost(-firstPage.offset.toFloat()) + } + deltaLeft < 0 -> { + deltaLeft.fastCoerceAtLeast(-lastPage.offset.toFloat()) + } + else -> + 0f + } + } + + val consumedInPager = -pagerState.dispatchRawDelta(-availableForPager) + deltaLeft -= consumedInPager + Timber.d("consumed $consumedInPager in pager") + + val consumedInSecond = consumeInWebview(secondTargetPage.index, deltaLeft) + deltaLeft -= consumedInSecond + Timber.d("consumed $consumedInSecond in ${secondTargetPage.index}") + + Timber.d("scrollBy left $deltaLeft") + + return when (deltaLeft) { + 0f -> available + available -> 0f + else -> rawScrollBy(deltaLeft) + } + } + + private fun consumeInWebview(targetPage: Int, available: Float): Float { + val scrollController = resourceStates[targetPage].scrollController.value + ?: return available // WebView is not ready, consume everything. + + return -scrollController.scrollBy(-available.mainAxisOffset).mainAxisValue + } + + override fun onScroll(available: Offset): Offset { + Timber.d("onScroll ${available.x}") + val consumed = -scrollBy(-available.mainAxisValue) + return consumed.mainAxisOffset + } + + override suspend fun onFling(available: Velocity): Velocity { + Timber.d("onFling ${available.x}") + var velocityLeft = available.mainAxisValue + pagerState.scroll { + with(flingBehavior) { + with(this@ReflowableScrollDispatcher) { + velocityLeft = -performFling(-velocityLeft) + } + } + } + + return if ((available.mainAxisValue - velocityLeft).isNaN()) { + available + } else { + available - velocityLeft.mainAxisVelocity + } + } + + private val Offset.mainAxisValue: Float get() = when (pagerOrientation) { + Orientation.Vertical -> y + Orientation.Horizontal -> x + } + + private val Velocity.mainAxisValue: Float get() = when (pagerOrientation) { + Orientation.Vertical -> y + Orientation.Horizontal -> x + } + + private val Float.mainAxisOffset: Offset get() = when (pagerOrientation) { + Orientation.Vertical -> Offset(0f, this) + Orientation.Horizontal -> Offset(this, 0f) + } + + private val Float.mainAxisVelocity: Velocity get() = when (pagerOrientation) { + Orientation.Vertical -> Velocity(0f, this) + Orientation.Horizontal -> Velocity(this, 0f) + } +} diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/PagerSnapLayoutInfoProvider.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/PagerSnapLayoutInfoProvider.kt index 7e96de3667..5d229dc764 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/PagerSnapLayoutInfoProvider.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/PagerSnapLayoutInfoProvider.kt @@ -1,3 +1,9 @@ +/* + * Copyright 2024 Readium Foundation. All rights reserved. + * Use of this source code is governed by the BSD-style license + * available in the top-level LICENSE file of the project. + */ + /* * Copyright 2024 The Android Open Source Project * @@ -25,18 +31,22 @@ import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.util.fastForEach import kotlin.math.abs import kotlin.math.absoluteValue +import org.readium.navigator.web.webview.DefaultPositionThreshold +import timber.log.Timber internal interface PagingLayoutInfo { val orientation: Orientation val density: Density - val positionThresholdFraction: Float + val positionThresholdFraction: Float get() = + with(density) { + val minThreshold = minOf(DefaultPositionThreshold.toPx(), pageSize / 2f) + minThreshold / pageSize.toFloat() + } val pageSize: Int val pageSpacing: Int val upDownDifference: Offset - val pageCount: Int - val firstVisiblePage: Int val reverseLayout: Boolean - val visiblePageOffsets: List + val visiblePageOffsets: List val canScrollForward: Boolean val canScrollBackward: Boolean } @@ -52,7 +62,9 @@ internal fun SnapLayoutInfoProvider( } override fun calculateSnapOffset(velocity: Float): Float { + Timber.d("Fling calculateSnapOffset $velocity") val (lowerBoundOffset, upperBoundOffset) = searchForSnappingBounds() + Timber.d("Fling lowerBound $lowerBoundOffset upperBound $upperBoundOffset") val finalDistance = calculateFinalSnappingBound( @@ -61,6 +73,8 @@ internal fun SnapLayoutInfoProvider( upperBoundOffset ) + Timber.d("Fling finalDistance $finalDistance") + check( finalDistance == lowerBoundOffset || finalDistance == upperBoundOffset || @@ -92,12 +106,12 @@ internal fun SnapLayoutInfoProvider( // Find page that is closest to the snap position, but before it if (offset <= 0 && offset > lowerBoundOffset) { - lowerBoundOffset = offset + lowerBoundOffset = offset.toFloat() } // Find page that is closest to the snap position, but after it if (offset >= 0 && offset < upperBoundOffset) { - upperBoundOffset = offset + upperBoundOffset = offset.toFloat() } } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/PagingFlingBehavior.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/PagingFlingBehavior.kt index fca1d99f82..681305360f 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/PagingFlingBehavior.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/PagingFlingBehavior.kt @@ -1,3 +1,9 @@ +/* + * Copyright 2024 Readium Foundation. All rights reserved. + * Use of this source code is governed by the BSD-style license + * available in the top-level LICENSE file of the project. + */ + /* * Copyright 2024 The Android Open Source Project * @@ -22,16 +28,20 @@ import androidx.compose.animation.core.VisibilityThreshold import androidx.compose.animation.core.spring import androidx.compose.animation.rememberSplineBasedDecay import androidx.compose.foundation.gestures.FlingBehavior +import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.gestures.TargetedFlingBehavior import androidx.compose.foundation.pager.PagerState import androidx.compose.runtime.Composable import androidx.compose.runtime.remember +import androidx.compose.ui.geometry.Offset import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.unit.Density import org.readium.navigator.web.snapping.PagingLayoutInfo import org.readium.navigator.web.snapping.SnapLayoutInfoProvider import org.readium.navigator.web.snapping.calculateFinalSnappingBound import org.readium.navigator.web.snapping.snapFlingBehavior +import org.readium.navigator.web.webview.DefaultPositionThreshold /** * A [snapFlingBehavior] that will snap pages to the start of the layout. One can use the @@ -101,6 +111,7 @@ internal fun pagingFlingBehavior( "snapPositionalThreshold should be a number between 0 and 1. " + "You've specified $snapPositionalThreshold" } + val density = LocalDensity.current val layoutDirection = LocalLayoutDirection.current return remember( @@ -123,6 +134,144 @@ internal fun pagingFlingBehavior( upperBoundOffset = upperBound ) } + snapFlingBehavior( + snapLayoutInfoProvider = snapLayoutInfoProvider, + decayAnimationSpec = decayAnimationSpec, + snapAnimationSpec = snapAnimationSpec + ) + } +} + +/** + * A [snapFlingBehavior] that will snap pages to the start of the layout. One can use the + * given parameters to control how the snapping animation will happen. + * @see androidx.compose.foundation.gestures.snapping.snapFlingBehavior for more information + * on what which parameter controls in the overall snapping animation. + * + * The animation specs used by the fling behavior will depend on 2 factors: + * 1) The gesture velocity. + * 2) The target page proposed by [pagerSnapDistance]. + * + * If you're using single page snapping (the most common use case for [Pager]), there won't + * be enough space to actually run a decay animation to approach the target page, so the Pager + * will always use the snapping animation from [snapAnimationSpec]. + * If you're using multi-page snapping (this means you're abs(targetPage - currentPage) > 1) + * the Pager may use [decayAnimationSpec] or [snapAnimationSpec] to approach the + * targetPage, it will depend on the velocity generated by the triggering gesture. + * If the gesture has a high enough velocity to approach the target page, the Pager will use + * [decayAnimationSpec] followed by [snapAnimationSpec] for the final step of the + * animation. If the gesture doesn't have enough velocity, the Pager will use + * [snapAnimationSpec] + [snapAnimationSpec] in a similar fashion. + * + * @param state The [PagerState] that controls the which to which this FlingBehavior will + * be applied to. + * @param pagerSnapDistance A way to control the snapping destination for this [Pager]. + * The default behavior will result in any fling going to the next page in the direction of the + * fling (if the fling has enough velocity, otherwise the Pager will bounce back). Use + * [PagerSnapDistance.atMost] to define a maximum number of pages this [Pager] is allowed to + * fling after scrolling is finished and fling has started. + * @param decayAnimationSpec The animation spec used to approach the target offset. When + * the fling velocity is large enough. Large enough means large enough to naturally decay. For + * single page snapping this usually never happens since there won't be enough space to run a + * decay animation. + * @param snapAnimationSpec The animation spec used to finally snap to the position. This + * animation will be often used in 2 cases: 1) There was enough space to an approach animation, + * the Pager will use [snapAnimationSpec] in the last step of the animation to settle the page + * into position. 2) There was not enough space to run the approach animation. + * @param snapPositionalThreshold If the fling has a low velocity (e.g. slow scroll), + * this fling behavior will use this snap threshold in order to determine if the pager should + * snap back or move forward. Use a number between 0 and 1 as a fraction of the page size that + * needs to be scrolled before the Pager considers it should move to the next page. + * For instance, if snapPositionalThreshold = 0.35, it means if this pager is scrolled with a + * slow velocity and the Pager scrolls more than 35% of the page size, then will jump to the + * next page, if not it scrolls back. + * Note that any fling that has high enough velocity will *always* move to the next page + * in the direction of the fling. + * + * @return An instance of [FlingBehavior] that will perform Snapping to the next page by + * default. The animation will be governed by the post scroll velocity and the Pager will use + * either + * [snapAnimationSpec] or [decayAnimationSpec] to approach the snapped position + * If a velocity is not high enough the pager will use [snapAnimationSpec] to reach the snapped + * position. If the velocity is high enough, the Pager will use the logic described in + * [decayAnimationSpec] and [snapAnimationSpec]. + */ +@Composable +internal fun pagingFlingBehavior( + state: PagerState, + decayAnimationSpec: DecayAnimationSpec = rememberSplineBasedDecay(), + snapAnimationSpec: AnimationSpec = spring( + stiffness = Spring.StiffnessMediumLow, + visibilityThreshold = Int.VisibilityThreshold.toFloat() + ), + @FloatRange(from = 0.0, to = 1.0) snapPositionalThreshold: Float = 0.5f, +): TargetedFlingBehavior { + require(snapPositionalThreshold in 0f..1f) { + "snapPositionalThreshold should be a number between 0 and 1. " + + "You've specified $snapPositionalThreshold" + } + + val density = LocalDensity.current + val layoutDirection = LocalLayoutDirection.current + return remember( + state, + decayAnimationSpec, + snapAnimationSpec, + density, + layoutDirection + ) { + val pagingLayoutInfoAdapter = object : PagingLayoutInfo { + + override val orientation: Orientation + get() = state.layoutInfo.orientation + + override val density: Density + get() = density + + override val positionThresholdFraction: Float + get() = with(density) { + val minThreshold = minOf(DefaultPositionThreshold.toPx(), pageSize / 2f) + minThreshold / pageSize.toFloat() + } + + override val pageSize: Int + get() = state.layoutInfo.pageSize + + override val pageSpacing: Int + get() = state.layoutInfo.pageSpacing + + override val upDownDifference: Offset + get() = Offset.Zero + + val firstVisiblePage: Int + get() = state.layoutInfo.visiblePagesInfo.first().offset + + override val reverseLayout: Boolean + get() = state.layoutInfo.reverseLayout + + override val visiblePageOffsets: List + get() = state.layoutInfo.visiblePagesInfo.map { it.offset } + + override val canScrollForward: Boolean + get() = state.canScrollForward + + override val canScrollBackward: Boolean + get() = state.canScrollBackward + } + + val snapLayoutInfoProvider = + SnapLayoutInfoProvider( + pagingLayoutInfoAdapter, + ) { flingVelocity, lowerBound, upperBound -> + calculateFinalSnappingBound( + pagingLayoutInfo = pagingLayoutInfoAdapter, + layoutDirection = layoutDirection, + snapPositionalThreshold = snapPositionalThreshold, + flingVelocity = flingVelocity, + lowerBoundOffset = lowerBound, + upperBoundOffset = upperBound + ) + } snapFlingBehavior( snapLayoutInfoProvider = snapLayoutInfoProvider, diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewLayoutInfoProvider.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewLayoutInfoProvider.kt index ae6ca29537..1480d83164 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewLayoutInfoProvider.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewLayoutInfoProvider.kt @@ -14,7 +14,7 @@ internal class WebViewLayoutInfoProvider( override val orientation: Orientation, override val reverseLayout: Boolean, private val viewportSize: DpSize, - private val webView: RelaxedWebView, + private val webView: RelaxedWebView? = null, ) : PagingLayoutInfo { override val positionThresholdFraction: Float get() = @@ -31,17 +31,17 @@ internal class WebViewLayoutInfoProvider( override val upDownDifference: Offset get() = Offset.Zero // FIXME - override val pageCount: Int get() = - ceil(webView.width / pageSize.toDouble()).toInt() + val pageCount: Int get() = + ceil(webView!!.width / pageSize.toDouble()).toInt() - override val firstVisiblePage: Int get() = - webView.scrollX * pageCount / webView.width + val firstVisiblePage: Int get() = + webView!!.scrollX * pageCount / webView.width - override val visiblePageOffsets: List - get() = buildList { + override val visiblePageOffsets: List + get() = buildList { // two pages are visible // the first one starts at firstVisiblePage * pageSize in the Webview document coordinates - val firstVisibleOffset = (firstVisiblePage * pageSize - webView.scrollX).toFloat() + val firstVisibleOffset = (firstVisiblePage * pageSize - webView!!.scrollX) add((firstVisibleOffset + pageSize)) add(firstVisibleOffset) } @@ -49,25 +49,25 @@ internal class WebViewLayoutInfoProvider( override val canScrollForward: Boolean get() = when { orientation == Orientation.Horizontal && reverseLayout -> - webView.canScrollLeft + webView!!.canScrollLeft orientation == Orientation.Horizontal -> - webView.canScrollRight + webView!!.canScrollRight orientation == Orientation.Vertical && reverseLayout -> - webView.canScrollTop + webView!!.canScrollTop else -> - webView.canScrollBottom + webView!!.canScrollBottom } override val canScrollBackward: Boolean get() = when { orientation == Orientation.Horizontal && reverseLayout -> - webView.canScrollRight + webView!!.canScrollRight orientation == Orientation.Horizontal -> - webView.canScrollLeft + webView!!.canScrollLeft orientation == Orientation.Vertical && reverseLayout -> - webView.canScrollBottom + webView!!.canScrollBottom else -> - webView.canScrollTop + webView!!.canScrollTop } } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollController.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollController.kt index c0ea8c4562..ecd6bb8718 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollController.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollController.kt @@ -1,12 +1,30 @@ package org.readium.navigator.web.webview import androidx.compose.foundation.gestures.Orientation +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.util.fastCoerceAtLeast +import androidx.compose.ui.util.fastCoerceAtMost +import androidx.compose.ui.util.fastRoundToInt import kotlin.math.ceil import kotlin.math.floor +import timber.log.Timber internal class WebViewScrollController( private val webView: RelaxedWebView, ) { + private var unconsumedDelta: Offset = Offset.Zero + + val scrollX: Int + get() = webView.scrollX + + val scrollY: Int + get() = webView.scrollY + + val maxScrollX: Int + get() = webView.maxScrollX + + val maxScrollY: Int + get() = webView.maxScrollY val canMoveLeft: Boolean get() = webView.scrollX > webView.width / 2 == true @@ -36,6 +54,36 @@ internal class WebViewScrollController( webView.scrollBy(0, webView.width) } + fun scrollBy(delta: Offset): Offset { + // val delta = delta + unconsumedDelta + + val coercedX = + if (delta.x < 0) { + delta.x.fastCoerceAtLeast(-webView.scrollX.toFloat()) + } else { + delta.x.fastCoerceAtMost((webView.maxScrollX - webView.scrollX).toFloat()) + } + + val coercedY = + if (delta.y < 0) { + delta.y.fastCoerceAtLeast((-webView.scrollY.toFloat())) + } else { + delta.y.fastCoerceAtMost((webView.maxScrollY - webView.scrollY).toFloat()) + } + + val roundedX = coercedX.fastRoundToInt() + + val roundedY = coercedY.fastRoundToInt() + + Timber.d("Webview ${delta.x} $coercedX ${webView.scrollX} ${webView.maxScrollX}") + webView.scrollBy(roundedX, roundedY) + /*unconsumedDelta = Offset( + x = coercedX - roundedX, + y = coercedY - roundedY + )*/ + return Offset(coercedX, coercedY) - unconsumedDelta + } + fun scrollToProgression(progression: Double, scrollOrientation: Orientation) { webView.scrollToProgression(progression, scrollOrientation) } From 39d55b9f5bda8db272178d29fa0cdfcd1499de53 Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Wed, 9 Apr 2025 14:45:29 +0200 Subject: [PATCH 29/88] Clean up --- .../navigator/web/ReflowableWebRendition.kt | 3 + .../navigator/web/gestures/Fling2DBehavior.kt | 9 ++ .../web/reflowable/ReflowableResource.kt | 85 ++----------------- .../reflowable/ReflowableScrollDispatcher.kt | 16 ++++ .../ResourceNestedScrollConnection.kt | 80 ----------------- .../snapping/PagerSnapLayoutInfoProvider.kt | 4 +- .../web/snapping/PagingFlingBehavior.kt | 2 +- .../web/webview/WebViewLayoutInfoProvider.kt | 74 ---------------- .../web/webview/WebViewScrollController.kt | 27 +++--- 9 files changed, 53 insertions(+), 247 deletions(-) delete mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ResourceNestedScrollConnection.kt delete mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewLayoutInfoProvider.kt diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt index 1212a01289..3352e6696f 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt @@ -187,6 +187,9 @@ public fun ReflowableWebRendition( val newLocation = ReflowableWebLocation(itemHref, it) state.updateLocation(newLocation) } + }, + onDocumentResized = { + scrollDispatcher.onDocumentResized(index) } ) } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/gestures/Fling2DBehavior.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/gestures/Fling2DBehavior.kt index c025d18fe6..40248178c2 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/gestures/Fling2DBehavior.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/gestures/Fling2DBehavior.kt @@ -50,3 +50,12 @@ internal interface Fling2DBehavior { */ suspend fun Scroll2DScope.performFling(initialVelocity: Velocity): Velocity } + +internal class ConsumingFling2DBehavior : Fling2DBehavior { + + override suspend fun Scroll2DScope.performFling( + initialVelocity: Velocity, + ): Velocity { + return initialVelocity + } +} diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt index 4f2cf5c8d4..c93db80051 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt @@ -13,9 +13,7 @@ import android.view.MotionEvent import android.view.View import android.webkit.WebView import androidx.compose.foundation.background -import androidx.compose.foundation.gestures.FlingBehavior import androidx.compose.foundation.gestures.Orientation -import androidx.compose.foundation.gestures.ScrollScope import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize @@ -27,20 +25,16 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Modifier -import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color import androidx.compose.ui.input.pointer.pointerInput -import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.DpOffset import androidx.compose.ui.unit.DpSize -import androidx.compose.ui.unit.Velocity import androidx.compose.ui.zIndex import org.readium.navigator.common.TapEvent import org.readium.navigator.web.css.Layout import org.readium.navigator.web.css.RsProperties import org.readium.navigator.web.css.UserProperties -import org.readium.navigator.web.gestures.Fling2DBehavior -import org.readium.navigator.web.gestures.Scroll2DScope +import org.readium.navigator.web.gestures.ConsumingFling2DBehavior import org.readium.navigator.web.gestures.scrollable2D import org.readium.navigator.web.util.AbsolutePaddingValues import org.readium.navigator.web.util.WebViewClient @@ -78,6 +72,7 @@ internal fun ReflowableResource( onTap: (TapEvent) -> Unit, onLinkActivated: (Url, String) -> Unit, onScrollChanged: (Double) -> Unit, + onDocumentResized: () -> Unit, ) { Box( modifier = Modifier.fillMaxSize(), @@ -103,42 +98,8 @@ internal fun ReflowableResource( val contentIsLaidOut = remember(webViewState.webView) { mutableStateOf(false) } - val density = LocalDensity.current - - val webViewViewport = DpSize( - width = viewportSize.width - padding.left - padding.right, - height = viewportSize.height - padding.top - padding.bottom - ) - val scrollableState = remember(resourceState) { WebViewScrollable2DState(resourceState.href) } - val flingBehavior = - object : Fling2DBehavior { - override suspend fun Scroll2DScope.performFling( - initialVelocity: Velocity, - ): Velocity { - return initialVelocity - } - } - - /*if (scroll) { - null - } else { - webViewState.webView - ?.let { - pagingFlingBehavior( - WebViewLayoutInfoProvider( - density, - scrollOrientation.value, - reverseLayout, - webViewViewport, - it - ) - ) - } - } - ?.toFling2DBehavior(orientation = scrollOrientation.value) */ - resourceState.scrollableState = scrollableState val documentStateApi = remember(webViewState.webView,) { @@ -169,11 +130,7 @@ internal fun ReflowableResource( } }, onDocumentResizedDelegate = { - // If a previous resource is resized, we might need to scroll it again to the end - if (resourceState.progression is EndProgression) { - val scrollControllerNow = resourceState.scrollController.value - scrollControllerNow?.scrollToProgression(1.0, scrollOrientation.value) - } + onDocumentResized.invoke() } ) } @@ -213,9 +170,6 @@ internal fun ReflowableResource( webViewState.webView?.let { gesturesApi.registerOnWebView(it) } } - /*val resourceScrollConnection = - ResourceNestedScrollConnection(pagerState, scrollableState, scrollOrientation.value) -*/ // Hide content before initial position is settled if (!contentIsLaidOut.value) { Box( @@ -241,11 +195,11 @@ internal fun ReflowableResource( } } ) - } // .nestedScroll(resourceScrollConnection) + } .scrollable2D( enabled = enableScroll, state = scrollableState, - flingBehavior = flingBehavior, + flingBehavior = ConsumingFling2DBehavior(), reverseDirection = !reverseLayout, orientation = scrollOrientation.value ) @@ -285,32 +239,3 @@ internal fun ReflowableResource( } } } - -private fun FlingBehavior.toFling2DBehavior(orientation: Orientation) = - object : Fling2DBehavior { - override suspend fun Scroll2DScope.performFling( - initialVelocity: Velocity, - ): Velocity { - val scrollScope = object : ScrollScope { - override fun scrollBy(pixels: Float): Float = - when (orientation) { - Orientation.Vertical -> scrollBy(Offset(0f, pixels)).y - Orientation.Horizontal -> scrollBy(Offset(pixels, 0f)).x - } - } - - val velocity = - when (orientation) { - Orientation.Vertical -> initialVelocity.y - Orientation.Horizontal -> initialVelocity.x - } - - val remainingVelocity = - scrollScope.performFling(velocity) - - return when (orientation) { - Orientation.Vertical -> Velocity(0f, remainingVelocity) - Orientation.Horizontal -> Velocity(remainingVelocity, 0f) - } - } - } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableScrollDispatcher.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableScrollDispatcher.kt index e8af5cf232..72c637c623 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableScrollDispatcher.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableScrollDispatcher.kt @@ -121,6 +121,22 @@ internal class ReflowableScrollDispatcher( } } + fun onDocumentResized(index: Int) { + val firstPage = pagerState.layoutInfo.visiblePagesInfo.first() + + val lastPage = pagerState.layoutInfo.visiblePagesInfo.last() + + if (firstPage == lastPage || firstPage.index != index) { + return + } + + val scrollController = resourceStates[index].scrollController.value!! + val scrolled = scrollController.scrollToEnd(pagerOrientation) + if (scrolled > 0) { + rawScrollBy(scrolled.toFloat()) + } + } + private val Offset.mainAxisValue: Float get() = when (pagerOrientation) { Orientation.Vertical -> y Orientation.Horizontal -> x diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ResourceNestedScrollConnection.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ResourceNestedScrollConnection.kt deleted file mode 100644 index f52b61e3f4..0000000000 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ResourceNestedScrollConnection.kt +++ /dev/null @@ -1,80 +0,0 @@ -package org.readium.navigator.web.reflowable - -import androidx.compose.foundation.gestures.Orientation -import androidx.compose.foundation.pager.PagerState -import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.input.nestedscroll.NestedScrollConnection -import androidx.compose.ui.input.nestedscroll.NestedScrollSource -import androidx.compose.ui.unit.Velocity -import org.readium.navigator.web.webview.RelaxedWebView -import org.readium.navigator.web.webview.WebViewScrollable2DState - -internal class ResourceNestedScrollConnection( - private val pagerState: PagerState, - private val resourceState: WebViewScrollable2DState, - private val orientation: Orientation, -) : NestedScrollConnection { - - override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { - val webViewNow = resourceState.webView ?: return available - val current = webViewNow.current - val max = webViewNow.max - - val availableDir = - if (orientation == Orientation.Horizontal) available.x else available.y - - val webViewIsGoingToConsume = - (availableDir > 0 && current > 0) || (availableDir < 0 && current < max) - - return if (webViewIsGoingToConsume) { - // Ensure the WebView is well positioned before consuming - val consumed = scrollToCurrentPage() - Offset( - x = if (orientation == Orientation.Horizontal) consumed else 0f, - y = if (orientation == Orientation.Vertical) consumed else 0f - ) - } else { - Offset.Zero - } - } - - override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity { - if (orientation == Orientation.Vertical) { - // Mode scroll, the WebView is not paginated. - return Velocity.Zero - } - - val webViewNow = resourceState.webView ?: return available - val currentX = webViewNow.scrollX - val maxX = webViewNow.maxScrollX - val pageSize = webViewNow.width - - // WebView stopped scrolling because reaching a good snap position. - val webViewCanStillScroll = - (available.x < 0 && maxX - currentX > pageSize / 2) || (available.x >= 0 && currentX > 1.5 * pageSize) - - return if (webViewCanStillScroll) { - // Ensure Webview is the only one who's visible - scrollToCurrentPage() - // Consume everything left - available - } else { - Velocity.Zero - } - } - - private fun scrollToCurrentPage(): Float { - val currentPageInfo = pagerState.layoutInfo.visiblePagesInfo - .first { it.index == pagerState.currentPage } - - val delta = -currentPageInfo.offset.toFloat() - val consumed = -pagerState.dispatchRawDelta(-delta) - return consumed - } - - private val RelaxedWebView.current get() = - if (orientation == Orientation.Horizontal) scrollX else scrollY - - private val RelaxedWebView.max get() = - if (orientation == Orientation.Horizontal) maxScrollX else maxScrollY -} diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/PagerSnapLayoutInfoProvider.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/PagerSnapLayoutInfoProvider.kt index 5d229dc764..9e2ed58913 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/PagerSnapLayoutInfoProvider.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/PagerSnapLayoutInfoProvider.kt @@ -28,10 +28,10 @@ import androidx.compose.foundation.gestures.snapping.SnapLayoutInfoProvider import androidx.compose.ui.geometry.Offset import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.LayoutDirection +import androidx.compose.ui.unit.dp import androidx.compose.ui.util.fastForEach import kotlin.math.abs import kotlin.math.absoluteValue -import org.readium.navigator.web.webview.DefaultPositionThreshold import timber.log.Timber internal interface PagingLayoutInfo { @@ -255,3 +255,5 @@ internal fun calculateFinalSnappingBound( } private val debug: Boolean = false + +internal val DefaultPositionThreshold = 56.dp diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/PagingFlingBehavior.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/PagingFlingBehavior.kt index 681305360f..e21180797f 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/PagingFlingBehavior.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/PagingFlingBehavior.kt @@ -37,11 +37,11 @@ import androidx.compose.ui.geometry.Offset import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.unit.Density +import org.readium.navigator.web.snapping.DefaultPositionThreshold import org.readium.navigator.web.snapping.PagingLayoutInfo import org.readium.navigator.web.snapping.SnapLayoutInfoProvider import org.readium.navigator.web.snapping.calculateFinalSnappingBound import org.readium.navigator.web.snapping.snapFlingBehavior -import org.readium.navigator.web.webview.DefaultPositionThreshold /** * A [snapFlingBehavior] that will snap pages to the start of the layout. One can use the diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewLayoutInfoProvider.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewLayoutInfoProvider.kt deleted file mode 100644 index 1480d83164..0000000000 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewLayoutInfoProvider.kt +++ /dev/null @@ -1,74 +0,0 @@ -package org.readium.navigator.web.webview - -import androidx.compose.foundation.gestures.Orientation -import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.unit.Density -import androidx.compose.ui.unit.DpSize -import androidx.compose.ui.unit.dp -import kotlin.math.ceil -import kotlin.math.roundToInt -import org.readium.navigator.web.snapping.PagingLayoutInfo - -internal class WebViewLayoutInfoProvider( - override val density: Density, - override val orientation: Orientation, - override val reverseLayout: Boolean, - private val viewportSize: DpSize, - private val webView: RelaxedWebView? = null, -) : PagingLayoutInfo { - - override val positionThresholdFraction: Float get() = - with(density) { - val minThreshold = minOf(DefaultPositionThreshold.toPx(), pageSize / 2f) - minThreshold / pageSize.toFloat() - } - - override val pageSize: Int = - with(density) { viewportSize.width.toPx().roundToInt() } - - override val pageSpacing: Int = 0 - - override val upDownDifference: Offset get() = - Offset.Zero // FIXME - - val pageCount: Int get() = - ceil(webView!!.width / pageSize.toDouble()).toInt() - - val firstVisiblePage: Int get() = - webView!!.scrollX * pageCount / webView.width - - override val visiblePageOffsets: List - get() = buildList { - // two pages are visible - // the first one starts at firstVisiblePage * pageSize in the Webview document coordinates - val firstVisibleOffset = (firstVisiblePage * pageSize - webView!!.scrollX) - add((firstVisibleOffset + pageSize)) - add(firstVisibleOffset) - } - - override val canScrollForward: Boolean - get() = when { - orientation == Orientation.Horizontal && reverseLayout -> - webView!!.canScrollLeft - orientation == Orientation.Horizontal -> - webView!!.canScrollRight - orientation == Orientation.Vertical && reverseLayout -> - webView!!.canScrollTop - else -> - webView!!.canScrollBottom - } - - override val canScrollBackward: Boolean - get() = when { - orientation == Orientation.Horizontal && reverseLayout -> - webView!!.canScrollRight - orientation == Orientation.Horizontal -> - webView!!.canScrollLeft - orientation == Orientation.Vertical && reverseLayout -> - webView!!.canScrollBottom - else -> - webView!!.canScrollTop - } -} - -internal val DefaultPositionThreshold = 56.dp diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollController.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollController.kt index ecd6bb8718..35b643fcc0 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollController.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollController.kt @@ -7,13 +7,10 @@ import androidx.compose.ui.util.fastCoerceAtMost import androidx.compose.ui.util.fastRoundToInt import kotlin.math.ceil import kotlin.math.floor -import timber.log.Timber internal class WebViewScrollController( private val webView: RelaxedWebView, ) { - private var unconsumedDelta: Offset = Offset.Zero - val scrollX: Int get() = webView.scrollX @@ -55,8 +52,6 @@ internal class WebViewScrollController( } fun scrollBy(delta: Offset): Offset { - // val delta = delta + unconsumedDelta - val coercedX = if (delta.x < 0) { delta.x.fastCoerceAtLeast(-webView.scrollX.toFloat()) @@ -75,19 +70,29 @@ internal class WebViewScrollController( val roundedY = coercedY.fastRoundToInt() - Timber.d("Webview ${delta.x} $coercedX ${webView.scrollX} ${webView.maxScrollX}") webView.scrollBy(roundedX, roundedY) - /*unconsumedDelta = Offset( - x = coercedX - roundedX, - y = coercedY - roundedY - )*/ - return Offset(coercedX, coercedY) - unconsumedDelta + return Offset(coercedX, coercedY) } fun scrollToProgression(progression: Double, scrollOrientation: Orientation) { webView.scrollToProgression(progression, scrollOrientation) } + fun scrollToEnd(scrollOrientation: Orientation): Int { + return when (scrollOrientation) { + Orientation.Vertical -> { + val delta = webView.maxScrollY - scrollY + webView.scrollBy(0, delta) + delta + } + Orientation.Horizontal -> { + val delta = webView.maxScrollX - scrollX + webView.scrollBy(delta, 0) + delta + } + } + } + fun progression(scrollOrientation: Orientation) = webView.progression(scrollOrientation) } From 3527573fa75751072dc7c58f03f1ff1be85a6426 Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Thu, 10 Apr 2025 15:21:29 +0200 Subject: [PATCH 30/88] Repair FXL --- .../navigator/web/FixedWebRendition.kt | 42 ++++++++++ .../navigator/web/FixedWebRenditionState.kt | 8 +- .../navigator/web/ReflowableWebRendition.kt | 7 +- .../web/fixed/DoubleViewportSpread.kt | 7 ++ .../web/fixed/FixedPagingLayoutInfo.kt | 52 ++++++++++++ .../web/fixed/SingleViewportSpread.kt | 7 ++ .../web/fixed/SpreadNestedScrollConnection.kt | 76 ++++++++++------- .../navigator/web/fixed/SpreadScrollState.kt | 19 +++++ .../navigator/web/fixed/SpreadWebView.kt | 41 +++++++++- .../navigator/web/gestures/Fling2DBehavior.kt | 42 ++++++++++ .../navigator/web/pager/PageScrollState.kt | 15 ++++ .../navigator/web/pager/ScrollDispatcher.kt | 8 +- .../ScrollDispatcherImpl.kt} | 81 ++++++++++--------- .../reflowable/ReflowablePagingLayoutInfo.kt | 6 ++ .../web/reflowable/ReflowableResource.kt | 15 ++-- .../web/reflowable/ReflowableResourceState.kt | 8 +- 16 files changed, 340 insertions(+), 94 deletions(-) create mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/FixedPagingLayoutInfo.kt create mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadScrollState.kt create mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/pager/PageScrollState.kt rename readium/navigators/web/src/main/java/org/readium/navigator/web/{reflowable/ReflowableScrollDispatcher.kt => pager/ScrollDispatcherImpl.kt} (67%) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt index 5468e7817d..f9fda81dea 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt @@ -34,12 +34,16 @@ import org.readium.navigator.common.defaultHyperlinkListener import org.readium.navigator.common.defaultInputListener import org.readium.navigator.web.fixed.DoubleSpreadState import org.readium.navigator.web.fixed.DoubleViewportSpread +import org.readium.navigator.web.fixed.FixedPagingLayoutInfo import org.readium.navigator.web.fixed.SingleSpreadState import org.readium.navigator.web.fixed.SingleViewportSpread +import org.readium.navigator.web.fixed.SpreadScrollState +import org.readium.navigator.web.gestures.toFling2DBehavior import org.readium.navigator.web.layout.DoubleViewportSpread import org.readium.navigator.web.layout.SingleViewportSpread import org.readium.navigator.web.location.FixedWebLocation import org.readium.navigator.web.pager.RenditionPager +import org.readium.navigator.web.pager.ScrollDispatcherImpl import org.readium.navigator.web.util.AbsolutePaddingValues import org.readium.navigator.web.util.DisplayArea import org.readium.navigator.web.util.WebViewServer @@ -48,6 +52,7 @@ import org.readium.r2.shared.ExperimentalReadiumApi import org.readium.r2.shared.util.AbsoluteUrl import org.readium.r2.shared.util.RelativeUrl import org.readium.r2.shared.util.Url +import pagingFlingBehavior @SuppressLint("UnusedBoxWithConstraintsScope") @ExperimentalReadiumApi @@ -94,9 +99,40 @@ public fun FixedWebRendition( val hyperlinkListenerState = rememberUpdatedState(hyperlinkListener) + val density = LocalDensity.current + + val scrollStates = remember(state, state.layoutDelegate.layout.value) { + state.layoutDelegate.layout.value.spreads + .map { SpreadScrollState() } + } + + val flingBehavior = run { + val pagingLayoutInfo = remember(state, scrollStates) { + FixedPagingLayoutInfo( + pagerState = state.pagerState, + pageStates = scrollStates, + orientation = Orientation.Horizontal, + density = density + ) + } + pagingFlingBehavior(pagingLayoutInfo) + }.toFling2DBehavior(Orientation.Horizontal) + + val scrollDispatcher = remember(state, scrollStates) { + ScrollDispatcherImpl( + pagerState = state.pagerState, + resourceStates = scrollStates, + flingBehavior = flingBehavior, + pagerOrientation = Orientation.Horizontal, + ) + } + + scrollDispatcher.flingBehavior = flingBehavior + RenditionPager( modifier = Modifier, state = state.pagerState, + scrollDispatcher = scrollDispatcher, orientation = Orientation.Horizontal, beyondViewportPageCount = 2, key = { index -> state.layoutDelegate.layout.value.pageIndexForSpread(index) }, @@ -106,6 +142,7 @@ public fun FixedWebRendition( is SingleViewportSpread -> { val spreadState = remember(state) { SingleSpreadState( + index = index, htmlData = state.preloadedData.fixedSingleContent, publicationBaseUrl = WebViewServer.publicationBaseHref, webViewClient = state.webViewClient, @@ -116,6 +153,7 @@ public fun FixedWebRendition( } SingleViewportSpread( + pagerState = state.pagerState, onTap = { inputListenerState.value.onTap(it, TapContext(viewportSize.value)) }, onLinkActivated = { url, outerHtml -> coroutineScope.launch { @@ -123,6 +161,7 @@ public fun FixedWebRendition( } }, state = spreadState, + scrollState = scrollStates[index], backgroundColor = backgroundColor, reverseScrollDirection = !reverseLayout ) @@ -130,6 +169,7 @@ public fun FixedWebRendition( is DoubleViewportSpread -> { val spreadState = remember(state) { DoubleSpreadState( + index = index, htmlData = state.preloadedData.fixedDoubleContent, publicationBaseUrl = WebViewServer.publicationBaseHref, webViewClient = state.webViewClient, @@ -140,6 +180,7 @@ public fun FixedWebRendition( } DoubleViewportSpread( + pagerState = state.pagerState, onTap = { inputListenerState.value.onTap(it, TapContext(viewportSize.value)) }, onLinkActivated = { url, outerHtml -> coroutineScope.launch { @@ -147,6 +188,7 @@ public fun FixedWebRendition( } }, state = spreadState, + scrollState = scrollStates[index], backgroundColor = backgroundColor, reverseScrollDirection = !reverseLayout ) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionState.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionState.kt index 046705fe7c..160b41be79 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionState.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionState.kt @@ -65,6 +65,10 @@ public class FixedWebRenditionState internal constructor( initialSettings ) + private val initialSpread = layoutDelegate.layout.value + .spreadIndexForHref(initialLocation.href) + ?: 0 + internal val hyperlinkProcessor = HyperlinkProcessor(publication.container) @@ -92,10 +96,6 @@ public class FixedWebRenditionState internal constructor( WebViewClient(webViewServer) internal val pagerState: PagerState = run { - val initialSpread = layoutDelegate.layout.value - .spreadIndexForHref(initialLocation.href) - ?: 0 - PagerState( currentPage = initialSpread, pageCount = { layoutDelegate.layout.value.spreads.size } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt index 3352e6696f..f11667b1ff 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt @@ -36,11 +36,12 @@ import org.readium.navigator.common.NullInputListener import org.readium.navigator.common.TapContext import org.readium.navigator.common.defaultHyperlinkListener import org.readium.navigator.common.defaultInputListener +import org.readium.navigator.web.gestures.toFling2DBehavior import org.readium.navigator.web.location.ReflowableWebLocation import org.readium.navigator.web.pager.RenditionPager +import org.readium.navigator.web.pager.ScrollDispatcherImpl import org.readium.navigator.web.reflowable.ReflowablePagingLayoutInfo import org.readium.navigator.web.reflowable.ReflowableResource -import org.readium.navigator.web.reflowable.ReflowableScrollDispatcher import org.readium.navigator.web.util.AbsolutePaddingValues import org.readium.navigator.web.util.WebViewServer import org.readium.r2.navigator.preferences.ReadingProgression @@ -132,10 +133,10 @@ public fun ReflowableWebRendition( ) } pagingFlingBehavior(pagingLayoutInfo) - } + }.toFling2DBehavior(orientation) val scrollDispatcher = remember(state) { - ReflowableScrollDispatcher( + ScrollDispatcherImpl( pagerState = state.pagerState, resourceStates = state.resourceStates, flingBehavior = flingBehavior, diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/DoubleViewportSpread.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/DoubleViewportSpread.kt index c5672b7c7c..2afc108686 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/DoubleViewportSpread.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/DoubleViewportSpread.kt @@ -10,6 +10,7 @@ package org.readium.navigator.web.fixed import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.pager.PagerState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.State @@ -34,6 +35,8 @@ import org.readium.r2.shared.util.Url @Composable internal fun DoubleViewportSpread( + pagerState: PagerState, + scrollState: SpreadScrollState, onTap: (TapEvent) -> Unit, onLinkActivated: (Url, String) -> Unit, state: DoubleSpreadState, @@ -78,7 +81,10 @@ internal fun DoubleViewportSpread( } SpreadWebView( + spreadIndex = state.index, + pagerState = pagerState, state = webViewState, + spreadScrollState = scrollState, client = state.webViewClient, onTap = onTap, onLinkActivated = { url, outerHtml -> @@ -95,6 +101,7 @@ internal fun DoubleViewportSpread( } internal class DoubleSpreadState( + val index: Int, val htmlData: String, val publicationBaseUrl: AbsoluteUrl, val webViewClient: WebViewClient, diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/FixedPagingLayoutInfo.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/FixedPagingLayoutInfo.kt new file mode 100644 index 0000000000..a92c8e2a3a --- /dev/null +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/FixedPagingLayoutInfo.kt @@ -0,0 +1,52 @@ +/* + * Copyright 2024 Readium Foundation. All rights reserved. + * Use of this source code is governed by the BSD-style license + * available in the top-level LICENSE file of the project. + */ + +package org.readium.navigator.web.fixed + +import androidx.compose.foundation.gestures.Orientation +import androidx.compose.foundation.pager.PagerState +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.unit.Density +import org.readium.navigator.web.pager.PageScrollState +import org.readium.navigator.web.snapping.PagingLayoutInfo + +internal class FixedPagingLayoutInfo( + private val pagerState: PagerState, + private val pageStates: List, + override val orientation: Orientation, + override val density: Density, +) : PagingLayoutInfo { + + override val pageSize: Int get() = + pagerState.layoutInfo.pageSize + + override val pageSpacing: Int get() = + 0 + + override val upDownDifference: Offset + get() = Offset.Zero + + override val reverseLayout: Boolean get() = + false + + override val canScrollForward: Boolean + get() = pagerState.layoutInfo.visiblePagesInfo.last() + .let { pageInfo -> pageInfo.index < pagerState.pageCount - 1 || pageInfo.offset > 0 } || run { + val lastResourceState = pageStates[pagerState.pageCount - 1] + val scrollController = lastResourceState.scrollController.value ?: return false + return scrollController.canMoveRight + } + + override val canScrollBackward: Boolean + get() = pagerState.layoutInfo.visiblePagesInfo.first() + .let { pageInfo -> pageInfo.index > 0 || pageInfo.offset < 0 } || run { + val scrollController = pageStates[0].scrollController.value ?: return false + return scrollController.canMoveLeft + } + + override val visiblePageOffsets: List + get() = pagerState.layoutInfo.visiblePagesInfo.map { it.offset } +} diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SingleViewportSpread.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SingleViewportSpread.kt index f54a719a4e..336f38d0c6 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SingleViewportSpread.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SingleViewportSpread.kt @@ -10,6 +10,7 @@ package org.readium.navigator.web.fixed import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.pager.PagerState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.State @@ -34,9 +35,11 @@ import org.readium.r2.shared.util.Url @Composable internal fun SingleViewportSpread( + pagerState: PagerState, onTap: (TapEvent) -> Unit, onLinkActivated: (Url, String) -> Unit, state: SingleSpreadState, + scrollState: SpreadScrollState, backgroundColor: Color, reverseScrollDirection: Boolean, ) { @@ -78,7 +81,10 @@ internal fun SingleViewportSpread( } SpreadWebView( + spreadIndex = state.index, + pagerState = pagerState, state = webViewState, + spreadScrollState = scrollState, client = state.webViewClient, onTap = onTap, onLinkActivated = { url, outerHtml -> @@ -95,6 +101,7 @@ internal fun SingleViewportSpread( } internal class SingleSpreadState( + val index: Int, val htmlData: String, val publicationBaseUrl: AbsoluteUrl, val webViewClient: WebViewClient, diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadNestedScrollConnection.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadNestedScrollConnection.kt index 5c22e463a8..edc6ad6094 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadNestedScrollConnection.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadNestedScrollConnection.kt @@ -6,57 +6,77 @@ package org.readium.navigator.web.fixed +import androidx.compose.foundation.pager.PagerState import androidx.compose.ui.geometry.Offset import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.NestedScrollSource import androidx.compose.ui.unit.Velocity import kotlin.math.abs -import org.readium.navigator.web.webview.RelaxedWebView +import org.readium.navigator.web.gestures.Fling2DBehavior import org.readium.navigator.web.webview.WebViewScrollable2DState internal class SpreadNestedScrollConnection( + private val spreadIndex: Int, + private val pagerState: PagerState, private val webviewState: WebViewScrollable2DState, + private val scrollController: SpreadScrollState, + private var flingBehavior: Fling2DBehavior, ) : NestedScrollConnection { - override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { + var consumedHere: Boolean = false + + override fun onPostScroll( + consumed: Offset, + available: Offset, + source: NestedScrollSource, + ): Offset { if (source != NestedScrollSource.UserInput) { return Offset.Zero } - val webViewNow = webviewState.webView ?: return Offset.Zero + if (!pagerShowsOnlyThisSpread()) { + // Let the main dispatcher scroll only horizontally. + return Offset.Zero + } - // For some reason, scrollX can vary by 1 or 2 pixels without any call to scrollTo. - val webViewCannotScrollHorizontally = - (webViewNow.scrollX < 3 && available.x > 0) || - ((webViewNow.maxScrollX - webViewNow.scrollX) < 3 && available.x < 0) + val scrollController = scrollController.scrollController.value + ?: return available - if (webViewCannotScrollHorizontally) { - snapWebview(webViewNow) - } + consumedHere = true - val isGestureHorizontal = - (abs(available.y) / abs(available.x)) < 0.58 // tan(Pi/6) + return -scrollController.scrollBy(-available) + } + + override suspend fun onPostFling( + consumed: Velocity, + available: Velocity, + ): Velocity { + var velocityLeft = available - return if (webViewCannotScrollHorizontally && isGestureHorizontal) { - // If the gesture is mostly horizontal and the spread has nothing to consume horizontally, - // we consume everything vertically. - Offset(0f, available.y) - } else { - Offset.Zero + // The main dispatcher will do a fling in any case. We restrain ourselves from + // doing one here if that of the main dispatcher will be significant to prevent + // strange visual behaviors. + if (consumedHere && pagerShowsOnlyThisSpread()) { + webviewState.scroll { + velocityLeft = with(flingBehavior) { -performFling(-velocityLeft) } + } } - } - override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity { - val webViewNow = webviewState.webView ?: return Velocity.Zero - snapWebview(webViewNow) - return Velocity.Zero + consumedHere = false + + return Velocity( + x = if ((available.x - velocityLeft.x).isNaN()) available.x else available.x - velocityLeft.x, + y = if ((available.y - velocityLeft.y).isNaN()) available.y else available.y - velocityLeft.y + ) } - private fun snapWebview(webview: RelaxedWebView) { - if ((webview.maxScrollX - webview.scrollX) < 15) { - webview.scrollTo(webview.maxScrollX, webview.scrollY) - } else if (webview.scrollX in (0 until 15)) { - webview.scrollTo(0, webview.scrollY) + private fun pagerShowsOnlyThisSpread(): Boolean { + val visiblePages = pagerState.layoutInfo.visiblePagesInfo + val otherPages = visiblePages.filter { it.index != spreadIndex } + val mostlyThis = otherPages.all { abs(it.offset) > 0.95 * pagerState.layoutInfo.pageSize } + if (mostlyThis) { + pagerState.requestScrollToPage(spreadIndex) } + return mostlyThis } } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadScrollState.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadScrollState.kt new file mode 100644 index 0000000000..582feac21a --- /dev/null +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadScrollState.kt @@ -0,0 +1,19 @@ +/* + * Copyright 2024 Readium Foundation. All rights reserved. + * Use of this source code is governed by the BSD-style license + * available in the top-level LICENSE file of the project. + */ + +package org.readium.navigator.web.fixed + +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.Stable +import androidx.compose.runtime.mutableStateOf +import org.readium.navigator.web.pager.PageScrollState +import org.readium.navigator.web.webview.WebViewScrollController + +@Stable +internal class SpreadScrollState : PageScrollState { + + override val scrollController: MutableState = mutableStateOf(null) +} diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt index 6b97f0d1d5..1b1d0306c1 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt @@ -8,16 +8,22 @@ package org.readium.navigator.web.fixed import android.annotation.SuppressLint import android.view.View +import android.webkit.WebView import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.pager.PagerState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.unit.DpOffset import org.readium.navigator.common.TapEvent +import org.readium.navigator.web.gestures.NullFling2DBehavior +import org.readium.navigator.web.gestures.Scrollable2DDefaults +import org.readium.navigator.web.gestures.Scrollable2DState import org.readium.navigator.web.gestures.scrollable2D import org.readium.navigator.web.util.WebViewClient import org.readium.navigator.web.webapi.DocumentStateApi @@ -25,6 +31,7 @@ import org.readium.navigator.web.webapi.GesturesApi import org.readium.navigator.web.webapi.GesturesListener import org.readium.navigator.web.webview.RelaxedWebView import org.readium.navigator.web.webview.WebView +import org.readium.navigator.web.webview.WebViewScrollController import org.readium.navigator.web.webview.WebViewScrollable2DState import org.readium.navigator.web.webview.WebViewState import org.readium.r2.shared.ExperimentalReadiumApi @@ -34,7 +41,10 @@ import org.readium.r2.shared.util.AbsoluteUrl @SuppressLint("SetJavaScriptEnabled") @Composable internal fun SpreadWebView( + pagerState: PagerState, + spreadIndex: Int, state: WebViewState, + spreadScrollState: SpreadScrollState, client: WebViewClient, onScriptsLoaded: () -> Unit, onTap: (TapEvent) -> Unit, @@ -44,10 +54,33 @@ internal fun SpreadWebView( ) { val scrollableState = remember { WebViewScrollable2DState() } - val spreadNestedScrollConnection = SpreadNestedScrollConnection(scrollableState) + val flingBehavior = Scrollable2DDefaults.flingBehavior() + + val spreadNestedScrollConnection = + SpreadNestedScrollConnection(spreadIndex, pagerState, scrollableState, spreadScrollState, flingBehavior) val documentStateApi = remember(onScriptsLoaded) { - DocumentStateApi(onScriptsLoaded, {}, {}) + DocumentStateApi( + onScriptsLoadedDelegate = onScriptsLoaded, + onDocumentLoadedDelegate = { + state.webView?.apply { + post { + postVisualStateCallback( + 0, + object : WebView.VisualStateCallback() { + override fun onComplete(requestId: Long) { + with(this@apply) { + val scrollController = WebViewScrollController(this) + spreadScrollState.scrollController.value = scrollController + } + } + } + ) + } + } + }, + onDocumentResizedDelegate = {} + ) } val gesturesApi = remember(onTap) { @@ -74,8 +107,9 @@ internal fun SpreadWebView( modifier = Modifier .nestedScroll(spreadNestedScrollConnection) .scrollable2D( - state = scrollableState, + state = Scrollable2DState { Offset.Zero }, reverseDirection = reverseScrollDirection, + flingBehavior = NullFling2DBehavior() ) .fillMaxSize(), client = client, @@ -93,6 +127,7 @@ internal fun SpreadWebView( webview.setLayerType(View.LAYER_TYPE_HARDWARE, null) }, onDispose = { + spreadScrollState.scrollController.value = null scrollableState.webView = null } ) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/gestures/Fling2DBehavior.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/gestures/Fling2DBehavior.kt index 40248178c2..214c6437ed 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/gestures/Fling2DBehavior.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/gestures/Fling2DBehavior.kt @@ -22,7 +22,11 @@ package org.readium.navigator.web.gestures +import androidx.compose.foundation.gestures.FlingBehavior +import androidx.compose.foundation.gestures.Orientation +import androidx.compose.foundation.gestures.ScrollScope import androidx.compose.runtime.Stable +import androidx.compose.ui.geometry.Offset import androidx.compose.ui.unit.Velocity /** @@ -53,9 +57,47 @@ internal interface Fling2DBehavior { internal class ConsumingFling2DBehavior : Fling2DBehavior { + override suspend fun Scroll2DScope.performFling( + initialVelocity: Velocity, + ): Velocity { + return Velocity.Zero + } +} + +internal class NullFling2DBehavior : Fling2DBehavior { + override suspend fun Scroll2DScope.performFling( initialVelocity: Velocity, ): Velocity { return initialVelocity } } + +internal fun FlingBehavior.toFling2DBehavior(orientation: Orientation) = + object : Fling2DBehavior { + override suspend fun Scroll2DScope.performFling( + initialVelocity: Velocity, + ): Velocity { + val scrollScope = object : ScrollScope { + override fun scrollBy(pixels: Float): Float = + when (orientation) { + Orientation.Vertical -> scrollBy(Offset(0f, pixels)).y + Orientation.Horizontal -> scrollBy(Offset(pixels, 0f)).x + } + } + + val velocity = + when (orientation) { + Orientation.Vertical -> initialVelocity.y + Orientation.Horizontal -> initialVelocity.x + } + + val remainingVelocity = + scrollScope.performFling(velocity) + + return when (orientation) { + Orientation.Vertical -> Velocity(0f, remainingVelocity) + Orientation.Horizontal -> Velocity(remainingVelocity, 0f) + } + } + } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/PageScrollState.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/PageScrollState.kt new file mode 100644 index 0000000000..e34cb21daa --- /dev/null +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/PageScrollState.kt @@ -0,0 +1,15 @@ +/* + * Copyright 2024 Readium Foundation. All rights reserved. + * Use of this source code is governed by the BSD-style license + * available in the top-level LICENSE file of the project. + */ + +package org.readium.navigator.web.pager + +import androidx.compose.runtime.MutableState +import org.readium.navigator.web.webview.WebViewScrollController + +internal interface PageScrollState { + + val scrollController: MutableState +} diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollDispatcher.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollDispatcher.kt index 8b6d63031b..69eb5ee7f0 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollDispatcher.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollDispatcher.kt @@ -22,7 +22,11 @@ internal class DelegatingNestedScrollConnection( private val scrollDispatcher: ScrollDispatcher, ) : NestedScrollConnection { - override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { + override fun onPostScroll( + consumed: Offset, + available: Offset, + source: NestedScrollSource, + ): Offset { if (source == NestedScrollSource.UserInput) { scrollDispatcher.onScroll(available) } @@ -30,7 +34,7 @@ internal class DelegatingNestedScrollConnection( return available } - override suspend fun onPreFling(available: Velocity): Velocity { + override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity { scrollDispatcher.onFling(available) return available } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableScrollDispatcher.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollDispatcherImpl.kt similarity index 67% rename from readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableScrollDispatcher.kt rename to readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollDispatcherImpl.kt index 72c637c623..3a65a3fb31 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableScrollDispatcher.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollDispatcherImpl.kt @@ -1,35 +1,28 @@ -/* - * Copyright 2024 Readium Foundation. All rights reserved. - * Use of this source code is governed by the BSD-style license - * available in the top-level LICENSE file of the project. - */ +package org.readium.navigator.web.pager -package org.readium.navigator.web.reflowable - -import androidx.compose.foundation.gestures.FlingBehavior import androidx.compose.foundation.gestures.Orientation -import androidx.compose.foundation.gestures.ScrollScope import androidx.compose.foundation.pager.PagerState import androidx.compose.ui.geometry.Offset import androidx.compose.ui.unit.Velocity import androidx.compose.ui.util.fastCoerceAtLeast import androidx.compose.ui.util.fastCoerceAtMost -import org.readium.navigator.web.pager.ScrollDispatcher +import org.readium.navigator.web.gestures.Fling2DBehavior +import org.readium.navigator.web.gestures.Scroll2DScope import timber.log.Timber -internal class ReflowableScrollDispatcher( +internal class ScrollDispatcherImpl( private val pagerState: PagerState, - private val resourceStates: List, + private val resourceStates: List, internal var pagerOrientation: Orientation, - internal var flingBehavior: FlingBehavior, -) : ScrollDispatcher, ScrollScope { + internal var flingBehavior: Fling2DBehavior, +) : ScrollDispatcher, Scroll2DScope { - override fun scrollBy(available: Float): Float { - return -rawScrollBy(-available) + override fun scrollBy(available: Offset): Offset { + return -rawScrollBy(-available.mainAxisValue).mainAxisOffset } private fun rawScrollBy(available: Float): Float { - Timber.d("scrollBy available $available") + Timber.Forest.d("scrollBy available $available") var deltaLeft = available val firstPage = pagerState.layoutInfo.visiblePagesInfo.first() @@ -48,7 +41,7 @@ internal class ReflowableScrollDispatcher( val consumedInFirst = consumeInWebview(firstTargetPage.index, deltaLeft) deltaLeft -= consumedInFirst - Timber.d("consumed $consumedInFirst in ${firstTargetPage.index}") + Timber.Forest.d("consumed $consumedInFirst in ${firstTargetPage.index}") val availableForPager = if (firstPage.index == lastPage.index) { @@ -75,13 +68,13 @@ internal class ReflowableScrollDispatcher( val consumedInPager = -pagerState.dispatchRawDelta(-availableForPager) deltaLeft -= consumedInPager - Timber.d("consumed $consumedInPager in pager") + Timber.Forest.d("consumed $consumedInPager in pager") val consumedInSecond = consumeInWebview(secondTargetPage.index, deltaLeft) deltaLeft -= consumedInSecond - Timber.d("consumed $consumedInSecond in ${secondTargetPage.index}") + Timber.Forest.d("consumed $consumedInSecond in ${secondTargetPage.index}") - Timber.d("scrollBy left $deltaLeft") + Timber.Forest.d("scrollBy left $deltaLeft") return when (deltaLeft) { 0f -> available @@ -98,27 +91,33 @@ internal class ReflowableScrollDispatcher( } override fun onScroll(available: Offset): Offset { - Timber.d("onScroll ${available.x}") - val consumed = -scrollBy(-available.mainAxisValue) - return consumed.mainAxisOffset + Timber.Forest.d("onScroll ${available.x}") + return -scrollBy(-available) } override suspend fun onFling(available: Velocity): Velocity { - Timber.d("onFling ${available.x}") - var velocityLeft = available.mainAxisValue + Timber.Forest.d("onFling ${available.x}") + var velocityLeft = available pagerState.scroll { with(flingBehavior) { - with(this@ReflowableScrollDispatcher) { + with(this@ScrollDispatcherImpl) { velocityLeft = -performFling(-velocityLeft) } } } - return if ((available.mainAxisValue - velocityLeft).isNaN()) { - available - } else { - available - velocityLeft.mainAxisVelocity - } + return Velocity( + x = if ((available.x - velocityLeft.x).isNaN()) { + available.x + } else { + available.x - velocityLeft.x + }, + y = if ((available.y - velocityLeft.y).isNaN()) { + available.y + } else { + available.y - velocityLeft.y + } + ) } fun onDocumentResized(index: Int) { @@ -147,13 +146,15 @@ internal class ReflowableScrollDispatcher( Orientation.Horizontal -> x } - private val Float.mainAxisOffset: Offset get() = when (pagerOrientation) { - Orientation.Vertical -> Offset(0f, this) - Orientation.Horizontal -> Offset(this, 0f) - } + private val Float.mainAxisOffset: Offset + get() = when (pagerOrientation) { + Orientation.Vertical -> Offset(0f, this) + Orientation.Horizontal -> Offset(this, 0f) + } - private val Float.mainAxisVelocity: Velocity get() = when (pagerOrientation) { - Orientation.Vertical -> Velocity(0f, this) - Orientation.Horizontal -> Velocity(this, 0f) - } + private val Float.mainAxisVelocity: Velocity + get() = when (pagerOrientation) { + Orientation.Vertical -> Velocity(0f, this) + Orientation.Horizontal -> Velocity(this, 0f) + } } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowablePagingLayoutInfo.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowablePagingLayoutInfo.kt index b66910711a..d0edc2f1ce 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowablePagingLayoutInfo.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowablePagingLayoutInfo.kt @@ -1,3 +1,9 @@ +/* + * Copyright 2024 Readium Foundation. All rights reserved. + * Use of this source code is governed by the BSD-style license + * available in the top-level LICENSE file of the project. + */ + package org.readium.navigator.web.reflowable import androidx.compose.foundation.gestures.Orientation diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt index c93db80051..95f446481f 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt @@ -25,6 +25,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.unit.DpOffset @@ -34,7 +35,8 @@ import org.readium.navigator.common.TapEvent import org.readium.navigator.web.css.Layout import org.readium.navigator.web.css.RsProperties import org.readium.navigator.web.css.UserProperties -import org.readium.navigator.web.gestures.ConsumingFling2DBehavior +import org.readium.navigator.web.gestures.NullFling2DBehavior +import org.readium.navigator.web.gestures.Scrollable2DState import org.readium.navigator.web.gestures.scrollable2D import org.readium.navigator.web.util.AbsolutePaddingValues import org.readium.navigator.web.util.WebViewClient @@ -46,7 +48,6 @@ import org.readium.navigator.web.webapi.GesturesApi import org.readium.navigator.web.webview.RelaxedWebView import org.readium.navigator.web.webview.WebView import org.readium.navigator.web.webview.WebViewScrollController -import org.readium.navigator.web.webview.WebViewScrollable2DState import org.readium.navigator.web.webview.rememberWebViewState import org.readium.r2.shared.ExperimentalReadiumApi import org.readium.r2.shared.util.AbsoluteUrl @@ -98,11 +99,9 @@ internal fun ReflowableResource( val contentIsLaidOut = remember(webViewState.webView) { mutableStateOf(false) } - val scrollableState = remember(resourceState) { WebViewScrollable2DState(resourceState.href) } + val scrollableState = remember { Scrollable2DState { Offset.Zero } } - resourceState.scrollableState = scrollableState - - val documentStateApi = remember(webViewState.webView,) { + val documentStateApi = remember(webViewState.webView) { DocumentStateApi( onScriptsLoadedDelegate = { scriptsLoaded.value = true @@ -199,7 +198,7 @@ internal fun ReflowableResource( .scrollable2D( enabled = enableScroll, state = scrollableState, - flingBehavior = ConsumingFling2DBehavior(), + flingBehavior = NullFling2DBehavior(), reverseDirection = !reverseLayout, orientation = scrollOrientation.value ) @@ -210,7 +209,6 @@ internal fun ReflowableResource( factory = { RelaxedWebView(it) }, client = webViewClient, onCreated = { webview -> - scrollableState.webView = webview webview.settings.javaScriptEnabled = true webview.settings.setSupportZoom(false) webview.settings.builtInZoomControls = false @@ -232,7 +230,6 @@ internal fun ReflowableResource( } }, onDispose = { - scrollableState.webView = null resourceState.scrollController.value = null } ) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResourceState.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResourceState.kt index d56aab5693..83e71e3092 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResourceState.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResourceState.kt @@ -9,8 +9,8 @@ package org.readium.navigator.web.reflowable import androidx.compose.runtime.MutableState import androidx.compose.runtime.Stable import androidx.compose.runtime.mutableStateOf +import org.readium.navigator.web.pager.PageScrollState import org.readium.navigator.web.webview.WebViewScrollController -import org.readium.navigator.web.webview.WebViewScrollable2DState import org.readium.r2.shared.util.Url @Stable @@ -18,13 +18,11 @@ internal class ReflowableResourceState( val index: Int, val href: Url, initialProgression: Progression, -) { +) : PageScrollState { var progression: Progression = initialProgression - val scrollController: MutableState = mutableStateOf(null) - - var scrollableState: WebViewScrollable2DState? = null + override val scrollController: MutableState = mutableStateOf(null) } internal sealed interface Progression { From de0889a47dc135b96b5175dfe1aa661416a46300 Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Thu, 10 Apr 2025 17:54:36 +0200 Subject: [PATCH 31/88] Ugrade Readium CSS to 2.0.0-beta08 --- .../demo/preferences/PreferenceViews.kt | 2 +- .../demo/preferences/UserPreferences.kt | 146 +++++++++--------- .../readium/navigator/web/css/Properties.kt | 6 - .../readium/navigator/web/css/ReadiumCss.kt | 5 +- .../web/preferences/ReflowableWebDefaults.kt | 3 - .../preferences/ReflowableWebPreferences.kt | 9 -- .../ReflowableWebPreferencesEditor.kt | 86 +++-------- .../web/preferences/ReflowableWebSettings.kt | 3 - .../ReflowableWebSettingsResolver.kt | 3 - 9 files changed, 90 insertions(+), 173 deletions(-) diff --git a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/preferences/PreferenceViews.kt b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/preferences/PreferenceViews.kt index ee936b6dfe..8340b41c3d 100644 --- a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/preferences/PreferenceViews.kt +++ b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/preferences/PreferenceViews.kt @@ -105,7 +105,7 @@ private fun ButtonGroupItem( ) { option -> Text( text = formatValue(option), - style = MaterialTheme.typography.labelSmall + style = MaterialTheme.typography.labelSmall, ) } } diff --git a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/preferences/UserPreferences.kt b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/preferences/UserPreferences.kt index 2ad60e56cb..bbbd67976f 100644 --- a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/preferences/UserPreferences.kt +++ b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/preferences/UserPreferences.kt @@ -107,7 +107,6 @@ fun

, S : Settings, E : PreferencesEditor> UserPreferen horizontalMargins = editor.horizontalMargins, paragraphIndent = editor.paragraphIndent, paragraphSpacing = editor.paragraphSpacing, - publisherStyles = editor.publisherStyles, readingProgression = editor.readingProgression, scroll = editor.scroll, textAlign = editor.textAlign, @@ -211,14 +210,12 @@ private fun ReflowableUserPreferences( horizontalMargins: RangePreference? = null, paragraphIndent: RangePreference? = null, paragraphSpacing: RangePreference? = null, - publisherStyles: Preference? = null, readingProgression: EnumPreference? = null, scroll: Preference? = null, textAlign: EnumPreference? = null, textColor: Preference? = null, textNormalization: Preference? = null, theme: EnumPreference? = null, - typeScale: RangePreference? = null, verticalText: Preference? = null, wordSpacing: RangePreference? = null, ) { @@ -273,7 +270,7 @@ private fun ReflowableUserPreferences( Divider() } - if (theme != null || textColor != null || imageFilter != null) { + if (theme != null || imageFilter != null || textColor != null || backgroundColor != null) { if (theme != null) { ButtonGroupItem( title = "Theme", @@ -317,7 +314,10 @@ private fun ReflowableUserPreferences( Divider() } - if (fontFamily != null || fontSize != null || textNormalization != null) { + if (fontFamily != null || fontSize != null || + fontWeight != null || textNormalization != null || + lineHeight != null || paragraphSpacing != null + ) { if (fontFamily != null) { MenuItem( title = "Typeface", @@ -360,88 +360,80 @@ private fun ReflowableUserPreferences( ) } - Divider() - } - - if (publisherStyles != null) { - SwitchItem( - title = "Publisher styles", - preference = publisherStyles - ) - - if (!(publisherStyles.value ?: publisherStyles.effectiveValue)) { - if (textAlign != null) { - ButtonGroupItem( - title = "Alignment", - preference = textAlign - ) { value -> - when (value) { - ReadiumTextAlign.CENTER -> "Center" - ReadiumTextAlign.JUSTIFY -> "Justify" - ReadiumTextAlign.START -> "Start" - ReadiumTextAlign.END -> "End" - ReadiumTextAlign.LEFT -> "Left" - ReadiumTextAlign.RIGHT -> "Right" - null -> "Default" - } - } - } + if (lineHeight != null) { + StepperItem( + title = "Line height", + preference = lineHeight + ) + } - if (typeScale != null) { - StepperItem( - title = "Type scale", - preference = typeScale - ) - } + if (paragraphSpacing != null) { + StepperItem( + title = "Paragraph spacing", + preference = paragraphSpacing + ) + } - if (lineHeight != null) { - StepperItem( - title = "Line height", - preference = lineHeight - ) - } + Divider() + } - if (paragraphIndent != null) { - StepperItem( - title = "Paragraph indent", - preference = paragraphIndent + if (textAlign != null || paragraphIndent != null || wordSpacing != null || + letterSpacing != null || hyphens != null || ligatures != null + ) { + if (textAlign != null) { + ButtonGroupItem( + title = "Alignment", + preference = textAlign.withSupportedValues( + ReadiumTextAlign.LEFT, + ReadiumTextAlign.RIGHT, + ReadiumTextAlign.JUSTIFY ) + ) { value -> + when (value) { + ReadiumTextAlign.CENTER -> "Center" + ReadiumTextAlign.JUSTIFY -> "Justify" + ReadiumTextAlign.START -> "Start" + ReadiumTextAlign.END -> "End" + ReadiumTextAlign.LEFT -> "Left" + ReadiumTextAlign.RIGHT -> "Right" + null -> "Default" + } } + } - if (paragraphSpacing != null) { - StepperItem( - title = "Paragraph spacing", - preference = paragraphSpacing - ) - } + if (paragraphIndent != null) { + StepperItem( + title = "Paragraph indent", + preference = paragraphIndent + ) + } - if (wordSpacing != null) { - StepperItem( - title = "Word spacing", - preference = wordSpacing - ) - } + if (wordSpacing != null) { + StepperItem( + title = "Word spacing", + preference = wordSpacing + ) + } - if (letterSpacing != null) { - StepperItem( - title = "Letter spacing", - preference = letterSpacing - ) - } + if (letterSpacing != null) { + StepperItem( + title = "Letter spacing", + preference = letterSpacing + ) + } - if (hyphens != null) { - SwitchItem( - title = "Hyphens", - preference = hyphens - ) - } + if (hyphens != null) { + SwitchItem( + title = "Hyphens", + preference = hyphens + ) + } - if (ligatures != null) { - SwitchItem( - title = "Ligatures", - preference = ligatures - ) - } + if (ligatures != null) { + SwitchItem( + title = "Ligatures", + preference = ligatures + ) } } } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/Properties.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/Properties.kt index 8ccdb2242f..29e20ab022 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/Properties.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/Properties.kt @@ -59,8 +59,6 @@ public interface Properties : Cssable { * @param fontSize Increasing and decreasing the root font-size. It will serve as a reference * for the cascade. To reset, remove the required flag. * @param lineLength Increasing and decreasing the line length. - * @param advancedSettings This flag is required to apply the font-size and/or advanced user - * settings. * @param textAlign The alignment (text-align) the user prefers. It impacts body, li, and p * which are not children of blockquote and figcaption. Requires: advancedSettings * @param lineHeight Increasing and decreasing leading (line-height). It impacts body, p, li and @@ -108,7 +106,6 @@ public data class UserProperties( val lineLength: Length? = null, // Advanced settings - val advancedSettings: Boolean? = null, val textAlign: TextAlign? = null, val lineHeight: Either? = null, // line-height supports unitless numbers val paraSpacing: Length? = null, @@ -145,9 +142,6 @@ public data class UserProperties( putCss("--USER__fontFamily", fontFamily) putCss("--USER__fontSize", fontSize) putCss("--USER__lineLength", lineLength) - - // Advanced settings - putCss("--USER__advancedSettings", flag("advanced", advancedSettings)) putCss("--USER__textAlign", textAlign) lineHeight ?.onLeft { putCss("--USER__lineHeight", it) } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCss.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCss.kt index 0536ba9093..5942fde1dc 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCss.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCss.kt @@ -6,7 +6,7 @@ package org.readium.navigator.web.css -import android.net.Uri +import androidx.core.net.toUri import org.jsoup.Jsoup import org.jsoup.nodes.Document import org.jsoup.nodes.Element @@ -144,7 +144,7 @@ internal data class ReadiumCss( if (googleFonts.isNotEmpty()) { val families = googleFonts.joinToString("|") { it.name } - val uri = Uri.parse("https://fonts.googleapis.com/css") + val uri = "https://fonts.googleapis.com/css".toUri() .buildUpon() .appendQueryParameter("family", families) .build() @@ -322,7 +322,6 @@ internal fun ReadiumCss.update(settings: ReflowableWebSettings, useReadiumCssFon } else { null }, - advancedSettings = !publisherStyles, textAlign = when (textAlign) { TextAlign.JUSTIFY -> CssTextAlign.JUSTIFY TextAlign.LEFT -> CssTextAlign.LEFT diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebDefaults.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebDefaults.kt index afd424411f..87750917d8 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebDefaults.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebDefaults.kt @@ -8,7 +8,6 @@ package org.readium.navigator.web.preferences import org.readium.r2.navigator.preferences.ImageFilter import org.readium.r2.navigator.preferences.ReadingProgression -import org.readium.r2.navigator.preferences.Spread import org.readium.r2.navigator.preferences.TextAlign import org.readium.r2.shared.ExperimentalReadiumApi import org.readium.r2.shared.util.Language @@ -34,10 +33,8 @@ public data class ReflowableWebDefaults( val pageMargins: Double? = null, val paragraphIndent: Double? = null, val paragraphSpacing: Double? = null, - val publisherStyles: Boolean? = null, val readingProgression: ReadingProgression? = null, val scroll: Boolean? = null, - val spread: Spread? = null, val textAlign: TextAlign? = null, val textNormalization: Boolean? = null, val wordSpacing: Double? = null, diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferences.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferences.kt index c9a4a4d7c2..bf298efd5a 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferences.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferences.kt @@ -29,13 +29,9 @@ import org.readium.r2.shared.util.Language * @param horizontalMargins Factor applied to horizontal margins. * @param paragraphIndent Text indentation for paragraphs. * @param paragraphSpacing Vertical margins for paragraphs. - * @param publisherStyles Indicates whether the original publisher styles should be observed. - * Many settings require this to be off. * @param readingProgression Direction of the reading progression across resources. * @param scroll Indicates if the overflow of resources should be handled using scrolling * instead of synthetic pagination. - * @param spread Indicates if the fixed-layout publication should be rendered with a - * synthetic spread (dual-page). * @param textAlign Page text alignment. * @param textColor Default page text color. * @param textNormalization Normalize text styles to increase accessibility. @@ -62,10 +58,8 @@ public data class ReflowableWebPreferences( val horizontalMargins: Double? = null, val paragraphIndent: Double? = null, val paragraphSpacing: Double? = null, - val publisherStyles: Boolean? = null, val readingProgression: ReadingProgression? = null, val scroll: Boolean? = null, - val spread: Spread? = null, val textAlign: TextAlign? = null, val textColor: Color? = null, val textNormalization: Boolean? = null, @@ -81,7 +75,6 @@ public data class ReflowableWebPreferences( require(letterSpacing == null || letterSpacing >= 0) require(horizontalMargins == null || horizontalMargins >= 0) require(paragraphSpacing == null || paragraphSpacing >= 0) - require(spread in listOf(null, Spread.NEVER, Spread.ALWAYS)) require(wordSpacing == null || wordSpacing >= 0) } @@ -102,10 +95,8 @@ public data class ReflowableWebPreferences( horizontalMargins = other.horizontalMargins ?: horizontalMargins, paragraphIndent = other.paragraphIndent ?: paragraphIndent, paragraphSpacing = other.paragraphSpacing ?: paragraphSpacing, - publisherStyles = other.publisherStyles ?: publisherStyles, readingProgression = other.readingProgression ?: readingProgression, scroll = other.scroll ?: scroll, - spread = other.spread ?: spread, textAlign = other.textAlign ?: textAlign, textColor = other.textColor ?: textColor, textNormalization = other.textNormalization ?: textNormalization, diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesEditor.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesEditor.kt index 5d8318f79d..46fa208452 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesEditor.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesEditor.kt @@ -95,8 +95,7 @@ public class ReflowableWebPreferencesEditor internal constructor( /** * Number of reflowable columns to display (one-page view or two-page spread). * - * Only effective when: - * - [scroll] is off + * Only effective when [scroll] is off. */ public val columnCount: EnumPreference = EnumPreferenceDelegate( @@ -154,9 +153,7 @@ public class ReflowableWebPreferencesEditor internal constructor( /** * Enable hyphenation for latin languages. * - * Only effective when: - * - [publisherStyles] is off - * - the layout is LTR + * Only effective when the layout is LTR. */ public val hyphens: Preference = PreferenceDelegate( @@ -165,15 +162,14 @@ public class ReflowableWebPreferencesEditor internal constructor( state.settings.hyphens ?: (state.settings.textAlign == TextAlign.JUSTIFY) }, - getIsEffective = ::isHyphensEffective, + getIsEffective = { state.layout.stylesheets == Layout.Stylesheets.Default }, updateValue = { value -> updateValues { it.copy(hyphens = value) } } ) /** * Filter applied to images in dark theme. * - * Only effective when: - * - the [theme] is set to [Theme.DARK] + * Only effective when the [theme] is set to [Theme.DARK]. */ public val imageFilter: EnumPreference = EnumPreferenceDelegate( @@ -200,15 +196,13 @@ public class ReflowableWebPreferencesEditor internal constructor( /** * Space between letters. * - * Only effective when: - * - [publisherStyles] is off - * - the layout is LTR + * Only effective when the layout is LTR. */ public val letterSpacing: RangePreference = RangePreferenceDelegate( getValue = { preferences.letterSpacing }, getEffectiveValue = { state.settings.letterSpacing ?: 0.0 }, - getIsEffective = ::isLetterSpacingEffective, + getIsEffective = { state.layout.stylesheets == Layout.Stylesheets.Default }, updateValue = { value -> updateValues { it.copy(letterSpacing = value) } }, supportedRange = 0.0..1.0, progressionStrategy = DoubleIncrement(0.1), @@ -218,29 +212,24 @@ public class ReflowableWebPreferencesEditor internal constructor( /** * Enable ligatures in Arabic. * - * Only effective when: - * - [publisherStyles] is off - * - the layout is RTL + * Only effective when the layout is RTL. */ public val ligatures: Preference = PreferenceDelegate( getValue = { preferences.ligatures }, - getEffectiveValue = { state.settings.ligatures ?: false }, - getIsEffective = ::isLigaturesEffective, + getEffectiveValue = { state.settings.ligatures == true }, + getIsEffective = { state.layout.stylesheets == Layout.Stylesheets.Rtl }, updateValue = { value -> updateValues { it.copy(ligatures = value) } } ) /** * Leading line height. - * - * Only effective when: - * - [publisherStyles] is off */ public val lineHeight: RangePreference = RangePreferenceDelegate( getValue = { preferences.lineHeight }, getEffectiveValue = { state.settings.lineHeight ?: 1.2 }, - getIsEffective = { !state.settings.publisherStyles }, + getIsEffective = { true }, updateValue = { value -> updateValues { it.copy(lineHeight = value) } }, supportedRange = 1.0..2.0, progressionStrategy = DoubleIncrement(0.1), @@ -264,9 +253,7 @@ public class ReflowableWebPreferencesEditor internal constructor( /** * Text indentation for paragraphs. * - * Only effective when: - * - [publisherStyles] is off - * - the layout is LTR or RTL + * Only effective when the layout is LTR or RTL. */ public val paragraphIndent: RangePreference = RangePreferenceDelegate( @@ -281,33 +268,18 @@ public class ReflowableWebPreferencesEditor internal constructor( /** * Vertical margins for paragraphs. - * - * Only effective when: - * - [publisherStyles] is off */ public val paragraphSpacing: RangePreference = RangePreferenceDelegate( getValue = { preferences.paragraphSpacing }, getEffectiveValue = { state.settings.paragraphSpacing ?: 0.0 }, - getIsEffective = { !state.settings.publisherStyles }, + getIsEffective = { true }, updateValue = { value -> updateValues { it.copy(paragraphSpacing = value) } }, supportedRange = 0.0..2.0, progressionStrategy = DoubleIncrement(0.1), valueFormatter = percentFormatter() ) - /** - * Indicates whether the original publisher styles should be observed. Many advanced settings - * require this to be off. - */ - public val publisherStyles: Preference = - PreferenceDelegate( - getValue = { preferences.publisherStyles }, - getEffectiveValue = { state.settings.publisherStyles }, - getIsEffective = { true }, - updateValue = { value -> updateValues { it.copy(publisherStyles = value) } } - ) - /** * Direction of the reading progression across resources. * @@ -326,8 +298,7 @@ public class ReflowableWebPreferencesEditor internal constructor( * Indicates if the overflow of resources should be handled using scrolling instead of synthetic * pagination. * - * Only effective when: - * - [verticalText] is off + * Only effective when [verticalText] is off. */ public val scroll: Preference = PreferenceDelegate( @@ -340,9 +311,7 @@ public class ReflowableWebPreferencesEditor internal constructor( /** * Page text alignment. * - * Only effective when: - * - [publisherStyles] is off - * - the layout is LTR or RTL + * Only effective when the layout is LTR or RTL. */ public val textAlign: EnumPreference = EnumPreferenceDelegate( @@ -413,14 +382,13 @@ public class ReflowableWebPreferencesEditor internal constructor( /** * Space between words. * - * Only effective when: - * - the layout is LTR + * Only effective when the layout is LTR. */ public val wordSpacing: RangePreference = RangePreferenceDelegate( getValue = { preferences.wordSpacing }, getEffectiveValue = { state.settings.wordSpacing ?: 0.0 }, - getIsEffective = ::isWordSpacingEffective, + getIsEffective = { state.layout.stylesheets == Layout.Stylesheets.Default }, updateValue = { value -> updateValues { it.copy(wordSpacing = value) } }, supportedRange = 0.0..1.0, progressionStrategy = DoubleIncrement(0.1), @@ -446,27 +414,9 @@ public class ReflowableWebPreferencesEditor internal constructor( ) } - private fun isHyphensEffective() = - state.layout.stylesheets == Layout.Stylesheets.Default && - !state.settings.publisherStyles - - private fun isLetterSpacingEffective() = - state.layout.stylesheets == Layout.Stylesheets.Default && - !state.settings.publisherStyles - - private fun isLigaturesEffective() = - state.layout.stylesheets == Layout.Stylesheets.Rtl && - !state.settings.publisherStyles - private fun isParagraphIndentEffective() = - state.layout.stylesheets in listOf(Layout.Stylesheets.Default, Layout.Stylesheets.Rtl) && - !state.settings.publisherStyles + state.layout.stylesheets in listOf(Layout.Stylesheets.Default, Layout.Stylesheets.Rtl) private fun isTextAlignEffective() = - state.layout.stylesheets in listOf(Layout.Stylesheets.Default, Layout.Stylesheets.Rtl) && - !state.settings.publisherStyles - - private fun isWordSpacingEffective(): Boolean = - state.layout.stylesheets == Layout.Stylesheets.Default && - !state.settings.publisherStyles + state.layout.stylesheets in listOf(Layout.Stylesheets.Default, Layout.Stylesheets.Rtl) } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettings.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettings.kt index 22899d020a..1026ffdbc1 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettings.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettings.kt @@ -11,7 +11,6 @@ import org.readium.r2.navigator.preferences.Configurable import org.readium.r2.navigator.preferences.FontFamily import org.readium.r2.navigator.preferences.ImageFilter import org.readium.r2.navigator.preferences.ReadingProgression -import org.readium.r2.navigator.preferences.Spread import org.readium.r2.navigator.preferences.TextAlign import org.readium.r2.navigator.preferences.Theme import org.readium.r2.shared.ExperimentalReadiumApi @@ -33,10 +32,8 @@ public data class ReflowableWebSettings( val horizontalMargins: Double, val paragraphIndent: Double?, val paragraphSpacing: Double?, - val publisherStyles: Boolean, val readingProgression: ReadingProgression, val scroll: Boolean, - val spread: Spread, val textAlign: TextAlign?, val textColor: Color?, val textNormalization: Boolean, diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettingsResolver.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettingsResolver.kt index 689fc1b729..2d153b2a57 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettingsResolver.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebSettingsResolver.kt @@ -9,7 +9,6 @@ package org.readium.navigator.web.preferences import org.readium.navigator.web.util.isCjk import org.readium.navigator.web.util.isRtl import org.readium.r2.navigator.preferences.ReadingProgression -import org.readium.r2.navigator.preferences.Spread import org.readium.r2.navigator.preferences.Theme import org.readium.r2.shared.ExperimentalReadiumApi import org.readium.r2.shared.publication.Metadata @@ -53,10 +52,8 @@ internal class ReflowableWebSettingsResolver( horizontalMargins = preferences.horizontalMargins ?: defaults.pageMargins ?: 1.0, paragraphIndent = preferences.paragraphIndent ?: defaults.paragraphIndent, paragraphSpacing = preferences.paragraphSpacing ?: defaults.paragraphSpacing, - publisherStyles = preferences.publisherStyles ?: defaults.publisherStyles ?: true, readingProgression = readingProgression, scroll = scroll, - spread = preferences.spread ?: defaults.spread ?: Spread.NEVER, textAlign = preferences.textAlign ?: defaults.textAlign, textColor = preferences.textColor, textNormalization = preferences.textNormalization ?: defaults.textNormalization ?: false, From 1cb097d3306df3ec2858e47a90b557f6dcadba8c Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Thu, 10 Apr 2025 21:07:13 +0200 Subject: [PATCH 32/88] Clean up --- .../navigator/web/FixedWebRendition.kt | 6 +- .../navigator/web/ReflowableWebRendition.kt | 6 +- .../web/css/FontFamilyDeclaration.kt | 5 +- .../readium/navigator/web/css/ReadiumCss.kt | 3 +- .../web/fixed/FixedPagingLayoutInfo.kt | 2 +- .../navigator/web/layout/LayoutResolver.kt | 3 +- .../FlingBehavior.kt} | 179 ++++-- .../pager/LoggingNestedScrollConnection.kt | 43 -- .../web/pager/LoggingTargetedFlingBehavior.kt | 27 - .../web/pager/PageNestedScrollConnection.kt | 38 -- .../navigator/web/pager/PageScrollState.kt | 15 - .../web/pager/PagerNestedScrollConnection.kt | 155 ------ .../navigator/web/pager/RenditionPager.kt | 105 ++-- .../navigator/web/pager/ScrollDispatcher.kt | 163 +++++- .../web/pager/ScrollDispatcherImpl.kt | 160 ------ .../reflowable/ReflowablePagingLayoutInfo.kt | 2 +- .../LazyListSnapLayoutInfoProvider.kt | 42 -- .../web/snapping/PagingFlingBehavior.kt | 282 ---------- .../web/snapping/SnapFlingBehavior.kt | 522 ------------------ 19 files changed, 355 insertions(+), 1403 deletions(-) rename readium/navigators/web/src/main/java/org/readium/navigator/web/{snapping/PagerSnapLayoutInfoProvider.kt => pager/FlingBehavior.kt} (62%) delete mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/pager/LoggingNestedScrollConnection.kt delete mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/pager/LoggingTargetedFlingBehavior.kt delete mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/pager/PageNestedScrollConnection.kt delete mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/pager/PageScrollState.kt delete mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/pager/PagerNestedScrollConnection.kt delete mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollDispatcherImpl.kt delete mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/LazyListSnapLayoutInfoProvider.kt delete mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/PagingFlingBehavior.kt delete mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/SnapFlingBehavior.kt diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt index f9fda81dea..30d5c9ce86 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt @@ -43,7 +43,8 @@ import org.readium.navigator.web.layout.DoubleViewportSpread import org.readium.navigator.web.layout.SingleViewportSpread import org.readium.navigator.web.location.FixedWebLocation import org.readium.navigator.web.pager.RenditionPager -import org.readium.navigator.web.pager.ScrollDispatcherImpl +import org.readium.navigator.web.pager.ScrollDispatcher +import org.readium.navigator.web.pager.pagingFlingBehavior import org.readium.navigator.web.util.AbsolutePaddingValues import org.readium.navigator.web.util.DisplayArea import org.readium.navigator.web.util.WebViewServer @@ -52,7 +53,6 @@ import org.readium.r2.shared.ExperimentalReadiumApi import org.readium.r2.shared.util.AbsoluteUrl import org.readium.r2.shared.util.RelativeUrl import org.readium.r2.shared.util.Url -import pagingFlingBehavior @SuppressLint("UnusedBoxWithConstraintsScope") @ExperimentalReadiumApi @@ -119,7 +119,7 @@ public fun FixedWebRendition( }.toFling2DBehavior(Orientation.Horizontal) val scrollDispatcher = remember(state, scrollStates) { - ScrollDispatcherImpl( + ScrollDispatcher( pagerState = state.pagerState, resourceStates = scrollStates, flingBehavior = flingBehavior, diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt index f11667b1ff..5cd466fec3 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt @@ -39,7 +39,8 @@ import org.readium.navigator.common.defaultInputListener import org.readium.navigator.web.gestures.toFling2DBehavior import org.readium.navigator.web.location.ReflowableWebLocation import org.readium.navigator.web.pager.RenditionPager -import org.readium.navigator.web.pager.ScrollDispatcherImpl +import org.readium.navigator.web.pager.ScrollDispatcher +import org.readium.navigator.web.pager.pagingFlingBehavior import org.readium.navigator.web.reflowable.ReflowablePagingLayoutInfo import org.readium.navigator.web.reflowable.ReflowableResource import org.readium.navigator.web.util.AbsolutePaddingValues @@ -49,7 +50,6 @@ import org.readium.r2.shared.ExperimentalReadiumApi import org.readium.r2.shared.util.AbsoluteUrl import org.readium.r2.shared.util.RelativeUrl import org.readium.r2.shared.util.Url -import pagingFlingBehavior @SuppressLint("UnusedBoxWithConstraintsScope") @ExperimentalReadiumApi @@ -136,7 +136,7 @@ public fun ReflowableWebRendition( }.toFling2DBehavior(orientation) val scrollDispatcher = remember(state) { - ScrollDispatcherImpl( + ScrollDispatcher( pagerState = state.pagerState, resourceStates = state.resourceStates, flingBehavior = flingBehavior, diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/FontFamilyDeclaration.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/FontFamilyDeclaration.kt index 2bcb702818..469bc22d8a 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/FontFamilyDeclaration.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/FontFamilyDeclaration.kt @@ -4,6 +4,8 @@ * available in the top-level LICENSE file of the project. */ +@file:OptIn(ExperimentalReadiumApi::class) + package org.readium.navigator.web.css import org.readium.r2.shared.ExperimentalReadiumApi @@ -16,7 +18,6 @@ import org.readium.r2.shared.util.Url * @param alternates Specifies a list of alternative font families used as fallbacks when symbols * are missing from [fontFamily]. */ -@ExperimentalReadiumApi internal fun buildFontFamilyDeclaration( fontFamily: String, alternates: List, @@ -30,7 +31,6 @@ internal fun buildFontFamilyDeclaration( * @param alternates Specifies a list of alternative font families used as fallbacks when symbols * are missing from [fontFamily]. */ -@ExperimentalReadiumApi internal data class FontFamilyDeclaration( val fontFamily: String, val alternates: List, @@ -40,7 +40,6 @@ internal data class FontFamilyDeclaration( /** * An immutable font face declaration. */ -@ExperimentalReadiumApi internal data class FontFaceDeclaration( val fontFamily: String, val sources: List, diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCss.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCss.kt index 5942fde1dc..b70ba66fb8 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCss.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCss.kt @@ -4,6 +4,8 @@ * available in the top-level LICENSE file of the project. */ +@file:OptIn(ExperimentalReadiumApi::class) + package org.readium.navigator.web.css import androidx.core.net.toUri @@ -25,7 +27,6 @@ import org.readium.r2.shared.util.Either import org.readium.r2.shared.util.RelativeUrl import org.readium.r2.shared.util.Url -@ExperimentalReadiumApi internal data class ReadiumCss( val layout: Layout = Layout(language = null, Layout.Stylesheets.Default, ReadingProgression.LTR), val rsProperties: RsProperties = RsProperties(), diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/FixedPagingLayoutInfo.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/FixedPagingLayoutInfo.kt index a92c8e2a3a..30bf1853d9 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/FixedPagingLayoutInfo.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/FixedPagingLayoutInfo.kt @@ -11,7 +11,7 @@ import androidx.compose.foundation.pager.PagerState import androidx.compose.ui.geometry.Offset import androidx.compose.ui.unit.Density import org.readium.navigator.web.pager.PageScrollState -import org.readium.navigator.web.snapping.PagingLayoutInfo +import org.readium.navigator.web.pager.PagingLayoutInfo internal class FixedPagingLayoutInfo( private val pagerState: PagerState, diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/layout/LayoutResolver.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/layout/LayoutResolver.kt index b7a68f1977..6adb8fc9ee 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/layout/LayoutResolver.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/layout/LayoutResolver.kt @@ -4,6 +4,8 @@ * available in the top-level LICENSE file of the project. */ +@file:OptIn(ExperimentalReadiumApi::class) + package org.readium.navigator.web.layout import org.readium.navigator.web.fixed.FixedWebPublication @@ -12,7 +14,6 @@ import org.readium.r2.navigator.preferences.ReadingProgression import org.readium.r2.shared.ExperimentalReadiumApi import org.readium.r2.shared.publication.presentation.Presentation -@OptIn(ExperimentalReadiumApi::class) internal class LayoutResolver( private val readingOrder: FixedWebPublication.ReadingOrder, ) { diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/PagerSnapLayoutInfoProvider.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/FlingBehavior.kt similarity index 62% rename from readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/PagerSnapLayoutInfoProvider.kt rename to readium/navigators/web/src/main/java/org/readium/navigator/web/pager/FlingBehavior.kt index 9e2ed58913..c7ef178902 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/PagerSnapLayoutInfoProvider.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/FlingBehavior.kt @@ -20,12 +20,27 @@ * limitations under the License. */ -package org.readium.navigator.web.snapping - +package org.readium.navigator.web.pager + +import android.annotation.SuppressLint +import androidx.annotation.FloatRange +import androidx.compose.animation.core.AnimationSpec +import androidx.compose.animation.core.DecayAnimationSpec +import androidx.compose.animation.core.Spring +import androidx.compose.animation.core.VisibilityThreshold +import androidx.compose.animation.core.spring +import androidx.compose.animation.rememberSplineBasedDecay import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.gestures.FlingBehavior import androidx.compose.foundation.gestures.Orientation +import androidx.compose.foundation.gestures.TargetedFlingBehavior import androidx.compose.foundation.gestures.snapping.SnapLayoutInfoProvider +import androidx.compose.foundation.gestures.snapping.snapFlingBehavior +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp @@ -51,16 +66,80 @@ internal interface PagingLayoutInfo { val canScrollBackward: Boolean } -internal fun SnapLayoutInfoProvider( +/** + * A [snapFlingBehavior] that will snap pages to the start of the layout. One can use the + * given parameters to control how the snapping animation will happen. + * @see snapFlingBehavior for more information + * on what which parameter controls in the overall snapping animation. + * @param layoutInfo The [PagingLayoutInfo] that describes the pager layout. + * @param snapAnimationSpec The animation spec used to finally snap to the position. This + * animation will be often used in 2 cases: 1) There was enough space to an approach animation, + * the Pager will use [snapAnimationSpec] in the last step of the animation to settle the page + * into position. 2) There was not enough space to run the approach animation. + * @param snapPositionalThreshold If the fling has a low velocity (e.g. slow scroll), + * this fling behavior will use this snap threshold in order to determine if the pager should + * snap back or move forward. Use a number between 0 and 1 as a fraction of the page size that + * needs to be scrolled before the Pager considers it should move to the next page. + * For instance, if snapPositionalThreshold = 0.35, it means if this pager is scrolled with a + * slow velocity and the Pager scrolls more than 35% of the page size, then will jump to the + * next page, if not it scrolls back. + * Note that any fling that has high enough velocity will *always* move to the next page + * in the direction of the fling. + * + * @return An instance of [FlingBehavior] that will perform Snapping to the next page by + * default. + */ +@Composable +internal fun pagingFlingBehavior( + layoutInfo: PagingLayoutInfo, + decayAnimationSpec: DecayAnimationSpec = rememberSplineBasedDecay(), + snapAnimationSpec: AnimationSpec = spring( + stiffness = Spring.StiffnessMediumLow, + visibilityThreshold = Int.VisibilityThreshold.toFloat() + ), + @FloatRange(from = 0.0, to = 1.0) snapPositionalThreshold: Float = 0.5f, +): TargetedFlingBehavior { + require(snapPositionalThreshold in 0f..1f) { + "snapPositionalThreshold should be a number between 0 and 1. " + + "You've specified $snapPositionalThreshold" + } + + val density = LocalDensity.current + val layoutDirection = LocalLayoutDirection.current + return remember( + layoutInfo, + decayAnimationSpec, + snapAnimationSpec, + density, + layoutDirection + ) { + val snapLayoutInfoProvider = + SnapLayoutInfoProvider( + layoutInfo, + ) { flingVelocity, lowerBound, upperBound -> + calculateFinalSnappingBound( + pagingLayoutInfo = layoutInfo, + layoutDirection = layoutDirection, + snapPositionalThreshold = snapPositionalThreshold, + flingVelocity = flingVelocity, + lowerBoundOffset = lowerBound, + upperBoundOffset = upperBound + ) + } + snapFlingBehavior( + snapLayoutInfoProvider = snapLayoutInfoProvider, + decayAnimationSpec = decayAnimationSpec, + snapAnimationSpec = snapAnimationSpec + ) + } +} + +private fun SnapLayoutInfoProvider( pagingLayoutInfo: PagingLayoutInfo, calculateFinalSnappingBound: (Float, Float, Float) -> Float, ): SnapLayoutInfoProvider { return object : SnapLayoutInfoProvider { - fun Float.isValidDistance(): Boolean { - return this != Float.POSITIVE_INFINITY && this != Float.NEGATIVE_INFINITY - } - override fun calculateSnapOffset(velocity: Float): Float { Timber.d("Fling calculateSnapOffset $velocity") val (lowerBoundOffset, upperBoundOffset) = searchForSnappingBounds() @@ -83,9 +162,9 @@ internal fun SnapLayoutInfoProvider( "Final Snapping Offset Should Be one of $lowerBoundOffset, $upperBoundOffset or 0.0" } - debugLog { "Snapping to=$finalDistance" } + Timber.d("Snapping to=$finalDistance") - return if (finalDistance.isValidDistance()) { + return if (finalDistance.isFinite()) { finalDistance } else { 0f @@ -98,7 +177,7 @@ internal fun SnapLayoutInfoProvider( ): Float = 0f private fun searchForSnappingBounds(): Pair { - debugLog { "Calculating Snapping Bounds" } + Timber.d("Calculating Snapping Bounds") var lowerBoundOffset = Float.NEGATIVE_INFINITY var upperBoundOffset = Float.POSITIVE_INFINITY @@ -150,33 +229,13 @@ internal fun SnapLayoutInfoProvider( } } -private fun PagingLayoutInfo.isLtrDragging() = dragGestureDelta() > 0 -private fun PagingLayoutInfo.isScrollingForward(): Boolean { - val reverseScrollDirection = reverseLayout - return ( - isLtrDragging() && reverseScrollDirection || - !isLtrDragging() && !reverseScrollDirection - ) -} - -private fun PagingLayoutInfo.dragGestureDelta() = if (orientation == Orientation.Horizontal) { - upDownDifference.x -} else { - upDownDifference.y -} - -private inline fun debugLog(generateMsg: () -> String) { - if (debug) { - println("PagerSnapLayoutInfoProvider: ${generateMsg()}") - } -} - /** * Given two possible bounds that this Pager can settle in represented by [lowerBoundOffset] and * [upperBoundOffset], this function will decide which one of them it will settle to. */ +@SuppressLint("BinaryOperationInTimber") @OptIn(ExperimentalFoundationApi::class) -internal fun calculateFinalSnappingBound( +private fun calculateFinalSnappingBound( pagingLayoutInfo: PagingLayoutInfo, layoutDirection: LayoutDirection, snapPositionalThreshold: Float, @@ -193,11 +252,11 @@ internal fun calculateFinalSnappingBound( !pagingLayoutInfo.isScrollingForward() } } - debugLog { + Timber.d( "isLtrDragging=${pagingLayoutInfo.isLtrDragging()} " + "isForward=$isForward " + "layoutDirection=$layoutDirection" - } + ) // how many pages have I scrolled using a drag gesture. val pageSize = pagingLayoutInfo.pageSize val offsetFromSnappedPosition = @@ -216,17 +275,17 @@ internal fun calculateFinalSnappingBound( val finalSnappingItem = with(pagingLayoutInfo.density) { calculateFinalSnappingItem(flingVelocity) } - debugLog { + Timber.d( "\nfinalSnappingItem=$finalSnappingItem" + "\nlower=$lowerBoundOffset" + "\nupper=$upperBoundOffset" - } + ) return when (finalSnappingItem) { FinalSnappingItem.ClosestItem -> { if (offsetFromSnappedPositionOverflow.absoluteValue > snapPositionalThreshold) { // If we crossed the threshold, go to the next bound - debugLog { "Crossed Snap Positional Threshold" } + Timber.d("Crossed Snap Positional Threshold") if (isForward) upperBoundOffset else lowerBoundOffset } else { // if we haven't crossed the threshold. but scrolled minimally, we should @@ -234,11 +293,11 @@ internal fun calculateFinalSnappingBound( if (abs(offsetFromSnappedPosition) >= abs(pagingLayoutInfo.positionThresholdFraction) ) { - debugLog { "Crossed Positional Threshold Fraction" } + Timber.d("Crossed Positional Threshold Fraction") if (isForward) lowerBoundOffset else upperBoundOffset } else { // if we haven't scrolled minimally, settle for the closest bound - debugLog { "Snap To Closest" } + Timber.d("Snap To Closest") if (lowerBoundOffset.absoluteValue < upperBoundOffset.absoluteValue) { lowerBoundOffset } else { @@ -254,6 +313,44 @@ internal fun calculateFinalSnappingBound( } } -private val debug: Boolean = false - internal val DefaultPositionThreshold = 56.dp + +@JvmInline +private value class FinalSnappingItem( + @Suppress("unused") private val value: Int, +) { + companion object { + + val ClosestItem: FinalSnappingItem = FinalSnappingItem(0) + + val NextItem: FinalSnappingItem = FinalSnappingItem(1) + + val PreviousItem: FinalSnappingItem = FinalSnappingItem(2) + } +} + +private fun Density.calculateFinalSnappingItem(velocity: Float): FinalSnappingItem { + return if (velocity.absoluteValue < MinFlingVelocityDp.toPx()) { + FinalSnappingItem.ClosestItem + } else { + if (velocity > 0) FinalSnappingItem.NextItem else FinalSnappingItem.PreviousItem + } +} + +private val MinFlingVelocityDp = 400.dp + +private fun PagingLayoutInfo.isLtrDragging() = dragGestureDelta() > 0 + +private fun PagingLayoutInfo.isScrollingForward(): Boolean { + val reverseScrollDirection = reverseLayout + return ( + isLtrDragging() && reverseScrollDirection || + !isLtrDragging() && !reverseScrollDirection + ) +} + +private fun PagingLayoutInfo.dragGestureDelta() = if (orientation == Orientation.Horizontal) { + upDownDifference.x +} else { + upDownDifference.y +} diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/LoggingNestedScrollConnection.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/LoggingNestedScrollConnection.kt deleted file mode 100644 index 22ba5ee883..0000000000 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/LoggingNestedScrollConnection.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2024 Readium Foundation. All rights reserved. - * Use of this source code is governed by the BSD-style license - * available in the top-level LICENSE file of the project. - */ - -package org.readium.navigator.web.pager - -import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.input.nestedscroll.NestedScrollConnection -import androidx.compose.ui.input.nestedscroll.NestedScrollSource -import androidx.compose.ui.unit.Velocity -import timber.log.Timber - -@Suppress("unused") -internal class LoggingNestedScrollConnection( - private val delegateNestedScrollConnection: NestedScrollConnection, -) : NestedScrollConnection { - - override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity { - Timber.d("onPostFling consumed $consumed, available $available") - return delegateNestedScrollConnection.onPostFling(consumed, available) - } - - override fun onPostScroll( - consumed: Offset, - available: Offset, - source: NestedScrollSource, - ): Offset { - Timber.d("onPostScroll consumed, $consumed, available $available") - return delegateNestedScrollConnection.onPostScroll(consumed, available, source) - } - - override suspend fun onPreFling(available: Velocity): Velocity { - Timber.d("onPreFling available $available") - return delegateNestedScrollConnection.onPreFling(available) - } - - override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { - Timber.d("onPreScroll available $available") - return delegateNestedScrollConnection.onPreScroll(available, source) - } -} diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/LoggingTargetedFlingBehavior.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/LoggingTargetedFlingBehavior.kt deleted file mode 100644 index b98423af33..0000000000 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/LoggingTargetedFlingBehavior.kt +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2024 Readium Foundation. All rights reserved. - * Use of this source code is governed by the BSD-style license - * available in the top-level LICENSE file of the project. - */ - -package org.readium.navigator.web.pager - -import androidx.compose.foundation.gestures.ScrollScope -import androidx.compose.foundation.gestures.TargetedFlingBehavior -import timber.log.Timber - -@Suppress("unused") -internal class LoggingTargetedFlingBehavior( - private val delegate: TargetedFlingBehavior, -) : TargetedFlingBehavior { - - override suspend fun ScrollScope.performFling( - initialVelocity: Float, - onRemainingDistanceUpdated: (Float) -> Unit, - ): Float { - Timber.d("performFling $initialVelocity") - return with(delegate) { - performFling(initialVelocity, onRemainingDistanceUpdated) - } - } -} diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/PageNestedScrollConnection.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/PageNestedScrollConnection.kt deleted file mode 100644 index c71b2c262f..0000000000 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/PageNestedScrollConnection.kt +++ /dev/null @@ -1,38 +0,0 @@ -package org.readium.navigator.web.pager - -import androidx.compose.foundation.pager.PagerState -import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.input.nestedscroll.NestedScrollConnection -import androidx.compose.ui.input.nestedscroll.NestedScrollSource -import androidx.compose.ui.util.fastCoerceAtLeast -import androidx.compose.ui.util.fastCoerceAtMost - -internal class PageNestedScrollConnection( - private val index: Int, - private val pagerState: PagerState, -) : NestedScrollConnection { - - override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { - if (source != NestedScrollSource.UserInput) { - return Offset.Zero - } - - val pageInfo = pagerState.layoutInfo.visiblePagesInfo.firstOrNull { it.index == index } - ?: return Offset.Zero - - // If the current resource doesn't start with the pager (i.e pageInfo.offset != 0), allow - // the pager to scroll just as much as needed to make this resource the only visible one. - // If the user moves in the opposite direction, do not allow the pager to move of course. - val availableForPager = when { - available.x > 0 && pageInfo.offset < 0 -> - available.x.fastCoerceAtMost(-pageInfo.offset.toFloat()) - available.x < 0 && pageInfo.offset > 0 -> - available.x.fastCoerceAtLeast(-pageInfo.offset.toFloat()) - else -> - 0f - } - - val consumed = -pagerState.dispatchRawDelta(-availableForPager) - return Offset(consumed, 0f) - } -} diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/PageScrollState.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/PageScrollState.kt deleted file mode 100644 index e34cb21daa..0000000000 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/PageScrollState.kt +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright 2024 Readium Foundation. All rights reserved. - * Use of this source code is governed by the BSD-style license - * available in the top-level LICENSE file of the project. - */ - -package org.readium.navigator.web.pager - -import androidx.compose.runtime.MutableState -import org.readium.navigator.web.webview.WebViewScrollController - -internal interface PageScrollState { - - val scrollController: MutableState -} diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/PagerNestedScrollConnection.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/PagerNestedScrollConnection.kt deleted file mode 100644 index b597d9150d..0000000000 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/PagerNestedScrollConnection.kt +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright 2024 Readium Foundation. All rights reserved. - * Use of this source code is governed by the BSD-style license - * available in the top-level LICENSE file of the project. - */ - -package org.readium.navigator.web.pager - -import androidx.compose.foundation.MutatePriority -import androidx.compose.foundation.gestures.FlingBehavior -import androidx.compose.foundation.gestures.Orientation -import androidx.compose.foundation.pager.PagerState -import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.input.nestedscroll.NestedScrollConnection -import androidx.compose.ui.input.nestedscroll.NestedScrollSource -import androidx.compose.ui.unit.Velocity -import kotlin.math.abs -import timber.log.Timber - -internal class PagerNestedScrollConnection( - private val state: PagerState, - private val flingBehavior: FlingBehavior, - private val orientation: Orientation, -) : NestedScrollConnection { - - private var consumedCrossAxis = false - - private val PagerState.firstVisibleOffset get() = - layoutInfo.visiblePagesInfo.first().offset - - private val PagerState.lastVisibleOffset get() = - layoutInfo.visiblePagesInfo.last().offset - - /*override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { - if (source != NestedScrollSource.UserInput) { - return Offset.Zero - } - - if (state.layoutInfo.visiblePagesInfo.size <= 1) { - return Offset.Zero - } - - // rounding and drag only - if (source != NestedScrollSource.UserInput || abs(state.currentPageOffsetFraction) < 1e-6) { - return Offset.Zero - } - - val delta = if (orientation == Orientation.Horizontal) available.x else available.y - - val minBound = -(state.layoutInfo.pageSize + state.firstVisibleOffset).toFloat() - - val maxBound = (state.layoutInfo.pageSize - state.lastVisibleOffset).toFloat() - - val coerced = delta.coerceIn(minBound, maxBound) - val consumed = -state.dispatchRawDelta(-coerced) - - return Offset( - x = if (orientation == Orientation.Horizontal) consumed else available.x, - y = if (orientation == Orientation.Vertical) consumed else available.y - ) - }*/ - - override suspend fun onPreFling(available: Velocity): Velocity { - if (state.layoutInfo.visiblePagesInfo.size > 1) { - val availableDir = - if (orientation == Orientation.Horizontal) available.x else available.y - - var remaining: Float = availableDir - state.scroll(scrollPriority = MutatePriority.Default) { - with(flingBehavior) { - remaining = -performFling(-availableDir) - } - } - - val consumed = - if ((availableDir - remaining).isNaN()) { - availableDir - } else { - availableDir - remaining - } - - return Velocity( - x = if (orientation == Orientation.Horizontal) consumed else 0f, - y = if (orientation == Orientation.Vertical) consumed else 0f - ) - } - - return Velocity.Zero - } - - override fun onPostScroll( - consumed: Offset, - available: Offset, - source: NestedScrollSource, - ): Offset { - if (orientation == Orientation.Horizontal && abs(consumed.y) > 0 || - orientation == Orientation.Vertical && abs(consumed.x) > 0 - ) { - consumedCrossAxis = true - return Offset.Zero - } - - if (source != NestedScrollSource.UserInput) { - return Offset.Zero - } - - val availableDir = - if (orientation == Orientation.Horizontal) available.x else available.y - - val consumed = -state.dispatchRawDelta(-availableDir) - Timber.d("pager onPostScroll available ${available.x} consumedNow $consumed") - return Offset( - x = if (orientation == Orientation.Horizontal) consumed else 0f, - y = if (orientation == Orientation.Vertical) consumed else 0f - ) - } - - override suspend fun onPostFling( - consumed: Velocity, - available: Velocity, - ): Velocity { - if (consumedCrossAxis) { - consumedCrossAxis = false - return Velocity.Zero - } - - // fling has a weird behavior when velocity is null. Surprisingly, it doesn't snap to - // the closest position. It doesn't seem to be an issue in onPreFling though. - if (available == Velocity.Zero) { - return available - } - - val availableDir = - if (orientation == Orientation.Horizontal) available.x else available.y - - var remaining = availableDir - state.scroll(scrollPriority = MutatePriority.Default) { - with(flingBehavior) { - remaining = -performFling(-availableDir) - } - } - - val consumed = - if ((availableDir - remaining).isNaN()) { - availableDir - } else { - availableDir - remaining - } - - return Velocity( - x = if (orientation == Orientation.Horizontal) consumed else available.x, - y = if (orientation == Orientation.Vertical) consumed else available.y - ) - } -} diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/RenditionPager.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/RenditionPager.kt index 5388559b06..525bd935c3 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/RenditionPager.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/RenditionPager.kt @@ -9,85 +9,102 @@ package org.readium.navigator.web.pager import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.gestures.ScrollScope import androidx.compose.foundation.gestures.TargetedFlingBehavior -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.PagerScope import androidx.compose.foundation.pager.PagerState import androidx.compose.foundation.pager.VerticalPager import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Offset import androidx.compose.ui.input.nestedscroll.NestedScrollConnection +import androidx.compose.ui.input.nestedscroll.NestedScrollSource import androidx.compose.ui.input.nestedscroll.nestedScroll +import androidx.compose.ui.unit.Velocity @Composable internal fun RenditionPager( modifier: Modifier = Modifier, state: PagerState, - scrollDispatcher: ScrollDispatcher? = null, + scrollDispatcher: ScrollDispatcher, orientation: Orientation, reverseLayout: Boolean, - beyondViewportPageCount: Int = 2, + beyondViewportPageCount: Int, key: ((index: Int) -> Any)? = null, pageContent: @Composable PagerScope.(Int) -> Unit, ) { - val flingBehavior = /*PagerDefaults.flingBehavior( - state = state, - pagerSnapDistance = PagerSnapDistance.atMost(0) - ) */ object : TargetedFlingBehavior { - override suspend fun ScrollScope.performFling( - initialVelocity: Float, - onRemainingDistanceUpdated: (Float) -> Unit, - ): Float { - return initialVelocity - } - } + // A nested scroll connection is the only way to get separate drag and fling events + // from the scrollable modifiers. So we catch all events in the "post phase" and pass them to + // the provided ScrollDispatcher for processing. + val scrollDispatcherNestedScrollConnection = + ScrollDispatcherNestedScrollConnection(scrollDispatcher) - val nestedScrollConnection = object : NestedScrollConnection { - } /*PagerNestedScrollConnection( - state, - flingBehavior, - orientation - )*/ + val modifier = modifier + .nestedScroll(scrollDispatcherNestedScrollConnection) - val updatedPageContent: @Composable PagerScope.(Int) -> Unit = { index -> - Box( - modifier = Modifier, // .nestedScroll(PageNestedScrollConnection(index, state)), - propagateMinConstraints = true - ) { - pageContent(index) - } - } + // Disable built-in pager behavior as it is not suitable. + val pageNestedScrollConnection = NullNestedScrollConnection - val delegatingNestedScrollConnection = - scrollDispatcher?.let { DelegatingNestedScrollConnection(it) } + // Disable scroll detection built-in in the pager as we need 2D gestures in fixed layout. + val userScrollEnabled = false + val flingBehavior = NullTargetedFlingBehavior if (orientation == Orientation.Horizontal) { HorizontalPager( - modifier = modifier.let { modifier -> delegatingNestedScrollConnection?.let { modifier.nestedScroll(it) } ?: modifier }, - // Pages must intercept all scroll gestures so the pager moves - // only through the PagerNestedScrollConnection. - userScrollEnabled = false, state = state, + modifier = modifier, beyondViewportPageCount = beyondViewportPageCount, - reverseLayout = reverseLayout, flingBehavior = flingBehavior, + userScrollEnabled = userScrollEnabled, key = key, - pageNestedScrollConnection = nestedScrollConnection, - pageContent = updatedPageContent + reverseLayout = reverseLayout, + pageNestedScrollConnection = pageNestedScrollConnection, + pageContent = pageContent ) } else { VerticalPager( - modifier = modifier.let { modifier -> delegatingNestedScrollConnection?.let { modifier.nestedScroll(it) } ?: modifier }, - // Pages must intercept all scroll gestures so the pager moves - // only through the PagerNestedScrollConnection. - userScrollEnabled = false, state = state, + modifier = modifier, beyondViewportPageCount = beyondViewportPageCount, - reverseLayout = reverseLayout, flingBehavior = flingBehavior, + userScrollEnabled = userScrollEnabled, key = key, - pageNestedScrollConnection = nestedScrollConnection, - pageContent = updatedPageContent + reverseLayout = reverseLayout, + pageNestedScrollConnection = pageNestedScrollConnection, + pageContent = pageContent ) } } + +private object NullNestedScrollConnection : NestedScrollConnection + +private class ScrollDispatcherNestedScrollConnection( + private val scrollDispatcher: ScrollDispatcher, +) : NestedScrollConnection { + + override fun onPostScroll( + consumed: Offset, + available: Offset, + source: NestedScrollSource, + ): Offset { + if (source == NestedScrollSource.UserInput) { + scrollDispatcher.onScroll(available) + } + + return available + } + + override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity { + scrollDispatcher.onFling(available) + return available + } +} + +private object NullTargetedFlingBehavior : TargetedFlingBehavior { + + override suspend fun ScrollScope.performFling( + initialVelocity: Float, + onRemainingDistanceUpdated: (Float) -> Unit, + ): Float { + return initialVelocity + } +} diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollDispatcher.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollDispatcher.kt index 69eb5ee7f0..35df48c238 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollDispatcher.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollDispatcher.kt @@ -6,36 +6,157 @@ package org.readium.navigator.web.pager +import androidx.compose.foundation.gestures.Orientation +import androidx.compose.foundation.pager.PagerState +import androidx.compose.runtime.MutableState import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.input.nestedscroll.NestedScrollConnection -import androidx.compose.ui.input.nestedscroll.NestedScrollSource import androidx.compose.ui.unit.Velocity +import androidx.compose.ui.util.fastCoerceAtLeast +import androidx.compose.ui.util.fastCoerceAtMost +import org.readium.navigator.web.gestures.Fling2DBehavior +import org.readium.navigator.web.gestures.Scroll2DScope +import org.readium.navigator.web.webview.WebViewScrollController +import timber.log.Timber -internal interface ScrollDispatcher { +internal interface PageScrollState { - fun onScroll(available: Offset): Offset - - suspend fun onFling(available: Velocity): Velocity + val scrollController: MutableState } -internal class DelegatingNestedScrollConnection( - private val scrollDispatcher: ScrollDispatcher, -) : NestedScrollConnection { - - override fun onPostScroll( - consumed: Offset, - available: Offset, - source: NestedScrollSource, - ): Offset { - if (source == NestedScrollSource.UserInput) { - scrollDispatcher.onScroll(available) +internal class ScrollDispatcher( + private val pagerState: PagerState, + private val resourceStates: List, + internal var pagerOrientation: Orientation, + internal var flingBehavior: Fling2DBehavior, +) : Scroll2DScope { + + override fun scrollBy(available: Offset): Offset { + return -rawScrollBy(-available.mainAxisValue).mainAxisOffset + } + + private fun rawScrollBy(available: Float): Float { + Timber.Forest.d("scrollBy available $available") + var deltaLeft = available + + val firstPage = pagerState.layoutInfo.visiblePagesInfo.first() + + val lastPage = pagerState.layoutInfo.visiblePagesInfo.last() + + val firstTargetPage = when { + available >= 0 -> lastPage + else -> firstPage + } + + val secondTargetPage = when { + available >= 0 -> firstPage + else -> lastPage } - return available + val consumedInFirst = consumeInWebview(firstTargetPage.index, deltaLeft) + deltaLeft -= consumedInFirst + Timber.Forest.d("consumed $consumedInFirst in ${firstTargetPage.index}") + + val availableForPager = + if (firstPage.index == lastPage.index) { + when { + deltaLeft > 0 -> + deltaLeft.fastCoerceAtMost(pagerState.layoutInfo.pageSize.toFloat()) + deltaLeft < 0 -> + deltaLeft.coerceAtLeast(-pagerState.layoutInfo.pageSize.toFloat()) + else -> + 0f + } + } else { + when { + deltaLeft > 0 -> { + deltaLeft.fastCoerceAtMost(-firstPage.offset.toFloat()) + } + deltaLeft < 0 -> { + deltaLeft.fastCoerceAtLeast(-lastPage.offset.toFloat()) + } + else -> + 0f + } + } + + val consumedInPager = -pagerState.dispatchRawDelta(-availableForPager) + deltaLeft -= consumedInPager + Timber.Forest.d("consumed $consumedInPager in pager") + + val consumedInSecond = consumeInWebview(secondTargetPage.index, deltaLeft) + deltaLeft -= consumedInSecond + Timber.Forest.d("consumed $consumedInSecond in ${secondTargetPage.index}") + + Timber.Forest.d("scrollBy left $deltaLeft") + + return when (deltaLeft) { + 0f -> available + available -> 0f + else -> rawScrollBy(deltaLeft) + } } - override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity { - scrollDispatcher.onFling(available) - return available + private fun consumeInWebview(targetPage: Int, available: Float): Float { + val scrollController = resourceStates[targetPage].scrollController.value + ?: return available // WebView is not ready, consume everything. + + return -scrollController.scrollBy(-available.mainAxisOffset).mainAxisValue } + + fun onScroll(available: Offset): Offset { + Timber.Forest.d("onScroll ${available.x}") + return -scrollBy(-available) + } + + suspend fun onFling(available: Velocity): Velocity { + Timber.Forest.d("onFling ${available.x}") + var velocityLeft = available + pagerState.scroll { + with(flingBehavior) { + with(this@ScrollDispatcher) { + velocityLeft = -performFling(-velocityLeft) + } + } + } + + return Velocity( + x = if ((available.x - velocityLeft.x).isNaN()) { + available.x + } else { + available.x - velocityLeft.x + }, + y = if ((available.y - velocityLeft.y).isNaN()) { + available.y + } else { + available.y - velocityLeft.y + } + ) + } + + fun onDocumentResized(index: Int) { + val firstPage = pagerState.layoutInfo.visiblePagesInfo.first() + + val lastPage = pagerState.layoutInfo.visiblePagesInfo.last() + + if (firstPage == lastPage || firstPage.index != index) { + return + } + + val scrollController = resourceStates[index].scrollController.value!! + val scrolled = scrollController.scrollToEnd(pagerOrientation) + if (scrolled > 0) { + rawScrollBy(scrolled.toFloat()) + } + } + + private val Offset.mainAxisValue: Float get() = when (pagerOrientation) { + Orientation.Vertical -> y + Orientation.Horizontal -> x + } + + private val Float.mainAxisOffset: Offset + get() = when (pagerOrientation) { + Orientation.Vertical -> Offset(0f, this) + Orientation.Horizontal -> Offset(this, 0f) + } } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollDispatcherImpl.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollDispatcherImpl.kt deleted file mode 100644 index 3a65a3fb31..0000000000 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollDispatcherImpl.kt +++ /dev/null @@ -1,160 +0,0 @@ -package org.readium.navigator.web.pager - -import androidx.compose.foundation.gestures.Orientation -import androidx.compose.foundation.pager.PagerState -import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.unit.Velocity -import androidx.compose.ui.util.fastCoerceAtLeast -import androidx.compose.ui.util.fastCoerceAtMost -import org.readium.navigator.web.gestures.Fling2DBehavior -import org.readium.navigator.web.gestures.Scroll2DScope -import timber.log.Timber - -internal class ScrollDispatcherImpl( - private val pagerState: PagerState, - private val resourceStates: List, - internal var pagerOrientation: Orientation, - internal var flingBehavior: Fling2DBehavior, -) : ScrollDispatcher, Scroll2DScope { - - override fun scrollBy(available: Offset): Offset { - return -rawScrollBy(-available.mainAxisValue).mainAxisOffset - } - - private fun rawScrollBy(available: Float): Float { - Timber.Forest.d("scrollBy available $available") - var deltaLeft = available - - val firstPage = pagerState.layoutInfo.visiblePagesInfo.first() - - val lastPage = pagerState.layoutInfo.visiblePagesInfo.last() - - val firstTargetPage = when { - available >= 0 -> lastPage - else -> firstPage - } - - val secondTargetPage = when { - available >= 0 -> firstPage - else -> lastPage - } - - val consumedInFirst = consumeInWebview(firstTargetPage.index, deltaLeft) - deltaLeft -= consumedInFirst - Timber.Forest.d("consumed $consumedInFirst in ${firstTargetPage.index}") - - val availableForPager = - if (firstPage.index == lastPage.index) { - when { - deltaLeft > 0 -> - deltaLeft.fastCoerceAtMost(pagerState.layoutInfo.pageSize.toFloat()) - deltaLeft < 0 -> - deltaLeft.coerceAtLeast(-pagerState.layoutInfo.pageSize.toFloat()) - else -> - 0f - } - } else { - when { - deltaLeft > 0 -> { - deltaLeft.fastCoerceAtMost(-firstPage.offset.toFloat()) - } - deltaLeft < 0 -> { - deltaLeft.fastCoerceAtLeast(-lastPage.offset.toFloat()) - } - else -> - 0f - } - } - - val consumedInPager = -pagerState.dispatchRawDelta(-availableForPager) - deltaLeft -= consumedInPager - Timber.Forest.d("consumed $consumedInPager in pager") - - val consumedInSecond = consumeInWebview(secondTargetPage.index, deltaLeft) - deltaLeft -= consumedInSecond - Timber.Forest.d("consumed $consumedInSecond in ${secondTargetPage.index}") - - Timber.Forest.d("scrollBy left $deltaLeft") - - return when (deltaLeft) { - 0f -> available - available -> 0f - else -> rawScrollBy(deltaLeft) - } - } - - private fun consumeInWebview(targetPage: Int, available: Float): Float { - val scrollController = resourceStates[targetPage].scrollController.value - ?: return available // WebView is not ready, consume everything. - - return -scrollController.scrollBy(-available.mainAxisOffset).mainAxisValue - } - - override fun onScroll(available: Offset): Offset { - Timber.Forest.d("onScroll ${available.x}") - return -scrollBy(-available) - } - - override suspend fun onFling(available: Velocity): Velocity { - Timber.Forest.d("onFling ${available.x}") - var velocityLeft = available - pagerState.scroll { - with(flingBehavior) { - with(this@ScrollDispatcherImpl) { - velocityLeft = -performFling(-velocityLeft) - } - } - } - - return Velocity( - x = if ((available.x - velocityLeft.x).isNaN()) { - available.x - } else { - available.x - velocityLeft.x - }, - y = if ((available.y - velocityLeft.y).isNaN()) { - available.y - } else { - available.y - velocityLeft.y - } - ) - } - - fun onDocumentResized(index: Int) { - val firstPage = pagerState.layoutInfo.visiblePagesInfo.first() - - val lastPage = pagerState.layoutInfo.visiblePagesInfo.last() - - if (firstPage == lastPage || firstPage.index != index) { - return - } - - val scrollController = resourceStates[index].scrollController.value!! - val scrolled = scrollController.scrollToEnd(pagerOrientation) - if (scrolled > 0) { - rawScrollBy(scrolled.toFloat()) - } - } - - private val Offset.mainAxisValue: Float get() = when (pagerOrientation) { - Orientation.Vertical -> y - Orientation.Horizontal -> x - } - - private val Velocity.mainAxisValue: Float get() = when (pagerOrientation) { - Orientation.Vertical -> y - Orientation.Horizontal -> x - } - - private val Float.mainAxisOffset: Offset - get() = when (pagerOrientation) { - Orientation.Vertical -> Offset(0f, this) - Orientation.Horizontal -> Offset(this, 0f) - } - - private val Float.mainAxisVelocity: Velocity - get() = when (pagerOrientation) { - Orientation.Vertical -> Velocity(0f, this) - Orientation.Horizontal -> Velocity(this, 0f) - } -} diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowablePagingLayoutInfo.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowablePagingLayoutInfo.kt index d0edc2f1ce..2c5437fd94 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowablePagingLayoutInfo.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowablePagingLayoutInfo.kt @@ -10,7 +10,7 @@ import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.pager.PagerState import androidx.compose.ui.geometry.Offset import androidx.compose.ui.unit.Density -import org.readium.navigator.web.snapping.PagingLayoutInfo +import org.readium.navigator.web.pager.PagingLayoutInfo import timber.log.Timber internal class ReflowablePagingLayoutInfo( diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/LazyListSnapLayoutInfoProvider.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/LazyListSnapLayoutInfoProvider.kt deleted file mode 100644 index 0f4a4ec8ef..0000000000 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/LazyListSnapLayoutInfoProvider.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.readium.navigator.web.snapping - -import androidx.compose.ui.unit.Density -import kotlin.math.absoluteValue - -@JvmInline -internal value class FinalSnappingItem internal constructor( - @Suppress("unused") private val value: Int, -) { - companion object { - - val ClosestItem: FinalSnappingItem = FinalSnappingItem(0) - - val NextItem: FinalSnappingItem = FinalSnappingItem(1) - - val PreviousItem: FinalSnappingItem = FinalSnappingItem(2) - } -} - -internal fun Density.calculateFinalSnappingItem(velocity: Float): FinalSnappingItem { - return if (velocity.absoluteValue < MinFlingVelocityDp.toPx()) { - FinalSnappingItem.ClosestItem - } else { - if (velocity > 0) FinalSnappingItem.NextItem else FinalSnappingItem.PreviousItem - } -} diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/PagingFlingBehavior.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/PagingFlingBehavior.kt deleted file mode 100644 index e21180797f..0000000000 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/PagingFlingBehavior.kt +++ /dev/null @@ -1,282 +0,0 @@ -/* - * Copyright 2024 Readium Foundation. All rights reserved. - * Use of this source code is governed by the BSD-style license - * available in the top-level LICENSE file of the project. - */ - -/* - * Copyright 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import androidx.annotation.FloatRange -import androidx.compose.animation.core.AnimationSpec -import androidx.compose.animation.core.DecayAnimationSpec -import androidx.compose.animation.core.Spring -import androidx.compose.animation.core.VisibilityThreshold -import androidx.compose.animation.core.spring -import androidx.compose.animation.rememberSplineBasedDecay -import androidx.compose.foundation.gestures.FlingBehavior -import androidx.compose.foundation.gestures.Orientation -import androidx.compose.foundation.gestures.TargetedFlingBehavior -import androidx.compose.foundation.pager.PagerState -import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember -import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.platform.LocalLayoutDirection -import androidx.compose.ui.unit.Density -import org.readium.navigator.web.snapping.DefaultPositionThreshold -import org.readium.navigator.web.snapping.PagingLayoutInfo -import org.readium.navigator.web.snapping.SnapLayoutInfoProvider -import org.readium.navigator.web.snapping.calculateFinalSnappingBound -import org.readium.navigator.web.snapping.snapFlingBehavior - -/** - * A [snapFlingBehavior] that will snap pages to the start of the layout. One can use the - * given parameters to control how the snapping animation will happen. - * @see androidx.compose.foundation.gestures.snapping.snapFlingBehavior for more information - * on what which parameter controls in the overall snapping animation. - * - * The animation specs used by the fling behavior will depend on 2 factors: - * 1) The gesture velocity. - * 2) The target page proposed by [pagerSnapDistance]. - * - * If you're using single page snapping (the most common use case for [Pager]), there won't - * be enough space to actually run a decay animation to approach the target page, so the Pager - * will always use the snapping animation from [snapAnimationSpec]. - * If you're using multi-page snapping (this means you're abs(targetPage - currentPage) > 1) - * the Pager may use [decayAnimationSpec] or [snapAnimationSpec] to approach the - * targetPage, it will depend on the velocity generated by the triggering gesture. - * If the gesture has a high enough velocity to approach the target page, the Pager will use - * [decayAnimationSpec] followed by [snapAnimationSpec] for the final step of the - * animation. If the gesture doesn't have enough velocity, the Pager will use - * [snapAnimationSpec] + [snapAnimationSpec] in a similar fashion. - * - * @param state The [PagerState] that controls the which to which this FlingBehavior will - * be applied to. - * @param pagerSnapDistance A way to control the snapping destination for this [Pager]. - * The default behavior will result in any fling going to the next page in the direction of the - * fling (if the fling has enough velocity, otherwise the Pager will bounce back). Use - * [PagerSnapDistance.atMost] to define a maximum number of pages this [Pager] is allowed to - * fling after scrolling is finished and fling has started. - * @param decayAnimationSpec The animation spec used to approach the target offset. When - * the fling velocity is large enough. Large enough means large enough to naturally decay. For - * single page snapping this usually never happens since there won't be enough space to run a - * decay animation. - * @param snapAnimationSpec The animation spec used to finally snap to the position. This - * animation will be often used in 2 cases: 1) There was enough space to an approach animation, - * the Pager will use [snapAnimationSpec] in the last step of the animation to settle the page - * into position. 2) There was not enough space to run the approach animation. - * @param snapPositionalThreshold If the fling has a low velocity (e.g. slow scroll), - * this fling behavior will use this snap threshold in order to determine if the pager should - * snap back or move forward. Use a number between 0 and 1 as a fraction of the page size that - * needs to be scrolled before the Pager considers it should move to the next page. - * For instance, if snapPositionalThreshold = 0.35, it means if this pager is scrolled with a - * slow velocity and the Pager scrolls more than 35% of the page size, then will jump to the - * next page, if not it scrolls back. - * Note that any fling that has high enough velocity will *always* move to the next page - * in the direction of the fling. - * - * @return An instance of [FlingBehavior] that will perform Snapping to the next page by - * default. The animation will be governed by the post scroll velocity and the Pager will use - * either - * [snapAnimationSpec] or [decayAnimationSpec] to approach the snapped position - * If a velocity is not high enough the pager will use [snapAnimationSpec] to reach the snapped - * position. If the velocity is high enough, the Pager will use the logic described in - * [decayAnimationSpec] and [snapAnimationSpec]. - */ -@Composable -internal fun pagingFlingBehavior( - state: PagingLayoutInfo, - decayAnimationSpec: DecayAnimationSpec = rememberSplineBasedDecay(), - snapAnimationSpec: AnimationSpec = spring( - stiffness = Spring.StiffnessMediumLow, - visibilityThreshold = Int.VisibilityThreshold.toFloat() - ), - @FloatRange(from = 0.0, to = 1.0) snapPositionalThreshold: Float = 0.5f, -): TargetedFlingBehavior { - require(snapPositionalThreshold in 0f..1f) { - "snapPositionalThreshold should be a number between 0 and 1. " + - "You've specified $snapPositionalThreshold" - } - - val density = LocalDensity.current - val layoutDirection = LocalLayoutDirection.current - return remember( - state, - decayAnimationSpec, - snapAnimationSpec, - density, - layoutDirection - ) { - val snapLayoutInfoProvider = - SnapLayoutInfoProvider( - state, - ) { flingVelocity, lowerBound, upperBound -> - calculateFinalSnappingBound( - pagingLayoutInfo = state, - layoutDirection = layoutDirection, - snapPositionalThreshold = snapPositionalThreshold, - flingVelocity = flingVelocity, - lowerBoundOffset = lowerBound, - upperBoundOffset = upperBound - ) - } - snapFlingBehavior( - snapLayoutInfoProvider = snapLayoutInfoProvider, - decayAnimationSpec = decayAnimationSpec, - snapAnimationSpec = snapAnimationSpec - ) - } -} - -/** - * A [snapFlingBehavior] that will snap pages to the start of the layout. One can use the - * given parameters to control how the snapping animation will happen. - * @see androidx.compose.foundation.gestures.snapping.snapFlingBehavior for more information - * on what which parameter controls in the overall snapping animation. - * - * The animation specs used by the fling behavior will depend on 2 factors: - * 1) The gesture velocity. - * 2) The target page proposed by [pagerSnapDistance]. - * - * If you're using single page snapping (the most common use case for [Pager]), there won't - * be enough space to actually run a decay animation to approach the target page, so the Pager - * will always use the snapping animation from [snapAnimationSpec]. - * If you're using multi-page snapping (this means you're abs(targetPage - currentPage) > 1) - * the Pager may use [decayAnimationSpec] or [snapAnimationSpec] to approach the - * targetPage, it will depend on the velocity generated by the triggering gesture. - * If the gesture has a high enough velocity to approach the target page, the Pager will use - * [decayAnimationSpec] followed by [snapAnimationSpec] for the final step of the - * animation. If the gesture doesn't have enough velocity, the Pager will use - * [snapAnimationSpec] + [snapAnimationSpec] in a similar fashion. - * - * @param state The [PagerState] that controls the which to which this FlingBehavior will - * be applied to. - * @param pagerSnapDistance A way to control the snapping destination for this [Pager]. - * The default behavior will result in any fling going to the next page in the direction of the - * fling (if the fling has enough velocity, otherwise the Pager will bounce back). Use - * [PagerSnapDistance.atMost] to define a maximum number of pages this [Pager] is allowed to - * fling after scrolling is finished and fling has started. - * @param decayAnimationSpec The animation spec used to approach the target offset. When - * the fling velocity is large enough. Large enough means large enough to naturally decay. For - * single page snapping this usually never happens since there won't be enough space to run a - * decay animation. - * @param snapAnimationSpec The animation spec used to finally snap to the position. This - * animation will be often used in 2 cases: 1) There was enough space to an approach animation, - * the Pager will use [snapAnimationSpec] in the last step of the animation to settle the page - * into position. 2) There was not enough space to run the approach animation. - * @param snapPositionalThreshold If the fling has a low velocity (e.g. slow scroll), - * this fling behavior will use this snap threshold in order to determine if the pager should - * snap back or move forward. Use a number between 0 and 1 as a fraction of the page size that - * needs to be scrolled before the Pager considers it should move to the next page. - * For instance, if snapPositionalThreshold = 0.35, it means if this pager is scrolled with a - * slow velocity and the Pager scrolls more than 35% of the page size, then will jump to the - * next page, if not it scrolls back. - * Note that any fling that has high enough velocity will *always* move to the next page - * in the direction of the fling. - * - * @return An instance of [FlingBehavior] that will perform Snapping to the next page by - * default. The animation will be governed by the post scroll velocity and the Pager will use - * either - * [snapAnimationSpec] or [decayAnimationSpec] to approach the snapped position - * If a velocity is not high enough the pager will use [snapAnimationSpec] to reach the snapped - * position. If the velocity is high enough, the Pager will use the logic described in - * [decayAnimationSpec] and [snapAnimationSpec]. - */ -@Composable -internal fun pagingFlingBehavior( - state: PagerState, - decayAnimationSpec: DecayAnimationSpec = rememberSplineBasedDecay(), - snapAnimationSpec: AnimationSpec = spring( - stiffness = Spring.StiffnessMediumLow, - visibilityThreshold = Int.VisibilityThreshold.toFloat() - ), - @FloatRange(from = 0.0, to = 1.0) snapPositionalThreshold: Float = 0.5f, -): TargetedFlingBehavior { - require(snapPositionalThreshold in 0f..1f) { - "snapPositionalThreshold should be a number between 0 and 1. " + - "You've specified $snapPositionalThreshold" - } - - val density = LocalDensity.current - val layoutDirection = LocalLayoutDirection.current - return remember( - state, - decayAnimationSpec, - snapAnimationSpec, - density, - layoutDirection - ) { - val pagingLayoutInfoAdapter = object : PagingLayoutInfo { - - override val orientation: Orientation - get() = state.layoutInfo.orientation - - override val density: Density - get() = density - - override val positionThresholdFraction: Float - get() = with(density) { - val minThreshold = minOf(DefaultPositionThreshold.toPx(), pageSize / 2f) - minThreshold / pageSize.toFloat() - } - - override val pageSize: Int - get() = state.layoutInfo.pageSize - - override val pageSpacing: Int - get() = state.layoutInfo.pageSpacing - - override val upDownDifference: Offset - get() = Offset.Zero - - val firstVisiblePage: Int - get() = state.layoutInfo.visiblePagesInfo.first().offset - - override val reverseLayout: Boolean - get() = state.layoutInfo.reverseLayout - - override val visiblePageOffsets: List - get() = state.layoutInfo.visiblePagesInfo.map { it.offset } - - override val canScrollForward: Boolean - get() = state.canScrollForward - - override val canScrollBackward: Boolean - get() = state.canScrollBackward - } - - val snapLayoutInfoProvider = - SnapLayoutInfoProvider( - pagingLayoutInfoAdapter, - ) { flingVelocity, lowerBound, upperBound -> - calculateFinalSnappingBound( - pagingLayoutInfo = pagingLayoutInfoAdapter, - layoutDirection = layoutDirection, - snapPositionalThreshold = snapPositionalThreshold, - flingVelocity = flingVelocity, - lowerBoundOffset = lowerBound, - upperBoundOffset = upperBound - ) - } - - snapFlingBehavior( - snapLayoutInfoProvider = snapLayoutInfoProvider, - decayAnimationSpec = decayAnimationSpec, - snapAnimationSpec = snapAnimationSpec - ) - } -} diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/SnapFlingBehavior.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/SnapFlingBehavior.kt deleted file mode 100644 index ef09a9cf11..0000000000 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/snapping/SnapFlingBehavior.kt +++ /dev/null @@ -1,522 +0,0 @@ -/* - * Copyright 2024 Readium Foundation. All rights reserved. - * Use of this source code is governed by the BSD-style license - * available in the top-level LICENSE file of the project. - */ - -/* - * Copyright 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.readium.navigator.web.snapping - -import androidx.compose.animation.core.AnimationScope -import androidx.compose.animation.core.AnimationSpec -import androidx.compose.animation.core.AnimationState -import androidx.compose.animation.core.AnimationVector -import androidx.compose.animation.core.AnimationVector1D -import androidx.compose.animation.core.DecayAnimationSpec -import androidx.compose.animation.core.Spring -import androidx.compose.animation.core.animateDecay -import androidx.compose.animation.core.animateTo -import androidx.compose.animation.core.calculateTargetValue -import androidx.compose.animation.core.copy -import androidx.compose.animation.core.spring -import androidx.compose.animation.rememberSplineBasedDecay -import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.gestures.FlingBehavior -import androidx.compose.foundation.gestures.ScrollScope -import androidx.compose.foundation.gestures.TargetedFlingBehavior -import androidx.compose.foundation.gestures.snapping.SnapLayoutInfoProvider -import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember -import androidx.compose.ui.MotionDurationScale -import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.unit.dp -import kotlin.math.abs -import kotlin.math.absoluteValue -import kotlin.math.sign -import kotlinx.coroutines.withContext - -/** - * A [TargetedFlingBehavior] that performs snapping to a given position in a layout. - * - * You can use [SnapLayoutInfoProvider.calculateApproachOffset] to - * indicate that snapping should happen after this offset. If the velocity generated by the - * fling is high enough to get there, we'll use [decayAnimationSpec] to get to that offset - * and then we'll snap to the next bound calculated by - * [SnapLayoutInfoProvider.calculateSnapOffset] using [snapAnimationSpec]. - * - * If the velocity is not high enough, we'll use [snapAnimationSpec] to approach and the same spec - * to snap into place. - * - * Please refer to the sample to learn how to use this API. - * @sample androidx.compose.foundation.samples.SnapFlingBehaviorSimpleSample - * @sample androidx.compose.foundation.samples.SnapFlingBehaviorCustomizedSample - * - * @param snapLayoutInfoProvider The information about the layout being snapped. - * @param decayAnimationSpec The animation spec used to approach the target offset when - * the fling velocity is large enough. Large enough means large enough to naturally decay. - * @param snapAnimationSpec The animation spec used to finally snap to the correct bound. - * - */ -@OptIn(ExperimentalFoundationApi::class) -internal fun snapFlingBehavior( - snapLayoutInfoProvider: SnapLayoutInfoProvider, - decayAnimationSpec: DecayAnimationSpec, - snapAnimationSpec: AnimationSpec, -): TargetedFlingBehavior { - return SnapFlingBehavior(snapLayoutInfoProvider, decayAnimationSpec, snapAnimationSpec) -} - -@ExperimentalFoundationApi -private class SnapFlingBehavior( - private val snapLayoutInfoProvider: SnapLayoutInfoProvider, - private val decayAnimationSpec: DecayAnimationSpec, - private val snapAnimationSpec: AnimationSpec, -) : TargetedFlingBehavior { - - internal var motionScaleDuration = DefaultScrollMotionDurationScale - - /** - * Perform a snapping fling animation with given velocity and suspend until fling has - * finished. This will behave the same way as [performFling] except it will report on - * each remainingOffsetUpdate using the [onRemainingDistanceUpdated] lambda. - * - * @param initialVelocity velocity available for fling in the orientation specified in - * [androidx.compose.foundation.gestures.scrollable] that invoked this method. - * - * @param onRemainingDistanceUpdated a lambda that will be called anytime the - * distance to the settling offset is updated. The settling offset is the final offset where - * this fling will stop and may change depending on the snapping animation progression. - * - * @return remaining velocity after fling operation has ended - */ - override suspend fun ScrollScope.performFling( - initialVelocity: Float, - onRemainingDistanceUpdated: (Float) -> Unit, - ): Float { - val (remainingOffset, remainingState) = fling(initialVelocity, onRemainingDistanceUpdated) - - debugLog { "Post Settling Offset=$remainingOffset" } - // READIUM CHANGE BEGIN - - /* - // No remaining offset means we've used everything, no need to propagate velocity. Otherwise - // we couldn't use everything (probably because we have hit the min/max bounds of the - // containing layout) we should propagate the offset. - return if (remainingOffset == 0f) NoVelocity else remainingState.velocity - */ - - /** - * We definitely need to propagate the remaining velocity because nested scroll connections - * might want to use it. - */ - return remainingState.velocity - - // READIUM CHANGE END - } - - private suspend fun ScrollScope.fling( - initialVelocity: Float, - onRemainingScrollOffsetUpdate: (Float) -> Unit, - ): AnimationResult { - val result = withContext(motionScaleDuration) { - val decayOffset = - decayAnimationSpec.calculateTargetValue( - initialVelocity = initialVelocity, - initialValue = 0.0f - ) - - val initialOffset = - snapLayoutInfoProvider.calculateApproachOffset(initialVelocity, decayOffset) - - check(!initialOffset.isNaN()) { - "calculateApproachOffset returned NaN. Please use a valid value." - } - - // ensure offset sign and value are correct - var remainingScrollOffset = abs(initialOffset) * sign(initialVelocity) - - onRemainingScrollOffsetUpdate(remainingScrollOffset) // First Scroll Offset - - val animationState = tryApproach( - remainingScrollOffset, - initialVelocity - ) { delta -> - remainingScrollOffset -= delta - onRemainingScrollOffsetUpdate(remainingScrollOffset) - } - - val finalSnapOffset = - snapLayoutInfoProvider.calculateSnapOffset(animationState.velocity) - - check(!finalSnapOffset.isNaN()) { - "calculateSnapOffset returned NaN. Please use a valid value." - } - - remainingScrollOffset = finalSnapOffset - - debugLog { "Settling Final Bound=$remainingScrollOffset" } - - animateWithTarget( - remainingScrollOffset, - remainingScrollOffset, - animationState.copy(value = 0f), // re-use the velocity and timestamp from state - snapAnimationSpec - ) { delta -> - remainingScrollOffset -= delta - onRemainingScrollOffsetUpdate(remainingScrollOffset) - } - } - - onRemainingScrollOffsetUpdate(0f) // Animation finished or was cancelled - return result - } - - private suspend fun ScrollScope.tryApproach( - offset: Float, - velocity: Float, - updateRemainingScrollOffset: (Float) -> Unit, - ): AnimationState { - // If we don't have velocity or approach offset, we shouldn't run the approach animation - return if (offset.absoluteValue == 0.0f || - velocity.absoluteValue == 0.0f - ) { - AnimationState(offset, velocity) - } else { - runApproach( - offset, - velocity, - updateRemainingScrollOffset - ).currentAnimationState - } - } - - private suspend fun ScrollScope.runApproach( - initialTargetOffset: Float, - initialVelocity: Float, - onAnimationStep: (delta: Float) -> Unit, - ): AnimationResult { - val animation = - if (isDecayApproachPossible(offset = initialTargetOffset, velocity = initialVelocity)) { - debugLog { "High Velocity Approach" } - DecayApproachAnimation(decayAnimationSpec) - } else { - debugLog { "Low Velocity Approach" } - TargetApproachAnimation(snapAnimationSpec) - } - - return approach( - initialTargetOffset, - initialVelocity, - animation, - onAnimationStep - ) - } - - /** - * If we can approach the target and still have velocity left - */ - private fun isDecayApproachPossible( - offset: Float, - velocity: Float, - ): Boolean { - val decayOffset = decayAnimationSpec.calculateTargetValue(NoDistance, velocity) - debugLog { - "Evaluating decay possibility with " + - "decayOffset=$decayOffset and proposed approach=$offset" - } - return decayOffset.absoluteValue >= offset.absoluteValue - } - - @Suppress("Deprecation") - override fun equals(other: Any?): Boolean { - return if (other is SnapFlingBehavior) { - other.snapAnimationSpec == this.snapAnimationSpec && - other.decayAnimationSpec == this.decayAnimationSpec && - other.snapLayoutInfoProvider == this.snapLayoutInfoProvider - } else { - false - } - } - - override fun hashCode(): Int = 0 - .let { 31 * it + snapAnimationSpec.hashCode() } - .let { 31 * it + decayAnimationSpec.hashCode() } - .let { 31 * it + snapLayoutInfoProvider.hashCode() } -} - -/** - * Creates and remember a [FlingBehavior] that performs snapping. - * @param snapLayoutInfoProvider The information about the layout that will do snapping - */ -@Composable -internal fun rememberSnapFlingBehavior( - snapLayoutInfoProvider: SnapLayoutInfoProvider, -): TargetedFlingBehavior { - val density = LocalDensity.current - val highVelocityApproachSpec: DecayAnimationSpec = rememberSplineBasedDecay() - return remember( - snapLayoutInfoProvider, - highVelocityApproachSpec, - density - ) { - snapFlingBehavior( - snapLayoutInfoProvider = snapLayoutInfoProvider, - decayAnimationSpec = highVelocityApproachSpec, - snapAnimationSpec = spring(stiffness = Spring.StiffnessMediumLow) - ) - } -} - -/** - * To ensure we do not overshoot, the approach animation is divided into 2 parts. - * - * In the initial animation we animate up until targetOffset. At this point we will have fulfilled - * the requirement of [SnapLayoutInfoProvider.calculateApproachOffset] and we should snap to the - * next [SnapLayoutInfoProvider.calculateSnapOffset]. - * - * The second part of the approach is a UX improvement. If the target offset is too far (in here, we - * define too far as over half a step offset away) we continue the approach animation a bit further - * and leave the remainder to be snapped. - */ -private suspend fun ScrollScope.approach( - initialTargetOffset: Float, - initialVelocity: Float, - animation: ApproachAnimation, - onAnimationStep: (delta: Float) -> Unit, -): AnimationResult { - return animation.approachAnimation( - this, - initialTargetOffset, - initialVelocity, - onAnimationStep - ) -} - -private class AnimationResult( - val remainingOffset: T, - val currentAnimationState: AnimationState, -) { - operator fun component1(): T = remainingOffset - operator fun component2(): AnimationState = currentAnimationState -} - -private operator fun > ClosedFloatingPointRange.component1(): T = this.start -private operator fun > ClosedFloatingPointRange.component2(): T = - this.endInclusive - -/** - * Run a [DecayAnimationSpec] animation up to before [targetOffset] using [animationState] - * - * @param targetOffset The destination of this animation. Since this is a decay animation, we can - * use this value to prevent the animation to run until the end. - * @param animationState The previous [AnimationState] for continuation purposes. - * @param decayAnimationSpec The [DecayAnimationSpec] that will drive this animation - * @param onAnimationStep Called for each new scroll delta emitted by the animation cycle. - */ -private suspend fun ScrollScope.animateDecay( - targetOffset: Float, - animationState: AnimationState, - decayAnimationSpec: DecayAnimationSpec, - onAnimationStep: (delta: Float) -> Unit, -): AnimationResult { - var previousValue = 0f - - fun AnimationScope.consumeDelta(delta: Float) { - val consumed = scrollBy(delta) - onAnimationStep(consumed) - if (abs(delta - consumed) > 0.5f) cancelAnimation() - } - - animationState.animateDecay( - decayAnimationSpec, - sequentialAnimation = animationState.velocity != 0f - ) { - if (abs(value) >= abs(targetOffset)) { - val finalValue = value.coerceToTarget(targetOffset) - val finalDelta = finalValue - previousValue - consumeDelta(finalDelta) - cancelAnimation() - previousValue = finalValue - } else { - val delta = value - previousValue - consumeDelta(delta) - previousValue = value - } - } - - debugLog { - "Decay Animation: Proposed Offset=$targetOffset Achieved Offset=$previousValue" - } - return AnimationResult( - targetOffset - previousValue, - animationState - ) -} - -/** - * Runs a [AnimationSpec] to snap the list into [targetOffset]. Uses [cancelOffset] to stop this - * animation before it reaches the target. - * - * @param targetOffset The final target of this animation - * @param cancelOffset If we'd like to finish the animation earlier we use this value - * @param animationState The current animation state for continuation purposes - * @param animationSpec The [AnimationSpec] that will drive this animation - * @param onAnimationStep Called for each new scroll delta emitted by the animation cycle. - */ -private suspend fun ScrollScope.animateWithTarget( - targetOffset: Float, - cancelOffset: Float, - animationState: AnimationState, - animationSpec: AnimationSpec, - onAnimationStep: (delta: Float) -> Unit, -): AnimationResult { - var consumedUpToNow = 0f - val initialVelocity = animationState.velocity - animationState.animateTo( - targetOffset, - animationSpec = animationSpec, - sequentialAnimation = (animationState.velocity != 0f) - ) { - val realValue = value.coerceToTarget(cancelOffset) - val delta = realValue - consumedUpToNow - val consumed = scrollBy(delta) - onAnimationStep(consumed) - // stop when unconsumed or when we reach the desired value - if (abs(delta - consumed) > 0.5f || realValue != value) { - cancelAnimation() - } - consumedUpToNow += consumed - } - - debugLog { - "Snap Animation: Proposed Offset=$targetOffset Achieved Offset=$consumedUpToNow" - } - - // Always course correct velocity so they don't become too large. - val finalVelocity = animationState.velocity.coerceToTarget(initialVelocity) - return AnimationResult( - targetOffset - consumedUpToNow, - animationState.copy(velocity = finalVelocity) - ) -} - -private fun Float.coerceToTarget(target: Float): Float { - if (target == 0f) return 0f - return if (target > 0) coerceAtMost(target) else coerceAtLeast(target) -} - -/** - * The animations used to approach offset and approach half a step offset. - */ -private interface ApproachAnimation { - suspend fun approachAnimation( - scope: ScrollScope, - offset: T, - velocity: T, - onAnimationStep: (delta: T) -> Unit, - ): AnimationResult -} - -private class TargetApproachAnimation( - private val animationSpec: AnimationSpec, -) : ApproachAnimation { - override suspend fun approachAnimation( - scope: ScrollScope, - offset: Float, - velocity: Float, - onAnimationStep: (delta: Float) -> Unit, - ): AnimationResult { - val animationState = AnimationState(initialValue = 0f, initialVelocity = velocity) - val targetOffset = offset.absoluteValue * sign(velocity) - return with(scope) { - animateWithTarget( - targetOffset = targetOffset, - cancelOffset = offset, - animationState = animationState, - animationSpec = animationSpec, - onAnimationStep = onAnimationStep - ) - } - } -} - -private class DecayApproachAnimation( - private val decayAnimationSpec: DecayAnimationSpec, -) : ApproachAnimation { - override suspend fun approachAnimation( - scope: ScrollScope, - offset: Float, - velocity: Float, - onAnimationStep: (delta: Float) -> Unit, - ): AnimationResult { - val animationState = AnimationState(initialValue = 0f, initialVelocity = velocity) - return with(scope) { - animateDecay(offset, animationState, decayAnimationSpec, onAnimationStep) - } - } -} - -internal val MinFlingVelocityDp = 400.dp -internal const val NoDistance = 0f -internal const val NoVelocity = 0f - -internal fun calculateFinalOffset( - snappingOffset: FinalSnappingItem, - lowerBound: Float, - upperBound: Float, -): Float { - fun Float.isValidDistance(): Boolean { - return this != Float.POSITIVE_INFINITY && this != Float.NEGATIVE_INFINITY - } - - debugLog { "Proposed Bounds: Lower=$lowerBound Upper=$upperBound" } - - val finalDistance = when (snappingOffset) { - FinalSnappingItem.ClosestItem -> { - if (abs(upperBound) <= abs(lowerBound)) { - upperBound - } else { - lowerBound - } - } - - FinalSnappingItem.NextItem -> upperBound - FinalSnappingItem.PreviousItem -> lowerBound - else -> NoDistance - } - - return if (finalDistance.isValidDistance()) { - finalDistance - } else { - NoDistance - } -} - -private const val DEBUG = false - -private inline fun debugLog(generateMsg: () -> String) { - if (DEBUG) { - println("SnapFlingBehavior: ${generateMsg()}") - } -} - -private const val DefaultScrollMotionDurationScaleFactor = 1f -internal val DefaultScrollMotionDurationScale = object : MotionDurationScale { - override val scaleFactor: Float - get() = DefaultScrollMotionDurationScaleFactor -} From 855bed8fca6af2662b1fe2afc1236f42b2245cb4 Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Fri, 11 Apr 2025 08:31:55 +0200 Subject: [PATCH 33/88] Fix Readium CSS upgrade --- readium/navigators/web/scripts/package.json | 2 +- readium/navigators/web/scripts/pnpm-lock.yaml | 8 +- .../readium-css/ReadiumCSS-after.css | 323 +++++++++++------- .../readium-css/ReadiumCSS-before.css | 34 +- .../readium-css/ReadiumCSS-default.css | 2 +- .../cjk-horizontal/ReadiumCSS-after.css | 260 +++++++++----- .../cjk-horizontal/ReadiumCSS-before.css | 34 +- .../cjk-horizontal/ReadiumCSS-default.css | 2 +- .../cjk-vertical/ReadiumCSS-after.css | 239 ++++++++----- .../cjk-vertical/ReadiumCSS-before.css | 34 +- .../cjk-vertical/ReadiumCSS-default.css | 2 +- .../readium-css/rtl/ReadiumCSS-after.css | 275 +++++++++------ .../readium-css/rtl/ReadiumCSS-before.css | 34 +- .../readium-css/rtl/ReadiumCSS-default.css | 2 +- 14 files changed, 802 insertions(+), 449 deletions(-) diff --git a/readium/navigators/web/scripts/package.json b/readium/navigators/web/scripts/package.json index 80ad0d93dc..880982a7fc 100644 --- a/readium/navigators/web/scripts/package.json +++ b/readium/navigators/web/scripts/package.json @@ -27,7 +27,7 @@ "vite": "^5.4.1", "webpack": "^5.88.2", "webpack-cli": "^5.1.4", - "@readium/css": "2.0.0-alpha.5" + "@readium/css": "2.0.0-beta.7" }, "dependencies": { "approx-string-match": "^1.1.0", diff --git a/readium/navigators/web/scripts/pnpm-lock.yaml b/readium/navigators/web/scripts/pnpm-lock.yaml index 14a0c197b7..59ffbe0c86 100644 --- a/readium/navigators/web/scripts/pnpm-lock.yaml +++ b/readium/navigators/web/scripts/pnpm-lock.yaml @@ -32,8 +32,8 @@ devDependencies: specifier: ^7.22.20 version: 7.22.20(@babel/core@7.23.0) '@readium/css': - specifier: 2.0.0-alpha.5 - version: 2.0.0-alpha.5 + specifier: 2.0.0-beta.7 + version: 2.0.0-beta.7 '@typescript-eslint/eslint-plugin': specifier: ^8.3.0 version: 8.3.0(@typescript-eslint/parser@8.3.0)(eslint@8.57.0)(typescript@5.5.4) @@ -1553,8 +1553,8 @@ packages: fastq: 1.17.1 dev: true - /@readium/css@2.0.0-alpha.5: - resolution: {integrity: sha512-m3wC4z8lO0ny9k+SuCUpuAWDF4rF3FnfSvYXMUfQb4yYUGi5YEMzVIFPiexs3gDUU2JtpVPGXDAVZmTmRbSjPQ==} + /@readium/css@2.0.0-beta.7: + resolution: {integrity: sha512-OoHrhc2/f38o1Qj+y2k9upS6YI2K+hhoItVfJdzVLpXDFWdtY7vA7vqbTLAvICzbrrU3q983OfyEHX8JTYQ14g==} dev: true /@rollup/rollup-android-arm-eabi@4.20.0: diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-after.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-after.css index 5b9090a12c..0e153a3e17 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-after.css +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-after.css @@ -1,5 +1,5 @@ /* - * Readium CSS (v. 2.0.0-alpha.5) + * Readium CSS (v. 2.0.0-beta.7) * Developers: Jiminy Panoz * Copyright (c) 2017. Readium Foundation. All rights reserved. * Use of this source code is governed by a BSD-style license which is detailed in the @@ -15,12 +15,18 @@ @namespace svg url("http://www.w3.org/2000/svg"); :root{ - --RS__colWidth:100vw; - --RS__colCount:1; - --RS__colGap:0; - --RS__defaultLineLength:40rem; - --RS__pageGutter:0; + --RS__viewportWidth:100%; + + --RS__pageGutter:0; + + --RS__defaultLineLength:40rem; + + --RS__colGap:0; + + --RS__colCount:1; + + --RS__colWidth:100vw; } @page{ @@ -51,8 +57,8 @@ padding:0 !important; margin:0 !important; font-size:100% !important; - - -webkit-text-size-adjust:100%; + -webkit-text-size-adjust:none; + text-size-adjust:none; box-sizing:border-box; -webkit-touch-callout:none; } @@ -91,8 +97,8 @@ body{ } :root[style*="readium-scroll-on"] body{ + max-width:var(--RS__defaultLineLength) !important; overflow:auto; - --RS__defaultLineLength:40rem !important; } @supports (overflow: clip){ @@ -107,13 +113,18 @@ body{ } :root[style*="readium-night-on"]{ - --RS__backgroundColor:#000000; - --RS__textColor:#FEFEFE; - --RS__linkColor:#63caff; - --RS__visitedColor:#0099E5; - --RS__selectionBackgroundColor:#b4d8fe; --RS__selectionTextColor:inherit; + + --RS__selectionBackgroundColor:#b4d8fe; + + --RS__visitedColor:#0099E5; + + --RS__linkColor:#63caff; + + --RS__textColor:#FEFEFE; + + --RS__backgroundColor:#000000; } :root[style*="readium-night-on"] *:not(a){ @@ -144,31 +155,19 @@ body{ filter:invert(100%); } -:root[style*="readium-night-on"][style*="readium-darken-on"] img{ - -webkit-filter:brightness(80%); - filter:brightness(80%); -} +:root[style*="readium-sepia-on"]{ -:root[style*="readium-night-on"][style*="readium-invert-on"] img{ - -webkit-filter:invert(100%); - filter:invert(100%); -} + --RS__selectionTextColor:inherit; -:root[style*="readium-night-on"][style*="readium-darken-on"][style*="readium-invert-on"] img{ - -webkit-filter:brightness(80%) invert(100%); - filter:brightness(80%) invert(100%); -} + --RS__selectionBackgroundColor:#b4d8fe; -:root[style*="readium-sepia-on"]{ - --RS__backgroundColor:#faf4e8; - --RS__textColor:#121212; + --RS__visitedColor:#551A8B; --RS__linkColor:#0000EE; - --RS__visitedColor:#551A8B; - --RS__selectionBackgroundColor:#b4d8fe; - --RS__selectionTextColor:inherit; - --RS__defaultLineLength:40.01rem; + --RS__textColor:#121212; + + --RS__backgroundColor:#faf4e8; } :root[style*="readium-sepia-on"] *:not(a){ @@ -186,12 +185,6 @@ body{ color:var(--RS__visitedColor); } -:root[style*="readium-sepia-on"] svg, -:root[style*="readium-sepia-on"] img{ - background-color:transparent !important; - mix-blend-mode:multiply; -} - @media screen and (-ms-high-contrast: active){ :root{ @@ -258,6 +251,49 @@ body{ @media screen and (prefers-reduced-motion){ } +:root[style*="--USER__backgroundColor"]{ + background-color:var(--USER__backgroundColor) !important; +} + +:root[style*="--USER__backgroundColor"] *{ + background-color:transparent !important; +} + +:root[style*="--USER__textColor"]{ + color:var(--USER__textColor) !important; +} + +:root[style*="--USER__textColor"] *:not(a){ + color:inherit !important; + background-color:transparent !important; + border-color:currentcolor !important; +} + +:root[style*="--USER__textColor"] svg text{ + fill:currentcolor !important; + stroke:none !important; +} + +:root[style*="--USER__linkColor"] a:link, +:root[style*="--USER__linkColor"] a:link *{ + color:var(--USER__linkColor) !important; +} + +:root[style*="--USER__visitedColor"] a:visited, +:root[style*="--USER__visitedColor"] a:visited *{ + color:var(--USER__visitedColor) !important; +} + +:root[style*="--USER__selectionBackgroundColor"][style*="--USER__selectionTextColor"] ::-moz-selection{ + color:var(--USER__selectionTextColor) !important; + background-color:var(--USER__selectionBackgroundColor) !important; +} + +:root[style*="--USER__selectionBackgroundColor"][style*="--USER__selectionTextColor"] ::selection{ + color:var(--USER__selectionTextColor) !important; + background-color:var(--USER__selectionBackgroundColor) !important; +} + :root[style*="--USER__colCount"]{ -webkit-column-count:var(--USER__colCount); -moz-column-count:var(--USER__colCount); @@ -284,56 +320,21 @@ body{ max-width:var(--USER__lineLength) !important; } -:root[style*="--USER__backgroundColor"]{ - background-color:var(--USER__backgroundColor) !important; -} - -:root[style*="--USER__backgroundColor"] *{ - background-color:transparent !important; -} - -:root[style*="--USER__textColor"]{ - color:var(--USER__textColor) !important; -} - -:root[style*="--USER__textColor"] *:not(h1):not(h2):not(h3):not(h4):not(h5):not(h6):not(pre){ - color:inherit !important; -} - -:root[style*="readium-advanced-on"][style*="--USER__textAlign"]{ +:root[style*="--USER__textAlign"]{ text-align:var(--USER__textAlign); } -:root[style*="readium-advanced-on"][style*="--USER__textAlign"] body, -:root[style*="readium-advanced-on"][style*="--USER__textAlign"] *:not(blockquote):not(figcaption) p, -:root[style*="readium-advanced-on"][style*="--USER__textAlign"] li{ +:root[style*="--USER__textAlign"] body, +:root[style*="--USER__textAlign"] p:not(blockquote p):not(figcaption p):not(hgroup p), +:root[style*="--USER__textAlign"] li, +:root[style*="--USER__textAlign"] dd{ text-align:var(--USER__textAlign) !important; -moz-text-align-last:auto !important; -epub-text-align-last:auto !important; text-align-last:auto !important; } -:root[style*="readium-advanced-on"][style*="--USER__textAlign: justify"] body, -:root[style*="readium-advanced-on"][style*="--USER__textAlign:justify"] body{ - -webkit-hyphens:auto; - -moz-hyphens:auto; - -ms-hyphens:auto; - -epub-hyphens:auto; - hyphens:auto; -} - -:root[style*="readium-advanced-on"][style*="--USER__textAlign: left"] body, -:root[style*="readium-advanced-on"][style*="--USER__textAlign:left"] body, -:root[style*="readium-advanced-on"][style*="--USER__textAlign: right"] body, -:root[style*="readium-advanced-on"][style*="--USER__textAlign:right"] body{ - -webkit-hyphens:none; - -moz-hyphens:none; - -ms-hyphens:none; - -epub-hyphens:none; - hyphens:none; -} - -:root[style*="readium-advanced-on"][style*="--USER__bodyHyphens"]{ +:root[style*="--USER__bodyHyphens"]{ -webkit-hyphens:var(--USER__bodyHyphens) !important; -moz-hyphens:var(--USER__bodyHyphens) !important; -ms-hyphens:var(--USER__bodyHyphens) !important; @@ -341,11 +342,11 @@ body{ hyphens:var(--USER__bodyHyphens) !important; } -:root[style*="readium-advanced-on"][style*="--USER__bodyHyphens"] body, -:root[style*="readium-advanced-on"][style*="--USER__bodyHyphens"] p, -:root[style*="readium-advanced-on"][style*="--USER__bodyHyphens"] li, -:root[style*="readium-advanced-on"][style*="--USER__bodyHyphens"] div, -:root[style*="readium-advanced-on"][style*="--USER__bodyHyphens"] dd{ +:root[style*="--USER__bodyHyphens"] body, +:root[style*="--USER__bodyHyphens"] p, +:root[style*="--USER__bodyHyphens"] li, +:root[style*="--USER__bodyHyphens"] div, +:root[style*="--USER__bodyHyphens"] dd{ -webkit-hyphens:inherit; -moz-hyphens:inherit; -ms-hyphens:inherit; @@ -406,7 +407,7 @@ body{ vertical-align:baseline !important; } -:root[style*="--USER__fontSize"]{ +:root[style*="--USER__fontSize"] body{ zoom:var(--USER__fontSize) !important; } @@ -417,52 +418,56 @@ body{ } } -:root[style*="readium-advanced-on"][style*="--USER__lineHeight"]{ +:root[style*="--USER__lineHeight"]{ line-height:var(--USER__lineHeight) !important; } -:root[style*="readium-advanced-on"][style*="--USER__lineHeight"] body, -:root[style*="readium-advanced-on"][style*="--USER__lineHeight"] p, -:root[style*="readium-advanced-on"][style*="--USER__lineHeight"] li, -:root[style*="readium-advanced-on"][style*="--USER__lineHeight"] div{ +:root[style*="--USER__lineHeight"] body, +:root[style*="--USER__lineHeight"] p, +:root[style*="--USER__lineHeight"] li, +:root[style*="--USER__lineHeight"] div{ line-height:inherit; } -:root[style*="readium-advanced-on"][style*="--USER__paraSpacing"] p{ +:root[style*="--USER__paraSpacing"] p{ margin-top:var(--USER__paraSpacing) !important; margin-bottom:var(--USER__paraSpacing) !important; } -:root[style*="readium-advanced-on"][style*="--USER__paraIndent"] p{ +:root[style*="--USER__paraIndent"] p{ text-indent:var(--USER__paraIndent) !important; } -:root[style*="readium-advanced-on"][style*="--USER__paraIndent"] p *, -:root[style*="readium-advanced-on"][style*="--USER__paraIndent"] p:first-letter{ +:root[style*="--USER__paraIndent"] p *, +:root[style*="--USER__paraIndent"] p:first-letter{ text-indent:0 !important; } -:root[style*="readium-advanced-on"][style*="--USER__wordSpacing"] h1, -:root[style*="readium-advanced-on"][style*="--USER__wordSpacing"] h2, -:root[style*="readium-advanced-on"][style*="--USER__wordSpacing"] h3, -:root[style*="readium-advanced-on"][style*="--USER__wordSpacing"] h4, -:root[style*="readium-advanced-on"][style*="--USER__wordSpacing"] h5, -:root[style*="readium-advanced-on"][style*="--USER__wordSpacing"] h6, -:root[style*="readium-advanced-on"][style*="--USER__wordSpacing"] p, -:root[style*="readium-advanced-on"][style*="--USER__wordSpacing"] li, -:root[style*="readium-advanced-on"][style*="--USER__wordSpacing"] div{ +:root[style*="--USER__wordSpacing"] h1, +:root[style*="--USER__wordSpacing"] h2, +:root[style*="--USER__wordSpacing"] h3, +:root[style*="--USER__wordSpacing"] h4, +:root[style*="--USER__wordSpacing"] h5, +:root[style*="--USER__wordSpacing"] h6, +:root[style*="--USER__wordSpacing"] p, +:root[style*="--USER__wordSpacing"] li, +:root[style*="--USER__wordSpacing"] div, +:root[style*="--USER__wordSpacing"] dt, +:root[style*="--USER__wordSpacing"] dd{ word-spacing:var(--USER__wordSpacing); } -:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] h1, -:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] h2, -:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] h3, -:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] h4, -:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] h5, -:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] h6, -:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] p, -:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] li, -:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] div{ +:root[style*="--USER__letterSpacing"] h1, +:root[style*="--USER__letterSpacing"] h2, +:root[style*="--USER__letterSpacing"] h3, +:root[style*="--USER__letterSpacing"] h4, +:root[style*="--USER__letterSpacing"] h5, +:root[style*="--USER__letterSpacing"] h6, +:root[style*="--USER__letterSpacing"] p, +:root[style*="--USER__letterSpacing"] li, +:root[style*="--USER__letterSpacing"] div, +:root[style*="--USER__letterSpacing"] dt, +:root[style*="--USER__letterSpacing"] dd{ letter-spacing:var(--USER__letterSpacing); font-variant:none; } @@ -484,59 +489,115 @@ body{ font-optical-sizing:var(--USER__fontOpticalSizing) !important; } +:root[style*="readium-blend-on"] svg, +:root[style*="readium-blend-on"] img{ + background-color:transparent !important; + mix-blend-mode:multiply !important; +} + +:root[style*="--USER__darkenImages"] img{ + -webkit-filter:brightness(var(--USER__darkenImages)) !important; + filter:brightness(var(--USER__darkenImages)) !important; +} + +:root[style*="readium-darken-on"] img{ + -webkit-filter:brightness(80%) !important; + filter:brightness(80%) !important; +} + +:root[style*="--USER__invertImages"] img{ + -webkit-filter:invert(var(--USER__invertImages)) !important; + filter:invert(var(--USER__invertImages)) !important; +} + +:root[style*="readium-invert-on"] img{ + -webkit-filter:invert(100%) !important; + filter:invert(100%) !important; +} + +:root[style*="--USER__darkenImages"][style*="--USER__invertImages"] img{ + -webkit-filter:brightness(var(--USER__darkenImages)) invert(var(--USER__invertImages)) !important; + filter:brightness(var(--USER__darkenImages)) invert(var(--USER__invertImages)) !important; +} + +:root[style*="readium-darken-on"][style*="--USER__invertImages"] img{ + -webkit-filter:brightness(80%) invert(var(--USER__invertImages)) !important; + filter:brightness(80%) invert(var(--USER__invertImages)) !important; +} + +:root[style*="--USER__darkenImages"][style*="readium-invert-on"] img{ + -webkit-filter:brightness(var(--USER__darkenImages)) invert(100%) !important; + filter:brightness(var(--USER__darkenImages)) invert(100%) !important; +} + +:root[style*="readium-darken-on"][style*="readium-invert-on"] img{ + -webkit-filter:brightness(80%) invert(100%) !important; + filter:brightness(80%) invert(100%) !important; +} + +:root[style*="--USER__invertGaiji"] img[class*="gaiji"]{ + -webkit-filter:invert(var(--USER__invertGaiji)) !important; + filter:invert(var(--USER__invertGaiji)) !important; +} + +:root[style*="readium-invertGaiji-on"] img[class*="gaiji"]{ + -webkit-filter:invert(100%) !important; + filter:invert(100%) !important; +} + @supports not (zoom: 1){ - :root[style*="readium-advanced-on"]{ + :root[style*="readium-normalize-on"]{ --USER__typeScale:1.2; } - :root[style*="readium-advanced-on"] p, - :root[style*="readium-advanced-on"] li, - :root[style*="readium-advanced-on"] div, - :root[style*="readium-advanced-on"] pre, - :root[style*="readium-advanced-on"] dd{ + :root[style*="readium-normalize-on"] p, + :root[style*="readium-normalize-on"] li, + :root[style*="readium-normalize-on"] div, + :root[style*="readium-normalize-on"] pre, + :root[style*="readium-normalize-on"] dd{ font-size:1rem !important; } - :root[style*="readium-advanced-on"] h1{ + :root[style*="readium-normalize-on"] h1{ font-size:1.75rem !important; font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important; } - :root[style*="readium-advanced-on"] h2{ + :root[style*="readium-normalize-on"] h2{ font-size:1.5rem !important; font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important; } - :root[style*="readium-advanced-on"] h3{ + :root[style*="readium-normalize-on"] h3{ font-size:1.25rem !important; font-size:calc(1rem * var(--USER__typeScale)) !important; } - :root[style*="readium-advanced-on"] h4, - :root[style*="readium-advanced-on"] h5, - :root[style*="readium-advanced-on"] h6{ + :root[style*="readium-normalize-on"] h4, + :root[style*="readium-normalize-on"] h5, + :root[style*="readium-normalize-on"] h6{ font-size:1rem !important; } - :root[style*="readium-advanced-on"] small{ + :root[style*="readium-normalize-on"] small{ font-size:smaller !important; } - :root[style*="readium-advanced-on"] sub, - :root[style*="readium-advanced-on"] sup{ + :root[style*="readium-normalize-on"] sub, + :root[style*="readium-normalize-on"] sup{ font-size:67.5% !important; } - :root[style*="readium-advanced-on"][style*="--USER__typeScale"] h1{ + :root[style*="readium-normalize-on"][style*="--USER__typeScale"] h1{ font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important; } - :root[style*="readium-advanced-on"][style*="--USER__typeScale"] h2{ + :root[style*="readium-normalize-on"][style*="--USER__typeScale"] h2{ font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important; } - :root[style*="readium-advanced-on"][style*="--USER__typeScale"] h3{ + :root[style*="readium-normalize-on"][style*="--USER__typeScale"] h3{ font-size:calc(1rem * var(--USER__typeScale)) !important; } } \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-before.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-before.css index 2c16fe32fd..a98ae32ae0 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-before.css +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-before.css @@ -1,5 +1,5 @@ /* - * Readium CSS (v. 2.0.0-alpha.5) + * Readium CSS (v. 2.0.0-beta.7) * Developers: Jiminy Panoz * Copyright (c) 2017. Readium Foundation. All rights reserved. * Use of this source code is governed by a BSD-style license which is detailed in the @@ -24,14 +24,20 @@ } :root{ - --RS__oldStyleTf:"Iowan Old Style", sitka, "Sitka Text", palatino, "Book Antiqua", "URW Palladio L", p052, serif; - --RS__modernTf:athelas, constantia, charter, "Bitstream Charter", cambria, "Georgia Pro", georgia, serif; - --RS__sansTf:-ui-sans-serif, -apple-system, system-ui, blinkmacsystemfont, "Segoe UI Variable", "Segoe UI", inter, roboto, "Helvetica Neue", "Arial Nova", "Liberation Sans", arial, sans-serif; - --RS__humanistTf:seravek, calibri, "Gill Sans Nova", roboto, ubuntu, "DejaVu Sans", source-sans-pro, sans-serif; - --RS__monospaceTf:ui-monospace, "Andale Mono", "Cascadia Code", "Source Code Pro", menlo, consolas, "DejaVu Sans Mono", monospace; + + --RS__monospaceTf:ui-monospace, 'Andale Mono', 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', monospace; + + --RS__humanistTf:Seravek, Calibri, 'Gill Sans Nova', Roboto, Ubuntu, 'DejaVu Sans', source-sans-pro, sans-serif; + + --RS__sansTf:-ui-sans-serif, -apple-system, system-ui, BlinkMacSystemFont, 'Segoe UI Variable', 'Segoe UI', Inter, Roboto, 'Helvetica Neue', 'Arial Nova', 'Liberation Sans', Arial, sans-serif; + + --RS__modernTf:Athelas, Constantia, Charter, 'Bitstream Charter', Cambria, 'Georgia Pro', Georgia, serif; + + --RS__oldStyleTf:'Iowan Old Style', Sitka, 'Sitka Text', Palatino, 'Book Antiqua', 'URW Palladio L', P052, serif; --RS__baseFontFamily:var(--RS__oldStyleTf); --RS__lineHeightCompensation:1; - --RS__baseLineHeight:calc((1em + (2ex - 1ch) - ((1rem - 16px) * 0.1667)) * var(--RS__lineHeightCompensation)); + + --RS__baseLineHeight:calc(1.5 * var(--RS__lineHeightCompensation)); } html{ @@ -188,10 +194,18 @@ math{ } :root{ - --RS__backgroundColor:#FFFFFF; - --RS__textColor:#121212; - --RS__selectionBackgroundColor:#b4d8fe; + --RS__selectionTextColor:inherit; + + --RS__selectionBackgroundColor:#b4d8fe; + + --RS__visitedColor:#551A8B; + + --RS__linkColor:#0000EE; + + --RS__textColor:#121212; + + --RS__backgroundColor:#FFFFFF; } :root{ diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-default.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-default.css index e9918d4424..02e4e80c11 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-default.css +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-default.css @@ -1,5 +1,5 @@ /* - * Readium CSS (v. 2.0.0-alpha.5) + * Readium CSS (v. 2.0.0-beta.7) * Developers: Jiminy Panoz * Copyright (c) 2017. Readium Foundation. All rights reserved. * Use of this source code is governed by a BSD-style license which is detailed in the diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-horizontal/ReadiumCSS-after.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-horizontal/ReadiumCSS-after.css index 4871a2162a..7706672a46 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-horizontal/ReadiumCSS-after.css +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-horizontal/ReadiumCSS-after.css @@ -1,5 +1,5 @@ /* - * Readium CSS (v. 2.0.0-alpha.5) + * Readium CSS (v. 2.0.0-beta.7) * Developers: Jiminy Panoz * Copyright (c) 2017. Readium Foundation. All rights reserved. * Use of this source code is governed by a BSD-style license which is detailed in the @@ -15,12 +15,18 @@ @namespace svg url("http://www.w3.org/2000/svg"); :root{ - --RS__colWidth:100vw; - --RS__colCount:1; - --RS__colGap:0; - --RS__defaultLineLength:40rem; - --RS__pageGutter:0; + --RS__viewportWidth:100%; + + --RS__pageGutter:0; + + --RS__defaultLineLength:40rem; + + --RS__colGap:0; + + --RS__colCount:1; + + --RS__colWidth:100vw; } @page{ @@ -51,8 +57,8 @@ padding:0 !important; margin:0 !important; font-size:100% !important; - - -webkit-text-size-adjust:100%; + -webkit-text-size-adjust:none; + text-size-adjust:none; box-sizing:border-box; -webkit-touch-callout:none; } @@ -91,8 +97,8 @@ body{ } :root[style*="readium-scroll-on"] body{ + max-width:var(--RS__defaultLineLength) !important; overflow:auto; - --RS__defaultLineLength:40rem !important; } @supports (overflow: clip){ @@ -107,13 +113,18 @@ body{ } :root[style*="readium-night-on"]{ - --RS__backgroundColor:#000000; - --RS__textColor:#FEFEFE; - --RS__linkColor:#63caff; - --RS__visitedColor:#0099E5; - --RS__selectionBackgroundColor:#b4d8fe; --RS__selectionTextColor:inherit; + + --RS__selectionBackgroundColor:#b4d8fe; + + --RS__visitedColor:#0099E5; + + --RS__linkColor:#63caff; + + --RS__textColor:#FEFEFE; + + --RS__backgroundColor:#000000; } :root[style*="readium-night-on"] *:not(a){ @@ -144,31 +155,19 @@ body{ filter:invert(100%); } -:root[style*="readium-night-on"][style*="readium-darken-on"] img{ - -webkit-filter:brightness(80%); - filter:brightness(80%); -} +:root[style*="readium-sepia-on"]{ -:root[style*="readium-night-on"][style*="readium-invert-on"] img{ - -webkit-filter:invert(100%); - filter:invert(100%); -} + --RS__selectionTextColor:inherit; -:root[style*="readium-night-on"][style*="readium-darken-on"][style*="readium-invert-on"] img{ - -webkit-filter:brightness(80%) invert(100%); - filter:brightness(80%) invert(100%); -} + --RS__selectionBackgroundColor:#b4d8fe; -:root[style*="readium-sepia-on"]{ - --RS__backgroundColor:#faf4e8; - --RS__textColor:#121212; + --RS__visitedColor:#551A8B; --RS__linkColor:#0000EE; - --RS__visitedColor:#551A8B; - --RS__selectionBackgroundColor:#b4d8fe; - --RS__selectionTextColor:inherit; - --RS__defaultLineLength:40.01rem; + --RS__textColor:#121212; + + --RS__backgroundColor:#faf4e8; } :root[style*="readium-sepia-on"] *:not(a){ @@ -186,12 +185,6 @@ body{ color:var(--RS__visitedColor); } -:root[style*="readium-sepia-on"] svg, -:root[style*="readium-sepia-on"] img{ - background-color:transparent !important; - mix-blend-mode:multiply; -} - @media screen and (-ms-high-contrast: active){ :root{ @@ -258,6 +251,49 @@ body{ @media screen and (prefers-reduced-motion){ } +:root[style*="--USER__backgroundColor"]{ + background-color:var(--USER__backgroundColor) !important; +} + +:root[style*="--USER__backgroundColor"] *{ + background-color:transparent !important; +} + +:root[style*="--USER__textColor"]{ + color:var(--USER__textColor) !important; +} + +:root[style*="--USER__textColor"] *:not(a){ + color:inherit !important; + background-color:transparent !important; + border-color:currentcolor !important; +} + +:root[style*="--USER__textColor"] svg text{ + fill:currentcolor !important; + stroke:none !important; +} + +:root[style*="--USER__linkColor"] a:link, +:root[style*="--USER__linkColor"] a:link *{ + color:var(--USER__linkColor) !important; +} + +:root[style*="--USER__visitedColor"] a:visited, +:root[style*="--USER__visitedColor"] a:visited *{ + color:var(--USER__visitedColor) !important; +} + +:root[style*="--USER__selectionBackgroundColor"][style*="--USER__selectionTextColor"] ::-moz-selection{ + color:var(--USER__selectionTextColor) !important; + background-color:var(--USER__selectionBackgroundColor) !important; +} + +:root[style*="--USER__selectionBackgroundColor"][style*="--USER__selectionTextColor"] ::selection{ + color:var(--USER__selectionTextColor) !important; + background-color:var(--USER__selectionBackgroundColor) !important; +} + :root[style*="--USER__colCount"]{ -webkit-column-count:var(--USER__colCount); -moz-column-count:var(--USER__colCount); @@ -284,22 +320,6 @@ body{ max-width:var(--USER__lineLength) !important; } -:root[style*="--USER__backgroundColor"]{ - background-color:var(--USER__backgroundColor) !important; -} - -:root[style*="--USER__backgroundColor"] *{ - background-color:transparent !important; -} - -:root[style*="--USER__textColor"]{ - color:var(--USER__textColor) !important; -} - -:root[style*="--USER__textColor"] *:not(h1):not(h2):not(h3):not(h4):not(h5):not(h6):not(pre){ - color:inherit !important; -} - :root[style*="readium-font-on"][style*="--USER__fontFamily"]{ font-family:var(--USER__fontFamily) !important; } @@ -308,7 +328,7 @@ body{ font-family:inherit !important; } -:root[style*="--USER__fontSize"]{ +:root[style*="--USER__fontSize"] body{ zoom:var(--USER__fontSize) !important; } @@ -319,18 +339,18 @@ body{ } } -:root[style*="readium-advanced-on"][style*="--USER__lineHeight"]{ +:root[style*="--USER__lineHeight"]{ line-height:var(--USER__lineHeight) !important; } -:root[style*="readium-advanced-on"][style*="--USER__lineHeight"] body, -:root[style*="readium-advanced-on"][style*="--USER__lineHeight"] p, -:root[style*="readium-advanced-on"][style*="--USER__lineHeight"] li, -:root[style*="readium-advanced-on"][style*="--USER__lineHeight"] div{ +:root[style*="--USER__lineHeight"] body, +:root[style*="--USER__lineHeight"] p, +:root[style*="--USER__lineHeight"] li, +:root[style*="--USER__lineHeight"] div{ line-height:inherit; } -:root[style*="readium-advanced-on"][style*="--USER__paraSpacing"] p{ +:root[style*="--USER__paraSpacing"] p{ margin-top:var(--USER__paraSpacing) !important; margin-bottom:var(--USER__paraSpacing) !important; } @@ -352,77 +372,135 @@ body{ font-optical-sizing:var(--USER__fontOpticalSizing) !important; } -:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] h1, -:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] h2, -:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] h3, -:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] h4, -:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] h5, -:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] h6, -:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] p, -:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] li, -:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] div{ +:root[style*="--USER__letterSpacing"] h1, +:root[style*="--USER__letterSpacing"] h2, +:root[style*="--USER__letterSpacing"] h3, +:root[style*="--USER__letterSpacing"] h4, +:root[style*="--USER__letterSpacing"] h5, +:root[style*="--USER__letterSpacing"] h6, +:root[style*="--USER__letterSpacing"] p, +:root[style*="--USER__letterSpacing"] li, +:root[style*="--USER__letterSpacing"] div, +:root[style*="--USER__letterSpacing"] dt, +:root[style*="--USER__letterSpacing"] dd{ letter-spacing:var(--USER__letterSpacing); font-variant:none; } -:root[style*="readium-advanced-on"][style*="readium-noRuby-on"] body rt, -:root[style*="readium-advanced-on"][style*="readium-noRuby-on"] body rp{ +:root[style*="readium-noRuby-on"] body rt, +:root[style*="readium-noRuby-on"] body rp{ display:none; } +:root[style*="readium-blend-on"] svg, +:root[style*="readium-blend-on"] img{ + background-color:transparent !important; + mix-blend-mode:multiply !important; +} + +:root[style*="--USER__darkenImages"] img{ + -webkit-filter:brightness(var(--USER__darkenImages)) !important; + filter:brightness(var(--USER__darkenImages)) !important; +} + +:root[style*="readium-darken-on"] img{ + -webkit-filter:brightness(80%) !important; + filter:brightness(80%) !important; +} + +:root[style*="--USER__invertImages"] img{ + -webkit-filter:invert(var(--USER__invertImages)) !important; + filter:invert(var(--USER__invertImages)) !important; +} + +:root[style*="readium-invert-on"] img{ + -webkit-filter:invert(100%) !important; + filter:invert(100%) !important; +} + +:root[style*="--USER__darkenImages"][style*="--USER__invertImages"] img{ + -webkit-filter:brightness(var(--USER__darkenImages)) invert(var(--USER__invertImages)) !important; + filter:brightness(var(--USER__darkenImages)) invert(var(--USER__invertImages)) !important; +} + +:root[style*="readium-darken-on"][style*="--USER__invertImages"] img{ + -webkit-filter:brightness(80%) invert(var(--USER__invertImages)) !important; + filter:brightness(80%) invert(var(--USER__invertImages)) !important; +} + +:root[style*="--USER__darkenImages"][style*="readium-invert-on"] img{ + -webkit-filter:brightness(var(--USER__darkenImages)) invert(100%) !important; + filter:brightness(var(--USER__darkenImages)) invert(100%) !important; +} + +:root[style*="readium-darken-on"][style*="readium-invert-on"] img{ + -webkit-filter:brightness(80%) invert(100%) !important; + filter:brightness(80%) invert(100%) !important; +} + +:root[style*="--USER__invertGaiji"] img[class*="gaiji"]{ + -webkit-filter:invert(var(--USER__invertGaiji)) !important; + filter:invert(var(--USER__invertGaiji)) !important; +} + +:root[style*="readium-invertGaiji-on"] img[class*="gaiji"]{ + -webkit-filter:invert(100%) !important; + filter:invert(100%) !important; +} + @supports not (zoom: 1){ - :root[style*="readium-advanced-on"]{ + :root[style*="readium-normalize-on"]{ --USER__typeScale:1.2; } - :root[style*="readium-advanced-on"] p, - :root[style*="readium-advanced-on"] li, - :root[style*="readium-advanced-on"] div, - :root[style*="readium-advanced-on"] pre, - :root[style*="readium-advanced-on"] dd{ + :root[style*="readium-normalize-on"] p, + :root[style*="readium-normalize-on"] li, + :root[style*="readium-normalize-on"] div, + :root[style*="readium-normalize-on"] pre, + :root[style*="readium-normalize-on"] dd{ font-size:1rem !important; } - :root[style*="readium-advanced-on"] h1{ + :root[style*="readium-normalize-on"] h1{ font-size:1.75rem !important; font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important; } - :root[style*="readium-advanced-on"] h2{ + :root[style*="readium-normalize-on"] h2{ font-size:1.5rem !important; font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important; } - :root[style*="readium-advanced-on"] h3{ + :root[style*="readium-normalize-on"] h3{ font-size:1.25rem !important; font-size:calc(1rem * var(--USER__typeScale)) !important; } - :root[style*="readium-advanced-on"] h4, - :root[style*="readium-advanced-on"] h5, - :root[style*="readium-advanced-on"] h6{ + :root[style*="readium-normalize-on"] h4, + :root[style*="readium-normalize-on"] h5, + :root[style*="readium-normalize-on"] h6{ font-size:1rem !important; } - :root[style*="readium-advanced-on"] small{ + :root[style*="readium-normalize-on"] small{ font-size:smaller !important; } - :root[style*="readium-advanced-on"] sub, - :root[style*="readium-advanced-on"] sup{ + :root[style*="readium-normalize-on"] sub, + :root[style*="readium-normalize-on"] sup{ font-size:67.5% !important; } - :root[style*="readium-advanced-on"][style*="--USER__typeScale"] h1{ + :root[style*="readium-normalize-on"][style*="--USER__typeScale"] h1{ font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important; } - :root[style*="readium-advanced-on"][style*="--USER__typeScale"] h2{ + :root[style*="readium-normalize-on"][style*="--USER__typeScale"] h2{ font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important; } - :root[style*="readium-advanced-on"][style*="--USER__typeScale"] h3{ + :root[style*="readium-normalize-on"][style*="--USER__typeScale"] h3{ font-size:calc(1rem * var(--USER__typeScale)) !important; } } \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-horizontal/ReadiumCSS-before.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-horizontal/ReadiumCSS-before.css index b4bfa36c26..b7009eac49 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-horizontal/ReadiumCSS-before.css +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-horizontal/ReadiumCSS-before.css @@ -1,5 +1,5 @@ /* - * Readium CSS (v. 2.0.0-alpha.5) + * Readium CSS (v. 2.0.0-beta.7) * Developers: Jiminy Panoz * Copyright (c) 2017. Readium Foundation. All rights reserved. * Use of this source code is governed by a BSD-style license which is detailed in the @@ -24,14 +24,20 @@ } :root{ - --RS__oldStyleTf:"Iowan Old Style", sitka, "Sitka Text", palatino, "Book Antiqua", "URW Palladio L", p052, serif; - --RS__modernTf:athelas, constantia, charter, "Bitstream Charter", cambria, "Georgia Pro", georgia, serif; - --RS__sansTf:-ui-sans-serif, -apple-system, system-ui, blinkmacsystemfont, "Segoe UI Variable", "Segoe UI", inter, roboto, "Helvetica Neue", "Arial Nova", "Liberation Sans", arial, sans-serif; - --RS__humanistTf:seravek, calibri, "Gill Sans Nova", roboto, ubuntu, "DejaVu Sans", source-sans-pro, sans-serif; - --RS__monospaceTf:ui-monospace, "Andale Mono", "Cascadia Code", "Source Code Pro", menlo, consolas, "DejaVu Sans Mono", monospace; + + --RS__monospaceTf:ui-monospace, 'Andale Mono', 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', monospace; + + --RS__humanistTf:Seravek, Calibri, 'Gill Sans Nova', Roboto, Ubuntu, 'DejaVu Sans', source-sans-pro, sans-serif; + + --RS__sansTf:-ui-sans-serif, -apple-system, system-ui, BlinkMacSystemFont, 'Segoe UI Variable', 'Segoe UI', Inter, Roboto, 'Helvetica Neue', 'Arial Nova', 'Liberation Sans', Arial, sans-serif; + + --RS__modernTf:Athelas, Constantia, Charter, 'Bitstream Charter', Cambria, 'Georgia Pro', Georgia, serif; + + --RS__oldStyleTf:'Iowan Old Style', Sitka, 'Sitka Text', Palatino, 'Book Antiqua', 'URW Palladio L', P052, serif; --RS__baseFontFamily:var(--RS__oldStyleTf); --RS__lineHeightCompensation:1; - --RS__baseLineHeight:calc((1em + (2ex - 1ch) - ((1rem - 16px) * 0.1667)) * var(--RS__lineHeightCompensation)); + + --RS__baseLineHeight:calc(1.5 * var(--RS__lineHeightCompensation)); } html{ @@ -188,10 +194,18 @@ math{ } :root{ - --RS__backgroundColor:#FFFFFF; - --RS__textColor:#121212; - --RS__selectionBackgroundColor:#b4d8fe; + --RS__selectionTextColor:inherit; + + --RS__selectionBackgroundColor:#b4d8fe; + + --RS__visitedColor:#551A8B; + + --RS__linkColor:#0000EE; + + --RS__textColor:#121212; + + --RS__backgroundColor:#FFFFFF; } :root{ diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-horizontal/ReadiumCSS-default.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-horizontal/ReadiumCSS-default.css index 2e0bc2ca37..9e84d5e5ab 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-horizontal/ReadiumCSS-default.css +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-horizontal/ReadiumCSS-default.css @@ -1,5 +1,5 @@ /* - * Readium CSS (v. 2.0.0-alpha.5) + * Readium CSS (v. 2.0.0-beta.7) * Developers: Jiminy Panoz * Copyright (c) 2017. Readium Foundation. All rights reserved. * Use of this source code is governed by a BSD-style license which is detailed in the diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-vertical/ReadiumCSS-after.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-vertical/ReadiumCSS-after.css index 638645fad1..4e89486f99 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-vertical/ReadiumCSS-after.css +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-vertical/ReadiumCSS-after.css @@ -1,5 +1,5 @@ /* - * Readium CSS (v. 2.0.0-alpha.5) + * Readium CSS (v. 2.0.0-beta.7) * Developers: Jiminy Panoz * Copyright (c) 2017. Readium Foundation. All rights reserved. * Use of this source code is governed by a BSD-style license which is detailed in the @@ -15,11 +15,18 @@ @namespace svg url("http://www.w3.org/2000/svg"); :root{ - --RS__colWidth:100vh; - --RS__colCount:1; - --RS__colGap:0; - --RS__defaultLineLength:40rem; - --RS__pageGutter:0; + + --RS__viewportWidth:100%; + + --RS__pageGutter:0; + + --RS__defaultLineLength:40rem; + + --RS__colGap:0; + + --RS__colCount:1; + + --RS__colWidth:100vw; } @page{ @@ -50,8 +57,8 @@ padding:0 !important; margin:0 !important; font-size:100% !important; - - -webkit-text-size-adjust:100%; + -webkit-text-size-adjust:none; + text-size-adjust:none; box-sizing:border-box; hanging-punctuation:last allow-end; @@ -101,7 +108,7 @@ body{ :root[style*="readium-scroll-on"] body, :root[style*="readium-noVerticalPagination-on"] body{ - --RS__defaultLineLength:40.01rem !important; + max-width:var(--RS__defaultLineLength) !important; } @supports (overflow: clip){ @@ -116,13 +123,18 @@ body{ } :root[style*="readium-night-on"]{ - --RS__backgroundColor:#000000; - --RS__textColor:#FEFEFE; - --RS__linkColor:#63caff; - --RS__visitedColor:#0099E5; - --RS__selectionBackgroundColor:#b4d8fe; --RS__selectionTextColor:inherit; + + --RS__selectionBackgroundColor:#b4d8fe; + + --RS__visitedColor:#0099E5; + + --RS__linkColor:#63caff; + + --RS__textColor:#FEFEFE; + + --RS__backgroundColor:#000000; } :root[style*="readium-night-on"] *:not(a){ @@ -153,31 +165,19 @@ body{ filter:invert(100%); } -:root[style*="readium-night-on"][style*="readium-darken-on"] img{ - -webkit-filter:brightness(80%); - filter:brightness(80%); -} +:root[style*="readium-sepia-on"]{ -:root[style*="readium-night-on"][style*="readium-invert-on"] img{ - -webkit-filter:invert(100%); - filter:invert(100%); -} + --RS__selectionTextColor:inherit; -:root[style*="readium-night-on"][style*="readium-darken-on"][style*="readium-invert-on"] img{ - -webkit-filter:brightness(80%) invert(100%); - filter:brightness(80%) invert(100%); -} + --RS__selectionBackgroundColor:#b4d8fe; -:root[style*="readium-sepia-on"]{ - --RS__backgroundColor:#faf4e8; - --RS__textColor:#121212; + --RS__visitedColor:#551A8B; --RS__linkColor:#0000EE; - --RS__visitedColor:#551A8B; - --RS__selectionBackgroundColor:#b4d8fe; - --RS__selectionTextColor:inherit; - --RS__defaultLineLength:40.01rem; + --RS__textColor:#121212; + + --RS__backgroundColor:#faf4e8; } :root[style*="readium-sepia-on"] *:not(a){ @@ -195,12 +195,6 @@ body{ color:var(--RS__visitedColor); } -:root[style*="readium-sepia-on"] svg, -:root[style*="readium-sepia-on"] img{ - background-color:transparent !important; - mix-blend-mode:multiply; -} - @media screen and (-ms-high-contrast: active){ :root{ @@ -267,10 +261,6 @@ body{ @media screen and (prefers-reduced-motion){ } -:root[style*="--USER__lineLength"] body{ - max-height:var(--USER__lineLength) !important; - } - :root[style*="--USER__backgroundColor"]{ background-color:var(--USER__backgroundColor) !important; } @@ -283,10 +273,41 @@ body{ color:var(--USER__textColor) !important; } -:root[style*="--USER__textColor"] *:not(h1):not(h2):not(h3):not(h4):not(h5):not(h6):not(pre){ +:root[style*="--USER__textColor"] *:not(a){ color:inherit !important; + background-color:transparent !important; + border-color:currentcolor !important; +} + +:root[style*="--USER__textColor"] svg text{ + fill:currentcolor !important; + stroke:none !important; +} + +:root[style*="--USER__linkColor"] a:link, +:root[style*="--USER__linkColor"] a:link *{ + color:var(--USER__linkColor) !important; } +:root[style*="--USER__visitedColor"] a:visited, +:root[style*="--USER__visitedColor"] a:visited *{ + color:var(--USER__visitedColor) !important; +} + +:root[style*="--USER__selectionBackgroundColor"][style*="--USER__selectionTextColor"] ::-moz-selection{ + color:var(--USER__selectionTextColor) !important; + background-color:var(--USER__selectionBackgroundColor) !important; +} + +:root[style*="--USER__selectionBackgroundColor"][style*="--USER__selectionTextColor"] ::selection{ + color:var(--USER__selectionTextColor) !important; + background-color:var(--USER__selectionBackgroundColor) !important; +} + +:root[style*="--USER__lineLength"] body{ + max-height:var(--USER__lineLength) !important; + } + :root[style*="readium-font-on"][style*="--USER__fontFamily"]{ font-family:var(--USER__fontFamily) !important; } @@ -295,7 +316,7 @@ body{ font-family:inherit !important; } -:root[style*="--USER__fontSize"]{ +:root[style*="--USER__fontSize"] body{ zoom:var(--USER__fontSize) !important; } @@ -306,18 +327,18 @@ body{ } } -:root[style*="readium-advanced-on"][style*="--USER__lineHeight"]{ +:root[style*="--USER__lineHeight"]{ line-height:var(--USER__lineHeight) !important; } -:root[style*="readium-advanced-on"][style*="--USER__lineHeight"] body, -:root[style*="readium-advanced-on"][style*="--USER__lineHeight"] p, -:root[style*="readium-advanced-on"][style*="--USER__lineHeight"] li, -:root[style*="readium-advanced-on"][style*="--USER__lineHeight"] div{ +:root[style*="--USER__lineHeight"] body, +:root[style*="--USER__lineHeight"] p, +:root[style*="--USER__lineHeight"] li, +:root[style*="--USER__lineHeight"] div{ line-height:inherit; } -:root[style*="readium-advanced-on"][style*="--USER__paraSpacing"] p{ +:root[style*="--USER__paraSpacing"] p{ margin-right:var(--USER__paraSpacing) !important; margin-left:var(--USER__paraSpacing) !important; } @@ -339,77 +360,135 @@ body{ font-optical-sizing:var(--USER__fontOpticalSizing) !important; } -:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] h1, -:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] h2, -:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] h3, -:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] h4, -:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] h5, -:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] h6, -:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] p, -:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] li, -:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] div{ +:root[style*="--USER__letterSpacing"] h1, +:root[style*="--USER__letterSpacing"] h2, +:root[style*="--USER__letterSpacing"] h3, +:root[style*="--USER__letterSpacing"] h4, +:root[style*="--USER__letterSpacing"] h5, +:root[style*="--USER__letterSpacing"] h6, +:root[style*="--USER__letterSpacing"] p, +:root[style*="--USER__letterSpacing"] li, +:root[style*="--USER__letterSpacing"] div, +:root[style*="--USER__letterSpacing"] dt, +:root[style*="--USER__letterSpacing"] dd{ letter-spacing:var(--USER__letterSpacing); font-variant:none; } -:root[style*="readium-advanced-on"][style*="readium-noRuby-on"] body rt, -:root[style*="readium-advanced-on"][style*="readium-noRuby-on"] body rp{ +:root[style*="readium-noRuby-on"] body rt, +:root[style*="readium-noRuby-on"] body rp{ display:none; } +:root[style*="readium-blend-on"] svg, +:root[style*="readium-blend-on"] img{ + background-color:transparent !important; + mix-blend-mode:multiply !important; +} + +:root[style*="--USER__darkenImages"] img{ + -webkit-filter:brightness(var(--USER__darkenImages)) !important; + filter:brightness(var(--USER__darkenImages)) !important; +} + +:root[style*="readium-darken-on"] img{ + -webkit-filter:brightness(80%) !important; + filter:brightness(80%) !important; +} + +:root[style*="--USER__invertImages"] img{ + -webkit-filter:invert(var(--USER__invertImages)) !important; + filter:invert(var(--USER__invertImages)) !important; +} + +:root[style*="readium-invert-on"] img{ + -webkit-filter:invert(100%) !important; + filter:invert(100%) !important; +} + +:root[style*="--USER__darkenImages"][style*="--USER__invertImages"] img{ + -webkit-filter:brightness(var(--USER__darkenImages)) invert(var(--USER__invertImages)) !important; + filter:brightness(var(--USER__darkenImages)) invert(var(--USER__invertImages)) !important; +} + +:root[style*="readium-darken-on"][style*="--USER__invertImages"] img{ + -webkit-filter:brightness(80%) invert(var(--USER__invertImages)) !important; + filter:brightness(80%) invert(var(--USER__invertImages)) !important; +} + +:root[style*="--USER__darkenImages"][style*="readium-invert-on"] img{ + -webkit-filter:brightness(var(--USER__darkenImages)) invert(100%) !important; + filter:brightness(var(--USER__darkenImages)) invert(100%) !important; +} + +:root[style*="readium-darken-on"][style*="readium-invert-on"] img{ + -webkit-filter:brightness(80%) invert(100%) !important; + filter:brightness(80%) invert(100%) !important; +} + +:root[style*="--USER__invertGaiji"] img[class*="gaiji"]{ + -webkit-filter:invert(var(--USER__invertGaiji)) !important; + filter:invert(var(--USER__invertGaiji)) !important; +} + +:root[style*="readium-invertGaiji-on"] img[class*="gaiji"]{ + -webkit-filter:invert(100%) !important; + filter:invert(100%) !important; +} + @supports not (zoom: 1){ - :root[style*="readium-advanced-on"]{ + :root[style*="readium-normalize-on"]{ --USER__typeScale:1.2; } - :root[style*="readium-advanced-on"] p, - :root[style*="readium-advanced-on"] li, - :root[style*="readium-advanced-on"] div, - :root[style*="readium-advanced-on"] pre, - :root[style*="readium-advanced-on"] dd{ + :root[style*="readium-normalize-on"] p, + :root[style*="readium-normalize-on"] li, + :root[style*="readium-normalize-on"] div, + :root[style*="readium-normalize-on"] pre, + :root[style*="readium-normalize-on"] dd{ font-size:1rem !important; } - :root[style*="readium-advanced-on"] h1{ + :root[style*="readium-normalize-on"] h1{ font-size:1.75rem !important; font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important; } - :root[style*="readium-advanced-on"] h2{ + :root[style*="readium-normalize-on"] h2{ font-size:1.5rem !important; font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important; } - :root[style*="readium-advanced-on"] h3{ + :root[style*="readium-normalize-on"] h3{ font-size:1.25rem !important; font-size:calc(1rem * var(--USER__typeScale)) !important; } - :root[style*="readium-advanced-on"] h4, - :root[style*="readium-advanced-on"] h5, - :root[style*="readium-advanced-on"] h6{ + :root[style*="readium-normalize-on"] h4, + :root[style*="readium-normalize-on"] h5, + :root[style*="readium-normalize-on"] h6{ font-size:1rem !important; } - :root[style*="readium-advanced-on"] small{ + :root[style*="readium-normalize-on"] small{ font-size:smaller !important; } - :root[style*="readium-advanced-on"] sub, - :root[style*="readium-advanced-on"] sup{ + :root[style*="readium-normalize-on"] sub, + :root[style*="readium-normalize-on"] sup{ font-size:67.5% !important; } - :root[style*="readium-advanced-on"][style*="--USER__typeScale"] h1{ + :root[style*="readium-normalize-on"][style*="--USER__typeScale"] h1{ font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important; } - :root[style*="readium-advanced-on"][style*="--USER__typeScale"] h2{ + :root[style*="readium-normalize-on"][style*="--USER__typeScale"] h2{ font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important; } - :root[style*="readium-advanced-on"][style*="--USER__typeScale"] h3{ + :root[style*="readium-normalize-on"][style*="--USER__typeScale"] h3{ font-size:calc(1rem * var(--USER__typeScale)) !important; } } \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-vertical/ReadiumCSS-before.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-vertical/ReadiumCSS-before.css index 12633a47bb..259f835576 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-vertical/ReadiumCSS-before.css +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-vertical/ReadiumCSS-before.css @@ -1,5 +1,5 @@ /* - * Readium CSS (v. 2.0.0-alpha.5) + * Readium CSS (v. 2.0.0-beta.7) * Developers: Jiminy Panoz * Copyright (c) 2017. Readium Foundation. All rights reserved. * Use of this source code is governed by a BSD-style license which is detailed in the @@ -24,14 +24,20 @@ } :root{ - --RS__oldStyleTf:"Iowan Old Style", sitka, "Sitka Text", palatino, "Book Antiqua", "URW Palladio L", p052, serif; - --RS__modernTf:athelas, constantia, charter, "Bitstream Charter", cambria, "Georgia Pro", georgia, serif; - --RS__sansTf:-ui-sans-serif, -apple-system, system-ui, blinkmacsystemfont, "Segoe UI Variable", "Segoe UI", inter, roboto, "Helvetica Neue", "Arial Nova", "Liberation Sans", arial, sans-serif; - --RS__humanistTf:seravek, calibri, "Gill Sans Nova", roboto, ubuntu, "DejaVu Sans", source-sans-pro, sans-serif; - --RS__monospaceTf:ui-monospace, "Andale Mono", "Cascadia Code", "Source Code Pro", menlo, consolas, "DejaVu Sans Mono", monospace; + + --RS__monospaceTf:ui-monospace, 'Andale Mono', 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', monospace; + + --RS__humanistTf:Seravek, Calibri, 'Gill Sans Nova', Roboto, Ubuntu, 'DejaVu Sans', source-sans-pro, sans-serif; + + --RS__sansTf:-ui-sans-serif, -apple-system, system-ui, BlinkMacSystemFont, 'Segoe UI Variable', 'Segoe UI', Inter, Roboto, 'Helvetica Neue', 'Arial Nova', 'Liberation Sans', Arial, sans-serif; + + --RS__modernTf:Athelas, Constantia, Charter, 'Bitstream Charter', Cambria, 'Georgia Pro', Georgia, serif; + + --RS__oldStyleTf:'Iowan Old Style', Sitka, 'Sitka Text', Palatino, 'Book Antiqua', 'URW Palladio L', P052, serif; --RS__baseFontFamily:var(--RS__oldStyleTf); --RS__lineHeightCompensation:1; - --RS__baseLineHeight:calc((1em + (2ex - 1ch) - ((1rem - 16px) * 0.1667)) * var(--RS__lineHeightCompensation)); + + --RS__baseLineHeight:calc(1.5 * var(--RS__lineHeightCompensation)); } html{ @@ -188,10 +194,18 @@ math{ } :root{ - --RS__backgroundColor:#FFFFFF; - --RS__textColor:#121212; - --RS__selectionBackgroundColor:#b4d8fe; + --RS__selectionTextColor:inherit; + + --RS__selectionBackgroundColor:#b4d8fe; + + --RS__visitedColor:#551A8B; + + --RS__linkColor:#0000EE; + + --RS__textColor:#121212; + + --RS__backgroundColor:#FFFFFF; } :root{ diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-vertical/ReadiumCSS-default.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-vertical/ReadiumCSS-default.css index d9513f9fed..4ee9de4600 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-vertical/ReadiumCSS-default.css +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-vertical/ReadiumCSS-default.css @@ -1,5 +1,5 @@ /* - * Readium CSS (v. 2.0.0-alpha.5) + * Readium CSS (v. 2.0.0-beta.7) * Developers: Jiminy Panoz * Copyright (c) 2017. Readium Foundation. All rights reserved. * Use of this source code is governed by a BSD-style license which is detailed in the diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/rtl/ReadiumCSS-after.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/rtl/ReadiumCSS-after.css index 7594380f6a..1f37e37a9a 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/rtl/ReadiumCSS-after.css +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/rtl/ReadiumCSS-after.css @@ -1,5 +1,5 @@ /* - * Readium CSS (v. 2.0.0-alpha.5) + * Readium CSS (v. 2.0.0-beta.7) * Developers: Jiminy Panoz * Copyright (c) 2017. Readium Foundation. All rights reserved. * Use of this source code is governed by a BSD-style license which is detailed in the @@ -15,12 +15,18 @@ @namespace svg url("http://www.w3.org/2000/svg"); :root{ - --RS__colWidth:100vw; - --RS__colCount:1; - --RS__colGap:0; - --RS__defaultLineLength:40rem; - --RS__pageGutter:0; + --RS__viewportWidth:100%; + + --RS__pageGutter:0; + + --RS__defaultLineLength:40rem; + + --RS__colGap:0; + + --RS__colCount:1; + + --RS__colWidth:100vw; } @page{ @@ -51,8 +57,8 @@ padding:0 !important; margin:0 !important; font-size:100% !important; - - -webkit-text-size-adjust:100%; + -webkit-text-size-adjust:none; + text-size-adjust:none; box-sizing:border-box; -webkit-touch-callout:none; } @@ -91,8 +97,8 @@ body{ } :root[style*="readium-scroll-on"] body{ + max-width:var(--RS__defaultLineLength) !important; overflow:auto; - --RS__defaultLineLength:40rem !important; } @supports (overflow: clip){ @@ -107,13 +113,18 @@ body{ } :root[style*="readium-night-on"]{ - --RS__backgroundColor:#000000; - --RS__textColor:#FEFEFE; - --RS__linkColor:#63caff; - --RS__visitedColor:#0099E5; - --RS__selectionBackgroundColor:#b4d8fe; --RS__selectionTextColor:inherit; + + --RS__selectionBackgroundColor:#b4d8fe; + + --RS__visitedColor:#0099E5; + + --RS__linkColor:#63caff; + + --RS__textColor:#FEFEFE; + + --RS__backgroundColor:#000000; } :root[style*="readium-night-on"] *:not(a){ @@ -144,31 +155,19 @@ body{ filter:invert(100%); } -:root[style*="readium-night-on"][style*="readium-darken-on"] img{ - -webkit-filter:brightness(80%); - filter:brightness(80%); -} +:root[style*="readium-sepia-on"]{ -:root[style*="readium-night-on"][style*="readium-invert-on"] img{ - -webkit-filter:invert(100%); - filter:invert(100%); -} + --RS__selectionTextColor:inherit; -:root[style*="readium-night-on"][style*="readium-darken-on"][style*="readium-invert-on"] img{ - -webkit-filter:brightness(80%) invert(100%); - filter:brightness(80%) invert(100%); -} + --RS__selectionBackgroundColor:#b4d8fe; -:root[style*="readium-sepia-on"]{ - --RS__backgroundColor:#faf4e8; - --RS__textColor:#121212; + --RS__visitedColor:#551A8B; --RS__linkColor:#0000EE; - --RS__visitedColor:#551A8B; - --RS__selectionBackgroundColor:#b4d8fe; - --RS__selectionTextColor:inherit; - --RS__defaultLineLength:40.01rem; + --RS__textColor:#121212; + + --RS__backgroundColor:#faf4e8; } :root[style*="readium-sepia-on"] *:not(a){ @@ -186,12 +185,6 @@ body{ color:var(--RS__visitedColor); } -:root[style*="readium-sepia-on"] svg, -:root[style*="readium-sepia-on"] img{ - background-color:transparent !important; - mix-blend-mode:multiply; -} - @media screen and (-ms-high-contrast: active){ :root{ @@ -258,6 +251,49 @@ body{ @media screen and (prefers-reduced-motion){ } +:root[style*="--USER__backgroundColor"]{ + background-color:var(--USER__backgroundColor) !important; +} + +:root[style*="--USER__backgroundColor"] *{ + background-color:transparent !important; +} + +:root[style*="--USER__textColor"]{ + color:var(--USER__textColor) !important; +} + +:root[style*="--USER__textColor"] *:not(a){ + color:inherit !important; + background-color:transparent !important; + border-color:currentcolor !important; +} + +:root[style*="--USER__textColor"] svg text{ + fill:currentcolor !important; + stroke:none !important; +} + +:root[style*="--USER__linkColor"] a:link, +:root[style*="--USER__linkColor"] a:link *{ + color:var(--USER__linkColor) !important; +} + +:root[style*="--USER__visitedColor"] a:visited, +:root[style*="--USER__visitedColor"] a:visited *{ + color:var(--USER__visitedColor) !important; +} + +:root[style*="--USER__selectionBackgroundColor"][style*="--USER__selectionTextColor"] ::-moz-selection{ + color:var(--USER__selectionTextColor) !important; + background-color:var(--USER__selectionBackgroundColor) !important; +} + +:root[style*="--USER__selectionBackgroundColor"][style*="--USER__selectionTextColor"] ::selection{ + color:var(--USER__selectionTextColor) !important; + background-color:var(--USER__selectionBackgroundColor) !important; +} + :root[style*="--USER__colCount"]{ -webkit-column-count:var(--USER__colCount); -moz-column-count:var(--USER__colCount); @@ -284,29 +320,14 @@ body{ max-width:var(--USER__lineLength) !important; } -:root[style*="--USER__backgroundColor"]{ - background-color:var(--USER__backgroundColor) !important; -} - -:root[style*="--USER__backgroundColor"] *{ - background-color:transparent !important; -} - -:root[style*="--USER__textColor"]{ - color:var(--USER__textColor) !important; -} - -:root[style*="--USER__textColor"] *:not(h1):not(h2):not(h3):not(h4):not(h5):not(h6):not(pre){ - color:inherit !important; -} - -:root[style*="readium-advanced-on"][style*="--USER__textAlign"]{ +:root[style*="--USER__textAlign"]{ text-align:var(--USER__textAlign); } -:root[style*="readium-advanced-on"][style*="--USER__textAlign"] body, -:root[style*="readium-advanced-on"][style*="--USER__textAlign"] *:not(blockquote):not(figcaption) p, -:root[style*="readium-advanced-on"][style*="--USER__textAlign"] li{ +:root[style*="--USER__textAlign"] body, +:root[style*="--USER__textAlign"] p:not(blockquote p):not(figcaption p):not(hgroup p), +:root[style*="--USER__textAlign"] li, +:root[style*="--USER__textAlign"] dd{ text-align:var(--USER__textAlign) !important; -moz-text-align-last:auto !important; -epub-text-align-last:auto !important; @@ -321,7 +342,7 @@ body{ font-family:inherit !important; } -:root[style*="--USER__fontSize"]{ +:root[style*="--USER__fontSize"] body{ zoom:var(--USER__fontSize) !important; } @@ -332,48 +353,50 @@ body{ } } -:root[style*="readium-advanced-on"][style*="--USER__lineHeight"]{ +:root[style*="--USER__lineHeight"]{ line-height:var(--USER__lineHeight) !important; } -:root[style*="readium-advanced-on"][style*="--USER__lineHeight"] body, -:root[style*="readium-advanced-on"][style*="--USER__lineHeight"] p, -:root[style*="readium-advanced-on"][style*="--USER__lineHeight"] li, -:root[style*="readium-advanced-on"][style*="--USER__lineHeight"] div{ +:root[style*="--USER__lineHeight"] body, +:root[style*="--USER__lineHeight"] p, +:root[style*="--USER__lineHeight"] li, +:root[style*="--USER__lineHeight"] div{ line-height:inherit; } -:root[style*="readium-advanced-on"][style*="--USER__paraSpacing"] p{ +:root[style*="--USER__paraSpacing"] p{ margin-top:var(--USER__paraSpacing) !important; margin-bottom:var(--USER__paraSpacing) !important; } -:root[style*="readium-advanced-on"][style*="--USER__paraIndent"] p{ +:root[style*="--USER__paraIndent"] p{ text-indent:var(--USER__paraIndent) !important; } -:root[style*="readium-advanced-on"][style*="--USER__paraIndent"] p *, -:root[style*="readium-advanced-on"][style*="--USER__paraIndent"] p:first-letter{ +:root[style*="--USER__paraIndent"] p *, +:root[style*="--USER__paraIndent"] p:first-letter{ text-indent:0 !important; } -:root[style*="readium-advanced-on"][style*="--USER__wordSpacing"] h1, -:root[style*="readium-advanced-on"][style*="--USER__wordSpacing"] h2, -:root[style*="readium-advanced-on"][style*="--USER__wordSpacing"] h3, -:root[style*="readium-advanced-on"][style*="--USER__wordSpacing"] h4, -:root[style*="readium-advanced-on"][style*="--USER__wordSpacing"] h5, -:root[style*="readium-advanced-on"][style*="--USER__wordSpacing"] h6, -:root[style*="readium-advanced-on"][style*="--USER__wordSpacing"] p, -:root[style*="readium-advanced-on"][style*="--USER__wordSpacing"] li, -:root[style*="readium-advanced-on"][style*="--USER__wordSpacing"] div{ +:root[style*="--USER__wordSpacing"] h1, +:root[style*="--USER__wordSpacing"] h2, +:root[style*="--USER__wordSpacing"] h3, +:root[style*="--USER__wordSpacing"] h4, +:root[style*="--USER__wordSpacing"] h5, +:root[style*="--USER__wordSpacing"] h6, +:root[style*="--USER__wordSpacing"] p, +:root[style*="--USER__wordSpacing"] li, +:root[style*="--USER__wordSpacing"] div, +:root[style*="--USER__wordSpacing"] dt, +:root[style*="--USER__wordSpacing"] dd{ word-spacing:var(--USER__wordSpacing); } -:root[style*="readium-advanced-on"][style*="--USER__arabicLigatures"]{ +:root[style*="--USER__ligatures"]{ font-variant-ligatures:var(--USER__ligatures) !important; } -:root[style*="readium-advanced-on"][style*="--USER__arabicLigatures"] *{ +:root[style*="--USER__ligatures"] *{ font-variant-ligatures:inherit !important; } @@ -394,59 +417,115 @@ body{ font-optical-sizing:var(--USER__fontOpticalSizing) !important; } +:root[style*="readium-blend-on"] svg, +:root[style*="readium-blend-on"] img{ + background-color:transparent !important; + mix-blend-mode:multiply !important; +} + +:root[style*="--USER__darkenImages"] img{ + -webkit-filter:brightness(var(--USER__darkenImages)) !important; + filter:brightness(var(--USER__darkenImages)) !important; +} + +:root[style*="readium-darken-on"] img{ + -webkit-filter:brightness(80%) !important; + filter:brightness(80%) !important; +} + +:root[style*="--USER__invertImages"] img{ + -webkit-filter:invert(var(--USER__invertImages)) !important; + filter:invert(var(--USER__invertImages)) !important; +} + +:root[style*="readium-invert-on"] img{ + -webkit-filter:invert(100%) !important; + filter:invert(100%) !important; +} + +:root[style*="--USER__darkenImages"][style*="--USER__invertImages"] img{ + -webkit-filter:brightness(var(--USER__darkenImages)) invert(var(--USER__invertImages)) !important; + filter:brightness(var(--USER__darkenImages)) invert(var(--USER__invertImages)) !important; +} + +:root[style*="readium-darken-on"][style*="--USER__invertImages"] img{ + -webkit-filter:brightness(80%) invert(var(--USER__invertImages)) !important; + filter:brightness(80%) invert(var(--USER__invertImages)) !important; +} + +:root[style*="--USER__darkenImages"][style*="readium-invert-on"] img{ + -webkit-filter:brightness(var(--USER__darkenImages)) invert(100%) !important; + filter:brightness(var(--USER__darkenImages)) invert(100%) !important; +} + +:root[style*="readium-darken-on"][style*="readium-invert-on"] img{ + -webkit-filter:brightness(80%) invert(100%) !important; + filter:brightness(80%) invert(100%) !important; +} + +:root[style*="--USER__invertGaiji"] img[class*="gaiji"]{ + -webkit-filter:invert(var(--USER__invertGaiji)) !important; + filter:invert(var(--USER__invertGaiji)) !important; +} + +:root[style*="readium-invertGaiji-on"] img[class*="gaiji"]{ + -webkit-filter:invert(100%) !important; + filter:invert(100%) !important; +} + @supports not (zoom: 1){ - :root[style*="readium-advanced-on"]{ + :root[style*="readium-normalize-on"]{ --USER__typeScale:1.2; } - :root[style*="readium-advanced-on"] p, - :root[style*="readium-advanced-on"] li, - :root[style*="readium-advanced-on"] div, - :root[style*="readium-advanced-on"] pre, - :root[style*="readium-advanced-on"] dd{ + :root[style*="readium-normalize-on"] p, + :root[style*="readium-normalize-on"] li, + :root[style*="readium-normalize-on"] div, + :root[style*="readium-normalize-on"] pre, + :root[style*="readium-normalize-on"] dd{ font-size:1rem !important; } - :root[style*="readium-advanced-on"] h1{ + :root[style*="readium-normalize-on"] h1{ font-size:1.75rem !important; font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important; } - :root[style*="readium-advanced-on"] h2{ + :root[style*="readium-normalize-on"] h2{ font-size:1.5rem !important; font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important; } - :root[style*="readium-advanced-on"] h3{ + :root[style*="readium-normalize-on"] h3{ font-size:1.25rem !important; font-size:calc(1rem * var(--USER__typeScale)) !important; } - :root[style*="readium-advanced-on"] h4, - :root[style*="readium-advanced-on"] h5, - :root[style*="readium-advanced-on"] h6{ + :root[style*="readium-normalize-on"] h4, + :root[style*="readium-normalize-on"] h5, + :root[style*="readium-normalize-on"] h6{ font-size:1rem !important; } - :root[style*="readium-advanced-on"] small{ + :root[style*="readium-normalize-on"] small{ font-size:smaller !important; } - :root[style*="readium-advanced-on"] sub, - :root[style*="readium-advanced-on"] sup{ + :root[style*="readium-normalize-on"] sub, + :root[style*="readium-normalize-on"] sup{ font-size:67.5% !important; } - :root[style*="readium-advanced-on"][style*="--USER__typeScale"] h1{ + :root[style*="readium-normalize-on"][style*="--USER__typeScale"] h1{ font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important; } - :root[style*="readium-advanced-on"][style*="--USER__typeScale"] h2{ + :root[style*="readium-normalize-on"][style*="--USER__typeScale"] h2{ font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important; } - :root[style*="readium-advanced-on"][style*="--USER__typeScale"] h3{ + :root[style*="readium-normalize-on"][style*="--USER__typeScale"] h3{ font-size:calc(1rem * var(--USER__typeScale)) !important; } } \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/rtl/ReadiumCSS-before.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/rtl/ReadiumCSS-before.css index b4bfa36c26..b7009eac49 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/rtl/ReadiumCSS-before.css +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/rtl/ReadiumCSS-before.css @@ -1,5 +1,5 @@ /* - * Readium CSS (v. 2.0.0-alpha.5) + * Readium CSS (v. 2.0.0-beta.7) * Developers: Jiminy Panoz * Copyright (c) 2017. Readium Foundation. All rights reserved. * Use of this source code is governed by a BSD-style license which is detailed in the @@ -24,14 +24,20 @@ } :root{ - --RS__oldStyleTf:"Iowan Old Style", sitka, "Sitka Text", palatino, "Book Antiqua", "URW Palladio L", p052, serif; - --RS__modernTf:athelas, constantia, charter, "Bitstream Charter", cambria, "Georgia Pro", georgia, serif; - --RS__sansTf:-ui-sans-serif, -apple-system, system-ui, blinkmacsystemfont, "Segoe UI Variable", "Segoe UI", inter, roboto, "Helvetica Neue", "Arial Nova", "Liberation Sans", arial, sans-serif; - --RS__humanistTf:seravek, calibri, "Gill Sans Nova", roboto, ubuntu, "DejaVu Sans", source-sans-pro, sans-serif; - --RS__monospaceTf:ui-monospace, "Andale Mono", "Cascadia Code", "Source Code Pro", menlo, consolas, "DejaVu Sans Mono", monospace; + + --RS__monospaceTf:ui-monospace, 'Andale Mono', 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', monospace; + + --RS__humanistTf:Seravek, Calibri, 'Gill Sans Nova', Roboto, Ubuntu, 'DejaVu Sans', source-sans-pro, sans-serif; + + --RS__sansTf:-ui-sans-serif, -apple-system, system-ui, BlinkMacSystemFont, 'Segoe UI Variable', 'Segoe UI', Inter, Roboto, 'Helvetica Neue', 'Arial Nova', 'Liberation Sans', Arial, sans-serif; + + --RS__modernTf:Athelas, Constantia, Charter, 'Bitstream Charter', Cambria, 'Georgia Pro', Georgia, serif; + + --RS__oldStyleTf:'Iowan Old Style', Sitka, 'Sitka Text', Palatino, 'Book Antiqua', 'URW Palladio L', P052, serif; --RS__baseFontFamily:var(--RS__oldStyleTf); --RS__lineHeightCompensation:1; - --RS__baseLineHeight:calc((1em + (2ex - 1ch) - ((1rem - 16px) * 0.1667)) * var(--RS__lineHeightCompensation)); + + --RS__baseLineHeight:calc(1.5 * var(--RS__lineHeightCompensation)); } html{ @@ -188,10 +194,18 @@ math{ } :root{ - --RS__backgroundColor:#FFFFFF; - --RS__textColor:#121212; - --RS__selectionBackgroundColor:#b4d8fe; + --RS__selectionTextColor:inherit; + + --RS__selectionBackgroundColor:#b4d8fe; + + --RS__visitedColor:#551A8B; + + --RS__linkColor:#0000EE; + + --RS__textColor:#121212; + + --RS__backgroundColor:#FFFFFF; } :root{ diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/rtl/ReadiumCSS-default.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/rtl/ReadiumCSS-default.css index 03f9e7dbe8..a77057515e 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/rtl/ReadiumCSS-default.css +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/rtl/ReadiumCSS-default.css @@ -1,5 +1,5 @@ /* - * Readium CSS (v. 2.0.0-alpha.5) + * Readium CSS (v. 2.0.0-beta.7) * Developers: Jiminy Panoz * Copyright (c) 2017. Readium Foundation. All rights reserved. * Use of this source code is governed by a BSD-style license which is detailed in the From 32875e82715db3bf014eaf4dbeace3e1ef229e43 Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Fri, 11 Apr 2025 08:56:07 +0200 Subject: [PATCH 34/88] Add virtual column when necessary --- .../src/index-reflowable-injectable.ts | 2 ++ .../web/scripts/src/util/columns.ts | 36 +++++++++++++++++++ .../generated/reflowable-injectable-script.js | 2 +- .../reflowable-injectable-script.js.map | 2 +- .../navigator/web/fixed/SpreadWebView.kt | 17 +++------ .../web/reflowable/ReflowableResource.kt | 29 ++++++--------- .../navigator/web/webview/WebViewCallbacks.kt | 22 ++++++++++++ 7 files changed, 76 insertions(+), 34 deletions(-) create mode 100644 readium/navigators/web/scripts/src/util/columns.ts create mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewCallbacks.kt diff --git a/readium/navigators/web/scripts/src/index-reflowable-injectable.ts b/readium/navigators/web/scripts/src/index-reflowable-injectable.ts index 76e01920c4..a8bb50f560 100644 --- a/readium/navigators/web/scripts/src/index-reflowable-injectable.ts +++ b/readium/navigators/web/scripts/src/index-reflowable-injectable.ts @@ -15,6 +15,7 @@ import { import { DocumentBridge } from "./bridge/all-document-bridge" import { CssBridge } from "./bridge/reflowable-css-bridge" import { GesturesDetector } from "./common/gestures" +import { appendVirtualColumnIfNeeded } from "./util/columns" declare global { interface Window { @@ -48,6 +49,7 @@ window.documentState.onScriptsLoaded() window.addEventListener("load", (event) => { const observer = new ResizeObserver(() => { requestAnimationFrame(() => { + appendVirtualColumnIfNeeded(window) window.documentState.onDocumentResized() }) }) diff --git a/readium/navigators/web/scripts/src/util/columns.ts b/readium/navigators/web/scripts/src/util/columns.ts new file mode 100644 index 0000000000..657036e17e --- /dev/null +++ b/readium/navigators/web/scripts/src/util/columns.ts @@ -0,0 +1,36 @@ +/** + * Having an odd number of columns when displaying two columns per screen causes snapping and page + * turning issues. To fix this, we insert a blank virtual column at the end of the resource. + */ +export function appendVirtualColumnIfNeeded(wnd: Window) { + const id = "readium-virtual-page" + let virtualCol = wnd.document.getElementById(id) + if (getColumnCountPerScreen(wnd) !== 2) { + if (virtualCol) { + virtualCol.remove() + } + } else { + const documentWidth = wnd.document.scrollingElement!.scrollWidth + const colCount = documentWidth / wnd.innerWidth + const hasOddColCount = (Math.round(colCount * 2) / 2) % 1 > 0.1 + if (hasOddColCount) { + if (virtualCol) virtualCol.remove() + else { + virtualCol = wnd.document.createElement("div") + virtualCol.setAttribute("id", id) + virtualCol.dataset.readium = "true" + virtualCol.style.breakBefore = "column" + virtualCol.innerHTML = "​" // zero-width space + wnd.document.body.appendChild(virtualCol) + } + } + } +} + +function getColumnCountPerScreen(wnd: Window) { + return parseInt( + wnd + .getComputedStyle(wnd.document.documentElement) + .getPropertyValue("column-count") + ) +} diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js index 008f954fdc..5802791a07 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js @@ -1,2 +1,2 @@ -!function(){"use strict";const e=new class{constructor(e){this.nativeApi=e}onTap(e){this.nativeApi.onTap(JSON.stringify(e))}onLinkActivated(e,t){this.nativeApi.onLinkActivated(e,t)}}(window.gestures),t={onTap:t=>{const n={x:(t.clientX-visualViewport.offsetLeft)*visualViewport.scale,y:(t.clientY-visualViewport.offsetTop)*visualViewport.scale};e.onTap(n)},onLinkActivated:(t,n)=>{e.onLinkActivated(t,n)}};new class{constructor(e,t){this.window=e,this.listener=t,document.addEventListener("click",(e=>{this.onClick(e)}),!1)}onClick(e){if(e.defaultPrevented)return;const t=this.window.getSelection();if(t&&"Range"==t.type)return;let n;n=e.target instanceof HTMLElement?this.nearestInteractiveElement(e.target):null,n?n instanceof HTMLAnchorElement&&this.listener.onLinkActivated(n.href,n.outerHTML):this.listener.onTap(e),e.stopPropagation(),e.preventDefault()}nearestInteractiveElement(e){return null==e?null:-1!=["a","audio","button","canvas","details","input","label","option","select","submit","textarea","video"].indexOf(e.nodeName.toLowerCase())||e.hasAttribute("contenteditable")&&"false"!=e.getAttribute("contenteditable").toLowerCase()?e:e.parentElement?this.nearestInteractiveElement(e.parentElement):null}}(window,t),Window.prototype.readiumcss=new class{constructor(e){this.document=e}setProperties(e){for(const[t,n]of e)this.setProperty(t,n)}setProperty(e,t){null===t||""===t?this.removeProperty(e):document.documentElement.style.setProperty(e,t,"important")}removeProperty(e){document.documentElement.style.removeProperty(e)}}(window.document),window.documentState.onScriptsLoaded(),window.addEventListener("load",(e=>{new ResizeObserver((()=>{requestAnimationFrame((()=>{window.documentState.onDocumentResized()}))})).observe(document.body),window.documentState.onDocumentLoaded()}))}(); +!function(){"use strict";const e=new class{constructor(e){this.nativeApi=e}onTap(e){this.nativeApi.onTap(JSON.stringify(e))}onLinkActivated(e,t){this.nativeApi.onLinkActivated(e,t)}}(window.gestures),t={onTap:t=>{const n={x:(t.clientX-visualViewport.offsetLeft)*visualViewport.scale,y:(t.clientY-visualViewport.offsetTop)*visualViewport.scale};e.onTap(n)},onLinkActivated:(t,n)=>{e.onLinkActivated(t,n)}};new class{constructor(e,t){this.window=e,this.listener=t,document.addEventListener("click",(e=>{this.onClick(e)}),!1)}onClick(e){if(e.defaultPrevented)return;const t=this.window.getSelection();if(t&&"Range"==t.type)return;let n;n=e.target instanceof HTMLElement?this.nearestInteractiveElement(e.target):null,n?n instanceof HTMLAnchorElement&&this.listener.onLinkActivated(n.href,n.outerHTML):this.listener.onTap(e),e.stopPropagation(),e.preventDefault()}nearestInteractiveElement(e){return null==e?null:-1!=["a","audio","button","canvas","details","input","label","option","select","submit","textarea","video"].indexOf(e.nodeName.toLowerCase())||e.hasAttribute("contenteditable")&&"false"!=e.getAttribute("contenteditable").toLowerCase()?e:e.parentElement?this.nearestInteractiveElement(e.parentElement):null}}(window,t),Window.prototype.readiumcss=new class{constructor(e){this.document=e}setProperties(e){for(const[t,n]of e)this.setProperty(t,n)}setProperty(e,t){null===t||""===t?this.removeProperty(e):document.documentElement.style.setProperty(e,t,"important")}removeProperty(e){document.documentElement.style.removeProperty(e)}}(window.document),window.documentState.onScriptsLoaded(),window.addEventListener("load",(e=>{new ResizeObserver((()=>{requestAnimationFrame((()=>{(function(e){const t="readium-virtual-page";let n=e.document.getElementById(t);if(2!==function(e){return parseInt(e.getComputedStyle(e.document.documentElement).getPropertyValue("column-count"))}(e))n&&n.remove();else{const o=e.document.scrollingElement.scrollWidth/e.innerWidth;Math.round(2*o)/2%1>.1&&(n?n.remove():(n=e.document.createElement("div"),n.setAttribute("id",t),n.dataset.readium="true",n.style.breakBefore="column",n.innerHTML="​",e.document.body.appendChild(n)))}})(window),window.documentState.onDocumentResized()}))})).observe(document.body),window.documentState.onDocumentLoaded()}))}(); //# sourceMappingURL=reflowable-injectable-script.js.map \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map index ed71e88c52..0ce3c97652 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map @@ -1 +1 @@ -{"version":3,"file":"reflowable-injectable-script.js","mappings":"yBAWA,MAAMA,EAAiB,ICXhB,MACH,WAAAC,CAAYC,GACRC,KAAKC,UAAYF,CACrB,CACA,KAAAG,CAAMC,GACFH,KAAKC,UAAUC,MAAME,KAAKC,UAAUF,GACxC,CACA,eAAAG,CAAgBC,EAAMC,GAClBR,KAAKC,UAAUK,gBAAgBC,EAAMC,EACzC,GDE6CC,OAAOC,UAClDC,EAAmB,CACrBT,MAAQC,IACJ,MAAMS,EAAW,CACbC,GAAIV,EAAMW,QAAUC,eAAeC,YAAcD,eAAeE,MAChEC,GAAIf,EAAMgB,QAAUJ,eAAeK,WAAaL,eAAeE,OAEnEpB,EAAeK,MAAMU,EAAS,EAElCN,gBAAiB,CAACC,EAAMC,KACpBX,EAAeS,gBAAgBC,EAAMC,EAAU,GAGvD,IExBO,MACH,WAAAV,CAAYW,EAAQY,GAChBrB,KAAKS,OAASA,EACdT,KAAKqB,SAAWA,EAChBC,SAASC,iBAAiB,SAAUpB,IAChCH,KAAKwB,QAAQrB,EAAM,IACpB,EACP,CACA,OAAAqB,CAAQrB,GACJ,GAAIA,EAAMsB,iBACN,OAEJ,MAAMC,EAAY1B,KAAKS,OAAOkB,eAC9B,GAAID,GAA+B,SAAlBA,EAAUE,KAIvB,OAEJ,IAAIC,EAEAA,EADA1B,EAAM2B,kBAAkBC,YACP/B,KAAKgC,0BAA0B7B,EAAM2B,QAGrC,KAEjBD,EACIA,aAA0BI,mBAC1BjC,KAAKqB,SAASf,gBAAgBuB,EAAetB,KAAMsB,EAAeK,WAItElC,KAAKqB,SAASnB,MAAMC,GAExBA,EAAMgC,kBACNhC,EAAMiC,gBACV,CAEA,yBAAAJ,CAA0BK,GACtB,OAAe,MAAXA,EACO,MAgBqD,GAdxC,CACpB,IACA,QACA,SACA,SACA,UACA,QACA,QACA,SACA,SACA,SACA,WACA,SAEgBC,QAAQD,EAAQE,SAASC,gBAIzCH,EAAQI,aAAa,oBACoC,SAAzDJ,EAAQK,aAAa,mBAAmBF,cAJjCH,EAQPA,EAAQM,cACD3C,KAAKgC,0BAA0BK,EAAQM,eAE3C,IACX,GF7CiBlC,OAAQE,GAC7BiC,OAAOC,UAAUC,WAAa,IGzBvB,MACH,WAAAhD,CAAYwB,GACRtB,KAAKsB,SAAWA,CACpB,CACA,aAAAyB,CAAcC,GACV,IAAK,MAAOC,EAAKC,KAAUF,EACvBhD,KAAKmD,YAAYF,EAAKC,EAE9B,CAEA,WAAAC,CAAYF,EAAKC,GACC,OAAVA,GAA4B,KAAVA,EAClBlD,KAAKoD,eAAeH,GAGP3B,SAAS+B,gBAGjBC,MAAMH,YAAYF,EAAKC,EAAO,YAE3C,CAEA,cAAAE,CAAeH,GACE3B,SAAS+B,gBACjBC,MAAMF,eAAeH,EAC9B,GHAwCxC,OAAOa,UACnDb,OAAO8C,cAAcC,kBAErB/C,OAAOc,iBAAiB,QAASpB,IACZ,IAAIsD,gBAAe,KAChCC,uBAAsB,KAClBjD,OAAO8C,cAAcI,mBAAmB,GAC1C,IAEGC,QAAQtC,SAASuC,MAC1BpD,OAAO8C,cAAcO,kBAAkB,G","sources":["webpack://readium-js/./src/index-reflowable-injectable.ts","webpack://readium-js/./src/bridge/all-gestures-bridge.ts","webpack://readium-js/./src/common/gestures.ts","webpack://readium-js/./src/bridge/reflowable-css-bridge.ts"],"sourcesContent":["//\n// Copyright 2024 Readium Foundation. All rights reserved.\n// Use of this source code is governed by the BSD-style license\n// available in the top-level LICENSE file of the project.\n//\n/**\n * Script loaded by reflowable resources.\n */\nimport { BridgeGesturesAdapter, } from \"./bridge/all-gestures-bridge\";\nimport { CssBridge } from \"./bridge/reflowable-css-bridge\";\nimport { GesturesDetector } from \"./common/gestures\";\nconst bridgeListener = new BridgeGesturesAdapter(window.gestures);\nconst gesturesListener = {\n onTap: (event) => {\n const tapEvent = {\n x: (event.clientX - visualViewport.offsetLeft) * visualViewport.scale,\n y: (event.clientY - visualViewport.offsetTop) * visualViewport.scale,\n };\n bridgeListener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n bridgeListener.onLinkActivated(href, outerHtml);\n },\n};\nnew GesturesDetector(window, gesturesListener);\nWindow.prototype.readiumcss = new CssBridge(window.document);\nwindow.documentState.onScriptsLoaded();\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nwindow.addEventListener(\"load\", (event) => {\n const observer = new ResizeObserver(() => {\n requestAnimationFrame(() => {\n window.documentState.onDocumentResized();\n });\n });\n observer.observe(document.body);\n window.documentState.onDocumentLoaded();\n});\n","export class BridgeGesturesAdapter {\n constructor(gesturesApi) {\n this.nativeApi = gesturesApi;\n }\n onTap(event) {\n this.nativeApi.onTap(JSON.stringify(event));\n }\n onLinkActivated(href, outerHtml) {\n this.nativeApi.onLinkActivated(href, outerHtml);\n }\n}\n","export class GesturesDetector {\n constructor(window, listener) {\n this.window = window;\n this.listener = listener;\n document.addEventListener(\"click\", (event) => {\n this.onClick(event);\n }, false);\n }\n onClick(event) {\n if (event.defaultPrevented) {\n return;\n }\n const selection = this.window.getSelection();\n if (selection && selection.type == \"Range\") {\n // There's an on-going selection, the tap will dismiss it so we don't forward it.\n // selection.type might be None (collapsed) or Caret with a collapsed range\n // when there is not true selection.\n return;\n }\n let nearestElement;\n if (event.target instanceof HTMLElement) {\n nearestElement = this.nearestInteractiveElement(event.target);\n }\n else {\n nearestElement = null;\n }\n if (nearestElement) {\n if (nearestElement instanceof HTMLAnchorElement) {\n this.listener.onLinkActivated(nearestElement.href, nearestElement.outerHTML);\n }\n }\n else {\n this.listener.onTap(event);\n }\n event.stopPropagation();\n event.preventDefault();\n }\n // See. https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling\n nearestInteractiveElement(element) {\n if (element == null) {\n return null;\n }\n const interactiveTags = [\n \"a\",\n \"audio\",\n \"button\",\n \"canvas\",\n \"details\",\n \"input\",\n \"label\",\n \"option\",\n \"select\",\n \"submit\",\n \"textarea\",\n \"video\",\n ];\n if (interactiveTags.indexOf(element.nodeName.toLowerCase()) != -1) {\n return element;\n }\n // Checks whether the element is editable by the user.\n if (element.hasAttribute(\"contenteditable\") &&\n element.getAttribute(\"contenteditable\").toLowerCase() != \"false\") {\n return element;\n }\n // Checks parents recursively because the touch might be for example on an inside a .\n if (element.parentElement) {\n return this.nearestInteractiveElement(element.parentElement);\n }\n return null;\n }\n}\n","export class CssBridge {\n constructor(document) {\n this.document = document;\n }\n setProperties(properties) {\n for (const [key, value] of properties) {\n this.setProperty(key, value);\n }\n }\n // For setting user setting.\n setProperty(key, value) {\n if (value === null || value === \"\") {\n this.removeProperty(key);\n }\n else {\n const root = document.documentElement;\n // The `!important` annotation is added with `setProperty()` because if it's part of the\n // `value`, it will be ignored by the Web View.\n root.style.setProperty(key, value, \"important\");\n }\n }\n // For removing user setting.\n removeProperty(key) {\n const root = document.documentElement;\n root.style.removeProperty(key);\n }\n}\n"],"names":["bridgeListener","constructor","gesturesApi","this","nativeApi","onTap","event","JSON","stringify","onLinkActivated","href","outerHtml","window","gestures","gesturesListener","tapEvent","x","clientX","visualViewport","offsetLeft","scale","y","clientY","offsetTop","listener","document","addEventListener","onClick","defaultPrevented","selection","getSelection","type","nearestElement","target","HTMLElement","nearestInteractiveElement","HTMLAnchorElement","outerHTML","stopPropagation","preventDefault","element","indexOf","nodeName","toLowerCase","hasAttribute","getAttribute","parentElement","Window","prototype","readiumcss","setProperties","properties","key","value","setProperty","removeProperty","documentElement","style","documentState","onScriptsLoaded","ResizeObserver","requestAnimationFrame","onDocumentResized","observe","body","onDocumentLoaded"],"sourceRoot":""} \ No newline at end of file +{"version":3,"file":"reflowable-injectable-script.js","mappings":"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","sources":["webpack://readium-js/./src/index-reflowable-injectable.ts","webpack://readium-js/./src/bridge/all-gestures-bridge.ts","webpack://readium-js/./src/common/gestures.ts","webpack://readium-js/./src/bridge/reflowable-css-bridge.ts","webpack://readium-js/./src/util/columns.ts"],"sourcesContent":["//\n// Copyright 2024 Readium Foundation. All rights reserved.\n// Use of this source code is governed by the BSD-style license\n// available in the top-level LICENSE file of the project.\n//\n/**\n * Script loaded by reflowable resources.\n */\nimport { BridgeGesturesAdapter, } from \"./bridge/all-gestures-bridge\";\nimport { CssBridge } from \"./bridge/reflowable-css-bridge\";\nimport { GesturesDetector } from \"./common/gestures\";\nimport { appendVirtualColumnIfNeeded } from \"./util/columns\";\nconst bridgeListener = new BridgeGesturesAdapter(window.gestures);\nconst gesturesListener = {\n onTap: (event) => {\n const tapEvent = {\n x: (event.clientX - visualViewport.offsetLeft) * visualViewport.scale,\n y: (event.clientY - visualViewport.offsetTop) * visualViewport.scale,\n };\n bridgeListener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n bridgeListener.onLinkActivated(href, outerHtml);\n },\n};\nnew GesturesDetector(window, gesturesListener);\nWindow.prototype.readiumcss = new CssBridge(window.document);\nwindow.documentState.onScriptsLoaded();\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nwindow.addEventListener(\"load\", (event) => {\n const observer = new ResizeObserver(() => {\n requestAnimationFrame(() => {\n appendVirtualColumnIfNeeded(window);\n window.documentState.onDocumentResized();\n });\n });\n observer.observe(document.body);\n window.documentState.onDocumentLoaded();\n});\n","export class BridgeGesturesAdapter {\n constructor(gesturesApi) {\n this.nativeApi = gesturesApi;\n }\n onTap(event) {\n this.nativeApi.onTap(JSON.stringify(event));\n }\n onLinkActivated(href, outerHtml) {\n this.nativeApi.onLinkActivated(href, outerHtml);\n }\n}\n","export class GesturesDetector {\n constructor(window, listener) {\n this.window = window;\n this.listener = listener;\n document.addEventListener(\"click\", (event) => {\n this.onClick(event);\n }, false);\n }\n onClick(event) {\n if (event.defaultPrevented) {\n return;\n }\n const selection = this.window.getSelection();\n if (selection && selection.type == \"Range\") {\n // There's an on-going selection, the tap will dismiss it so we don't forward it.\n // selection.type might be None (collapsed) or Caret with a collapsed range\n // when there is not true selection.\n return;\n }\n let nearestElement;\n if (event.target instanceof HTMLElement) {\n nearestElement = this.nearestInteractiveElement(event.target);\n }\n else {\n nearestElement = null;\n }\n if (nearestElement) {\n if (nearestElement instanceof HTMLAnchorElement) {\n this.listener.onLinkActivated(nearestElement.href, nearestElement.outerHTML);\n }\n }\n else {\n this.listener.onTap(event);\n }\n event.stopPropagation();\n event.preventDefault();\n }\n // See. https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling\n nearestInteractiveElement(element) {\n if (element == null) {\n return null;\n }\n const interactiveTags = [\n \"a\",\n \"audio\",\n \"button\",\n \"canvas\",\n \"details\",\n \"input\",\n \"label\",\n \"option\",\n \"select\",\n \"submit\",\n \"textarea\",\n \"video\",\n ];\n if (interactiveTags.indexOf(element.nodeName.toLowerCase()) != -1) {\n return element;\n }\n // Checks whether the element is editable by the user.\n if (element.hasAttribute(\"contenteditable\") &&\n element.getAttribute(\"contenteditable\").toLowerCase() != \"false\") {\n return element;\n }\n // Checks parents recursively because the touch might be for example on an inside a .\n if (element.parentElement) {\n return this.nearestInteractiveElement(element.parentElement);\n }\n return null;\n }\n}\n","export class CssBridge {\n constructor(document) {\n this.document = document;\n }\n setProperties(properties) {\n for (const [key, value] of properties) {\n this.setProperty(key, value);\n }\n }\n // For setting user setting.\n setProperty(key, value) {\n if (value === null || value === \"\") {\n this.removeProperty(key);\n }\n else {\n const root = document.documentElement;\n // The `!important` annotation is added with `setProperty()` because if it's part of the\n // `value`, it will be ignored by the Web View.\n root.style.setProperty(key, value, \"important\");\n }\n }\n // For removing user setting.\n removeProperty(key) {\n const root = document.documentElement;\n root.style.removeProperty(key);\n }\n}\n","/**\n * Having an odd number of columns when displaying two columns per screen causes snapping and page\n * turning issues. To fix this, we insert a blank virtual column at the end of the resource.\n */\nexport function appendVirtualColumnIfNeeded(wnd) {\n const id = \"readium-virtual-page\";\n let virtualCol = wnd.document.getElementById(id);\n if (getColumnCountPerScreen(wnd) !== 2) {\n if (virtualCol) {\n virtualCol.remove();\n }\n }\n else {\n const documentWidth = wnd.document.scrollingElement.scrollWidth;\n const colCount = documentWidth / wnd.innerWidth;\n const hasOddColCount = (Math.round(colCount * 2) / 2) % 1 > 0.1;\n if (hasOddColCount) {\n if (virtualCol)\n virtualCol.remove();\n else {\n virtualCol = wnd.document.createElement(\"div\");\n virtualCol.setAttribute(\"id\", id);\n virtualCol.dataset.readium = \"true\";\n virtualCol.style.breakBefore = \"column\";\n virtualCol.innerHTML = \"​\"; // zero-width space\n wnd.document.body.appendChild(virtualCol);\n }\n }\n }\n}\nfunction getColumnCountPerScreen(wnd) {\n return parseInt(wnd\n .getComputedStyle(wnd.document.documentElement)\n .getPropertyValue(\"column-count\"));\n}\n"],"names":["bridgeListener","constructor","gesturesApi","this","nativeApi","onTap","event","JSON","stringify","onLinkActivated","href","outerHtml","window","gestures","gesturesListener","tapEvent","x","clientX","visualViewport","offsetLeft","scale","y","clientY","offsetTop","listener","document","addEventListener","onClick","defaultPrevented","selection","getSelection","type","nearestElement","target","HTMLElement","nearestInteractiveElement","HTMLAnchorElement","outerHTML","stopPropagation","preventDefault","element","indexOf","nodeName","toLowerCase","hasAttribute","getAttribute","parentElement","Window","prototype","readiumcss","setProperties","properties","key","value","setProperty","removeProperty","documentElement","style","documentState","onScriptsLoaded","ResizeObserver","requestAnimationFrame","wnd","id","virtualCol","getElementById","parseInt","getComputedStyle","getPropertyValue","getColumnCountPerScreen","remove","colCount","scrollingElement","scrollWidth","innerWidth","Math","round","createElement","setAttribute","dataset","readium","breakBefore","innerHTML","body","appendChild","appendVirtualColumnIfNeeded","onDocumentResized","observe","onDocumentLoaded"],"sourceRoot":""} \ No newline at end of file diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt index 1b1d0306c1..3e982e9f3a 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt @@ -8,7 +8,6 @@ package org.readium.navigator.web.fixed import android.annotation.SuppressLint import android.view.View -import android.webkit.WebView import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.pager.PagerState import androidx.compose.runtime.Composable @@ -34,6 +33,7 @@ import org.readium.navigator.web.webview.WebView import org.readium.navigator.web.webview.WebViewScrollController import org.readium.navigator.web.webview.WebViewScrollable2DState import org.readium.navigator.web.webview.WebViewState +import org.readium.navigator.web.webview.invokeOnReadyToBeDrawn import org.readium.r2.shared.ExperimentalReadiumApi import org.readium.r2.shared.util.AbsoluteUrl @@ -64,18 +64,9 @@ internal fun SpreadWebView( onScriptsLoadedDelegate = onScriptsLoaded, onDocumentLoadedDelegate = { state.webView?.apply { - post { - postVisualStateCallback( - 0, - object : WebView.VisualStateCallback() { - override fun onComplete(requestId: Long) { - with(this@apply) { - val scrollController = WebViewScrollController(this) - spreadScrollState.scrollController.value = scrollController - } - } - } - ) + invokeOnReadyToBeDrawn { + val scrollController = WebViewScrollController(this) + spreadScrollState.scrollController.value = scrollController } } }, diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt index 95f446481f..3887ac98ec 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt @@ -11,7 +11,6 @@ package org.readium.navigator.web.reflowable import android.annotation.SuppressLint import android.view.MotionEvent import android.view.View -import android.webkit.WebView import androidx.compose.foundation.background import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.gestures.detectTapGestures @@ -48,6 +47,7 @@ import org.readium.navigator.web.webapi.GesturesApi import org.readium.navigator.web.webview.RelaxedWebView import org.readium.navigator.web.webview.WebView import org.readium.navigator.web.webview.WebViewScrollController +import org.readium.navigator.web.webview.invokeOnReadyToBeDrawn import org.readium.navigator.web.webview.rememberWebViewState import org.readium.r2.shared.ExperimentalReadiumApi import org.readium.r2.shared.util.AbsoluteUrl @@ -108,23 +108,14 @@ internal fun ReflowableResource( }, onDocumentLoadedDelegate = { webViewState.webView?.apply { - post { - postVisualStateCallback( - 0, - object : WebView.VisualStateCallback() { - override fun onComplete(requestId: Long) { - with(this@apply) { - val scrollController = WebViewScrollController(this) - scrollController.scrollToProgression(resourceState.progression.ratio, scrollOrientation.value) - resourceState.scrollController.value = scrollController - setOnScrollChangeListener { view, scrollX, scrollY, oldScrollX, oldScrollY -> - onScrollChanged(scrollController.progression(scrollOrientation.value)) - } - } - contentIsLaidOut.value = true - } - } - ) + invokeOnReadyToBeDrawn { + val scrollController = WebViewScrollController(this) + scrollController.scrollToProgression(resourceState.progression.ratio, scrollOrientation.value) + resourceState.scrollController.value = scrollController + setOnScrollChangeListener { view, scrollX, scrollY, oldScrollX, oldScrollY -> + onScrollChanged(scrollController.progression(scrollOrientation.value)) + } + contentIsLaidOut.value = true } } }, @@ -180,7 +171,7 @@ internal fun ReflowableResource( ) } // Changing font size invalidates the scroll position of the Webview - key(layout, scrollOrientation.value, userProperties) { + key(layout, scrollOrientation.value) { WebView( modifier = Modifier // Detect taps on padding diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewCallbacks.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewCallbacks.kt new file mode 100644 index 0000000000..fd4fdf16a4 --- /dev/null +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewCallbacks.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2024 Readium Foundation. All rights reserved. + * Use of this source code is governed by the BSD-style license + * available in the top-level LICENSE file of the project. + */ + +package org.readium.navigator.web.webview + +import android.webkit.WebView + +internal fun WebView.invokeOnReadyToBeDrawn(callback: (WebView) -> Unit) { + post { + postVisualStateCallback( + 0, + object : WebView.VisualStateCallback() { + override fun onComplete(requestId: Long) { + callback(this@invokeOnReadyToBeDrawn) + } + } + ) + } +} From ab2c42ab68ab1fedda9050618165834cad0951a2 Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Fri, 11 Apr 2025 13:36:53 +0200 Subject: [PATCH 35/88] Fix snapping issue due to padding included in page size --- .../web/scripts/src/util/columns.ts | 6 ++-- .../navigator/web/ReflowableWebRendition.kt | 35 ++++++------------- 2 files changed, 15 insertions(+), 26 deletions(-) diff --git a/readium/navigators/web/scripts/src/util/columns.ts b/readium/navigators/web/scripts/src/util/columns.ts index 657036e17e..f945898396 100644 --- a/readium/navigators/web/scripts/src/util/columns.ts +++ b/readium/navigators/web/scripts/src/util/columns.ts @@ -1,6 +1,8 @@ /** - * Having an odd number of columns when displaying two columns per screen causes snapping and page - * turning issues. To fix this, we insert a blank virtual column at the end of the resource. + * In paginated mode, the width of each resource must be a multiple of the viewport size + * for proper snapping. This may not be automatically the case if the number of + * columns in the resource is not a multiple of the number of columns fitting in the viewport. + * To fix this, we insert a blank virtual column at the end of the resource. */ export function appendVirtualColumnIfNeeded(wnd: Window) { const id = "readium-virtual-page" diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt index 5cd466fec3..04c8b85f9b 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt @@ -14,6 +14,7 @@ import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.displayCutout import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.runtime.Composable import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.remember @@ -80,19 +81,16 @@ public fun ReflowableWebRendition( val coroutineScope = rememberCoroutineScope() - val paginatedVerticalPadding = - when (LocalConfiguration.current.orientation) { - Configuration.ORIENTATION_LANDSCAPE -> AbsolutePaddingValues(vertical = 20.dp) - else -> AbsolutePaddingValues(vertical = 40.dp) - } - - val insetsPaddingValues = windowInsets.asAbsolutePaddingValues() - - val padding = + val resourcePadding = if (state.layoutDelegate.settings.value.scroll) { - insetsPaddingValues + AbsolutePaddingValues() } else { - insetsPaddingValues + paginatedVerticalPadding + when (LocalConfiguration.current.orientation) { + Configuration.ORIENTATION_LANDSCAPE -> + AbsolutePaddingValues(vertical = 20.dp) + else -> + AbsolutePaddingValues(vertical = 40.dp) + } } val backgroundColor = ( @@ -148,7 +146,7 @@ public fun ReflowableWebRendition( scrollDispatcher.pagerOrientation = orientation RenditionPager( - modifier = Modifier, + modifier = Modifier.windowInsetsPadding(windowInsets), state = state.pagerState, scrollDispatcher = scrollDispatcher, beyondViewportPageCount = 3, @@ -166,7 +164,7 @@ public fun ReflowableWebRendition( webViewClient = state.webViewClient, viewportSize = viewportSize.value, backgroundColor = Color(backgroundColor), - padding = padding, + padding = resourcePadding, reverseLayout = reverseLayout, scroll = state.layoutDelegate.settings.value.scroll, verticalText = state.layoutDelegate.settings.value.verticalText, @@ -197,17 +195,6 @@ public fun ReflowableWebRendition( } } -@Composable -private fun WindowInsets.asAbsolutePaddingValues(): AbsolutePaddingValues { - val density = LocalDensity.current - val layoutDirection = LocalLayoutDirection.current - val top = with(density) { getTop(density).toDp() } - val right = with(density) { getRight(density, layoutDirection).toDp() } - val bottom = with(density) { getBottom(density).toDp() } - val left = with(density) { getLeft(density, layoutDirection).toDp() } - return AbsolutePaddingValues(top = top, right = right, bottom = bottom, left = left) -} - private fun LayoutDirection.toReadingProgression(): ReadingProgression = when (this) { LayoutDirection.Ltr -> ReadingProgression.LTR From cb8cfa755eba1d0143413efc3485f5a25661989d Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Fri, 11 Apr 2025 13:58:37 +0200 Subject: [PATCH 36/88] Fix snapping issue --- .../navigator/web/reflowable/ReflowablePagingLayoutInfo.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowablePagingLayoutInfo.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowablePagingLayoutInfo.kt index 2c5437fd94..4701950c4c 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowablePagingLayoutInfo.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowablePagingLayoutInfo.kt @@ -58,7 +58,6 @@ internal class ReflowablePagingLayoutInfo( Timber.d("pager $pagerVisible webview $webViewVisible") val pageSize = pageSize - val firstPage = pagerState.layoutInfo.visiblePagesInfo.first() val lastPage = pagerState.layoutInfo.visiblePagesInfo.last() @@ -70,7 +69,11 @@ internal class ReflowablePagingLayoutInfo( Timber.d("visiblePageOffsets if $this") } else { val firstScrollController = resourceStates[firstPage.index].scrollController.value!! - add(lastPage.offset - pageSize) + val lastScrollController = resourceStates[lastPage.index].scrollController.value!! + // To get to the left bound, we first need to scroll the last visible page to zero. + add(lastPage.offset - pageSize - lastScrollController.scrollX) + // To get to the right bound, we first need to scroll the first visible page + // as far as possible. add(lastPage.offset + firstScrollController.maxScrollX - firstScrollController.scrollX) Timber.d("visiblePageOffsets else $this") } From adefc50a6bcb44b15fa70287e31a1b06b298ce5d Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Sat, 12 Apr 2025 06:46:43 +0200 Subject: [PATCH 37/88] Fix location restoration on preference or orientation change --- .../src/index-reflowable-injectable.ts | 18 ++++++- .../generated/reflowable-injectable-script.js | 2 +- .../reflowable-injectable-script.js.map | 2 +- .../navigator/web/ReflowableWebRendition.kt | 20 ++----- .../web/ReflowableWebRenditionState.kt | 37 +++++++++++-- .../reflowable/ReflowablePagingLayoutInfo.kt | 4 +- .../web/reflowable/ReflowableResource.kt | 53 ++++++++++++------- .../navigator/web/webview/RelaxedWebView.kt | 14 +++++ .../web/webview/WebViewScrollController.kt | 27 ++++++++-- 9 files changed, 131 insertions(+), 46 deletions(-) diff --git a/readium/navigators/web/scripts/src/index-reflowable-injectable.ts b/readium/navigators/web/scripts/src/index-reflowable-injectable.ts index a8bb50f560..c36918bff5 100644 --- a/readium/navigators/web/scripts/src/index-reflowable-injectable.ts +++ b/readium/navigators/web/scripts/src/index-reflowable-injectable.ts @@ -47,13 +47,27 @@ Window.prototype.readiumcss = new CssBridge(window.document) window.documentState.onScriptsLoaded() // eslint-disable-next-line @typescript-eslint/no-unused-vars window.addEventListener("load", (event) => { + let documentLoadedFired = false + const observer = new ResizeObserver(() => { requestAnimationFrame(() => { appendVirtualColumnIfNeeded(window) + + const scrollingElement = window.document.scrollingElement + + if ( + !documentLoadedFired && + (scrollingElement == null || + (scrollingElement.scrollHeight > 0 && + scrollingElement.scrollWidth > 0)) + ) { + console.log(`scrollWidth ${scrollingElement?.scrollWidth}`) + window.documentState.onDocumentLoaded() + documentLoadedFired = true + } + window.documentState.onDocumentResized() }) }) observer.observe(document.body) - - window.documentState.onDocumentLoaded() }) diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js index 5802791a07..b58a60eb3e 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js @@ -1,2 +1,2 @@ -!function(){"use strict";const e=new class{constructor(e){this.nativeApi=e}onTap(e){this.nativeApi.onTap(JSON.stringify(e))}onLinkActivated(e,t){this.nativeApi.onLinkActivated(e,t)}}(window.gestures),t={onTap:t=>{const n={x:(t.clientX-visualViewport.offsetLeft)*visualViewport.scale,y:(t.clientY-visualViewport.offsetTop)*visualViewport.scale};e.onTap(n)},onLinkActivated:(t,n)=>{e.onLinkActivated(t,n)}};new class{constructor(e,t){this.window=e,this.listener=t,document.addEventListener("click",(e=>{this.onClick(e)}),!1)}onClick(e){if(e.defaultPrevented)return;const t=this.window.getSelection();if(t&&"Range"==t.type)return;let n;n=e.target instanceof HTMLElement?this.nearestInteractiveElement(e.target):null,n?n instanceof HTMLAnchorElement&&this.listener.onLinkActivated(n.href,n.outerHTML):this.listener.onTap(e),e.stopPropagation(),e.preventDefault()}nearestInteractiveElement(e){return null==e?null:-1!=["a","audio","button","canvas","details","input","label","option","select","submit","textarea","video"].indexOf(e.nodeName.toLowerCase())||e.hasAttribute("contenteditable")&&"false"!=e.getAttribute("contenteditable").toLowerCase()?e:e.parentElement?this.nearestInteractiveElement(e.parentElement):null}}(window,t),Window.prototype.readiumcss=new class{constructor(e){this.document=e}setProperties(e){for(const[t,n]of e)this.setProperty(t,n)}setProperty(e,t){null===t||""===t?this.removeProperty(e):document.documentElement.style.setProperty(e,t,"important")}removeProperty(e){document.documentElement.style.removeProperty(e)}}(window.document),window.documentState.onScriptsLoaded(),window.addEventListener("load",(e=>{new ResizeObserver((()=>{requestAnimationFrame((()=>{(function(e){const t="readium-virtual-page";let n=e.document.getElementById(t);if(2!==function(e){return parseInt(e.getComputedStyle(e.document.documentElement).getPropertyValue("column-count"))}(e))n&&n.remove();else{const o=e.document.scrollingElement.scrollWidth/e.innerWidth;Math.round(2*o)/2%1>.1&&(n?n.remove():(n=e.document.createElement("div"),n.setAttribute("id",t),n.dataset.readium="true",n.style.breakBefore="column",n.innerHTML="​",e.document.body.appendChild(n)))}})(window),window.documentState.onDocumentResized()}))})).observe(document.body),window.documentState.onDocumentLoaded()}))}(); +!function(){"use strict";const e=new class{constructor(e){this.nativeApi=e}onTap(e){this.nativeApi.onTap(JSON.stringify(e))}onLinkActivated(e,t){this.nativeApi.onLinkActivated(e,t)}}(window.gestures),t={onTap:t=>{const n={x:(t.clientX-visualViewport.offsetLeft)*visualViewport.scale,y:(t.clientY-visualViewport.offsetTop)*visualViewport.scale};e.onTap(n)},onLinkActivated:(t,n)=>{e.onLinkActivated(t,n)}};new class{constructor(e,t){this.window=e,this.listener=t,document.addEventListener("click",(e=>{this.onClick(e)}),!1)}onClick(e){if(e.defaultPrevented)return;const t=this.window.getSelection();if(t&&"Range"==t.type)return;let n;n=e.target instanceof HTMLElement?this.nearestInteractiveElement(e.target):null,n?n instanceof HTMLAnchorElement&&this.listener.onLinkActivated(n.href,n.outerHTML):this.listener.onTap(e),e.stopPropagation(),e.preventDefault()}nearestInteractiveElement(e){return null==e?null:-1!=["a","audio","button","canvas","details","input","label","option","select","submit","textarea","video"].indexOf(e.nodeName.toLowerCase())||e.hasAttribute("contenteditable")&&"false"!=e.getAttribute("contenteditable").toLowerCase()?e:e.parentElement?this.nearestInteractiveElement(e.parentElement):null}}(window,t),Window.prototype.readiumcss=new class{constructor(e){this.document=e}setProperties(e){for(const[t,n]of e)this.setProperty(t,n)}setProperty(e,t){null===t||""===t?this.removeProperty(e):document.documentElement.style.setProperty(e,t,"important")}removeProperty(e){document.documentElement.style.removeProperty(e)}}(window.document),window.documentState.onScriptsLoaded(),window.addEventListener("load",(e=>{let t=!1;new ResizeObserver((()=>{requestAnimationFrame((()=>{!function(e){const t="readium-virtual-page";let n=e.document.getElementById(t);if(2!==function(e){return parseInt(e.getComputedStyle(e.document.documentElement).getPropertyValue("column-count"))}(e))n&&n.remove();else{const o=e.document.scrollingElement.scrollWidth/e.innerWidth;Math.round(2*o)/2%1>.1&&(n?n.remove():(n=e.document.createElement("div"),n.setAttribute("id",t),n.dataset.readium="true",n.style.breakBefore="column",n.innerHTML="​",e.document.body.appendChild(n)))}}(window);const e=window.document.scrollingElement;!t&&(null==e||e.scrollHeight>0&&e.scrollWidth>0)&&(console.log(`scrollWidth ${null==e?void 0:e.scrollWidth}`),window.documentState.onDocumentLoaded(),t=!0),window.documentState.onDocumentResized()}))})).observe(document.body)}))}(); //# sourceMappingURL=reflowable-injectable-script.js.map \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map index 0ce3c97652..aa9c0b8fc0 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map @@ -1 +1 @@ -{"version":3,"file":"reflowable-injectable-script.js","mappings":"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","sources":["webpack://readium-js/./src/index-reflowable-injectable.ts","webpack://readium-js/./src/bridge/all-gestures-bridge.ts","webpack://readium-js/./src/common/gestures.ts","webpack://readium-js/./src/bridge/reflowable-css-bridge.ts","webpack://readium-js/./src/util/columns.ts"],"sourcesContent":["//\n// Copyright 2024 Readium Foundation. All rights reserved.\n// Use of this source code is governed by the BSD-style license\n// available in the top-level LICENSE file of the project.\n//\n/**\n * Script loaded by reflowable resources.\n */\nimport { BridgeGesturesAdapter, } from \"./bridge/all-gestures-bridge\";\nimport { CssBridge } from \"./bridge/reflowable-css-bridge\";\nimport { GesturesDetector } from \"./common/gestures\";\nimport { appendVirtualColumnIfNeeded } from \"./util/columns\";\nconst bridgeListener = new BridgeGesturesAdapter(window.gestures);\nconst gesturesListener = {\n onTap: (event) => {\n const tapEvent = {\n x: (event.clientX - visualViewport.offsetLeft) * visualViewport.scale,\n y: (event.clientY - visualViewport.offsetTop) * visualViewport.scale,\n };\n bridgeListener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n bridgeListener.onLinkActivated(href, outerHtml);\n },\n};\nnew GesturesDetector(window, gesturesListener);\nWindow.prototype.readiumcss = new CssBridge(window.document);\nwindow.documentState.onScriptsLoaded();\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nwindow.addEventListener(\"load\", (event) => {\n const observer = new ResizeObserver(() => {\n requestAnimationFrame(() => {\n appendVirtualColumnIfNeeded(window);\n window.documentState.onDocumentResized();\n });\n });\n observer.observe(document.body);\n window.documentState.onDocumentLoaded();\n});\n","export class BridgeGesturesAdapter {\n constructor(gesturesApi) {\n this.nativeApi = gesturesApi;\n }\n onTap(event) {\n this.nativeApi.onTap(JSON.stringify(event));\n }\n onLinkActivated(href, outerHtml) {\n this.nativeApi.onLinkActivated(href, outerHtml);\n }\n}\n","export class GesturesDetector {\n constructor(window, listener) {\n this.window = window;\n this.listener = listener;\n document.addEventListener(\"click\", (event) => {\n this.onClick(event);\n }, false);\n }\n onClick(event) {\n if (event.defaultPrevented) {\n return;\n }\n const selection = this.window.getSelection();\n if (selection && selection.type == \"Range\") {\n // There's an on-going selection, the tap will dismiss it so we don't forward it.\n // selection.type might be None (collapsed) or Caret with a collapsed range\n // when there is not true selection.\n return;\n }\n let nearestElement;\n if (event.target instanceof HTMLElement) {\n nearestElement = this.nearestInteractiveElement(event.target);\n }\n else {\n nearestElement = null;\n }\n if (nearestElement) {\n if (nearestElement instanceof HTMLAnchorElement) {\n this.listener.onLinkActivated(nearestElement.href, nearestElement.outerHTML);\n }\n }\n else {\n this.listener.onTap(event);\n }\n event.stopPropagation();\n event.preventDefault();\n }\n // See. https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling\n nearestInteractiveElement(element) {\n if (element == null) {\n return null;\n }\n const interactiveTags = [\n \"a\",\n \"audio\",\n \"button\",\n \"canvas\",\n \"details\",\n \"input\",\n \"label\",\n \"option\",\n \"select\",\n \"submit\",\n \"textarea\",\n \"video\",\n ];\n if (interactiveTags.indexOf(element.nodeName.toLowerCase()) != -1) {\n return element;\n }\n // Checks whether the element is editable by the user.\n if (element.hasAttribute(\"contenteditable\") &&\n element.getAttribute(\"contenteditable\").toLowerCase() != \"false\") {\n return element;\n }\n // Checks parents recursively because the touch might be for example on an inside a .\n if (element.parentElement) {\n return this.nearestInteractiveElement(element.parentElement);\n }\n return null;\n }\n}\n","export class CssBridge {\n constructor(document) {\n this.document = document;\n }\n setProperties(properties) {\n for (const [key, value] of properties) {\n this.setProperty(key, value);\n }\n }\n // For setting user setting.\n setProperty(key, value) {\n if (value === null || value === \"\") {\n this.removeProperty(key);\n }\n else {\n const root = document.documentElement;\n // The `!important` annotation is added with `setProperty()` because if it's part of the\n // `value`, it will be ignored by the Web View.\n root.style.setProperty(key, value, \"important\");\n }\n }\n // For removing user setting.\n removeProperty(key) {\n const root = document.documentElement;\n root.style.removeProperty(key);\n }\n}\n","/**\n * Having an odd number of columns when displaying two columns per screen causes snapping and page\n * turning issues. To fix this, we insert a blank virtual column at the end of the resource.\n */\nexport function appendVirtualColumnIfNeeded(wnd) {\n const id = \"readium-virtual-page\";\n let virtualCol = wnd.document.getElementById(id);\n if (getColumnCountPerScreen(wnd) !== 2) {\n if (virtualCol) {\n virtualCol.remove();\n }\n }\n else {\n const documentWidth = wnd.document.scrollingElement.scrollWidth;\n const colCount = documentWidth / wnd.innerWidth;\n const hasOddColCount = (Math.round(colCount * 2) / 2) % 1 > 0.1;\n if (hasOddColCount) {\n if (virtualCol)\n virtualCol.remove();\n else {\n virtualCol = wnd.document.createElement(\"div\");\n virtualCol.setAttribute(\"id\", id);\n virtualCol.dataset.readium = \"true\";\n virtualCol.style.breakBefore = \"column\";\n virtualCol.innerHTML = \"​\"; // zero-width space\n wnd.document.body.appendChild(virtualCol);\n }\n }\n }\n}\nfunction getColumnCountPerScreen(wnd) {\n return parseInt(wnd\n .getComputedStyle(wnd.document.documentElement)\n .getPropertyValue(\"column-count\"));\n}\n"],"names":["bridgeListener","constructor","gesturesApi","this","nativeApi","onTap","event","JSON","stringify","onLinkActivated","href","outerHtml","window","gestures","gesturesListener","tapEvent","x","clientX","visualViewport","offsetLeft","scale","y","clientY","offsetTop","listener","document","addEventListener","onClick","defaultPrevented","selection","getSelection","type","nearestElement","target","HTMLElement","nearestInteractiveElement","HTMLAnchorElement","outerHTML","stopPropagation","preventDefault","element","indexOf","nodeName","toLowerCase","hasAttribute","getAttribute","parentElement","Window","prototype","readiumcss","setProperties","properties","key","value","setProperty","removeProperty","documentElement","style","documentState","onScriptsLoaded","ResizeObserver","requestAnimationFrame","wnd","id","virtualCol","getElementById","parseInt","getComputedStyle","getPropertyValue","getColumnCountPerScreen","remove","colCount","scrollingElement","scrollWidth","innerWidth","Math","round","createElement","setAttribute","dataset","readium","breakBefore","innerHTML","body","appendChild","appendVirtualColumnIfNeeded","onDocumentResized","observe","onDocumentLoaded"],"sourceRoot":""} \ No newline at end of file +{"version":3,"file":"reflowable-injectable-script.js","mappings":"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","sources":["webpack://readium-js/./src/index-reflowable-injectable.ts","webpack://readium-js/./src/bridge/all-gestures-bridge.ts","webpack://readium-js/./src/common/gestures.ts","webpack://readium-js/./src/bridge/reflowable-css-bridge.ts","webpack://readium-js/./src/util/columns.ts"],"sourcesContent":["//\n// Copyright 2024 Readium Foundation. All rights reserved.\n// Use of this source code is governed by the BSD-style license\n// available in the top-level LICENSE file of the project.\n//\n/**\n * Script loaded by reflowable resources.\n */\nimport { BridgeGesturesAdapter, } from \"./bridge/all-gestures-bridge\";\nimport { CssBridge } from \"./bridge/reflowable-css-bridge\";\nimport { GesturesDetector } from \"./common/gestures\";\nimport { appendVirtualColumnIfNeeded } from \"./util/columns\";\nconst bridgeListener = new BridgeGesturesAdapter(window.gestures);\nconst gesturesListener = {\n onTap: (event) => {\n const tapEvent = {\n x: (event.clientX - visualViewport.offsetLeft) * visualViewport.scale,\n y: (event.clientY - visualViewport.offsetTop) * visualViewport.scale,\n };\n bridgeListener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n bridgeListener.onLinkActivated(href, outerHtml);\n },\n};\nnew GesturesDetector(window, gesturesListener);\nWindow.prototype.readiumcss = new CssBridge(window.document);\nwindow.documentState.onScriptsLoaded();\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nwindow.addEventListener(\"load\", (event) => {\n let documentLoadedFired = false;\n const observer = new ResizeObserver(() => {\n requestAnimationFrame(() => {\n appendVirtualColumnIfNeeded(window);\n const scrollingElement = window.document.scrollingElement;\n if (!documentLoadedFired &&\n (scrollingElement == null ||\n (scrollingElement.scrollHeight > 0 &&\n scrollingElement.scrollWidth > 0))) {\n console.log(`scrollWidth ${scrollingElement === null || scrollingElement === void 0 ? void 0 : scrollingElement.scrollWidth}`);\n window.documentState.onDocumentLoaded();\n documentLoadedFired = true;\n }\n window.documentState.onDocumentResized();\n });\n });\n observer.observe(document.body);\n});\n","export class BridgeGesturesAdapter {\n constructor(gesturesApi) {\n this.nativeApi = gesturesApi;\n }\n onTap(event) {\n this.nativeApi.onTap(JSON.stringify(event));\n }\n onLinkActivated(href, outerHtml) {\n this.nativeApi.onLinkActivated(href, outerHtml);\n }\n}\n","export class GesturesDetector {\n constructor(window, listener) {\n this.window = window;\n this.listener = listener;\n document.addEventListener(\"click\", (event) => {\n this.onClick(event);\n }, false);\n }\n onClick(event) {\n if (event.defaultPrevented) {\n return;\n }\n const selection = this.window.getSelection();\n if (selection && selection.type == \"Range\") {\n // There's an on-going selection, the tap will dismiss it so we don't forward it.\n // selection.type might be None (collapsed) or Caret with a collapsed range\n // when there is not true selection.\n return;\n }\n let nearestElement;\n if (event.target instanceof HTMLElement) {\n nearestElement = this.nearestInteractiveElement(event.target);\n }\n else {\n nearestElement = null;\n }\n if (nearestElement) {\n if (nearestElement instanceof HTMLAnchorElement) {\n this.listener.onLinkActivated(nearestElement.href, nearestElement.outerHTML);\n }\n }\n else {\n this.listener.onTap(event);\n }\n event.stopPropagation();\n event.preventDefault();\n }\n // See. https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling\n nearestInteractiveElement(element) {\n if (element == null) {\n return null;\n }\n const interactiveTags = [\n \"a\",\n \"audio\",\n \"button\",\n \"canvas\",\n \"details\",\n \"input\",\n \"label\",\n \"option\",\n \"select\",\n \"submit\",\n \"textarea\",\n \"video\",\n ];\n if (interactiveTags.indexOf(element.nodeName.toLowerCase()) != -1) {\n return element;\n }\n // Checks whether the element is editable by the user.\n if (element.hasAttribute(\"contenteditable\") &&\n element.getAttribute(\"contenteditable\").toLowerCase() != \"false\") {\n return element;\n }\n // Checks parents recursively because the touch might be for example on an inside a .\n if (element.parentElement) {\n return this.nearestInteractiveElement(element.parentElement);\n }\n return null;\n }\n}\n","export class CssBridge {\n constructor(document) {\n this.document = document;\n }\n setProperties(properties) {\n for (const [key, value] of properties) {\n this.setProperty(key, value);\n }\n }\n // For setting user setting.\n setProperty(key, value) {\n if (value === null || value === \"\") {\n this.removeProperty(key);\n }\n else {\n const root = document.documentElement;\n // The `!important` annotation is added with `setProperty()` because if it's part of the\n // `value`, it will be ignored by the Web View.\n root.style.setProperty(key, value, \"important\");\n }\n }\n // For removing user setting.\n removeProperty(key) {\n const root = document.documentElement;\n root.style.removeProperty(key);\n }\n}\n","/**\n * In paginated mode, the width of each resource must be a multiple of the viewport size\n * for proper snapping. This may not be automatically the case if the number of\n * columns in the resource is not a multiple of the number of columns fitting in the viewport.\n * To fix this, we insert a blank virtual column at the end of the resource.\n */\nexport function appendVirtualColumnIfNeeded(wnd) {\n const id = \"readium-virtual-page\";\n let virtualCol = wnd.document.getElementById(id);\n if (getColumnCountPerScreen(wnd) !== 2) {\n if (virtualCol) {\n virtualCol.remove();\n }\n }\n else {\n const documentWidth = wnd.document.scrollingElement.scrollWidth;\n const colCount = documentWidth / wnd.innerWidth;\n const hasOddColCount = (Math.round(colCount * 2) / 2) % 1 > 0.1;\n if (hasOddColCount) {\n if (virtualCol)\n virtualCol.remove();\n else {\n virtualCol = wnd.document.createElement(\"div\");\n virtualCol.setAttribute(\"id\", id);\n virtualCol.dataset.readium = \"true\";\n virtualCol.style.breakBefore = \"column\";\n virtualCol.innerHTML = \"​\"; // zero-width space\n wnd.document.body.appendChild(virtualCol);\n }\n }\n }\n}\nfunction getColumnCountPerScreen(wnd) {\n return parseInt(wnd\n .getComputedStyle(wnd.document.documentElement)\n .getPropertyValue(\"column-count\"));\n}\n"],"names":["bridgeListener","constructor","gesturesApi","this","nativeApi","onTap","event","JSON","stringify","onLinkActivated","href","outerHtml","window","gestures","gesturesListener","tapEvent","x","clientX","visualViewport","offsetLeft","scale","y","clientY","offsetTop","listener","document","addEventListener","onClick","defaultPrevented","selection","getSelection","type","nearestElement","target","HTMLElement","nearestInteractiveElement","HTMLAnchorElement","outerHTML","stopPropagation","preventDefault","element","indexOf","nodeName","toLowerCase","hasAttribute","getAttribute","parentElement","Window","prototype","readiumcss","setProperties","properties","key","value","setProperty","removeProperty","documentElement","style","documentState","onScriptsLoaded","documentLoadedFired","ResizeObserver","requestAnimationFrame","wnd","id","virtualCol","getElementById","parseInt","getComputedStyle","getPropertyValue","getColumnCountPerScreen","remove","colCount","scrollingElement","scrollWidth","innerWidth","Math","round","createElement","setAttribute","dataset","readium","breakBefore","innerHTML","body","appendChild","appendVirtualColumnIfNeeded","scrollHeight","console","log","onDocumentLoaded","onDocumentResized","observe"],"sourceRoot":""} \ No newline at end of file diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt index 04c8b85f9b..092f4801e3 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt @@ -42,7 +42,6 @@ import org.readium.navigator.web.location.ReflowableWebLocation import org.readium.navigator.web.pager.RenditionPager import org.readium.navigator.web.pager.ScrollDispatcher import org.readium.navigator.web.pager.pagingFlingBehavior -import org.readium.navigator.web.reflowable.ReflowablePagingLayoutInfo import org.readium.navigator.web.reflowable.ReflowableResource import org.readium.navigator.web.util.AbsolutePaddingValues import org.readium.navigator.web.util.WebViewServer @@ -104,11 +103,12 @@ public fun ReflowableWebRendition( // First location update to trigger controller creation. // In the future, that should require access to the WebView. - state.updateLocation( - ReflowableWebLocation( + state.initController( + initialLocation = ReflowableWebLocation( href = state.publication.readingOrder.items[currentItemIndexState.value].href, progression = state.resourceStates[currentItemIndexState.value].progression.ratio - ) + ), + density = LocalDensity.current ) val orientation = when { @@ -117,20 +117,10 @@ public fun ReflowableWebRendition( else -> Orientation.Horizontal } - val density = LocalDensity.current - val flingBehavior = if (state.layoutDelegate.settings.value.scroll) { ScrollableDefaults.flingBehavior() } else { - val pagingLayoutInfo = remember(state) { - ReflowablePagingLayoutInfo( - pagerState = state.pagerState, - resourceStates = state.resourceStates, - orientation = orientation, - density = density - ) - } - pagingFlingBehavior(pagingLayoutInfo) + pagingFlingBehavior(state.controller!!.navigationDelegate.pagingLayoutInfo) }.toFling2DBehavior(orientation) val scrollDispatcher = remember(state) { diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt index ac2c6c4602..e38f6bcfa1 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt @@ -7,12 +7,14 @@ package org.readium.navigator.web import android.app.Application +import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.pager.PagerState import androidx.compose.runtime.MutableState import androidx.compose.runtime.Stable import androidx.compose.runtime.State import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.mutableStateOf +import androidx.compose.ui.unit.Density import org.readium.navigator.common.HyperlinkLocation import org.readium.navigator.common.LinkContext import org.readium.navigator.common.NavigationController @@ -27,9 +29,11 @@ import org.readium.navigator.web.css.buildFontFamilyDeclaration import org.readium.navigator.web.css.update import org.readium.navigator.web.location.ReflowableWebGoLocation import org.readium.navigator.web.location.ReflowableWebLocation +import org.readium.navigator.web.pager.PagingLayoutInfo import org.readium.navigator.web.preferences.ReflowableWebSettings import org.readium.navigator.web.reflowable.EndProgression import org.readium.navigator.web.reflowable.RatioProgression +import org.readium.navigator.web.reflowable.ReflowablePagingLayoutInfo import org.readium.navigator.web.reflowable.ReflowableResourceState import org.readium.navigator.web.reflowable.ReflowableWebPublication import org.readium.navigator.web.util.HyperlinkProcessor @@ -151,12 +155,16 @@ public class ReflowableWebRenditionState internal constructor( private lateinit var navigationDelegate: ReflowableNavigationDelegate + internal fun initController(initialLocation: ReflowableWebLocation, density: Density) { + initControllerIfNeeded(initialLocation, density) + updateLocation(initialLocation) + } + internal fun updateLocation(location: ReflowableWebLocation) { - initControllerIfNeeded(location) navigationDelegate.updateLocation(location) } - private fun initControllerIfNeeded(location: ReflowableWebLocation) { + private fun initControllerIfNeeded(location: ReflowableWebLocation, density: Density) { if (controller != null) { return } @@ -167,7 +175,8 @@ public class ReflowableWebRenditionState internal constructor( resourceStates, pagerState, layoutDelegate.settings, - location + location, + density ) controllerState.value = ReflowableWebRenditionController( @@ -180,7 +189,7 @@ public class ReflowableWebRenditionState internal constructor( @ExperimentalReadiumApi @Stable public class ReflowableWebRenditionController internal constructor( - private val navigationDelegate: ReflowableNavigationDelegate, + internal val navigationDelegate: ReflowableNavigationDelegate, layoutDelegate: ReflowableLayoutDelegate, ) : NavigationController by navigationDelegate, OverflowController by navigationDelegate, @@ -202,11 +211,19 @@ internal class ReflowableNavigationDelegate( private val pagerState: PagerState, private val settings: State, initialLocation: ReflowableWebLocation, + density: Density, ) : NavigationController, OverflowController { private val locationMutable: MutableState = mutableStateOf(initialLocation) + internal val pagingLayoutInfo: PagingLayoutInfo = + ReflowablePagingLayoutInfo( + pagerState = pagerState, + resourceStates = resourceStates, + density = density + ) + internal fun updateLocation(location: ReflowableWebLocation) { val index = checkNotNull(readingOrder.indexOfHref(location.href)) resourceStates[index].progression = RatioProgression(location.progression) @@ -223,6 +240,8 @@ internal class ReflowableNavigationDelegate( override suspend fun goTo(location: ReflowableWebGoLocation) { val resourceIndex = readingOrder.indexOfHref(location.href) ?: return pagerState.scrollToPage(resourceIndex) + val scrollController = resourceStates[resourceIndex].scrollController.value!! + location.progression?.let { scrollController.moveToProgression(it) } } override suspend fun goTo(location: ReflowableWebLocation) { @@ -312,4 +331,14 @@ internal class ReflowableNavigationDelegate( ReadingProgression.RTL -> canMoveRight } } + private fun WebViewScrollController.moveToProgression(progression: Double) { + moveToProgression( + progression = progression, + scroll = settings.value.scroll, + orientation = when (settings.value.verticalText) { + true -> Orientation.Vertical + false -> Orientation.Horizontal + } + ) + } } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowablePagingLayoutInfo.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowablePagingLayoutInfo.kt index 4701950c4c..da64a831fb 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowablePagingLayoutInfo.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowablePagingLayoutInfo.kt @@ -16,10 +16,12 @@ import timber.log.Timber internal class ReflowablePagingLayoutInfo( private val pagerState: PagerState, private val resourceStates: List, - override val orientation: Orientation, override val density: Density, ) : PagingLayoutInfo { + override val orientation: Orientation = + Orientation.Horizontal + override val pageSize: Int get() = pagerState.layoutInfo.pageSize diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt index 3887ac98ec..22861c6eab 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt @@ -52,6 +52,7 @@ import org.readium.navigator.web.webview.rememberWebViewState import org.readium.r2.shared.ExperimentalReadiumApi import org.readium.r2.shared.util.AbsoluteUrl import org.readium.r2.shared.util.Url +import timber.log.Timber @SuppressLint("SetJavaScriptEnabled", "ClickableViewAccessibility") @Composable @@ -109,17 +110,28 @@ internal fun ReflowableResource( onDocumentLoadedDelegate = { webViewState.webView?.apply { invokeOnReadyToBeDrawn { - val scrollController = WebViewScrollController(this) - scrollController.scrollToProgression(resourceState.progression.ratio, scrollOrientation.value) - resourceState.scrollController.value = scrollController - setOnScrollChangeListener { view, scrollX, scrollY, oldScrollX, oldScrollY -> - onScrollChanged(scrollController.progression(scrollOrientation.value)) + Timber.d("onDocumentLoadedDelegate ${resourceState.index} ${webViewState.webView?.width}") + requestLayout() + addOnLayoutChangeListener { view, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom -> + val scrollController = WebViewScrollController(this) + Timber.d("onLayoutChange ${resourceState.index} prog ${resourceState.progression.ratio} maxScrollX $maxScrollX pageSize ${pagerState.layoutInfo.pageSize}") + + scrollController.moveToProgression( + progression = resourceState.progression.ratio, + scroll = scroll, + orientation = scrollOrientation.value + ) + resourceState.scrollController.value = scrollController + setOnScrollChangeListener { view, scrollX, scrollY, oldScrollX, oldScrollY -> + onScrollChanged(scrollController.progression(scrollOrientation.value)) + } + contentIsLaidOut.value = true } - contentIsLaidOut.value = true } } }, onDocumentResizedDelegate = { + Timber.d("onDocumentResized ${resourceState.index} ${webViewState.webView?.width}") onDocumentResized.invoke() } ) @@ -137,6 +149,12 @@ internal fun ReflowableResource( LaunchedEffect(cssApi, rsProperties, userProperties) { cssApi?.setProperties(userProperties, rsProperties) + resourceState.scrollController.value + ?.moveToProgression( + progression = resourceState.progression.ratio, + scroll = scroll, + orientation = scrollOrientation.value + ) } val gesturesApi = remember(onTap, onLinkActivated) { @@ -170,8 +188,8 @@ internal fun ReflowableResource( content = {} ) } - // Changing font size invalidates the scroll position of the Webview - key(layout, scrollOrientation.value) { + + key(layout) { WebView( modifier = Modifier // Detect taps on padding @@ -209,16 +227,15 @@ internal fun ReflowableResource( webview.isVerticalScrollBarEnabled = false webview.isHorizontalScrollBarEnabled = false webview.setLayerType(View.LAYER_TYPE_HARDWARE, null) - if (scrollOrientation.value == Orientation.Horizontal) { - // Prevents vertical scrolling towards blank space. - // See https://github.com/readium/readium-css/issues/158 - webview.setOnTouchListener(object : View.OnTouchListener { - @SuppressLint("ClickableViewAccessibility") - override fun onTouch(view: View, event: MotionEvent): Boolean { - return (event.action == MotionEvent.ACTION_MOVE) - } - }) - } + // Prevents vertical scrolling towards blank space. + // See https://github.com/readium/readium-css/issues/158 + webview.setOnTouchListener(object : View.OnTouchListener { + @SuppressLint("ClickableViewAccessibility") + override fun onTouch(view: View, event: MotionEvent): Boolean { + return scrollOrientation.value == Orientation.Horizontal && + event.action == MotionEvent.ACTION_MOVE + } + }) }, onDispose = { resourceState.scrollController.value = null diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/RelaxedWebView.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/RelaxedWebView.kt index fc14b7997e..b2b82b94fc 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/RelaxedWebView.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/RelaxedWebView.kt @@ -43,4 +43,18 @@ internal class RelaxedWebView(context: Context) : WebView(context) { val horizontalScrollExtent: Int get() = computeHorizontalScrollExtent() + + private var nextLayoutListener: (() -> Unit) = {} + + fun setNextLayoutListener(block: () -> Unit) { + nextLayoutListener = block + } + + @Suppress("Deprecation") + @Deprecated("Deprecated in Java") + override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { + super.onLayout(changed, l, t, r, b) + nextLayoutListener.invoke() + nextLayoutListener = {} + } } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollController.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollController.kt index 35b643fcc0..d83c8e4298 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollController.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollController.kt @@ -7,6 +7,7 @@ import androidx.compose.ui.util.fastCoerceAtMost import androidx.compose.ui.util.fastRoundToInt import kotlin.math.ceil import kotlin.math.floor +import timber.log.Timber internal class WebViewScrollController( private val webView: RelaxedWebView, @@ -74,10 +75,6 @@ internal class WebViewScrollController( return Offset(coercedX, coercedY) } - fun scrollToProgression(progression: Double, scrollOrientation: Orientation) { - webView.scrollToProgression(progression, scrollOrientation) - } - fun scrollToEnd(scrollOrientation: Orientation): Int { return when (scrollOrientation) { Orientation.Vertical -> { @@ -95,6 +92,28 @@ internal class WebViewScrollController( fun progression(scrollOrientation: Orientation) = webView.progression(scrollOrientation) + + fun moveToProgression( + progression: Double, + scroll: Boolean, + orientation: Orientation, + ) { + Timber.d("moveToProgression $progression") + when (scroll) { + true -> { + webView.scrollToProgression( + progression = progression, + scrollOrientation = orientation + ) + } + false -> { + webView.scrollToProgression(progression, Orientation.Horizontal) + val offset = webView.scrollX % webView.width + Timber.d("moveToProgression scrollBy $offset ${webView.scrollX} ${webView.width}") + webView.scrollBy(-offset, 0) + } + } + } } private fun RelaxedWebView.scrollToProgression(progression: Double, scrollOrientation: Orientation) { From a2877799c3bc0c5d355832a142c72bb0ce4015c7 Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Sat, 12 Apr 2025 07:21:55 +0200 Subject: [PATCH 38/88] Remove Progression sealed class --- .../navigator/web/ReflowableWebRendition.kt | 2 +- .../navigator/web/ReflowableWebRenditionState.kt | 12 +++++------- .../web/reflowable/ReflowableResource.kt | 6 ++---- .../web/reflowable/ReflowableResourceState.kt | 16 +--------------- .../web/webview/WebViewScrollController.kt | 3 --- 5 files changed, 9 insertions(+), 30 deletions(-) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt index 092f4801e3..e7be8426d5 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt @@ -106,7 +106,7 @@ public fun ReflowableWebRendition( state.initController( initialLocation = ReflowableWebLocation( href = state.publication.readingOrder.items[currentItemIndexState.value].href, - progression = state.resourceStates[currentItemIndexState.value].progression.ratio + progression = state.resourceStates[currentItemIndexState.value].progression ), density = LocalDensity.current ) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt index e38f6bcfa1..d9f80b6587 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt @@ -31,8 +31,6 @@ import org.readium.navigator.web.location.ReflowableWebGoLocation import org.readium.navigator.web.location.ReflowableWebLocation import org.readium.navigator.web.pager.PagingLayoutInfo import org.readium.navigator.web.preferences.ReflowableWebSettings -import org.readium.navigator.web.reflowable.EndProgression -import org.readium.navigator.web.reflowable.RatioProgression import org.readium.navigator.web.reflowable.ReflowablePagingLayoutInfo import org.readium.navigator.web.reflowable.ReflowableResourceState import org.readium.navigator.web.reflowable.ReflowableWebPublication @@ -72,10 +70,10 @@ public class ReflowableWebRenditionState internal constructor( ReflowableResourceState( index = index, href = item.href, - initialProgression = when { - index < initialIndex -> EndProgression - index > initialIndex -> RatioProgression(0.0) - else -> RatioProgression(initialLocation.progression ?: 0.0) + progression = when { + index < initialIndex -> 1.0 + index > initialIndex -> 0.0 + else -> initialLocation.progression ?: 0.0 } ) } @@ -226,7 +224,7 @@ internal class ReflowableNavigationDelegate( internal fun updateLocation(location: ReflowableWebLocation) { val index = checkNotNull(readingOrder.indexOfHref(location.href)) - resourceStates[index].progression = RatioProgression(location.progression) + resourceStates[index].progression = location.progression locationMutable.value = location } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt index 22861c6eab..c3a84495fb 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt @@ -114,10 +114,8 @@ internal fun ReflowableResource( requestLayout() addOnLayoutChangeListener { view, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom -> val scrollController = WebViewScrollController(this) - Timber.d("onLayoutChange ${resourceState.index} prog ${resourceState.progression.ratio} maxScrollX $maxScrollX pageSize ${pagerState.layoutInfo.pageSize}") - scrollController.moveToProgression( - progression = resourceState.progression.ratio, + progression = resourceState.progression, scroll = scroll, orientation = scrollOrientation.value ) @@ -151,7 +149,7 @@ internal fun ReflowableResource( cssApi?.setProperties(userProperties, rsProperties) resourceState.scrollController.value ?.moveToProgression( - progression = resourceState.progression.ratio, + progression = resourceState.progression, scroll = scroll, orientation = scrollOrientation.value ) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResourceState.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResourceState.kt index 83e71e3092..f42fd6b68b 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResourceState.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResourceState.kt @@ -17,22 +17,8 @@ import org.readium.r2.shared.util.Url internal class ReflowableResourceState( val index: Int, val href: Url, - initialProgression: Progression, + var progression: Double, ) : PageScrollState { - var progression: Progression = initialProgression - override val scrollController: MutableState = mutableStateOf(null) } - -internal sealed interface Progression { - - val ratio: Double -} - -internal data class RatioProgression(override val ratio: Double) : Progression - -internal data object EndProgression : Progression { - - override val ratio: Double = 1.0 -} diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollController.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollController.kt index d83c8e4298..5ccade1487 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollController.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollController.kt @@ -7,7 +7,6 @@ import androidx.compose.ui.util.fastCoerceAtMost import androidx.compose.ui.util.fastRoundToInt import kotlin.math.ceil import kotlin.math.floor -import timber.log.Timber internal class WebViewScrollController( private val webView: RelaxedWebView, @@ -98,7 +97,6 @@ internal class WebViewScrollController( scroll: Boolean, orientation: Orientation, ) { - Timber.d("moveToProgression $progression") when (scroll) { true -> { webView.scrollToProgression( @@ -109,7 +107,6 @@ internal class WebViewScrollController( false -> { webView.scrollToProgression(progression, Orientation.Horizontal) val offset = webView.scrollX % webView.width - Timber.d("moveToProgression scrollBy $offset ${webView.scrollX} ${webView.width}") webView.scrollBy(-offset, 0) } } From 15cb73414444ef8457518f825f9c7f15f0b905ca Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Sun, 13 Apr 2025 09:26:24 +0200 Subject: [PATCH 39/88] Better fix location restoration on preference change --- .../scripts/src/bridge/all-document-bridge.ts | 2 +- .../web/scripts/src/index-fixed-double.ts | 2 +- .../web/scripts/src/index-fixed-single.ts | 2 +- .../src/index-reflowable-injectable.ts | 11 +++--- .../web/generated/fixed-double-script.js | 2 +- .../web/generated/fixed-double-script.js.map | 2 +- .../web/generated/fixed-single-script.js | 2 +- .../web/generated/fixed-single-script.js.map | 2 +- .../generated/reflowable-injectable-script.js | 2 +- .../reflowable-injectable-script.js.map | 2 +- .../navigator/web/fixed/SpreadWebView.kt | 2 +- .../web/reflowable/ReflowableResource.kt | 37 +++++++------------ .../navigator/web/webapi/DocumentStateApi.kt | 6 +-- 13 files changed, 32 insertions(+), 42 deletions(-) diff --git a/readium/navigators/web/scripts/src/bridge/all-document-bridge.ts b/readium/navigators/web/scripts/src/bridge/all-document-bridge.ts index f21e9b7d09..0acb0b48d4 100644 --- a/readium/navigators/web/scripts/src/bridge/all-document-bridge.ts +++ b/readium/navigators/web/scripts/src/bridge/all-document-bridge.ts @@ -1,5 +1,5 @@ export interface DocumentBridge { onScriptsLoaded: () => void - onDocumentLoaded: () => void + onDocumentLoadedAndSized: () => void onDocumentResized: () => void } diff --git a/readium/navigators/web/scripts/src/index-fixed-double.ts b/readium/navigators/web/scripts/src/index-fixed-double.ts index a6ab1d2a59..7aad79498e 100644 --- a/readium/navigators/web/scripts/src/index-fixed-double.ts +++ b/readium/navigators/web/scripts/src/index-fixed-double.ts @@ -39,5 +39,5 @@ Window.prototype.doubleArea = new FixedDoubleBridge( window.documentState.onScriptsLoaded() // eslint-disable-next-line @typescript-eslint/no-unused-vars window.addEventListener("load", (event) => { - window.documentState.onDocumentLoaded() + window.documentState.onDocumentLoadedAndSized() }) diff --git a/readium/navigators/web/scripts/src/index-fixed-single.ts b/readium/navigators/web/scripts/src/index-fixed-single.ts index 5d434d5a07..a83d0957f2 100644 --- a/readium/navigators/web/scripts/src/index-fixed-single.ts +++ b/readium/navigators/web/scripts/src/index-fixed-single.ts @@ -36,5 +36,5 @@ window.singleArea = new FixedSingleBridge( window.documentState.onScriptsLoaded() // eslint-disable-next-line @typescript-eslint/no-unused-vars window.addEventListener("load", (event) => { - window.documentState.onDocumentLoaded() + window.documentState.onDocumentLoadedAndSized() }) diff --git a/readium/navigators/web/scripts/src/index-reflowable-injectable.ts b/readium/navigators/web/scripts/src/index-reflowable-injectable.ts index c36918bff5..52781d5736 100644 --- a/readium/navigators/web/scripts/src/index-reflowable-injectable.ts +++ b/readium/navigators/web/scripts/src/index-reflowable-injectable.ts @@ -58,15 +58,14 @@ window.addEventListener("load", (event) => { if ( !documentLoadedFired && (scrollingElement == null || - (scrollingElement.scrollHeight > 0 && - scrollingElement.scrollWidth > 0)) + scrollingElement.scrollHeight > 0 || + scrollingElement.scrollWidth > 0) ) { - console.log(`scrollWidth ${scrollingElement?.scrollWidth}`) - window.documentState.onDocumentLoaded() + window.documentState.onDocumentLoadedAndSized() documentLoadedFired = true + } else { + window.documentState.onDocumentResized() } - - window.documentState.onDocumentResized() }) }) observer.observe(document.body) diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-double-script.js b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-double-script.js index 50b00c68bc..19c28ab244 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-double-script.js +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-double-script.js @@ -1,2 +1,2 @@ -!function(){"use strict";class t{constructor(t,e,i){if(this.margins={top:0,right:0,bottom:0,left:0},!e.contentWindow)throw Error("Iframe argument must have been attached to DOM.");this.listener=i,this.iframe=e}setMessagePort(t){t.onmessage=t=>{this.onMessageFromIframe(t)}}show(){this.iframe.style.display="unset"}hide(){this.iframe.style.display="none"}setMargins(t){this.margins!=t&&(this.iframe.style.marginTop=this.margins.top+"px",this.iframe.style.marginLeft=this.margins.left+"px",this.iframe.style.marginBottom=this.margins.bottom+"px",this.iframe.style.marginRight=this.margins.right+"px")}loadPage(t){this.iframe.src=t}setPlaceholder(t){this.iframe.style.visibility="hidden",this.iframe.style.width=t.width+"px",this.iframe.style.height=t.height+"px",this.size=t}onMessageFromIframe(t){const e=t.data;switch(e.kind){case"contentSize":return this.onContentSizeAvailable(e.size);case"tap":return this.listener.onTap({x:e.x,y:e.y});case"linkActivated":return this.onLinkActivated(e)}}onLinkActivated(t){try{const e=new URL(t.href,this.iframe.src);this.listener.onLinkActivated(e.toString(),t.outerHtml)}catch(t){}}onContentSizeAvailable(t){t&&(this.iframe.style.width=t.width+"px",this.iframe.style.height=t.height+"px",this.size=t,this.listener.onIframeLoaded())}}class e{setInitialScale(t){return this.initialScale=t,this}setMinimumScale(t){return this.minimumScale=t,this}setWidth(t){return this.width=t,this}setHeight(t){return this.height=t,this}build(){const t=[];return this.initialScale&&t.push("initial-scale="+this.initialScale),this.minimumScale&&t.push("minimum-scale="+this.minimumScale),this.width&&t.push("width="+this.width),this.height&&t.push("height="+this.height),t.join(", ")}}class i{constructor(t,e){this.window=t,this.listener=e,document.addEventListener("click",(t=>{this.onClick(t)}),!1)}onClick(t){if(t.defaultPrevented)return;const e=this.window.getSelection();if(e&&"Range"==e.type)return;let i;i=t.target instanceof HTMLElement?this.nearestInteractiveElement(t.target):null,i?i instanceof HTMLAnchorElement&&this.listener.onLinkActivated(i.href,i.outerHTML):this.listener.onTap(t),t.stopPropagation(),t.preventDefault()}nearestInteractiveElement(t){return null==t?null:-1!=["a","audio","button","canvas","details","input","label","option","select","submit","textarea","video"].indexOf(t.nodeName.toLowerCase())||t.hasAttribute("contenteditable")&&"false"!=t.getAttribute("contenteditable").toLowerCase()?t:t.parentElement?this.nearestInteractiveElement(t.parentElement):null}}class s{constructor(e,s,n,a,h){this.fit="contain",this.insets={top:0,right:0,bottom:0,left:0},e.addEventListener("message",(t=>{t.ports[0]&&(t.source===s.contentWindow?this.leftPage.setMessagePort(t.ports[0]):t.source==n.contentWindow&&this.rightPage.setMessagePort(t.ports[0]))})),new i(e,{onTap:t=>{const e={x:(t.clientX-visualViewport.offsetLeft)*visualViewport.scale,y:(t.clientY-visualViewport.offsetTop)*visualViewport.scale};h.onTap(e)},onLinkActivated:t=>{throw Error("No interactive element in the root document.")}});const o={onIframeLoaded:()=>{this.layout()},onTap:t=>{const e=s.getBoundingClientRect(),i={x:(t.x+e.left-visualViewport.offsetLeft)*visualViewport.scale,y:(t.y+e.top-visualViewport.offsetTop)*visualViewport.scale};h.onTap(i)},onLinkActivated:(t,e)=>{h.onLinkActivated(t,e)}},r={onIframeLoaded:()=>{this.layout()},onTap:t=>{const e=n.getBoundingClientRect(),i={x:(t.x+e.left-visualViewport.offsetLeft)*visualViewport.scale,y:(t.y+e.top-visualViewport.offsetTop)*visualViewport.scale};h.onTap(i)},onLinkActivated:(t,e)=>{h.onLinkActivated(t,e)}};this.leftPage=new t(e,s,o),this.rightPage=new t(e,n,r),this.metaViewport=a}loadSpread(t){this.leftPage.hide(),this.rightPage.hide(),this.spread=t,t.left&&this.leftPage.loadPage(t.left),t.right&&this.rightPage.loadPage(t.right)}setViewport(t,e){this.viewport==t&&this.insets==e||(this.viewport=t,this.insets=e,this.layout())}setFit(t){this.fit!=t&&(this.fit=t,this.layout())}layout(){if(!this.viewport||!this.leftPage.size&&this.spread.left||!this.rightPage.size&&this.spread.right)return;const t={top:this.insets.top,right:0,bottom:this.insets.bottom,left:this.insets.left};this.leftPage.setMargins(t);const i={top:this.insets.top,right:this.insets.right,bottom:this.insets.bottom,left:0};this.rightPage.setMargins(i),this.spread.right?this.spread.left||this.leftPage.setPlaceholder(this.rightPage.size):this.rightPage.setPlaceholder(this.leftPage.size);const s=this.leftPage.size.width+this.rightPage.size.width,n=Math.max(this.leftPage.size.height,this.rightPage.size.height),a={width:s,height:n},h={width:this.viewport.width-this.insets.left-this.insets.right,height:this.viewport.height-this.insets.top-this.insets.bottom},o=function(t,e,i){switch(t){case"contain":return function(t,e){const i=e.width/t.width,s=e.height/t.height;return Math.min(i,s)}(e,i);case"width":return function(t,e){return e.width/t.width}(e,i);case"height":return function(t,e){return e.height/t.height}(e,i)}}(this.fit,a,h);this.metaViewport.content=(new e).setInitialScale(o).setMinimumScale(o).setWidth(s).setHeight(n).build(),this.leftPage.show(),this.rightPage.show()}}class n{constructor(t){this.nativeApi=t}onTap(t){this.nativeApi.onTap(JSON.stringify(t))}onLinkActivated(t,e){this.nativeApi.onLinkActivated(t,e)}}const a=document.getElementById("page-left"),h=document.getElementById("page-right"),o=document.querySelector("meta[name=viewport]");Window.prototype.doubleArea=new class{constructor(t,e,i,a,h){const o=new n(h);this.manager=new s(t,e,i,a,o)}loadSpread(t){this.manager.loadSpread(t)}setViewport(t,e,i,s,n,a){const h={width:t,height:e},o={top:i,left:a,bottom:n,right:s};this.manager.setViewport(h,o)}setFit(t){if("contain"!=t&&"width"!=t&&"height"!=t)throw Error(`Invalid fit value: ${t}`);this.manager.setFit(t)}}(window,a,h,o,window.gestures),window.documentState.onScriptsLoaded(),window.addEventListener("load",(t=>{window.documentState.onDocumentLoaded()}))}(); +!function(){"use strict";class t{constructor(t,e,i){if(this.margins={top:0,right:0,bottom:0,left:0},!e.contentWindow)throw Error("Iframe argument must have been attached to DOM.");this.listener=i,this.iframe=e}setMessagePort(t){t.onmessage=t=>{this.onMessageFromIframe(t)}}show(){this.iframe.style.display="unset"}hide(){this.iframe.style.display="none"}setMargins(t){this.margins!=t&&(this.iframe.style.marginTop=this.margins.top+"px",this.iframe.style.marginLeft=this.margins.left+"px",this.iframe.style.marginBottom=this.margins.bottom+"px",this.iframe.style.marginRight=this.margins.right+"px")}loadPage(t){this.iframe.src=t}setPlaceholder(t){this.iframe.style.visibility="hidden",this.iframe.style.width=t.width+"px",this.iframe.style.height=t.height+"px",this.size=t}onMessageFromIframe(t){const e=t.data;switch(e.kind){case"contentSize":return this.onContentSizeAvailable(e.size);case"tap":return this.listener.onTap({x:e.x,y:e.y});case"linkActivated":return this.onLinkActivated(e)}}onLinkActivated(t){try{const e=new URL(t.href,this.iframe.src);this.listener.onLinkActivated(e.toString(),t.outerHtml)}catch(t){}}onContentSizeAvailable(t){t&&(this.iframe.style.width=t.width+"px",this.iframe.style.height=t.height+"px",this.size=t,this.listener.onIframeLoaded())}}class e{setInitialScale(t){return this.initialScale=t,this}setMinimumScale(t){return this.minimumScale=t,this}setWidth(t){return this.width=t,this}setHeight(t){return this.height=t,this}build(){const t=[];return this.initialScale&&t.push("initial-scale="+this.initialScale),this.minimumScale&&t.push("minimum-scale="+this.minimumScale),this.width&&t.push("width="+this.width),this.height&&t.push("height="+this.height),t.join(", ")}}class i{constructor(t,e){this.window=t,this.listener=e,document.addEventListener("click",(t=>{this.onClick(t)}),!1)}onClick(t){if(t.defaultPrevented)return;const e=this.window.getSelection();if(e&&"Range"==e.type)return;let i;i=t.target instanceof HTMLElement?this.nearestInteractiveElement(t.target):null,i?i instanceof HTMLAnchorElement&&this.listener.onLinkActivated(i.href,i.outerHTML):this.listener.onTap(t),t.stopPropagation(),t.preventDefault()}nearestInteractiveElement(t){return null==t?null:-1!=["a","audio","button","canvas","details","input","label","option","select","submit","textarea","video"].indexOf(t.nodeName.toLowerCase())||t.hasAttribute("contenteditable")&&"false"!=t.getAttribute("contenteditable").toLowerCase()?t:t.parentElement?this.nearestInteractiveElement(t.parentElement):null}}class s{constructor(e,s,n,a,h){this.fit="contain",this.insets={top:0,right:0,bottom:0,left:0},e.addEventListener("message",(t=>{t.ports[0]&&(t.source===s.contentWindow?this.leftPage.setMessagePort(t.ports[0]):t.source==n.contentWindow&&this.rightPage.setMessagePort(t.ports[0]))})),new i(e,{onTap:t=>{const e={x:(t.clientX-visualViewport.offsetLeft)*visualViewport.scale,y:(t.clientY-visualViewport.offsetTop)*visualViewport.scale};h.onTap(e)},onLinkActivated:t=>{throw Error("No interactive element in the root document.")}});const o={onIframeLoaded:()=>{this.layout()},onTap:t=>{const e=s.getBoundingClientRect(),i={x:(t.x+e.left-visualViewport.offsetLeft)*visualViewport.scale,y:(t.y+e.top-visualViewport.offsetTop)*visualViewport.scale};h.onTap(i)},onLinkActivated:(t,e)=>{h.onLinkActivated(t,e)}},r={onIframeLoaded:()=>{this.layout()},onTap:t=>{const e=n.getBoundingClientRect(),i={x:(t.x+e.left-visualViewport.offsetLeft)*visualViewport.scale,y:(t.y+e.top-visualViewport.offsetTop)*visualViewport.scale};h.onTap(i)},onLinkActivated:(t,e)=>{h.onLinkActivated(t,e)}};this.leftPage=new t(e,s,o),this.rightPage=new t(e,n,r),this.metaViewport=a}loadSpread(t){this.leftPage.hide(),this.rightPage.hide(),this.spread=t,t.left&&this.leftPage.loadPage(t.left),t.right&&this.rightPage.loadPage(t.right)}setViewport(t,e){this.viewport==t&&this.insets==e||(this.viewport=t,this.insets=e,this.layout())}setFit(t){this.fit!=t&&(this.fit=t,this.layout())}layout(){if(!this.viewport||!this.leftPage.size&&this.spread.left||!this.rightPage.size&&this.spread.right)return;const t={top:this.insets.top,right:0,bottom:this.insets.bottom,left:this.insets.left};this.leftPage.setMargins(t);const i={top:this.insets.top,right:this.insets.right,bottom:this.insets.bottom,left:0};this.rightPage.setMargins(i),this.spread.right?this.spread.left||this.leftPage.setPlaceholder(this.rightPage.size):this.rightPage.setPlaceholder(this.leftPage.size);const s=this.leftPage.size.width+this.rightPage.size.width,n=Math.max(this.leftPage.size.height,this.rightPage.size.height),a={width:s,height:n},h={width:this.viewport.width-this.insets.left-this.insets.right,height:this.viewport.height-this.insets.top-this.insets.bottom},o=function(t,e,i){switch(t){case"contain":return function(t,e){const i=e.width/t.width,s=e.height/t.height;return Math.min(i,s)}(e,i);case"width":return function(t,e){return e.width/t.width}(e,i);case"height":return function(t,e){return e.height/t.height}(e,i)}}(this.fit,a,h);this.metaViewport.content=(new e).setInitialScale(o).setMinimumScale(o).setWidth(s).setHeight(n).build(),this.leftPage.show(),this.rightPage.show()}}class n{constructor(t){this.nativeApi=t}onTap(t){this.nativeApi.onTap(JSON.stringify(t))}onLinkActivated(t,e){this.nativeApi.onLinkActivated(t,e)}}const a=document.getElementById("page-left"),h=document.getElementById("page-right"),o=document.querySelector("meta[name=viewport]");Window.prototype.doubleArea=new class{constructor(t,e,i,a,h){const o=new n(h);this.manager=new s(t,e,i,a,o)}loadSpread(t){this.manager.loadSpread(t)}setViewport(t,e,i,s,n,a){const h={width:t,height:e},o={top:i,left:a,bottom:n,right:s};this.manager.setViewport(h,o)}setFit(t){if("contain"!=t&&"width"!=t&&"height"!=t)throw Error(`Invalid fit value: ${t}`);this.manager.setFit(t)}}(window,a,h,o,window.gestures),window.documentState.onScriptsLoaded(),window.addEventListener("load",(t=>{window.documentState.onDocumentLoadedAndSized()}))}(); //# sourceMappingURL=fixed-double-script.js.map \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-double-script.js.map b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-double-script.js.map index 2cc1cf5eaa..ed6bda5bc7 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-double-script.js.map +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-double-script.js.map @@ -1 +1 @@ -{"version":3,"file":"fixed-double-script.js","mappings":"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","sources":["webpack://readium-js/./src/fixed/page-manager.ts","webpack://readium-js/./src/util/viewport.ts","webpack://readium-js/./src/common/gestures.ts","webpack://readium-js/./src/fixed/double-area-manager.ts","webpack://readium-js/./src/util/fit.ts","webpack://readium-js/./src/bridge/all-gestures-bridge.ts","webpack://readium-js/./src/index-fixed-double.ts","webpack://readium-js/./src/bridge/fixed-double-bridge.ts"],"sourcesContent":["/** Manages a fixed layout resource embedded in an iframe. */\nexport class PageManager {\n constructor(window, iframe, listener) {\n this.margins = { top: 0, right: 0, bottom: 0, left: 0 };\n if (!iframe.contentWindow) {\n throw Error(\"Iframe argument must have been attached to DOM.\");\n }\n this.listener = listener;\n this.iframe = iframe;\n }\n setMessagePort(messagePort) {\n messagePort.onmessage = (message) => {\n this.onMessageFromIframe(message);\n };\n }\n show() {\n this.iframe.style.display = \"unset\";\n }\n hide() {\n this.iframe.style.display = \"none\";\n }\n /** Sets page margins. */\n setMargins(margins) {\n if (this.margins == margins) {\n return;\n }\n this.iframe.style.marginTop = this.margins.top + \"px\";\n this.iframe.style.marginLeft = this.margins.left + \"px\";\n this.iframe.style.marginBottom = this.margins.bottom + \"px\";\n this.iframe.style.marginRight = this.margins.right + \"px\";\n }\n /** Loads page content. */\n loadPage(url) {\n this.iframe.src = url;\n }\n /** Sets the size of this page without content. */\n setPlaceholder(size) {\n this.iframe.style.visibility = \"hidden\";\n this.iframe.style.width = size.width + \"px\";\n this.iframe.style.height = size.height + \"px\";\n this.size = size;\n }\n onMessageFromIframe(event) {\n const message = event.data;\n switch (message.kind) {\n case \"contentSize\":\n return this.onContentSizeAvailable(message.size);\n case \"tap\":\n return this.listener.onTap({ x: message.x, y: message.y });\n case \"linkActivated\":\n return this.onLinkActivated(message);\n }\n }\n onLinkActivated(message) {\n try {\n const url = new URL(message.href, this.iframe.src);\n this.listener.onLinkActivated(url.toString(), message.outerHtml);\n }\n catch (_a) {\n // Do nothing if url is not valid.\n }\n }\n onContentSizeAvailable(size) {\n if (!size) {\n //FIXME: handle edge case\n return;\n }\n this.iframe.style.width = size.width + \"px\";\n this.iframe.style.height = size.height + \"px\";\n this.size = size;\n this.listener.onIframeLoaded();\n }\n}\n","export class ViewportStringBuilder {\n setInitialScale(scale) {\n this.initialScale = scale;\n return this;\n }\n setMinimumScale(scale) {\n this.minimumScale = scale;\n return this;\n }\n setWidth(width) {\n this.width = width;\n return this;\n }\n setHeight(height) {\n this.height = height;\n return this;\n }\n build() {\n const components = [];\n if (this.initialScale) {\n components.push(\"initial-scale=\" + this.initialScale);\n }\n if (this.minimumScale) {\n components.push(\"minimum-scale=\" + this.minimumScale);\n }\n if (this.width) {\n components.push(\"width=\" + this.width);\n }\n if (this.height) {\n components.push(\"height=\" + this.height);\n }\n return components.join(\", \");\n }\n}\nexport function parseViewportString(viewportString) {\n const regex = /(\\w+) *= *([^\\s,]+)/g;\n const properties = new Map();\n let match;\n while ((match = regex.exec(viewportString))) {\n if (match != null) {\n properties.set(match[1], match[2]);\n }\n }\n const width = parseFloat(properties.get(\"width\"));\n const height = parseFloat(properties.get(\"height\"));\n if (width && height) {\n return { width, height };\n }\n else {\n return undefined;\n }\n}\n","export class GesturesDetector {\n constructor(window, listener) {\n this.window = window;\n this.listener = listener;\n document.addEventListener(\"click\", (event) => {\n this.onClick(event);\n }, false);\n }\n onClick(event) {\n if (event.defaultPrevented) {\n return;\n }\n const selection = this.window.getSelection();\n if (selection && selection.type == \"Range\") {\n // There's an on-going selection, the tap will dismiss it so we don't forward it.\n // selection.type might be None (collapsed) or Caret with a collapsed range\n // when there is not true selection.\n return;\n }\n let nearestElement;\n if (event.target instanceof HTMLElement) {\n nearestElement = this.nearestInteractiveElement(event.target);\n }\n else {\n nearestElement = null;\n }\n if (nearestElement) {\n if (nearestElement instanceof HTMLAnchorElement) {\n this.listener.onLinkActivated(nearestElement.href, nearestElement.outerHTML);\n }\n }\n else {\n this.listener.onTap(event);\n }\n event.stopPropagation();\n event.preventDefault();\n }\n // See. https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling\n nearestInteractiveElement(element) {\n if (element == null) {\n return null;\n }\n const interactiveTags = [\n \"a\",\n \"audio\",\n \"button\",\n \"canvas\",\n \"details\",\n \"input\",\n \"label\",\n \"option\",\n \"select\",\n \"submit\",\n \"textarea\",\n \"video\",\n ];\n if (interactiveTags.indexOf(element.nodeName.toLowerCase()) != -1) {\n return element;\n }\n // Checks whether the element is editable by the user.\n if (element.hasAttribute(\"contenteditable\") &&\n element.getAttribute(\"contenteditable\").toLowerCase() != \"false\") {\n return element;\n }\n // Checks parents recursively because the touch might be for example on an inside a .\n if (element.parentElement) {\n return this.nearestInteractiveElement(element.parentElement);\n }\n return null;\n }\n}\n","import { computeScale } from \"../util/fit\";\nimport { PageManager } from \"./page-manager\";\nimport { ViewportStringBuilder } from \"../util/viewport\";\nimport { GesturesDetector } from \"../common/gestures\";\nexport class DoubleAreaManager {\n constructor(window, leftIframe, rightIframe, metaViewport, listener) {\n this.fit = \"contain\" /* Fit.Contain */;\n this.insets = { top: 0, right: 0, bottom: 0, left: 0 };\n window.addEventListener(\"message\", (event) => {\n if (!event.ports[0]) {\n return;\n }\n if (event.source === leftIframe.contentWindow) {\n this.leftPage.setMessagePort(event.ports[0]);\n }\n else if (event.source == rightIframe.contentWindow) {\n this.rightPage.setMessagePort(event.ports[0]);\n }\n });\n const wrapperGesturesListener = {\n onTap: (event) => {\n const tapEvent = {\n x: (event.clientX - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.clientY - visualViewport.offsetTop) * visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onLinkActivated: (_) => {\n throw Error(\"No interactive element in the root document.\");\n },\n };\n new GesturesDetector(window, wrapperGesturesListener);\n const leftPageListener = {\n onIframeLoaded: () => {\n this.layout();\n },\n onTap: (event) => {\n const boundingRect = leftIframe.getBoundingClientRect();\n const tapEvent = {\n x: (event.x + boundingRect.left - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.y + boundingRect.top - visualViewport.offsetTop) *\n visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n listener.onLinkActivated(href, outerHtml);\n },\n };\n const rightPageListener = {\n onIframeLoaded: () => {\n this.layout();\n },\n onTap: (event) => {\n const boundingRect = rightIframe.getBoundingClientRect();\n const tapEvent = {\n x: (event.x + boundingRect.left - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.y + boundingRect.top - visualViewport.offsetTop) *\n visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n listener.onLinkActivated(href, outerHtml);\n },\n };\n this.leftPage = new PageManager(window, leftIframe, leftPageListener);\n this.rightPage = new PageManager(window, rightIframe, rightPageListener);\n this.metaViewport = metaViewport;\n }\n loadSpread(spread) {\n this.leftPage.hide();\n this.rightPage.hide();\n this.spread = spread;\n if (spread.left) {\n this.leftPage.loadPage(spread.left);\n }\n if (spread.right) {\n this.rightPage.loadPage(spread.right);\n }\n }\n setViewport(size, insets) {\n if (this.viewport == size && this.insets == insets) {\n return;\n }\n this.viewport = size;\n this.insets = insets;\n this.layout();\n }\n setFit(fit) {\n if (this.fit == fit) {\n return;\n }\n this.fit = fit;\n this.layout();\n }\n layout() {\n if (!this.viewport ||\n (!this.leftPage.size && this.spread.left) ||\n (!this.rightPage.size && this.spread.right)) {\n return;\n }\n const leftMargins = {\n top: this.insets.top,\n right: 0,\n bottom: this.insets.bottom,\n left: this.insets.left,\n };\n this.leftPage.setMargins(leftMargins);\n const rightMargins = {\n top: this.insets.top,\n right: this.insets.right,\n bottom: this.insets.bottom,\n left: 0,\n };\n this.rightPage.setMargins(rightMargins);\n if (!this.spread.right) {\n this.rightPage.setPlaceholder(this.leftPage.size);\n }\n else if (!this.spread.left) {\n this.leftPage.setPlaceholder(this.rightPage.size);\n }\n const contentWidth = this.leftPage.size.width + this.rightPage.size.width;\n const contentHeight = Math.max(this.leftPage.size.height, this.rightPage.size.height);\n const contentSize = { width: contentWidth, height: contentHeight };\n const safeDrawingSize = {\n width: this.viewport.width - this.insets.left - this.insets.right,\n height: this.viewport.height - this.insets.top - this.insets.bottom,\n };\n const scale = computeScale(this.fit, contentSize, safeDrawingSize);\n this.metaViewport.content = new ViewportStringBuilder()\n .setInitialScale(scale)\n .setMinimumScale(scale)\n .setWidth(contentWidth)\n .setHeight(contentHeight)\n .build();\n this.leftPage.show();\n this.rightPage.show();\n }\n}\n","export function computeScale(fit, content, container) {\n switch (fit) {\n case \"contain\" /* Fit.Contain */:\n return fitContain(content, container);\n case \"width\" /* Fit.Width */:\n return fitWidth(content, container);\n case \"height\" /* Fit.Height */:\n return fitHeight(content, container);\n }\n}\nfunction fitContain(content, container) {\n const widthRatio = container.width / content.width;\n const heightRatio = container.height / content.height;\n return Math.min(widthRatio, heightRatio);\n}\nfunction fitWidth(content, container) {\n return container.width / content.width;\n}\nfunction fitHeight(content, container) {\n return container.height / content.height;\n}\n","export class BridgeGesturesAdapter {\n constructor(gesturesApi) {\n this.nativeApi = gesturesApi;\n }\n onTap(event) {\n this.nativeApi.onTap(JSON.stringify(event));\n }\n onLinkActivated(href, outerHtml) {\n this.nativeApi.onLinkActivated(href, outerHtml);\n }\n}\n","//\n// Copyright 2024 Readium Foundation. All rights reserved.\n// Use of this source code is governed by the BSD-style license\n// available in the top-level LICENSE file of the project.\n//\nimport { FixedDoubleBridge } from \"./bridge/fixed-double-bridge\";\nconst leftIframe = document.getElementById(\"page-left\");\nconst rightIframe = document.getElementById(\"page-right\");\nconst metaViewport = document.querySelector(\"meta[name=viewport]\");\nWindow.prototype.doubleArea = new FixedDoubleBridge(window, leftIframe, rightIframe, metaViewport, window.gestures);\nwindow.documentState.onScriptsLoaded();\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nwindow.addEventListener(\"load\", (event) => {\n window.documentState.onDocumentLoaded();\n});\n","import { DoubleAreaManager } from \"../fixed/double-area-manager\";\nimport { BridgeGesturesAdapter } from \"./all-gestures-bridge\";\nexport class FixedDoubleBridge {\n constructor(window, leftIframe, rightIframe, metaViewport, gestures) {\n const listener = new BridgeGesturesAdapter(gestures);\n this.manager = new DoubleAreaManager(window, leftIframe, rightIframe, metaViewport, listener);\n }\n loadSpread(spread) {\n this.manager.loadSpread(spread);\n }\n setViewport(viewporttWidth, viewportHeight, insetTop, insetRight, insetBottom, insetLeft) {\n const viewport = { width: viewporttWidth, height: viewportHeight };\n const insets = {\n top: insetTop,\n left: insetLeft,\n bottom: insetBottom,\n right: insetRight,\n };\n this.manager.setViewport(viewport, insets);\n }\n setFit(fit) {\n if (fit != \"contain\" && fit != \"width\" && fit != \"height\") {\n throw Error(`Invalid fit value: ${fit}`);\n }\n this.manager.setFit(fit);\n }\n}\n"],"names":["PageManager","constructor","window","iframe","listener","this","margins","top","right","bottom","left","contentWindow","Error","setMessagePort","messagePort","onmessage","message","onMessageFromIframe","show","style","display","hide","setMargins","marginTop","marginLeft","marginBottom","marginRight","loadPage","url","src","setPlaceholder","size","visibility","width","height","event","data","kind","onContentSizeAvailable","onTap","x","y","onLinkActivated","URL","href","toString","outerHtml","_a","onIframeLoaded","ViewportStringBuilder","setInitialScale","scale","initialScale","setMinimumScale","minimumScale","setWidth","setHeight","build","components","push","join","GesturesDetector","document","addEventListener","onClick","defaultPrevented","selection","getSelection","type","nearestElement","target","HTMLElement","nearestInteractiveElement","HTMLAnchorElement","outerHTML","stopPropagation","preventDefault","element","indexOf","nodeName","toLowerCase","hasAttribute","getAttribute","parentElement","DoubleAreaManager","leftIframe","rightIframe","metaViewport","fit","insets","ports","source","leftPage","rightPage","tapEvent","clientX","visualViewport","offsetLeft","clientY","offsetTop","_","leftPageListener","layout","boundingRect","getBoundingClientRect","rightPageListener","loadSpread","spread","setViewport","viewport","setFit","leftMargins","rightMargins","contentWidth","contentHeight","Math","max","contentSize","safeDrawingSize","content","container","widthRatio","heightRatio","min","fitContain","fitWidth","fitHeight","computeScale","BridgeGesturesAdapter","gesturesApi","nativeApi","JSON","stringify","getElementById","querySelector","Window","prototype","doubleArea","gestures","manager","viewporttWidth","viewportHeight","insetTop","insetRight","insetBottom","insetLeft","documentState","onScriptsLoaded","onDocumentLoaded"],"sourceRoot":""} \ No newline at end of file +{"version":3,"file":"fixed-double-script.js","mappings":"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","sources":["webpack://readium-js/./src/fixed/page-manager.ts","webpack://readium-js/./src/util/viewport.ts","webpack://readium-js/./src/common/gestures.ts","webpack://readium-js/./src/fixed/double-area-manager.ts","webpack://readium-js/./src/util/fit.ts","webpack://readium-js/./src/bridge/all-gestures-bridge.ts","webpack://readium-js/./src/index-fixed-double.ts","webpack://readium-js/./src/bridge/fixed-double-bridge.ts"],"sourcesContent":["/** Manages a fixed layout resource embedded in an iframe. */\nexport class PageManager {\n constructor(window, iframe, listener) {\n this.margins = { top: 0, right: 0, bottom: 0, left: 0 };\n if (!iframe.contentWindow) {\n throw Error(\"Iframe argument must have been attached to DOM.\");\n }\n this.listener = listener;\n this.iframe = iframe;\n }\n setMessagePort(messagePort) {\n messagePort.onmessage = (message) => {\n this.onMessageFromIframe(message);\n };\n }\n show() {\n this.iframe.style.display = \"unset\";\n }\n hide() {\n this.iframe.style.display = \"none\";\n }\n /** Sets page margins. */\n setMargins(margins) {\n if (this.margins == margins) {\n return;\n }\n this.iframe.style.marginTop = this.margins.top + \"px\";\n this.iframe.style.marginLeft = this.margins.left + \"px\";\n this.iframe.style.marginBottom = this.margins.bottom + \"px\";\n this.iframe.style.marginRight = this.margins.right + \"px\";\n }\n /** Loads page content. */\n loadPage(url) {\n this.iframe.src = url;\n }\n /** Sets the size of this page without content. */\n setPlaceholder(size) {\n this.iframe.style.visibility = \"hidden\";\n this.iframe.style.width = size.width + \"px\";\n this.iframe.style.height = size.height + \"px\";\n this.size = size;\n }\n onMessageFromIframe(event) {\n const message = event.data;\n switch (message.kind) {\n case \"contentSize\":\n return this.onContentSizeAvailable(message.size);\n case \"tap\":\n return this.listener.onTap({ x: message.x, y: message.y });\n case \"linkActivated\":\n return this.onLinkActivated(message);\n }\n }\n onLinkActivated(message) {\n try {\n const url = new URL(message.href, this.iframe.src);\n this.listener.onLinkActivated(url.toString(), message.outerHtml);\n }\n catch (_a) {\n // Do nothing if url is not valid.\n }\n }\n onContentSizeAvailable(size) {\n if (!size) {\n //FIXME: handle edge case\n return;\n }\n this.iframe.style.width = size.width + \"px\";\n this.iframe.style.height = size.height + \"px\";\n this.size = size;\n this.listener.onIframeLoaded();\n }\n}\n","export class ViewportStringBuilder {\n setInitialScale(scale) {\n this.initialScale = scale;\n return this;\n }\n setMinimumScale(scale) {\n this.minimumScale = scale;\n return this;\n }\n setWidth(width) {\n this.width = width;\n return this;\n }\n setHeight(height) {\n this.height = height;\n return this;\n }\n build() {\n const components = [];\n if (this.initialScale) {\n components.push(\"initial-scale=\" + this.initialScale);\n }\n if (this.minimumScale) {\n components.push(\"minimum-scale=\" + this.minimumScale);\n }\n if (this.width) {\n components.push(\"width=\" + this.width);\n }\n if (this.height) {\n components.push(\"height=\" + this.height);\n }\n return components.join(\", \");\n }\n}\nexport function parseViewportString(viewportString) {\n const regex = /(\\w+) *= *([^\\s,]+)/g;\n const properties = new Map();\n let match;\n while ((match = regex.exec(viewportString))) {\n if (match != null) {\n properties.set(match[1], match[2]);\n }\n }\n const width = parseFloat(properties.get(\"width\"));\n const height = parseFloat(properties.get(\"height\"));\n if (width && height) {\n return { width, height };\n }\n else {\n return undefined;\n }\n}\n","export class GesturesDetector {\n constructor(window, listener) {\n this.window = window;\n this.listener = listener;\n document.addEventListener(\"click\", (event) => {\n this.onClick(event);\n }, false);\n }\n onClick(event) {\n if (event.defaultPrevented) {\n return;\n }\n const selection = this.window.getSelection();\n if (selection && selection.type == \"Range\") {\n // There's an on-going selection, the tap will dismiss it so we don't forward it.\n // selection.type might be None (collapsed) or Caret with a collapsed range\n // when there is not true selection.\n return;\n }\n let nearestElement;\n if (event.target instanceof HTMLElement) {\n nearestElement = this.nearestInteractiveElement(event.target);\n }\n else {\n nearestElement = null;\n }\n if (nearestElement) {\n if (nearestElement instanceof HTMLAnchorElement) {\n this.listener.onLinkActivated(nearestElement.href, nearestElement.outerHTML);\n }\n }\n else {\n this.listener.onTap(event);\n }\n event.stopPropagation();\n event.preventDefault();\n }\n // See. https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling\n nearestInteractiveElement(element) {\n if (element == null) {\n return null;\n }\n const interactiveTags = [\n \"a\",\n \"audio\",\n \"button\",\n \"canvas\",\n \"details\",\n \"input\",\n \"label\",\n \"option\",\n \"select\",\n \"submit\",\n \"textarea\",\n \"video\",\n ];\n if (interactiveTags.indexOf(element.nodeName.toLowerCase()) != -1) {\n return element;\n }\n // Checks whether the element is editable by the user.\n if (element.hasAttribute(\"contenteditable\") &&\n element.getAttribute(\"contenteditable\").toLowerCase() != \"false\") {\n return element;\n }\n // Checks parents recursively because the touch might be for example on an inside a .\n if (element.parentElement) {\n return this.nearestInteractiveElement(element.parentElement);\n }\n return null;\n }\n}\n","import { computeScale } from \"../util/fit\";\nimport { PageManager } from \"./page-manager\";\nimport { ViewportStringBuilder } from \"../util/viewport\";\nimport { GesturesDetector } from \"../common/gestures\";\nexport class DoubleAreaManager {\n constructor(window, leftIframe, rightIframe, metaViewport, listener) {\n this.fit = \"contain\" /* Fit.Contain */;\n this.insets = { top: 0, right: 0, bottom: 0, left: 0 };\n window.addEventListener(\"message\", (event) => {\n if (!event.ports[0]) {\n return;\n }\n if (event.source === leftIframe.contentWindow) {\n this.leftPage.setMessagePort(event.ports[0]);\n }\n else if (event.source == rightIframe.contentWindow) {\n this.rightPage.setMessagePort(event.ports[0]);\n }\n });\n const wrapperGesturesListener = {\n onTap: (event) => {\n const tapEvent = {\n x: (event.clientX - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.clientY - visualViewport.offsetTop) * visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onLinkActivated: (_) => {\n throw Error(\"No interactive element in the root document.\");\n },\n };\n new GesturesDetector(window, wrapperGesturesListener);\n const leftPageListener = {\n onIframeLoaded: () => {\n this.layout();\n },\n onTap: (event) => {\n const boundingRect = leftIframe.getBoundingClientRect();\n const tapEvent = {\n x: (event.x + boundingRect.left - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.y + boundingRect.top - visualViewport.offsetTop) *\n visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n listener.onLinkActivated(href, outerHtml);\n },\n };\n const rightPageListener = {\n onIframeLoaded: () => {\n this.layout();\n },\n onTap: (event) => {\n const boundingRect = rightIframe.getBoundingClientRect();\n const tapEvent = {\n x: (event.x + boundingRect.left - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.y + boundingRect.top - visualViewport.offsetTop) *\n visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n listener.onLinkActivated(href, outerHtml);\n },\n };\n this.leftPage = new PageManager(window, leftIframe, leftPageListener);\n this.rightPage = new PageManager(window, rightIframe, rightPageListener);\n this.metaViewport = metaViewport;\n }\n loadSpread(spread) {\n this.leftPage.hide();\n this.rightPage.hide();\n this.spread = spread;\n if (spread.left) {\n this.leftPage.loadPage(spread.left);\n }\n if (spread.right) {\n this.rightPage.loadPage(spread.right);\n }\n }\n setViewport(size, insets) {\n if (this.viewport == size && this.insets == insets) {\n return;\n }\n this.viewport = size;\n this.insets = insets;\n this.layout();\n }\n setFit(fit) {\n if (this.fit == fit) {\n return;\n }\n this.fit = fit;\n this.layout();\n }\n layout() {\n if (!this.viewport ||\n (!this.leftPage.size && this.spread.left) ||\n (!this.rightPage.size && this.spread.right)) {\n return;\n }\n const leftMargins = {\n top: this.insets.top,\n right: 0,\n bottom: this.insets.bottom,\n left: this.insets.left,\n };\n this.leftPage.setMargins(leftMargins);\n const rightMargins = {\n top: this.insets.top,\n right: this.insets.right,\n bottom: this.insets.bottom,\n left: 0,\n };\n this.rightPage.setMargins(rightMargins);\n if (!this.spread.right) {\n this.rightPage.setPlaceholder(this.leftPage.size);\n }\n else if (!this.spread.left) {\n this.leftPage.setPlaceholder(this.rightPage.size);\n }\n const contentWidth = this.leftPage.size.width + this.rightPage.size.width;\n const contentHeight = Math.max(this.leftPage.size.height, this.rightPage.size.height);\n const contentSize = { width: contentWidth, height: contentHeight };\n const safeDrawingSize = {\n width: this.viewport.width - this.insets.left - this.insets.right,\n height: this.viewport.height - this.insets.top - this.insets.bottom,\n };\n const scale = computeScale(this.fit, contentSize, safeDrawingSize);\n this.metaViewport.content = new ViewportStringBuilder()\n .setInitialScale(scale)\n .setMinimumScale(scale)\n .setWidth(contentWidth)\n .setHeight(contentHeight)\n .build();\n this.leftPage.show();\n this.rightPage.show();\n }\n}\n","export function computeScale(fit, content, container) {\n switch (fit) {\n case \"contain\" /* Fit.Contain */:\n return fitContain(content, container);\n case \"width\" /* Fit.Width */:\n return fitWidth(content, container);\n case \"height\" /* Fit.Height */:\n return fitHeight(content, container);\n }\n}\nfunction fitContain(content, container) {\n const widthRatio = container.width / content.width;\n const heightRatio = container.height / content.height;\n return Math.min(widthRatio, heightRatio);\n}\nfunction fitWidth(content, container) {\n return container.width / content.width;\n}\nfunction fitHeight(content, container) {\n return container.height / content.height;\n}\n","export class BridgeGesturesAdapter {\n constructor(gesturesApi) {\n this.nativeApi = gesturesApi;\n }\n onTap(event) {\n this.nativeApi.onTap(JSON.stringify(event));\n }\n onLinkActivated(href, outerHtml) {\n this.nativeApi.onLinkActivated(href, outerHtml);\n }\n}\n","//\n// Copyright 2024 Readium Foundation. All rights reserved.\n// Use of this source code is governed by the BSD-style license\n// available in the top-level LICENSE file of the project.\n//\nimport { FixedDoubleBridge } from \"./bridge/fixed-double-bridge\";\nconst leftIframe = document.getElementById(\"page-left\");\nconst rightIframe = document.getElementById(\"page-right\");\nconst metaViewport = document.querySelector(\"meta[name=viewport]\");\nWindow.prototype.doubleArea = new FixedDoubleBridge(window, leftIframe, rightIframe, metaViewport, window.gestures);\nwindow.documentState.onScriptsLoaded();\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nwindow.addEventListener(\"load\", (event) => {\n window.documentState.onDocumentLoadedAndSized();\n});\n","import { DoubleAreaManager } from \"../fixed/double-area-manager\";\nimport { BridgeGesturesAdapter } from \"./all-gestures-bridge\";\nexport class FixedDoubleBridge {\n constructor(window, leftIframe, rightIframe, metaViewport, gestures) {\n const listener = new BridgeGesturesAdapter(gestures);\n this.manager = new DoubleAreaManager(window, leftIframe, rightIframe, metaViewport, listener);\n }\n loadSpread(spread) {\n this.manager.loadSpread(spread);\n }\n setViewport(viewporttWidth, viewportHeight, insetTop, insetRight, insetBottom, insetLeft) {\n const viewport = { width: viewporttWidth, height: viewportHeight };\n const insets = {\n top: insetTop,\n left: insetLeft,\n bottom: insetBottom,\n right: insetRight,\n };\n this.manager.setViewport(viewport, insets);\n }\n setFit(fit) {\n if (fit != \"contain\" && fit != \"width\" && fit != \"height\") {\n throw Error(`Invalid fit value: ${fit}`);\n }\n this.manager.setFit(fit);\n }\n}\n"],"names":["PageManager","constructor","window","iframe","listener","this","margins","top","right","bottom","left","contentWindow","Error","setMessagePort","messagePort","onmessage","message","onMessageFromIframe","show","style","display","hide","setMargins","marginTop","marginLeft","marginBottom","marginRight","loadPage","url","src","setPlaceholder","size","visibility","width","height","event","data","kind","onContentSizeAvailable","onTap","x","y","onLinkActivated","URL","href","toString","outerHtml","_a","onIframeLoaded","ViewportStringBuilder","setInitialScale","scale","initialScale","setMinimumScale","minimumScale","setWidth","setHeight","build","components","push","join","GesturesDetector","document","addEventListener","onClick","defaultPrevented","selection","getSelection","type","nearestElement","target","HTMLElement","nearestInteractiveElement","HTMLAnchorElement","outerHTML","stopPropagation","preventDefault","element","indexOf","nodeName","toLowerCase","hasAttribute","getAttribute","parentElement","DoubleAreaManager","leftIframe","rightIframe","metaViewport","fit","insets","ports","source","leftPage","rightPage","tapEvent","clientX","visualViewport","offsetLeft","clientY","offsetTop","_","leftPageListener","layout","boundingRect","getBoundingClientRect","rightPageListener","loadSpread","spread","setViewport","viewport","setFit","leftMargins","rightMargins","contentWidth","contentHeight","Math","max","contentSize","safeDrawingSize","content","container","widthRatio","heightRatio","min","fitContain","fitWidth","fitHeight","computeScale","BridgeGesturesAdapter","gesturesApi","nativeApi","JSON","stringify","getElementById","querySelector","Window","prototype","doubleArea","gestures","manager","viewporttWidth","viewportHeight","insetTop","insetRight","insetBottom","insetLeft","documentState","onScriptsLoaded","onDocumentLoadedAndSized"],"sourceRoot":""} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-single-script.js b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-single-script.js index c20c12c289..234cc5afaa 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-single-script.js +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-single-script.js @@ -1,2 +1,2 @@ -!function(){"use strict";class t{constructor(t,e,i){if(this.margins={top:0,right:0,bottom:0,left:0},!e.contentWindow)throw Error("Iframe argument must have been attached to DOM.");this.listener=i,this.iframe=e}setMessagePort(t){t.onmessage=t=>{this.onMessageFromIframe(t)}}show(){this.iframe.style.display="unset"}hide(){this.iframe.style.display="none"}setMargins(t){this.margins!=t&&(this.iframe.style.marginTop=this.margins.top+"px",this.iframe.style.marginLeft=this.margins.left+"px",this.iframe.style.marginBottom=this.margins.bottom+"px",this.iframe.style.marginRight=this.margins.right+"px")}loadPage(t){this.iframe.src=t}setPlaceholder(t){this.iframe.style.visibility="hidden",this.iframe.style.width=t.width+"px",this.iframe.style.height=t.height+"px",this.size=t}onMessageFromIframe(t){const e=t.data;switch(e.kind){case"contentSize":return this.onContentSizeAvailable(e.size);case"tap":return this.listener.onTap({x:e.x,y:e.y});case"linkActivated":return this.onLinkActivated(e)}}onLinkActivated(t){try{const e=new URL(t.href,this.iframe.src);this.listener.onLinkActivated(e.toString(),t.outerHtml)}catch(t){}}onContentSizeAvailable(t){t&&(this.iframe.style.width=t.width+"px",this.iframe.style.height=t.height+"px",this.size=t,this.listener.onIframeLoaded())}}class e{setInitialScale(t){return this.initialScale=t,this}setMinimumScale(t){return this.minimumScale=t,this}setWidth(t){return this.width=t,this}setHeight(t){return this.height=t,this}build(){const t=[];return this.initialScale&&t.push("initial-scale="+this.initialScale),this.minimumScale&&t.push("minimum-scale="+this.minimumScale),this.width&&t.push("width="+this.width),this.height&&t.push("height="+this.height),t.join(", ")}}class i{constructor(t,e){this.window=t,this.listener=e,document.addEventListener("click",(t=>{this.onClick(t)}),!1)}onClick(t){if(t.defaultPrevented)return;const e=this.window.getSelection();if(e&&"Range"==e.type)return;let i;i=t.target instanceof HTMLElement?this.nearestInteractiveElement(t.target):null,i?i instanceof HTMLAnchorElement&&this.listener.onLinkActivated(i.href,i.outerHTML):this.listener.onTap(t),t.stopPropagation(),t.preventDefault()}nearestInteractiveElement(t){return null==t?null:-1!=["a","audio","button","canvas","details","input","label","option","select","submit","textarea","video"].indexOf(t.nodeName.toLowerCase())||t.hasAttribute("contenteditable")&&"false"!=t.getAttribute("contenteditable").toLowerCase()?t:t.parentElement?this.nearestInteractiveElement(t.parentElement):null}}class s{constructor(e,s,n,a){this.fit="contain",this.insets={top:0,right:0,bottom:0,left:0},this.scale=1,e.addEventListener("message",(t=>{t.source===s.contentWindow&&t.ports[0]&&this.page.setMessagePort(t.ports[0])})),new i(e,{onTap:t=>{const e={x:(t.clientX-visualViewport.offsetLeft)*visualViewport.scale,y:(t.clientY-visualViewport.offsetTop)*visualViewport.scale};a.onTap(e)},onLinkActivated:t=>{throw Error("No interactive element in the root document.")}}),this.metaViewport=n;const o={onIframeLoaded:()=>{this.onIframeLoaded()},onTap:t=>{const e=s.getBoundingClientRect(),i={x:(t.x+e.left-visualViewport.offsetLeft)*visualViewport.scale,y:(t.y+e.top-visualViewport.offsetTop)*visualViewport.scale};a.onTap(i)},onLinkActivated:(t,e)=>{a.onLinkActivated(t,e)}};this.page=new t(e,s,o)}setViewport(t,e){this.viewport==t&&this.insets==e||(this.viewport=t,this.insets=e,this.layout())}setFit(t){this.fit!=t&&(this.fit=t,this.layout())}loadResource(t){this.page.hide(),this.page.loadPage(t)}onIframeLoaded(){this.page.size&&this.layout()}layout(){if(!this.page.size||!this.viewport)return;const t={top:this.insets.top,right:this.insets.right,bottom:this.insets.bottom,left:this.insets.left};this.page.setMargins(t);const i={width:this.viewport.width-this.insets.left-this.insets.right,height:this.viewport.height-this.insets.top-this.insets.bottom},s=function(t,e,i){switch(t){case"contain":return function(t,e){const i=e.width/t.width,s=e.height/t.height;return Math.min(i,s)}(e,i);case"width":return function(t,e){return e.width/t.width}(e,i);case"height":return function(t,e){return e.height/t.height}(e,i)}}(this.fit,this.page.size,i);this.metaViewport.content=(new e).setInitialScale(s).setMinimumScale(s).setWidth(this.page.size.width).setHeight(this.page.size.height).build(),this.scale=s,this.page.show()}}class n{constructor(t){this.nativeApi=t}onTap(t){this.nativeApi.onTap(JSON.stringify(t))}onLinkActivated(t,e){this.nativeApi.onLinkActivated(t,e)}}const a=document.getElementById("page"),o=document.querySelector("meta[name=viewport]");window.singleArea=new class{constructor(t,e,i,a){const o=new n(a);this.manager=new s(t,e,i,o)}loadResource(t){this.manager.loadResource(t)}setViewport(t,e,i,s,n,a){const o={width:t,height:e},h={top:i,left:a,bottom:n,right:s};this.manager.setViewport(o,h)}setFit(t){if("contain"!=t&&"width"!=t&&"height"!=t)throw Error(`Invalid fit value: ${t}`);this.manager.setFit(t)}}(window,a,o,window.gestures),window.documentState.onScriptsLoaded(),window.addEventListener("load",(t=>{window.documentState.onDocumentLoaded()}))}(); +!function(){"use strict";class t{constructor(t,e,i){if(this.margins={top:0,right:0,bottom:0,left:0},!e.contentWindow)throw Error("Iframe argument must have been attached to DOM.");this.listener=i,this.iframe=e}setMessagePort(t){t.onmessage=t=>{this.onMessageFromIframe(t)}}show(){this.iframe.style.display="unset"}hide(){this.iframe.style.display="none"}setMargins(t){this.margins!=t&&(this.iframe.style.marginTop=this.margins.top+"px",this.iframe.style.marginLeft=this.margins.left+"px",this.iframe.style.marginBottom=this.margins.bottom+"px",this.iframe.style.marginRight=this.margins.right+"px")}loadPage(t){this.iframe.src=t}setPlaceholder(t){this.iframe.style.visibility="hidden",this.iframe.style.width=t.width+"px",this.iframe.style.height=t.height+"px",this.size=t}onMessageFromIframe(t){const e=t.data;switch(e.kind){case"contentSize":return this.onContentSizeAvailable(e.size);case"tap":return this.listener.onTap({x:e.x,y:e.y});case"linkActivated":return this.onLinkActivated(e)}}onLinkActivated(t){try{const e=new URL(t.href,this.iframe.src);this.listener.onLinkActivated(e.toString(),t.outerHtml)}catch(t){}}onContentSizeAvailable(t){t&&(this.iframe.style.width=t.width+"px",this.iframe.style.height=t.height+"px",this.size=t,this.listener.onIframeLoaded())}}class e{setInitialScale(t){return this.initialScale=t,this}setMinimumScale(t){return this.minimumScale=t,this}setWidth(t){return this.width=t,this}setHeight(t){return this.height=t,this}build(){const t=[];return this.initialScale&&t.push("initial-scale="+this.initialScale),this.minimumScale&&t.push("minimum-scale="+this.minimumScale),this.width&&t.push("width="+this.width),this.height&&t.push("height="+this.height),t.join(", ")}}class i{constructor(t,e){this.window=t,this.listener=e,document.addEventListener("click",(t=>{this.onClick(t)}),!1)}onClick(t){if(t.defaultPrevented)return;const e=this.window.getSelection();if(e&&"Range"==e.type)return;let i;i=t.target instanceof HTMLElement?this.nearestInteractiveElement(t.target):null,i?i instanceof HTMLAnchorElement&&this.listener.onLinkActivated(i.href,i.outerHTML):this.listener.onTap(t),t.stopPropagation(),t.preventDefault()}nearestInteractiveElement(t){return null==t?null:-1!=["a","audio","button","canvas","details","input","label","option","select","submit","textarea","video"].indexOf(t.nodeName.toLowerCase())||t.hasAttribute("contenteditable")&&"false"!=t.getAttribute("contenteditable").toLowerCase()?t:t.parentElement?this.nearestInteractiveElement(t.parentElement):null}}class s{constructor(e,s,n,a){this.fit="contain",this.insets={top:0,right:0,bottom:0,left:0},this.scale=1,e.addEventListener("message",(t=>{t.source===s.contentWindow&&t.ports[0]&&this.page.setMessagePort(t.ports[0])})),new i(e,{onTap:t=>{const e={x:(t.clientX-visualViewport.offsetLeft)*visualViewport.scale,y:(t.clientY-visualViewport.offsetTop)*visualViewport.scale};a.onTap(e)},onLinkActivated:t=>{throw Error("No interactive element in the root document.")}}),this.metaViewport=n;const o={onIframeLoaded:()=>{this.onIframeLoaded()},onTap:t=>{const e=s.getBoundingClientRect(),i={x:(t.x+e.left-visualViewport.offsetLeft)*visualViewport.scale,y:(t.y+e.top-visualViewport.offsetTop)*visualViewport.scale};a.onTap(i)},onLinkActivated:(t,e)=>{a.onLinkActivated(t,e)}};this.page=new t(e,s,o)}setViewport(t,e){this.viewport==t&&this.insets==e||(this.viewport=t,this.insets=e,this.layout())}setFit(t){this.fit!=t&&(this.fit=t,this.layout())}loadResource(t){this.page.hide(),this.page.loadPage(t)}onIframeLoaded(){this.page.size&&this.layout()}layout(){if(!this.page.size||!this.viewport)return;const t={top:this.insets.top,right:this.insets.right,bottom:this.insets.bottom,left:this.insets.left};this.page.setMargins(t);const i={width:this.viewport.width-this.insets.left-this.insets.right,height:this.viewport.height-this.insets.top-this.insets.bottom},s=function(t,e,i){switch(t){case"contain":return function(t,e){const i=e.width/t.width,s=e.height/t.height;return Math.min(i,s)}(e,i);case"width":return function(t,e){return e.width/t.width}(e,i);case"height":return function(t,e){return e.height/t.height}(e,i)}}(this.fit,this.page.size,i);this.metaViewport.content=(new e).setInitialScale(s).setMinimumScale(s).setWidth(this.page.size.width).setHeight(this.page.size.height).build(),this.scale=s,this.page.show()}}class n{constructor(t){this.nativeApi=t}onTap(t){this.nativeApi.onTap(JSON.stringify(t))}onLinkActivated(t,e){this.nativeApi.onLinkActivated(t,e)}}const a=document.getElementById("page"),o=document.querySelector("meta[name=viewport]");window.singleArea=new class{constructor(t,e,i,a){const o=new n(a);this.manager=new s(t,e,i,o)}loadResource(t){this.manager.loadResource(t)}setViewport(t,e,i,s,n,a){const o={width:t,height:e},h={top:i,left:a,bottom:n,right:s};this.manager.setViewport(o,h)}setFit(t){if("contain"!=t&&"width"!=t&&"height"!=t)throw Error(`Invalid fit value: ${t}`);this.manager.setFit(t)}}(window,a,o,window.gestures),window.documentState.onScriptsLoaded(),window.addEventListener("load",(t=>{window.documentState.onDocumentLoadedAndSized()}))}(); //# sourceMappingURL=fixed-single-script.js.map \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-single-script.js.map b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-single-script.js.map index e94b47e25a..2a0b119de4 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-single-script.js.map +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-single-script.js.map @@ -1 +1 @@ -{"version":3,"file":"fixed-single-script.js","mappings":"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","sources":["webpack://readium-js/./src/fixed/page-manager.ts","webpack://readium-js/./src/util/viewport.ts","webpack://readium-js/./src/common/gestures.ts","webpack://readium-js/./src/fixed/single-area-manager.ts","webpack://readium-js/./src/util/fit.ts","webpack://readium-js/./src/bridge/all-gestures-bridge.ts","webpack://readium-js/./src/index-fixed-single.ts","webpack://readium-js/./src/bridge/fixed-single-bridge.ts"],"sourcesContent":["/** Manages a fixed layout resource embedded in an iframe. */\nexport class PageManager {\n constructor(window, iframe, listener) {\n this.margins = { top: 0, right: 0, bottom: 0, left: 0 };\n if (!iframe.contentWindow) {\n throw Error(\"Iframe argument must have been attached to DOM.\");\n }\n this.listener = listener;\n this.iframe = iframe;\n }\n setMessagePort(messagePort) {\n messagePort.onmessage = (message) => {\n this.onMessageFromIframe(message);\n };\n }\n show() {\n this.iframe.style.display = \"unset\";\n }\n hide() {\n this.iframe.style.display = \"none\";\n }\n /** Sets page margins. */\n setMargins(margins) {\n if (this.margins == margins) {\n return;\n }\n this.iframe.style.marginTop = this.margins.top + \"px\";\n this.iframe.style.marginLeft = this.margins.left + \"px\";\n this.iframe.style.marginBottom = this.margins.bottom + \"px\";\n this.iframe.style.marginRight = this.margins.right + \"px\";\n }\n /** Loads page content. */\n loadPage(url) {\n this.iframe.src = url;\n }\n /** Sets the size of this page without content. */\n setPlaceholder(size) {\n this.iframe.style.visibility = \"hidden\";\n this.iframe.style.width = size.width + \"px\";\n this.iframe.style.height = size.height + \"px\";\n this.size = size;\n }\n onMessageFromIframe(event) {\n const message = event.data;\n switch (message.kind) {\n case \"contentSize\":\n return this.onContentSizeAvailable(message.size);\n case \"tap\":\n return this.listener.onTap({ x: message.x, y: message.y });\n case \"linkActivated\":\n return this.onLinkActivated(message);\n }\n }\n onLinkActivated(message) {\n try {\n const url = new URL(message.href, this.iframe.src);\n this.listener.onLinkActivated(url.toString(), message.outerHtml);\n }\n catch (_a) {\n // Do nothing if url is not valid.\n }\n }\n onContentSizeAvailable(size) {\n if (!size) {\n //FIXME: handle edge case\n return;\n }\n this.iframe.style.width = size.width + \"px\";\n this.iframe.style.height = size.height + \"px\";\n this.size = size;\n this.listener.onIframeLoaded();\n }\n}\n","export class ViewportStringBuilder {\n setInitialScale(scale) {\n this.initialScale = scale;\n return this;\n }\n setMinimumScale(scale) {\n this.minimumScale = scale;\n return this;\n }\n setWidth(width) {\n this.width = width;\n return this;\n }\n setHeight(height) {\n this.height = height;\n return this;\n }\n build() {\n const components = [];\n if (this.initialScale) {\n components.push(\"initial-scale=\" + this.initialScale);\n }\n if (this.minimumScale) {\n components.push(\"minimum-scale=\" + this.minimumScale);\n }\n if (this.width) {\n components.push(\"width=\" + this.width);\n }\n if (this.height) {\n components.push(\"height=\" + this.height);\n }\n return components.join(\", \");\n }\n}\nexport function parseViewportString(viewportString) {\n const regex = /(\\w+) *= *([^\\s,]+)/g;\n const properties = new Map();\n let match;\n while ((match = regex.exec(viewportString))) {\n if (match != null) {\n properties.set(match[1], match[2]);\n }\n }\n const width = parseFloat(properties.get(\"width\"));\n const height = parseFloat(properties.get(\"height\"));\n if (width && height) {\n return { width, height };\n }\n else {\n return undefined;\n }\n}\n","export class GesturesDetector {\n constructor(window, listener) {\n this.window = window;\n this.listener = listener;\n document.addEventListener(\"click\", (event) => {\n this.onClick(event);\n }, false);\n }\n onClick(event) {\n if (event.defaultPrevented) {\n return;\n }\n const selection = this.window.getSelection();\n if (selection && selection.type == \"Range\") {\n // There's an on-going selection, the tap will dismiss it so we don't forward it.\n // selection.type might be None (collapsed) or Caret with a collapsed range\n // when there is not true selection.\n return;\n }\n let nearestElement;\n if (event.target instanceof HTMLElement) {\n nearestElement = this.nearestInteractiveElement(event.target);\n }\n else {\n nearestElement = null;\n }\n if (nearestElement) {\n if (nearestElement instanceof HTMLAnchorElement) {\n this.listener.onLinkActivated(nearestElement.href, nearestElement.outerHTML);\n }\n }\n else {\n this.listener.onTap(event);\n }\n event.stopPropagation();\n event.preventDefault();\n }\n // See. https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling\n nearestInteractiveElement(element) {\n if (element == null) {\n return null;\n }\n const interactiveTags = [\n \"a\",\n \"audio\",\n \"button\",\n \"canvas\",\n \"details\",\n \"input\",\n \"label\",\n \"option\",\n \"select\",\n \"submit\",\n \"textarea\",\n \"video\",\n ];\n if (interactiveTags.indexOf(element.nodeName.toLowerCase()) != -1) {\n return element;\n }\n // Checks whether the element is editable by the user.\n if (element.hasAttribute(\"contenteditable\") &&\n element.getAttribute(\"contenteditable\").toLowerCase() != \"false\") {\n return element;\n }\n // Checks parents recursively because the touch might be for example on an inside a .\n if (element.parentElement) {\n return this.nearestInteractiveElement(element.parentElement);\n }\n return null;\n }\n}\n","import { computeScale } from \"../util/fit\";\nimport { PageManager } from \"./page-manager\";\nimport { ViewportStringBuilder } from \"../util/viewport\";\nimport { GesturesDetector } from \"../common/gestures\";\nexport class SingleAreaManager {\n constructor(window, iframe, metaViewport, listener) {\n this.fit = \"contain\" /* Fit.Contain */;\n this.insets = { top: 0, right: 0, bottom: 0, left: 0 };\n this.scale = 1;\n window.addEventListener(\"message\", (event) => {\n if (event.source === iframe.contentWindow && event.ports[0]) {\n this.page.setMessagePort(event.ports[0]);\n }\n });\n const wrapperGesturesListener = {\n onTap: (event) => {\n const tapEvent = {\n x: (event.clientX - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.clientY - visualViewport.offsetTop) * visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onLinkActivated: (_) => {\n throw Error(\"No interactive element in the root document.\");\n },\n };\n new GesturesDetector(window, wrapperGesturesListener);\n this.metaViewport = metaViewport;\n const pageListener = {\n onIframeLoaded: () => {\n this.onIframeLoaded();\n },\n onTap: (event) => {\n const boundingRect = iframe.getBoundingClientRect();\n const tapEvent = {\n x: (event.x + boundingRect.left - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.y + boundingRect.top - visualViewport.offsetTop) *\n visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n listener.onLinkActivated(href, outerHtml);\n },\n };\n this.page = new PageManager(window, iframe, pageListener);\n }\n setViewport(viewport, insets) {\n if (this.viewport == viewport && this.insets == insets) {\n return;\n }\n this.viewport = viewport;\n this.insets = insets;\n this.layout();\n }\n setFit(fit) {\n if (this.fit == fit) {\n return;\n }\n this.fit = fit;\n this.layout();\n }\n loadResource(url) {\n this.page.hide();\n this.page.loadPage(url);\n }\n onIframeLoaded() {\n if (!this.page.size) {\n // FIXME: raise error\n }\n else {\n this.layout();\n }\n }\n layout() {\n if (!this.page.size || !this.viewport) {\n return;\n }\n const margins = {\n top: this.insets.top,\n right: this.insets.right,\n bottom: this.insets.bottom,\n left: this.insets.left,\n };\n this.page.setMargins(margins);\n const safeDrawingSize = {\n width: this.viewport.width - this.insets.left - this.insets.right,\n height: this.viewport.height - this.insets.top - this.insets.bottom,\n };\n const scale = computeScale(this.fit, this.page.size, safeDrawingSize);\n this.metaViewport.content = new ViewportStringBuilder()\n .setInitialScale(scale)\n .setMinimumScale(scale)\n .setWidth(this.page.size.width)\n .setHeight(this.page.size.height)\n .build();\n this.scale = scale;\n this.page.show();\n }\n}\n","export function computeScale(fit, content, container) {\n switch (fit) {\n case \"contain\" /* Fit.Contain */:\n return fitContain(content, container);\n case \"width\" /* Fit.Width */:\n return fitWidth(content, container);\n case \"height\" /* Fit.Height */:\n return fitHeight(content, container);\n }\n}\nfunction fitContain(content, container) {\n const widthRatio = container.width / content.width;\n const heightRatio = container.height / content.height;\n return Math.min(widthRatio, heightRatio);\n}\nfunction fitWidth(content, container) {\n return container.width / content.width;\n}\nfunction fitHeight(content, container) {\n return container.height / content.height;\n}\n","export class BridgeGesturesAdapter {\n constructor(gesturesApi) {\n this.nativeApi = gesturesApi;\n }\n onTap(event) {\n this.nativeApi.onTap(JSON.stringify(event));\n }\n onLinkActivated(href, outerHtml) {\n this.nativeApi.onLinkActivated(href, outerHtml);\n }\n}\n","//\n// Copyright 2024 Readium Foundation. All rights reserved.\n// Use of this source code is governed by the BSD-style license\n// available in the top-level LICENSE file of the project.\n//\nimport { FixedSingleBridge } from \"./bridge/fixed-single-bridge\";\nconst iframe = document.getElementById(\"page\");\nconst metaViewport = document.querySelector(\"meta[name=viewport]\");\nwindow.singleArea = new FixedSingleBridge(window, iframe, metaViewport, window.gestures);\nwindow.documentState.onScriptsLoaded();\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nwindow.addEventListener(\"load\", (event) => {\n window.documentState.onDocumentLoaded();\n});\n","import { SingleAreaManager } from \"../fixed/single-area-manager\";\nimport { BridgeGesturesAdapter } from \"./all-gestures-bridge\";\nexport class FixedSingleBridge {\n constructor(window, iframe, metaViewport, gestures) {\n const listener = new BridgeGesturesAdapter(gestures);\n this.manager = new SingleAreaManager(window, iframe, metaViewport, listener);\n }\n loadResource(url) {\n this.manager.loadResource(url);\n }\n setViewport(viewporttWidth, viewportHeight, insetTop, insetRight, insetBottom, insetLeft) {\n const viewport = { width: viewporttWidth, height: viewportHeight };\n const insets = {\n top: insetTop,\n left: insetLeft,\n bottom: insetBottom,\n right: insetRight,\n };\n this.manager.setViewport(viewport, insets);\n }\n setFit(fit) {\n if (fit != \"contain\" && fit != \"width\" && fit != \"height\") {\n throw Error(`Invalid fit value: ${fit}`);\n }\n this.manager.setFit(fit);\n }\n}\n"],"names":["PageManager","constructor","window","iframe","listener","this","margins","top","right","bottom","left","contentWindow","Error","setMessagePort","messagePort","onmessage","message","onMessageFromIframe","show","style","display","hide","setMargins","marginTop","marginLeft","marginBottom","marginRight","loadPage","url","src","setPlaceholder","size","visibility","width","height","event","data","kind","onContentSizeAvailable","onTap","x","y","onLinkActivated","URL","href","toString","outerHtml","_a","onIframeLoaded","ViewportStringBuilder","setInitialScale","scale","initialScale","setMinimumScale","minimumScale","setWidth","setHeight","build","components","push","join","GesturesDetector","document","addEventListener","onClick","defaultPrevented","selection","getSelection","type","nearestElement","target","HTMLElement","nearestInteractiveElement","HTMLAnchorElement","outerHTML","stopPropagation","preventDefault","element","indexOf","nodeName","toLowerCase","hasAttribute","getAttribute","parentElement","SingleAreaManager","metaViewport","fit","insets","source","ports","page","tapEvent","clientX","visualViewport","offsetLeft","clientY","offsetTop","_","pageListener","boundingRect","getBoundingClientRect","setViewport","viewport","layout","setFit","loadResource","safeDrawingSize","content","container","widthRatio","heightRatio","Math","min","fitContain","fitWidth","fitHeight","computeScale","BridgeGesturesAdapter","gesturesApi","nativeApi","JSON","stringify","getElementById","querySelector","singleArea","gestures","manager","viewporttWidth","viewportHeight","insetTop","insetRight","insetBottom","insetLeft","documentState","onScriptsLoaded","onDocumentLoaded"],"sourceRoot":""} \ No newline at end of file +{"version":3,"file":"fixed-single-script.js","mappings":"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","sources":["webpack://readium-js/./src/fixed/page-manager.ts","webpack://readium-js/./src/util/viewport.ts","webpack://readium-js/./src/common/gestures.ts","webpack://readium-js/./src/fixed/single-area-manager.ts","webpack://readium-js/./src/util/fit.ts","webpack://readium-js/./src/bridge/all-gestures-bridge.ts","webpack://readium-js/./src/index-fixed-single.ts","webpack://readium-js/./src/bridge/fixed-single-bridge.ts"],"sourcesContent":["/** Manages a fixed layout resource embedded in an iframe. */\nexport class PageManager {\n constructor(window, iframe, listener) {\n this.margins = { top: 0, right: 0, bottom: 0, left: 0 };\n if (!iframe.contentWindow) {\n throw Error(\"Iframe argument must have been attached to DOM.\");\n }\n this.listener = listener;\n this.iframe = iframe;\n }\n setMessagePort(messagePort) {\n messagePort.onmessage = (message) => {\n this.onMessageFromIframe(message);\n };\n }\n show() {\n this.iframe.style.display = \"unset\";\n }\n hide() {\n this.iframe.style.display = \"none\";\n }\n /** Sets page margins. */\n setMargins(margins) {\n if (this.margins == margins) {\n return;\n }\n this.iframe.style.marginTop = this.margins.top + \"px\";\n this.iframe.style.marginLeft = this.margins.left + \"px\";\n this.iframe.style.marginBottom = this.margins.bottom + \"px\";\n this.iframe.style.marginRight = this.margins.right + \"px\";\n }\n /** Loads page content. */\n loadPage(url) {\n this.iframe.src = url;\n }\n /** Sets the size of this page without content. */\n setPlaceholder(size) {\n this.iframe.style.visibility = \"hidden\";\n this.iframe.style.width = size.width + \"px\";\n this.iframe.style.height = size.height + \"px\";\n this.size = size;\n }\n onMessageFromIframe(event) {\n const message = event.data;\n switch (message.kind) {\n case \"contentSize\":\n return this.onContentSizeAvailable(message.size);\n case \"tap\":\n return this.listener.onTap({ x: message.x, y: message.y });\n case \"linkActivated\":\n return this.onLinkActivated(message);\n }\n }\n onLinkActivated(message) {\n try {\n const url = new URL(message.href, this.iframe.src);\n this.listener.onLinkActivated(url.toString(), message.outerHtml);\n }\n catch (_a) {\n // Do nothing if url is not valid.\n }\n }\n onContentSizeAvailable(size) {\n if (!size) {\n //FIXME: handle edge case\n return;\n }\n this.iframe.style.width = size.width + \"px\";\n this.iframe.style.height = size.height + \"px\";\n this.size = size;\n this.listener.onIframeLoaded();\n }\n}\n","export class ViewportStringBuilder {\n setInitialScale(scale) {\n this.initialScale = scale;\n return this;\n }\n setMinimumScale(scale) {\n this.minimumScale = scale;\n return this;\n }\n setWidth(width) {\n this.width = width;\n return this;\n }\n setHeight(height) {\n this.height = height;\n return this;\n }\n build() {\n const components = [];\n if (this.initialScale) {\n components.push(\"initial-scale=\" + this.initialScale);\n }\n if (this.minimumScale) {\n components.push(\"minimum-scale=\" + this.minimumScale);\n }\n if (this.width) {\n components.push(\"width=\" + this.width);\n }\n if (this.height) {\n components.push(\"height=\" + this.height);\n }\n return components.join(\", \");\n }\n}\nexport function parseViewportString(viewportString) {\n const regex = /(\\w+) *= *([^\\s,]+)/g;\n const properties = new Map();\n let match;\n while ((match = regex.exec(viewportString))) {\n if (match != null) {\n properties.set(match[1], match[2]);\n }\n }\n const width = parseFloat(properties.get(\"width\"));\n const height = parseFloat(properties.get(\"height\"));\n if (width && height) {\n return { width, height };\n }\n else {\n return undefined;\n }\n}\n","export class GesturesDetector {\n constructor(window, listener) {\n this.window = window;\n this.listener = listener;\n document.addEventListener(\"click\", (event) => {\n this.onClick(event);\n }, false);\n }\n onClick(event) {\n if (event.defaultPrevented) {\n return;\n }\n const selection = this.window.getSelection();\n if (selection && selection.type == \"Range\") {\n // There's an on-going selection, the tap will dismiss it so we don't forward it.\n // selection.type might be None (collapsed) or Caret with a collapsed range\n // when there is not true selection.\n return;\n }\n let nearestElement;\n if (event.target instanceof HTMLElement) {\n nearestElement = this.nearestInteractiveElement(event.target);\n }\n else {\n nearestElement = null;\n }\n if (nearestElement) {\n if (nearestElement instanceof HTMLAnchorElement) {\n this.listener.onLinkActivated(nearestElement.href, nearestElement.outerHTML);\n }\n }\n else {\n this.listener.onTap(event);\n }\n event.stopPropagation();\n event.preventDefault();\n }\n // See. https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling\n nearestInteractiveElement(element) {\n if (element == null) {\n return null;\n }\n const interactiveTags = [\n \"a\",\n \"audio\",\n \"button\",\n \"canvas\",\n \"details\",\n \"input\",\n \"label\",\n \"option\",\n \"select\",\n \"submit\",\n \"textarea\",\n \"video\",\n ];\n if (interactiveTags.indexOf(element.nodeName.toLowerCase()) != -1) {\n return element;\n }\n // Checks whether the element is editable by the user.\n if (element.hasAttribute(\"contenteditable\") &&\n element.getAttribute(\"contenteditable\").toLowerCase() != \"false\") {\n return element;\n }\n // Checks parents recursively because the touch might be for example on an inside a .\n if (element.parentElement) {\n return this.nearestInteractiveElement(element.parentElement);\n }\n return null;\n }\n}\n","import { computeScale } from \"../util/fit\";\nimport { PageManager } from \"./page-manager\";\nimport { ViewportStringBuilder } from \"../util/viewport\";\nimport { GesturesDetector } from \"../common/gestures\";\nexport class SingleAreaManager {\n constructor(window, iframe, metaViewport, listener) {\n this.fit = \"contain\" /* Fit.Contain */;\n this.insets = { top: 0, right: 0, bottom: 0, left: 0 };\n this.scale = 1;\n window.addEventListener(\"message\", (event) => {\n if (event.source === iframe.contentWindow && event.ports[0]) {\n this.page.setMessagePort(event.ports[0]);\n }\n });\n const wrapperGesturesListener = {\n onTap: (event) => {\n const tapEvent = {\n x: (event.clientX - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.clientY - visualViewport.offsetTop) * visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onLinkActivated: (_) => {\n throw Error(\"No interactive element in the root document.\");\n },\n };\n new GesturesDetector(window, wrapperGesturesListener);\n this.metaViewport = metaViewport;\n const pageListener = {\n onIframeLoaded: () => {\n this.onIframeLoaded();\n },\n onTap: (event) => {\n const boundingRect = iframe.getBoundingClientRect();\n const tapEvent = {\n x: (event.x + boundingRect.left - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.y + boundingRect.top - visualViewport.offsetTop) *\n visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n listener.onLinkActivated(href, outerHtml);\n },\n };\n this.page = new PageManager(window, iframe, pageListener);\n }\n setViewport(viewport, insets) {\n if (this.viewport == viewport && this.insets == insets) {\n return;\n }\n this.viewport = viewport;\n this.insets = insets;\n this.layout();\n }\n setFit(fit) {\n if (this.fit == fit) {\n return;\n }\n this.fit = fit;\n this.layout();\n }\n loadResource(url) {\n this.page.hide();\n this.page.loadPage(url);\n }\n onIframeLoaded() {\n if (!this.page.size) {\n // FIXME: raise error\n }\n else {\n this.layout();\n }\n }\n layout() {\n if (!this.page.size || !this.viewport) {\n return;\n }\n const margins = {\n top: this.insets.top,\n right: this.insets.right,\n bottom: this.insets.bottom,\n left: this.insets.left,\n };\n this.page.setMargins(margins);\n const safeDrawingSize = {\n width: this.viewport.width - this.insets.left - this.insets.right,\n height: this.viewport.height - this.insets.top - this.insets.bottom,\n };\n const scale = computeScale(this.fit, this.page.size, safeDrawingSize);\n this.metaViewport.content = new ViewportStringBuilder()\n .setInitialScale(scale)\n .setMinimumScale(scale)\n .setWidth(this.page.size.width)\n .setHeight(this.page.size.height)\n .build();\n this.scale = scale;\n this.page.show();\n }\n}\n","export function computeScale(fit, content, container) {\n switch (fit) {\n case \"contain\" /* Fit.Contain */:\n return fitContain(content, container);\n case \"width\" /* Fit.Width */:\n return fitWidth(content, container);\n case \"height\" /* Fit.Height */:\n return fitHeight(content, container);\n }\n}\nfunction fitContain(content, container) {\n const widthRatio = container.width / content.width;\n const heightRatio = container.height / content.height;\n return Math.min(widthRatio, heightRatio);\n}\nfunction fitWidth(content, container) {\n return container.width / content.width;\n}\nfunction fitHeight(content, container) {\n return container.height / content.height;\n}\n","export class BridgeGesturesAdapter {\n constructor(gesturesApi) {\n this.nativeApi = gesturesApi;\n }\n onTap(event) {\n this.nativeApi.onTap(JSON.stringify(event));\n }\n onLinkActivated(href, outerHtml) {\n this.nativeApi.onLinkActivated(href, outerHtml);\n }\n}\n","//\n// Copyright 2024 Readium Foundation. All rights reserved.\n// Use of this source code is governed by the BSD-style license\n// available in the top-level LICENSE file of the project.\n//\nimport { FixedSingleBridge } from \"./bridge/fixed-single-bridge\";\nconst iframe = document.getElementById(\"page\");\nconst metaViewport = document.querySelector(\"meta[name=viewport]\");\nwindow.singleArea = new FixedSingleBridge(window, iframe, metaViewport, window.gestures);\nwindow.documentState.onScriptsLoaded();\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nwindow.addEventListener(\"load\", (event) => {\n window.documentState.onDocumentLoadedAndSized();\n});\n","import { SingleAreaManager } from \"../fixed/single-area-manager\";\nimport { BridgeGesturesAdapter } from \"./all-gestures-bridge\";\nexport class FixedSingleBridge {\n constructor(window, iframe, metaViewport, gestures) {\n const listener = new BridgeGesturesAdapter(gestures);\n this.manager = new SingleAreaManager(window, iframe, metaViewport, listener);\n }\n loadResource(url) {\n this.manager.loadResource(url);\n }\n setViewport(viewporttWidth, viewportHeight, insetTop, insetRight, insetBottom, insetLeft) {\n const viewport = { width: viewporttWidth, height: viewportHeight };\n const insets = {\n top: insetTop,\n left: insetLeft,\n bottom: insetBottom,\n right: insetRight,\n };\n this.manager.setViewport(viewport, insets);\n }\n setFit(fit) {\n if (fit != \"contain\" && fit != \"width\" && fit != \"height\") {\n throw Error(`Invalid fit value: ${fit}`);\n }\n this.manager.setFit(fit);\n }\n}\n"],"names":["PageManager","constructor","window","iframe","listener","this","margins","top","right","bottom","left","contentWindow","Error","setMessagePort","messagePort","onmessage","message","onMessageFromIframe","show","style","display","hide","setMargins","marginTop","marginLeft","marginBottom","marginRight","loadPage","url","src","setPlaceholder","size","visibility","width","height","event","data","kind","onContentSizeAvailable","onTap","x","y","onLinkActivated","URL","href","toString","outerHtml","_a","onIframeLoaded","ViewportStringBuilder","setInitialScale","scale","initialScale","setMinimumScale","minimumScale","setWidth","setHeight","build","components","push","join","GesturesDetector","document","addEventListener","onClick","defaultPrevented","selection","getSelection","type","nearestElement","target","HTMLElement","nearestInteractiveElement","HTMLAnchorElement","outerHTML","stopPropagation","preventDefault","element","indexOf","nodeName","toLowerCase","hasAttribute","getAttribute","parentElement","SingleAreaManager","metaViewport","fit","insets","source","ports","page","tapEvent","clientX","visualViewport","offsetLeft","clientY","offsetTop","_","pageListener","boundingRect","getBoundingClientRect","setViewport","viewport","layout","setFit","loadResource","safeDrawingSize","content","container","widthRatio","heightRatio","Math","min","fitContain","fitWidth","fitHeight","computeScale","BridgeGesturesAdapter","gesturesApi","nativeApi","JSON","stringify","getElementById","querySelector","singleArea","gestures","manager","viewporttWidth","viewportHeight","insetTop","insetRight","insetBottom","insetLeft","documentState","onScriptsLoaded","onDocumentLoadedAndSized"],"sourceRoot":""} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js index b58a60eb3e..0acda0da6a 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js @@ -1,2 +1,2 @@ -!function(){"use strict";const e=new class{constructor(e){this.nativeApi=e}onTap(e){this.nativeApi.onTap(JSON.stringify(e))}onLinkActivated(e,t){this.nativeApi.onLinkActivated(e,t)}}(window.gestures),t={onTap:t=>{const n={x:(t.clientX-visualViewport.offsetLeft)*visualViewport.scale,y:(t.clientY-visualViewport.offsetTop)*visualViewport.scale};e.onTap(n)},onLinkActivated:(t,n)=>{e.onLinkActivated(t,n)}};new class{constructor(e,t){this.window=e,this.listener=t,document.addEventListener("click",(e=>{this.onClick(e)}),!1)}onClick(e){if(e.defaultPrevented)return;const t=this.window.getSelection();if(t&&"Range"==t.type)return;let n;n=e.target instanceof HTMLElement?this.nearestInteractiveElement(e.target):null,n?n instanceof HTMLAnchorElement&&this.listener.onLinkActivated(n.href,n.outerHTML):this.listener.onTap(e),e.stopPropagation(),e.preventDefault()}nearestInteractiveElement(e){return null==e?null:-1!=["a","audio","button","canvas","details","input","label","option","select","submit","textarea","video"].indexOf(e.nodeName.toLowerCase())||e.hasAttribute("contenteditable")&&"false"!=e.getAttribute("contenteditable").toLowerCase()?e:e.parentElement?this.nearestInteractiveElement(e.parentElement):null}}(window,t),Window.prototype.readiumcss=new class{constructor(e){this.document=e}setProperties(e){for(const[t,n]of e)this.setProperty(t,n)}setProperty(e,t){null===t||""===t?this.removeProperty(e):document.documentElement.style.setProperty(e,t,"important")}removeProperty(e){document.documentElement.style.removeProperty(e)}}(window.document),window.documentState.onScriptsLoaded(),window.addEventListener("load",(e=>{let t=!1;new ResizeObserver((()=>{requestAnimationFrame((()=>{!function(e){const t="readium-virtual-page";let n=e.document.getElementById(t);if(2!==function(e){return parseInt(e.getComputedStyle(e.document.documentElement).getPropertyValue("column-count"))}(e))n&&n.remove();else{const o=e.document.scrollingElement.scrollWidth/e.innerWidth;Math.round(2*o)/2%1>.1&&(n?n.remove():(n=e.document.createElement("div"),n.setAttribute("id",t),n.dataset.readium="true",n.style.breakBefore="column",n.innerHTML="​",e.document.body.appendChild(n)))}}(window);const e=window.document.scrollingElement;!t&&(null==e||e.scrollHeight>0&&e.scrollWidth>0)&&(console.log(`scrollWidth ${null==e?void 0:e.scrollWidth}`),window.documentState.onDocumentLoaded(),t=!0),window.documentState.onDocumentResized()}))})).observe(document.body)}))}(); +!function(){"use strict";const e=new class{constructor(e){this.nativeApi=e}onTap(e){this.nativeApi.onTap(JSON.stringify(e))}onLinkActivated(e,t){this.nativeApi.onLinkActivated(e,t)}}(window.gestures),t={onTap:t=>{const n={x:(t.clientX-visualViewport.offsetLeft)*visualViewport.scale,y:(t.clientY-visualViewport.offsetTop)*visualViewport.scale};e.onTap(n)},onLinkActivated:(t,n)=>{e.onLinkActivated(t,n)}};new class{constructor(e,t){this.window=e,this.listener=t,document.addEventListener("click",(e=>{this.onClick(e)}),!1)}onClick(e){if(e.defaultPrevented)return;const t=this.window.getSelection();if(t&&"Range"==t.type)return;let n;n=e.target instanceof HTMLElement?this.nearestInteractiveElement(e.target):null,n?n instanceof HTMLAnchorElement&&this.listener.onLinkActivated(n.href,n.outerHTML):this.listener.onTap(e),e.stopPropagation(),e.preventDefault()}nearestInteractiveElement(e){return null==e?null:-1!=["a","audio","button","canvas","details","input","label","option","select","submit","textarea","video"].indexOf(e.nodeName.toLowerCase())||e.hasAttribute("contenteditable")&&"false"!=e.getAttribute("contenteditable").toLowerCase()?e:e.parentElement?this.nearestInteractiveElement(e.parentElement):null}}(window,t),Window.prototype.readiumcss=new class{constructor(e){this.document=e}setProperties(e){for(const[t,n]of e)this.setProperty(t,n)}setProperty(e,t){null===t||""===t?this.removeProperty(e):document.documentElement.style.setProperty(e,t,"important")}removeProperty(e){document.documentElement.style.removeProperty(e)}}(window.document),window.documentState.onScriptsLoaded(),window.addEventListener("load",(e=>{let t=!1;new ResizeObserver((()=>{requestAnimationFrame((()=>{!function(e){const t="readium-virtual-page";let n=e.document.getElementById(t);if(2!==function(e){return parseInt(e.getComputedStyle(e.document.documentElement).getPropertyValue("column-count"))}(e))n&&n.remove();else{const o=e.document.scrollingElement.scrollWidth/e.innerWidth;Math.round(2*o)/2%1>.1&&(n?n.remove():(n=e.document.createElement("div"),n.setAttribute("id",t),n.dataset.readium="true",n.style.breakBefore="column",n.innerHTML="​",e.document.body.appendChild(n)))}}(window);const e=window.document.scrollingElement;!t&&(null==e||e.scrollHeight>0||e.scrollWidth>0)?(window.documentState.onDocumentLoadedAndSized(),t=!0):window.documentState.onDocumentResized()}))})).observe(document.body)}))}(); //# sourceMappingURL=reflowable-injectable-script.js.map \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map index aa9c0b8fc0..1260096914 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map @@ -1 +1 @@ -{"version":3,"file":"reflowable-injectable-script.js","mappings":"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","sources":["webpack://readium-js/./src/index-reflowable-injectable.ts","webpack://readium-js/./src/bridge/all-gestures-bridge.ts","webpack://readium-js/./src/common/gestures.ts","webpack://readium-js/./src/bridge/reflowable-css-bridge.ts","webpack://readium-js/./src/util/columns.ts"],"sourcesContent":["//\n// Copyright 2024 Readium Foundation. All rights reserved.\n// Use of this source code is governed by the BSD-style license\n// available in the top-level LICENSE file of the project.\n//\n/**\n * Script loaded by reflowable resources.\n */\nimport { BridgeGesturesAdapter, } from \"./bridge/all-gestures-bridge\";\nimport { CssBridge } from \"./bridge/reflowable-css-bridge\";\nimport { GesturesDetector } from \"./common/gestures\";\nimport { appendVirtualColumnIfNeeded } from \"./util/columns\";\nconst bridgeListener = new BridgeGesturesAdapter(window.gestures);\nconst gesturesListener = {\n onTap: (event) => {\n const tapEvent = {\n x: (event.clientX - visualViewport.offsetLeft) * visualViewport.scale,\n y: (event.clientY - visualViewport.offsetTop) * visualViewport.scale,\n };\n bridgeListener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n bridgeListener.onLinkActivated(href, outerHtml);\n },\n};\nnew GesturesDetector(window, gesturesListener);\nWindow.prototype.readiumcss = new CssBridge(window.document);\nwindow.documentState.onScriptsLoaded();\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nwindow.addEventListener(\"load\", (event) => {\n let documentLoadedFired = false;\n const observer = new ResizeObserver(() => {\n requestAnimationFrame(() => {\n appendVirtualColumnIfNeeded(window);\n const scrollingElement = window.document.scrollingElement;\n if (!documentLoadedFired &&\n (scrollingElement == null ||\n (scrollingElement.scrollHeight > 0 &&\n scrollingElement.scrollWidth > 0))) {\n console.log(`scrollWidth ${scrollingElement === null || scrollingElement === void 0 ? void 0 : scrollingElement.scrollWidth}`);\n window.documentState.onDocumentLoaded();\n documentLoadedFired = true;\n }\n window.documentState.onDocumentResized();\n });\n });\n observer.observe(document.body);\n});\n","export class BridgeGesturesAdapter {\n constructor(gesturesApi) {\n this.nativeApi = gesturesApi;\n }\n onTap(event) {\n this.nativeApi.onTap(JSON.stringify(event));\n }\n onLinkActivated(href, outerHtml) {\n this.nativeApi.onLinkActivated(href, outerHtml);\n }\n}\n","export class GesturesDetector {\n constructor(window, listener) {\n this.window = window;\n this.listener = listener;\n document.addEventListener(\"click\", (event) => {\n this.onClick(event);\n }, false);\n }\n onClick(event) {\n if (event.defaultPrevented) {\n return;\n }\n const selection = this.window.getSelection();\n if (selection && selection.type == \"Range\") {\n // There's an on-going selection, the tap will dismiss it so we don't forward it.\n // selection.type might be None (collapsed) or Caret with a collapsed range\n // when there is not true selection.\n return;\n }\n let nearestElement;\n if (event.target instanceof HTMLElement) {\n nearestElement = this.nearestInteractiveElement(event.target);\n }\n else {\n nearestElement = null;\n }\n if (nearestElement) {\n if (nearestElement instanceof HTMLAnchorElement) {\n this.listener.onLinkActivated(nearestElement.href, nearestElement.outerHTML);\n }\n }\n else {\n this.listener.onTap(event);\n }\n event.stopPropagation();\n event.preventDefault();\n }\n // See. https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling\n nearestInteractiveElement(element) {\n if (element == null) {\n return null;\n }\n const interactiveTags = [\n \"a\",\n \"audio\",\n \"button\",\n \"canvas\",\n \"details\",\n \"input\",\n \"label\",\n \"option\",\n \"select\",\n \"submit\",\n \"textarea\",\n \"video\",\n ];\n if (interactiveTags.indexOf(element.nodeName.toLowerCase()) != -1) {\n return element;\n }\n // Checks whether the element is editable by the user.\n if (element.hasAttribute(\"contenteditable\") &&\n element.getAttribute(\"contenteditable\").toLowerCase() != \"false\") {\n return element;\n }\n // Checks parents recursively because the touch might be for example on an inside a .\n if (element.parentElement) {\n return this.nearestInteractiveElement(element.parentElement);\n }\n return null;\n }\n}\n","export class CssBridge {\n constructor(document) {\n this.document = document;\n }\n setProperties(properties) {\n for (const [key, value] of properties) {\n this.setProperty(key, value);\n }\n }\n // For setting user setting.\n setProperty(key, value) {\n if (value === null || value === \"\") {\n this.removeProperty(key);\n }\n else {\n const root = document.documentElement;\n // The `!important` annotation is added with `setProperty()` because if it's part of the\n // `value`, it will be ignored by the Web View.\n root.style.setProperty(key, value, \"important\");\n }\n }\n // For removing user setting.\n removeProperty(key) {\n const root = document.documentElement;\n root.style.removeProperty(key);\n }\n}\n","/**\n * In paginated mode, the width of each resource must be a multiple of the viewport size\n * for proper snapping. This may not be automatically the case if the number of\n * columns in the resource is not a multiple of the number of columns fitting in the viewport.\n * To fix this, we insert a blank virtual column at the end of the resource.\n */\nexport function appendVirtualColumnIfNeeded(wnd) {\n const id = \"readium-virtual-page\";\n let virtualCol = wnd.document.getElementById(id);\n if (getColumnCountPerScreen(wnd) !== 2) {\n if (virtualCol) {\n virtualCol.remove();\n }\n }\n else {\n const documentWidth = wnd.document.scrollingElement.scrollWidth;\n const colCount = documentWidth / wnd.innerWidth;\n const hasOddColCount = (Math.round(colCount * 2) / 2) % 1 > 0.1;\n if (hasOddColCount) {\n if (virtualCol)\n virtualCol.remove();\n else {\n virtualCol = wnd.document.createElement(\"div\");\n virtualCol.setAttribute(\"id\", id);\n virtualCol.dataset.readium = \"true\";\n virtualCol.style.breakBefore = \"column\";\n virtualCol.innerHTML = \"​\"; // zero-width space\n wnd.document.body.appendChild(virtualCol);\n }\n }\n }\n}\nfunction getColumnCountPerScreen(wnd) {\n return parseInt(wnd\n .getComputedStyle(wnd.document.documentElement)\n .getPropertyValue(\"column-count\"));\n}\n"],"names":["bridgeListener","constructor","gesturesApi","this","nativeApi","onTap","event","JSON","stringify","onLinkActivated","href","outerHtml","window","gestures","gesturesListener","tapEvent","x","clientX","visualViewport","offsetLeft","scale","y","clientY","offsetTop","listener","document","addEventListener","onClick","defaultPrevented","selection","getSelection","type","nearestElement","target","HTMLElement","nearestInteractiveElement","HTMLAnchorElement","outerHTML","stopPropagation","preventDefault","element","indexOf","nodeName","toLowerCase","hasAttribute","getAttribute","parentElement","Window","prototype","readiumcss","setProperties","properties","key","value","setProperty","removeProperty","documentElement","style","documentState","onScriptsLoaded","documentLoadedFired","ResizeObserver","requestAnimationFrame","wnd","id","virtualCol","getElementById","parseInt","getComputedStyle","getPropertyValue","getColumnCountPerScreen","remove","colCount","scrollingElement","scrollWidth","innerWidth","Math","round","createElement","setAttribute","dataset","readium","breakBefore","innerHTML","body","appendChild","appendVirtualColumnIfNeeded","scrollHeight","console","log","onDocumentLoaded","onDocumentResized","observe"],"sourceRoot":""} \ No newline at end of file +{"version":3,"file":"reflowable-injectable-script.js","mappings":"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","sources":["webpack://readium-js/./src/index-reflowable-injectable.ts","webpack://readium-js/./src/bridge/all-gestures-bridge.ts","webpack://readium-js/./src/common/gestures.ts","webpack://readium-js/./src/bridge/reflowable-css-bridge.ts","webpack://readium-js/./src/util/columns.ts"],"sourcesContent":["//\n// Copyright 2024 Readium Foundation. All rights reserved.\n// Use of this source code is governed by the BSD-style license\n// available in the top-level LICENSE file of the project.\n//\n/**\n * Script loaded by reflowable resources.\n */\nimport { BridgeGesturesAdapter, } from \"./bridge/all-gestures-bridge\";\nimport { CssBridge } from \"./bridge/reflowable-css-bridge\";\nimport { GesturesDetector } from \"./common/gestures\";\nimport { appendVirtualColumnIfNeeded } from \"./util/columns\";\nconst bridgeListener = new BridgeGesturesAdapter(window.gestures);\nconst gesturesListener = {\n onTap: (event) => {\n const tapEvent = {\n x: (event.clientX - visualViewport.offsetLeft) * visualViewport.scale,\n y: (event.clientY - visualViewport.offsetTop) * visualViewport.scale,\n };\n bridgeListener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n bridgeListener.onLinkActivated(href, outerHtml);\n },\n};\nnew GesturesDetector(window, gesturesListener);\nWindow.prototype.readiumcss = new CssBridge(window.document);\nwindow.documentState.onScriptsLoaded();\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nwindow.addEventListener(\"load\", (event) => {\n let documentLoadedFired = false;\n const observer = new ResizeObserver(() => {\n requestAnimationFrame(() => {\n appendVirtualColumnIfNeeded(window);\n const scrollingElement = window.document.scrollingElement;\n if (!documentLoadedFired &&\n (scrollingElement == null ||\n scrollingElement.scrollHeight > 0 ||\n scrollingElement.scrollWidth > 0)) {\n window.documentState.onDocumentLoadedAndSized();\n documentLoadedFired = true;\n }\n else {\n window.documentState.onDocumentResized();\n }\n });\n });\n observer.observe(document.body);\n});\n","export class BridgeGesturesAdapter {\n constructor(gesturesApi) {\n this.nativeApi = gesturesApi;\n }\n onTap(event) {\n this.nativeApi.onTap(JSON.stringify(event));\n }\n onLinkActivated(href, outerHtml) {\n this.nativeApi.onLinkActivated(href, outerHtml);\n }\n}\n","export class GesturesDetector {\n constructor(window, listener) {\n this.window = window;\n this.listener = listener;\n document.addEventListener(\"click\", (event) => {\n this.onClick(event);\n }, false);\n }\n onClick(event) {\n if (event.defaultPrevented) {\n return;\n }\n const selection = this.window.getSelection();\n if (selection && selection.type == \"Range\") {\n // There's an on-going selection, the tap will dismiss it so we don't forward it.\n // selection.type might be None (collapsed) or Caret with a collapsed range\n // when there is not true selection.\n return;\n }\n let nearestElement;\n if (event.target instanceof HTMLElement) {\n nearestElement = this.nearestInteractiveElement(event.target);\n }\n else {\n nearestElement = null;\n }\n if (nearestElement) {\n if (nearestElement instanceof HTMLAnchorElement) {\n this.listener.onLinkActivated(nearestElement.href, nearestElement.outerHTML);\n }\n }\n else {\n this.listener.onTap(event);\n }\n event.stopPropagation();\n event.preventDefault();\n }\n // See. https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling\n nearestInteractiveElement(element) {\n if (element == null) {\n return null;\n }\n const interactiveTags = [\n \"a\",\n \"audio\",\n \"button\",\n \"canvas\",\n \"details\",\n \"input\",\n \"label\",\n \"option\",\n \"select\",\n \"submit\",\n \"textarea\",\n \"video\",\n ];\n if (interactiveTags.indexOf(element.nodeName.toLowerCase()) != -1) {\n return element;\n }\n // Checks whether the element is editable by the user.\n if (element.hasAttribute(\"contenteditable\") &&\n element.getAttribute(\"contenteditable\").toLowerCase() != \"false\") {\n return element;\n }\n // Checks parents recursively because the touch might be for example on an inside a .\n if (element.parentElement) {\n return this.nearestInteractiveElement(element.parentElement);\n }\n return null;\n }\n}\n","export class CssBridge {\n constructor(document) {\n this.document = document;\n }\n setProperties(properties) {\n for (const [key, value] of properties) {\n this.setProperty(key, value);\n }\n }\n // For setting user setting.\n setProperty(key, value) {\n if (value === null || value === \"\") {\n this.removeProperty(key);\n }\n else {\n const root = document.documentElement;\n // The `!important` annotation is added with `setProperty()` because if it's part of the\n // `value`, it will be ignored by the Web View.\n root.style.setProperty(key, value, \"important\");\n }\n }\n // For removing user setting.\n removeProperty(key) {\n const root = document.documentElement;\n root.style.removeProperty(key);\n }\n}\n","/**\n * In paginated mode, the width of each resource must be a multiple of the viewport size\n * for proper snapping. This may not be automatically the case if the number of\n * columns in the resource is not a multiple of the number of columns fitting in the viewport.\n * To fix this, we insert a blank virtual column at the end of the resource.\n */\nexport function appendVirtualColumnIfNeeded(wnd) {\n const id = \"readium-virtual-page\";\n let virtualCol = wnd.document.getElementById(id);\n if (getColumnCountPerScreen(wnd) !== 2) {\n if (virtualCol) {\n virtualCol.remove();\n }\n }\n else {\n const documentWidth = wnd.document.scrollingElement.scrollWidth;\n const colCount = documentWidth / wnd.innerWidth;\n const hasOddColCount = (Math.round(colCount * 2) / 2) % 1 > 0.1;\n if (hasOddColCount) {\n if (virtualCol)\n virtualCol.remove();\n else {\n virtualCol = wnd.document.createElement(\"div\");\n virtualCol.setAttribute(\"id\", id);\n virtualCol.dataset.readium = \"true\";\n virtualCol.style.breakBefore = \"column\";\n virtualCol.innerHTML = \"​\"; // zero-width space\n wnd.document.body.appendChild(virtualCol);\n }\n }\n }\n}\nfunction getColumnCountPerScreen(wnd) {\n return parseInt(wnd\n .getComputedStyle(wnd.document.documentElement)\n .getPropertyValue(\"column-count\"));\n}\n"],"names":["bridgeListener","constructor","gesturesApi","this","nativeApi","onTap","event","JSON","stringify","onLinkActivated","href","outerHtml","window","gestures","gesturesListener","tapEvent","x","clientX","visualViewport","offsetLeft","scale","y","clientY","offsetTop","listener","document","addEventListener","onClick","defaultPrevented","selection","getSelection","type","nearestElement","target","HTMLElement","nearestInteractiveElement","HTMLAnchorElement","outerHTML","stopPropagation","preventDefault","element","indexOf","nodeName","toLowerCase","hasAttribute","getAttribute","parentElement","Window","prototype","readiumcss","setProperties","properties","key","value","setProperty","removeProperty","documentElement","style","documentState","onScriptsLoaded","documentLoadedFired","ResizeObserver","requestAnimationFrame","wnd","id","virtualCol","getElementById","parseInt","getComputedStyle","getPropertyValue","getColumnCountPerScreen","remove","colCount","scrollingElement","scrollWidth","innerWidth","Math","round","createElement","setAttribute","dataset","readium","breakBefore","innerHTML","body","appendChild","appendVirtualColumnIfNeeded","scrollHeight","onDocumentLoadedAndSized","onDocumentResized","observe"],"sourceRoot":""} \ No newline at end of file diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt index 3e982e9f3a..eb719f86e4 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt @@ -62,7 +62,7 @@ internal fun SpreadWebView( val documentStateApi = remember(onScriptsLoaded) { DocumentStateApi( onScriptsLoadedDelegate = onScriptsLoaded, - onDocumentLoadedDelegate = { + onDocumentLoadedAndSizedDelegate = { state.webView?.apply { invokeOnReadyToBeDrawn { val scrollController = WebViewScrollController(this) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt index c3a84495fb..e8ee5fa85e 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt @@ -47,7 +47,6 @@ import org.readium.navigator.web.webapi.GesturesApi import org.readium.navigator.web.webview.RelaxedWebView import org.readium.navigator.web.webview.WebView import org.readium.navigator.web.webview.WebViewScrollController -import org.readium.navigator.web.webview.invokeOnReadyToBeDrawn import org.readium.navigator.web.webview.rememberWebViewState import org.readium.r2.shared.ExperimentalReadiumApi import org.readium.r2.shared.util.AbsoluteUrl @@ -107,24 +106,22 @@ internal fun ReflowableResource( onScriptsLoadedDelegate = { scriptsLoaded.value = true }, - onDocumentLoadedDelegate = { + onDocumentLoadedAndSizedDelegate = { webViewState.webView?.apply { - invokeOnReadyToBeDrawn { - Timber.d("onDocumentLoadedDelegate ${resourceState.index} ${webViewState.webView?.width}") - requestLayout() - addOnLayoutChangeListener { view, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom -> - val scrollController = WebViewScrollController(this) - scrollController.moveToProgression( - progression = resourceState.progression, - scroll = scroll, - orientation = scrollOrientation.value - ) - resourceState.scrollController.value = scrollController - setOnScrollChangeListener { view, scrollX, scrollY, oldScrollX, oldScrollY -> - onScrollChanged(scrollController.progression(scrollOrientation.value)) - } - contentIsLaidOut.value = true + Timber.d("onDocumentLoadedDelegate ${resourceState.index} ${webViewState.webView?.width}") + requestLayout() + setNextLayoutListener { + val scrollController = WebViewScrollController(this) + scrollController.moveToProgression( + progression = resourceState.progression, + scroll = scroll, + orientation = scrollOrientation.value + ) + resourceState.scrollController.value = scrollController + setOnScrollChangeListener { view, scrollX, scrollY, oldScrollX, oldScrollY -> + onScrollChanged(scrollController.progression(scrollOrientation.value)) } + contentIsLaidOut.value = true } } }, @@ -147,12 +144,6 @@ internal fun ReflowableResource( LaunchedEffect(cssApi, rsProperties, userProperties) { cssApi?.setProperties(userProperties, rsProperties) - resourceState.scrollController.value - ?.moveToProgression( - progression = resourceState.progression, - scroll = scroll, - orientation = scrollOrientation.value - ) } val gesturesApi = remember(onTap, onLinkActivated) { diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/webapi/DocumentStateApi.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/webapi/DocumentStateApi.kt index 4191e39f2b..c170bcdab9 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/webapi/DocumentStateApi.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/webapi/DocumentStateApi.kt @@ -11,7 +11,7 @@ import android.webkit.WebView internal class DocumentStateApi( private val onScriptsLoadedDelegate: () -> Unit, - private val onDocumentLoadedDelegate: () -> Unit, + private val onDocumentLoadedAndSizedDelegate: () -> Unit, private val onDocumentResizedDelegate: () -> Unit, ) { @@ -25,8 +25,8 @@ internal class DocumentStateApi( } @JavascriptInterface - fun onDocumentLoaded() { - onDocumentLoadedDelegate.invoke() + fun onDocumentLoadedAndSized() { + onDocumentLoadedAndSizedDelegate.invoke() } @JavascriptInterface From 64097e8e241a5c9580ddf3ceb028b60acac35780 Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Sun, 13 Apr 2025 16:10:34 +0200 Subject: [PATCH 40/88] Small fixes and cosmetic changes --- .../navigator/web/ReflowableWebRendition.kt | 87 ++++++----- .../web/ReflowableWebRenditionFactory.kt | 11 +- .../web/ReflowableWebRenditionState.kt | 135 ++++++++---------- .../navigator/web/pager/ScrollDispatcher.kt | 14 +- .../reflowable/ReflowablePagingLayoutInfo.kt | 2 +- .../web/reflowable/ReflowableResource.kt | 4 +- .../web/reflowable/ReflowableResourceState.kt | 2 +- .../reflowable/ReflowableWebPublication.kt | 2 +- 8 files changed, 127 insertions(+), 130 deletions(-) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt index e7be8426d5..faf32fe917 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt @@ -1,5 +1,5 @@ /* - * Copyright 2024 Readium Foundation. All rights reserved. + * Copyright 2025 Readium Foundation. All rights reserved. * Use of this source code is governed by the BSD-style license * available in the top-level LICENSE file of the project. */ @@ -8,7 +8,6 @@ package org.readium.navigator.web import android.annotation.SuppressLint import android.content.res.Configuration -import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.gestures.ScrollableDefaults import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.WindowInsets @@ -42,8 +41,11 @@ import org.readium.navigator.web.location.ReflowableWebLocation import org.readium.navigator.web.pager.RenditionPager import org.readium.navigator.web.pager.ScrollDispatcher import org.readium.navigator.web.pager.pagingFlingBehavior +import org.readium.navigator.web.reflowable.ReflowablePagingLayoutInfo import org.readium.navigator.web.reflowable.ReflowableResource +import org.readium.navigator.web.reflowable.ReflowableWebPublication import org.readium.navigator.web.util.AbsolutePaddingValues +import org.readium.navigator.web.util.HyperlinkProcessor import org.readium.navigator.web.util.WebViewServer import org.readium.r2.navigator.preferences.ReadingProgression import org.readium.r2.shared.ExperimentalReadiumApi @@ -67,13 +69,15 @@ public fun ReflowableWebRendition( ?: NullHyperlinkListener(), ) { BoxWithConstraints( - modifier = modifier.fillMaxSize(), + modifier = modifier + .fillMaxSize() + .windowInsetsPadding(windowInsets), propagateMinConstraints = true ) { val viewportSize = rememberUpdatedState(DpSize(maxWidth, maxHeight)) val readingProgression = - state.layoutDelegate.settings.value.readingProgression + state.layoutDelegate.overflow.value.readingProgression val reverseLayout = LocalLayoutDirection.current.toReadingProgression() != readingProgression @@ -81,7 +85,7 @@ public fun ReflowableWebRendition( val coroutineScope = rememberCoroutineScope() val resourcePadding = - if (state.layoutDelegate.settings.value.scroll) { + if (state.layoutDelegate.overflow.value.scroll) { AbsolutePaddingValues() } else { when (LocalConfiguration.current.orientation) { @@ -97,51 +101,53 @@ public fun ReflowableWebRendition( ?: state.layoutDelegate.settings.value.theme.backgroundColor ) - val currentItemIndexState = remember { derivedStateOf { state.pagerState.currentPage } } + val currentPageState = remember(state) { derivedStateOf { state.pagerState.currentPage } } - val inputListenerState = rememberUpdatedState(inputListener) - - // First location update to trigger controller creation. - // In the future, that should require access to the WebView. - state.initController( - initialLocation = ReflowableWebLocation( - href = state.publication.readingOrder.items[currentItemIndexState.value].href, - progression = state.resourceStates[currentItemIndexState.value].progression - ), - density = LocalDensity.current - ) - - val orientation = when { - state.layoutDelegate.settings.value.verticalText -> Orientation.Horizontal - state.layoutDelegate.settings.value.scroll -> Orientation.Vertical - else -> Orientation.Horizontal + if (state.controller == null) { + // Initialize controller. In the future, that should require access to a ready WebView. + state.initController( + location = ReflowableWebLocation( + href = state.publication.readingOrder.items[currentPageState.value].href, + progression = state.resourceStates[currentPageState.value].progression + ) + ) } - val flingBehavior = if (state.layoutDelegate.settings.value.scroll) { + val flingBehavior = if (state.layoutDelegate.overflow.value.scroll) { ScrollableDefaults.flingBehavior() } else { - pagingFlingBehavior(state.controller!!.navigationDelegate.pagingLayoutInfo) - }.toFling2DBehavior(orientation) + pagingFlingBehavior( + ReflowablePagingLayoutInfo( + pagerState = state.pagerState, + resourceStates = state.resourceStates, + density = LocalDensity.current + ) + ) + }.toFling2DBehavior(state.layoutDelegate.orientation) val scrollDispatcher = remember(state) { ScrollDispatcher( pagerState = state.pagerState, resourceStates = state.resourceStates, flingBehavior = flingBehavior, - pagerOrientation = orientation, + pagerOrientation = state.layoutDelegate.orientation, ) } scrollDispatcher.flingBehavior = flingBehavior - scrollDispatcher.pagerOrientation = orientation + scrollDispatcher.pagerOrientation = state.layoutDelegate.orientation + + val inputListenerState = rememberUpdatedState(inputListener) + + val hyperlinkListenerState = rememberUpdatedState(hyperlinkListener) RenditionPager( - modifier = Modifier.windowInsetsPadding(windowInsets), + modifier = Modifier, state = state.pagerState, scrollDispatcher = scrollDispatcher, beyondViewportPageCount = 3, reverseLayout = reverseLayout, - orientation = orientation + orientation = state.layoutDelegate.orientation ) { index -> val readyToScroll = ((index - 2)..(index + 2)).toList() .mapNotNull { state.resourceStates.getOrNull(it) } @@ -167,12 +173,17 @@ public fun ReflowableWebRendition( }, onLinkActivated = { url, outerHtml -> coroutineScope.launch { - onLinkActivated(url, outerHtml, state, hyperlinkListener) + state.hyperlinkProcessor.onLinkActivated( + url = url, + outerHtml = outerHtml, + readingOrder = state.publication.readingOrder, + listener = hyperlinkListenerState.value + ) } }, - onScrollChanged = { - if (index == currentItemIndexState.value) { - val itemHref = state.publication.readingOrder.items[index].href + onProgessionChange = { + if (index == currentPageState.value) { + val itemHref = state.publication.readingOrder[index].href val newLocation = ReflowableWebLocation(itemHref, it) state.updateLocation(newLocation) } @@ -192,15 +203,15 @@ private fun LayoutDirection.toReadingProgression(): ReadingProgression = } @OptIn(ExperimentalReadiumApi::class) -private suspend fun onLinkActivated( +private suspend fun HyperlinkProcessor.onLinkActivated( url: Url, outerHtml: String, - state: ReflowableWebRenditionState, + readingOrder: ReflowableWebPublication.ReadingOrder, listener: HyperlinkListener, ) { - val location = HyperlinkLocation(url.removeFragment()) - val isReadingOrder = state.publication.readingOrder.indexOfHref(url.removeFragment()) != null - val context = state.computeHyperlinkContext(url, outerHtml) + val location = HyperlinkLocation(url.removeFragment(), url.fragment) + val isReadingOrder = readingOrder.indexOfHref(url.removeFragment()) != null + val context = computeLinkContext(url, outerHtml) when { isReadingOrder -> listener.onReadingOrderLinkActivated(location, context) else -> when (url) { diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionFactory.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionFactory.kt index 1396f1f4cf..a7535a93b1 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionFactory.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionFactory.kt @@ -1,5 +1,5 @@ /* - * Copyright 2024 Readium Foundation. All rights reserved. + * Copyright 2025 Readium Foundation. All rights reserved. * Use of this source code is governed by the BSD-style license * available in the top-level LICENSE file of the project. */ @@ -29,8 +29,8 @@ import org.readium.r2.shared.util.Try * These components are meant to work together. Do not mix components from different * factory instances. */ -@OptIn(InternalReadiumApi::class) @ExperimentalReadiumApi +@OptIn(InternalReadiumApi::class) public class ReflowableWebRenditionFactory private constructor( private val application: Application, private val publication: Publication, @@ -101,14 +101,17 @@ public class ReflowableWebRenditionFactory private constructor( val initialLocation = initialLocation ?: ReflowableWebGoLocation(readingOrderItems[0].href) + val disableSelection = publication.findService(ContentProtectionService::class) + ?.isRestricted == true + val state = ReflowableWebRenditionState( application = application, publication = renditionPublication, - isRestricted = publication.findService(ContentProtectionService::class)?.isRestricted == true, initialSettings = initialSettings, initialLocation = initialLocation, - fontFamilyDeclarations = emptyList() + fontFamilyDeclarations = emptyList(), // FIXME: pass font family declarations + disableSelection = disableSelection ) return Try.success(state) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt index d9f80b6587..4697560662 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt @@ -1,5 +1,5 @@ /* - * Copyright 2024 Readium Foundation. All rights reserved. + * Copyright 2025 Readium Foundation. All rights reserved. * Use of this source code is governed by the BSD-style license * available in the top-level LICENSE file of the project. */ @@ -14,9 +14,7 @@ import androidx.compose.runtime.Stable import androidx.compose.runtime.State import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.mutableStateOf -import androidx.compose.ui.unit.Density import org.readium.navigator.common.HyperlinkLocation -import org.readium.navigator.common.LinkContext import org.readium.navigator.common.NavigationController import org.readium.navigator.common.Overflow import org.readium.navigator.common.OverflowController @@ -29,9 +27,7 @@ import org.readium.navigator.web.css.buildFontFamilyDeclaration import org.readium.navigator.web.css.update import org.readium.navigator.web.location.ReflowableWebGoLocation import org.readium.navigator.web.location.ReflowableWebLocation -import org.readium.navigator.web.pager.PagingLayoutInfo import org.readium.navigator.web.preferences.ReflowableWebSettings -import org.readium.navigator.web.reflowable.ReflowablePagingLayoutInfo import org.readium.navigator.web.reflowable.ReflowableResourceState import org.readium.navigator.web.reflowable.ReflowableWebPublication import org.readium.navigator.web.util.HyperlinkProcessor @@ -47,7 +43,6 @@ import org.readium.r2.navigator.preferences.ReadingProgression import org.readium.r2.shared.ExperimentalReadiumApi import org.readium.r2.shared.InternalReadiumApi import org.readium.r2.shared.util.RelativeUrl -import org.readium.r2.shared.util.Url import org.readium.r2.shared.util.mediatype.MediaType import org.readium.r2.shared.util.resource.Resource @@ -56,14 +51,22 @@ import org.readium.r2.shared.util.resource.Resource public class ReflowableWebRenditionState internal constructor( application: Application, internal val publication: ReflowableWebPublication, - isRestricted: Boolean, initialSettings: ReflowableWebSettings, - private val initialLocation: ReflowableWebGoLocation, + initialLocation: ReflowableWebGoLocation, private val rsProperties: RsProperties = RsProperties(), fontFamilyDeclarations: List, + disableSelection: Boolean, ) : RenditionState { - private val initialIndex = publication.readingOrder.indexOfHref(initialLocation.href) ?: 0 + override val controller: ReflowableWebRenditionController? get() = + controllerState.value + + private val controllerState: MutableState = + mutableStateOf(null) + + private val initialIndex = publication.readingOrder + .indexOfHref(initialLocation.href) + ?: 0 internal val resourceStates: List = publication.readingOrder.items.mapIndexed { index, item -> @@ -78,12 +81,6 @@ public class ReflowableWebRenditionState internal constructor( ) } - private val controllerState: MutableState = - mutableStateOf(null) - - override val controller: ReflowableWebRenditionController? get() = - controllerState.value - internal val layoutDelegate: ReflowableLayoutDelegate = ReflowableLayoutDelegate( initialSettings @@ -124,7 +121,7 @@ public class ReflowableWebRenditionState internal constructor( readiumCss = readiumCss.value, injectableScript = RelativeUrl("readium/navigators/web/generated/reflowable-injectable-script.js")!!, assetsBaseHref = assetsBaseHref, - disableSelection = isRestricted + disableSelection = disableSelection ) } @@ -148,58 +145,59 @@ public class ReflowableWebRenditionState internal constructor( pageCount = { publication.readingOrder.size } ) - internal suspend fun computeHyperlinkContext(originUrl: Url, outerHtml: String): LinkContext? = - hyperlinkProcessor.computeLinkContext(originUrl, outerHtml) - private lateinit var navigationDelegate: ReflowableNavigationDelegate - internal fun initController(initialLocation: ReflowableWebLocation, density: Density) { - initControllerIfNeeded(initialLocation, density) - updateLocation(initialLocation) - } - - internal fun updateLocation(location: ReflowableWebLocation) { - navigationDelegate.updateLocation(location) - } - - private fun initControllerIfNeeded(location: ReflowableWebLocation, density: Density) { - if (controller != null) { - return - } - + internal fun initController(location: ReflowableWebLocation) { navigationDelegate = ReflowableNavigationDelegate( publication.readingOrder, resourceStates, pagerState, - layoutDelegate.settings, - location, - density + layoutDelegate.overflow, + location ) controllerState.value = ReflowableWebRenditionController( navigationDelegate, layoutDelegate ) + updateLocation(location) + } + + internal fun updateLocation(location: ReflowableWebLocation) { + navigationDelegate.updateLocation(location) } } @ExperimentalReadiumApi @Stable public class ReflowableWebRenditionController internal constructor( - internal val navigationDelegate: ReflowableNavigationDelegate, + navigationDelegate: ReflowableNavigationDelegate, layoutDelegate: ReflowableLayoutDelegate, ) : NavigationController by navigationDelegate, OverflowController by navigationDelegate, SettingsController by layoutDelegate -@OptIn(ExperimentalReadiumApi::class) +@OptIn(ExperimentalReadiumApi::class, InternalReadiumApi::class) internal class ReflowableLayoutDelegate( initialSettings: ReflowableWebSettings, ) : SettingsController { override val settings: MutableState = mutableStateOf(initialSettings) + + internal val overflow: State = derivedStateOf { + with(settings.value) { + SimpleOverflow( + readingProgression = readingProgression, + scroll = scroll, + axis = if (scroll && !verticalText) Axis.VERTICAL else Axis.HORIZONTAL + ) + } + } + + internal val orientation: Orientation get() = + overflow.value.axis.toOrientation() } @OptIn(ExperimentalReadiumApi::class, InternalReadiumApi::class) @@ -207,21 +205,13 @@ internal class ReflowableNavigationDelegate( private val readingOrder: ReflowableWebPublication.ReadingOrder, private val resourceStates: List, private val pagerState: PagerState, - private val settings: State, + override val overflow: State, initialLocation: ReflowableWebLocation, - density: Density, ) : NavigationController, OverflowController { private val locationMutable: MutableState = mutableStateOf(initialLocation) - internal val pagingLayoutInfo: PagingLayoutInfo = - ReflowablePagingLayoutInfo( - pagerState = pagerState, - resourceStates = resourceStates, - density = density - ) - internal fun updateLocation(location: ReflowableWebLocation) { val index = checkNotNull(readingOrder.indexOfHref(location.href)) resourceStates[index].progression = location.progression @@ -238,25 +228,16 @@ internal class ReflowableNavigationDelegate( override suspend fun goTo(location: ReflowableWebGoLocation) { val resourceIndex = readingOrder.indexOfHref(location.href) ?: return pagerState.scrollToPage(resourceIndex) - val scrollController = resourceStates[resourceIndex].scrollController.value!! - location.progression?.let { scrollController.moveToProgression(it) } + location.progression?.let { // FIXME: goTo returns before the move has completed. + resourceStates[resourceIndex].progression = it + resourceStates[resourceIndex].scrollController.value?.moveToProgression(it) + } } override suspend fun goTo(location: ReflowableWebLocation) { goTo(ReflowableWebGoLocation(location.href, location.progression)) } - override val overflow: State = - derivedStateOf { - with(settings.value) { - SimpleOverflow( - readingProgression = readingProgression, - scroll = scroll, - axis = if (scroll && !verticalText) Axis.VERTICAL else Axis.HORIZONTAL - ) - } - } - // This information is not available when the WebView has not yet been composed or laid out. // We assume that the best UI behavior would be to have a possible forward button disabled // and then return false when we can't tell. @@ -269,7 +250,7 @@ internal class ReflowableNavigationDelegate( override val canMoveBackward: Boolean get() = pagerState.currentPage > 0 || run { - val currentResourceState = resourceStates[pagerState.currentPage] + val currentResourceState = resourceStates[0] val scrollController = currentResourceState.scrollController.value ?: return false return scrollController.canMoveBackward() } @@ -279,7 +260,7 @@ internal class ReflowableNavigationDelegate( val scrollController = currentResourceState.scrollController.value ?: return if (scrollController.canMoveForward()) { scrollController.moveForward() - } else { + } else if (pagerState.currentPage < readingOrder.items.size - 1) { pagerState.scrollToPage(pagerState.currentPage + 1) } } @@ -289,42 +270,42 @@ internal class ReflowableNavigationDelegate( val scrollController = currentResourceState.scrollController.value ?: return if (scrollController.canMoveBackward()) { scrollController.moveBackward() - } else { + } else if (pagerState.currentPage > 0) { pagerState.scrollToPage(pagerState.currentPage - 1) } } private fun WebViewScrollController.moveForward() = - when (settings.value.scroll) { + when (overflow.value.scroll) { true -> moveBottom() - false -> when (settings.value.readingProgression) { + false -> when (overflow.value.readingProgression) { ReadingProgression.LTR -> moveRight() ReadingProgression.RTL -> moveLeft() } } private fun WebViewScrollController.moveBackward() = - when (settings.value.scroll) { + when (overflow.value.scroll) { true -> moveTop() - false -> when (settings.value.readingProgression) { + false -> when (overflow.value.readingProgression) { ReadingProgression.LTR -> moveLeft() ReadingProgression.RTL -> moveRight() } } private fun WebViewScrollController.canMoveForward(): Boolean = - when (settings.value.scroll) { + when (overflow.value.scroll) { true -> canMoveBottom - false -> when (settings.value.readingProgression) { + false -> when (overflow.value.readingProgression) { ReadingProgression.LTR -> canMoveRight ReadingProgression.RTL -> canMoveLeft } } private fun WebViewScrollController.canMoveBackward(): Boolean = - when (settings.value.scroll) { + when (overflow.value.scroll) { true -> canMoveTop - false -> when (settings.value.readingProgression) { + false -> when (overflow.value.readingProgression) { ReadingProgression.LTR -> canMoveLeft ReadingProgression.RTL -> canMoveRight } @@ -332,11 +313,13 @@ internal class ReflowableNavigationDelegate( private fun WebViewScrollController.moveToProgression(progression: Double) { moveToProgression( progression = progression, - scroll = settings.value.scroll, - orientation = when (settings.value.verticalText) { - true -> Orientation.Vertical - false -> Orientation.Horizontal - } + scroll = overflow.value.scroll, + orientation = overflow.value.axis.toOrientation() ) } } + +private fun Axis.toOrientation() = when (this) { + Axis.HORIZONTAL -> Orientation.Horizontal + Axis.VERTICAL -> Orientation.Vertical +} diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollDispatcher.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollDispatcher.kt index 35df48c238..da46a3db35 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollDispatcher.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollDispatcher.kt @@ -35,7 +35,7 @@ internal class ScrollDispatcher( } private fun rawScrollBy(available: Float): Float { - Timber.Forest.d("scrollBy available $available") + Timber.d("scrollBy available $available") var deltaLeft = available val firstPage = pagerState.layoutInfo.visiblePagesInfo.first() @@ -54,7 +54,7 @@ internal class ScrollDispatcher( val consumedInFirst = consumeInWebview(firstTargetPage.index, deltaLeft) deltaLeft -= consumedInFirst - Timber.Forest.d("consumed $consumedInFirst in ${firstTargetPage.index}") + Timber.d("consumed $consumedInFirst in ${firstTargetPage.index}") val availableForPager = if (firstPage.index == lastPage.index) { @@ -81,13 +81,13 @@ internal class ScrollDispatcher( val consumedInPager = -pagerState.dispatchRawDelta(-availableForPager) deltaLeft -= consumedInPager - Timber.Forest.d("consumed $consumedInPager in pager") + Timber.d("consumed $consumedInPager in pager") val consumedInSecond = consumeInWebview(secondTargetPage.index, deltaLeft) deltaLeft -= consumedInSecond - Timber.Forest.d("consumed $consumedInSecond in ${secondTargetPage.index}") + Timber.d("consumed $consumedInSecond in ${secondTargetPage.index}") - Timber.Forest.d("scrollBy left $deltaLeft") + Timber.d("scrollBy left $deltaLeft") return when (deltaLeft) { 0f -> available @@ -104,12 +104,12 @@ internal class ScrollDispatcher( } fun onScroll(available: Offset): Offset { - Timber.Forest.d("onScroll ${available.x}") + Timber.d("onScroll ${available.x}") return -scrollBy(-available) } suspend fun onFling(available: Velocity): Velocity { - Timber.Forest.d("onFling ${available.x}") + Timber.d("onFling ${available.x}") var velocityLeft = available pagerState.scroll { with(flingBehavior) { diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowablePagingLayoutInfo.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowablePagingLayoutInfo.kt index da64a831fb..6947e9b457 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowablePagingLayoutInfo.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowablePagingLayoutInfo.kt @@ -1,5 +1,5 @@ /* - * Copyright 2024 Readium Foundation. All rights reserved. + * Copyright 2025 Readium Foundation. All rights reserved. * Use of this source code is governed by the BSD-style license * available in the top-level LICENSE file of the project. */ diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt index e8ee5fa85e..976d549e1b 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt @@ -72,7 +72,7 @@ internal fun ReflowableResource( enableScroll: Boolean, onTap: (TapEvent) -> Unit, onLinkActivated: (Url, String) -> Unit, - onScrollChanged: (Double) -> Unit, + onProgessionChange: (Double) -> Unit, onDocumentResized: () -> Unit, ) { Box( @@ -119,7 +119,7 @@ internal fun ReflowableResource( ) resourceState.scrollController.value = scrollController setOnScrollChangeListener { view, scrollX, scrollY, oldScrollX, oldScrollY -> - onScrollChanged(scrollController.progression(scrollOrientation.value)) + onProgessionChange(scrollController.progression(scrollOrientation.value)) } contentIsLaidOut.value = true } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResourceState.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResourceState.kt index f42fd6b68b..2e97ed4051 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResourceState.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResourceState.kt @@ -1,5 +1,5 @@ /* - * Copyright 2024 Readium Foundation. All rights reserved. + * Copyright 2025 Readium Foundation. All rights reserved. * Use of this source code is governed by the BSD-style license * available in the top-level LICENSE file of the project. */ diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableWebPublication.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableWebPublication.kt index ac5c29158a..06e9486c6a 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableWebPublication.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableWebPublication.kt @@ -1,5 +1,5 @@ /* - * Copyright 2024 Readium Foundation. All rights reserved. + * Copyright 2025 Readium Foundation. All rights reserved. * Use of this source code is governed by the BSD-style license * available in the top-level LICENSE file of the project. */ From 88d464a6fe7ede413f2329cc4a09ec1e6c5a885b Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Sun, 13 Apr 2025 16:21:59 +0200 Subject: [PATCH 41/88] Renaming --- .../navigator/web/ReflowableWebRendition.kt | 49 ++++++++++++------ .../web/ReflowableWebRenditionState.kt | 8 +-- .../web/css/FontFamilyDeclaration.kt | 38 +------------- .../{ReadiumCss.kt => ReadiumCssInjector.kt} | 48 ++++++++++++++--- .../css/{Layout.kt => ReadiumCssLayout.kt} | 6 +-- ...{Properties.kt => ReadiumCssProperties.kt} | 6 +-- .../ReflowableWebPreferencesEditor.kt | 20 ++++---- .../web/reflowable/ReflowableResource.kt | 51 +++++-------------- .../navigator/web/util/HtmlInjector.kt | 4 +- 9 files changed, 110 insertions(+), 120 deletions(-) rename readium/navigators/web/src/main/java/org/readium/navigator/web/css/{ReadiumCss.kt => ReadiumCssInjector.kt} (88%) rename readium/navigators/web/src/main/java/org/readium/navigator/web/css/{Layout.kt => ReadiumCssLayout.kt} (96%) rename readium/navigators/web/src/main/java/org/readium/navigator/web/css/{Properties.kt => ReadiumCssProperties.kt} (99%) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt index faf32fe917..954f8d1a59 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt @@ -8,7 +8,9 @@ package org.readium.navigator.web import android.annotation.SuppressLint import android.content.res.Configuration +import androidx.compose.foundation.background import androidx.compose.foundation.gestures.ScrollableDefaults +import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.displayCutout @@ -21,9 +23,11 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.unit.DpOffset import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp @@ -34,6 +38,7 @@ import org.readium.navigator.common.InputListener import org.readium.navigator.common.NullHyperlinkListener import org.readium.navigator.common.NullInputListener import org.readium.navigator.common.TapContext +import org.readium.navigator.common.TapEvent import org.readium.navigator.common.defaultHyperlinkListener import org.readium.navigator.common.defaultInputListener import org.readium.navigator.web.gestures.toFling2DBehavior @@ -69,9 +74,7 @@ public fun ReflowableWebRendition( ?: NullHyperlinkListener(), ) { BoxWithConstraints( - modifier = modifier - .fillMaxSize() - .windowInsetsPadding(windowInsets), + modifier = modifier.fillMaxSize(), propagateMinConstraints = true ) { val viewportSize = rememberUpdatedState(DpSize(maxWidth, maxHeight)) @@ -96,11 +99,6 @@ public fun ReflowableWebRendition( } } - val backgroundColor = ( - state.layoutDelegate.settings.value.backgroundColor?.int - ?: state.layoutDelegate.settings.value.theme.backgroundColor - ) - val currentPageState = remember(state) { derivedStateOf { state.pagerState.currentPage } } if (state.controller == null) { @@ -137,12 +135,32 @@ public fun ReflowableWebRendition( scrollDispatcher.flingBehavior = flingBehavior scrollDispatcher.pagerOrientation = state.layoutDelegate.orientation + val backgroundColor = Color( + state.layoutDelegate.settings.value.backgroundColor?.int + ?: state.layoutDelegate.settings.value.theme.backgroundColor + ) + val inputListenerState = rememberUpdatedState(inputListener) val hyperlinkListenerState = rememberUpdatedState(hyperlinkListener) RenditionPager( - modifier = Modifier, + modifier = Modifier + // Apply background on padding + .background(backgroundColor) + // Detect taps on padding + .pointerInput(Unit) { + detectTapGestures( + onTap = { + if (it.x >= 0 && it.y >= 0) { + val offset = DpOffset(x = it.x.toDp(), y = it.y.toDp()) + val event = TapEvent(offset) + inputListenerState.value.onTap(event, TapContext(viewportSize.value)) + } + } + ) + } + .windowInsetsPadding(windowInsets), state = state.pagerState, scrollDispatcher = scrollDispatcher, beyondViewportPageCount = 3, @@ -158,15 +176,14 @@ public fun ReflowableWebRendition( pagerState = state.pagerState, publicationBaseUrl = WebViewServer.publicationBaseHref, webViewClient = state.webViewClient, - viewportSize = viewportSize.value, - backgroundColor = Color(backgroundColor), + backgroundColor = backgroundColor, padding = resourcePadding, reverseLayout = reverseLayout, scroll = state.layoutDelegate.settings.value.scroll, - verticalText = state.layoutDelegate.settings.value.verticalText, - rsProperties = state.readiumCss.value.rsProperties, - userProperties = state.readiumCss.value.userProperties, - layout = state.readiumCss.value.layout, + orientation = state.layoutDelegate.orientation, + rsProperties = state.readiumCssInjector.value.rsProperties, + userProperties = state.readiumCssInjector.value.userProperties, + readiumCssLayout = state.readiumCssInjector.value.layout, enableScroll = readyToScroll, onTap = { tapEvent -> inputListenerState.value.onTap(tapEvent, TapContext(viewportSize.value)) @@ -181,7 +198,7 @@ public fun ReflowableWebRendition( ) } }, - onProgessionChange = { + onProgressionChange = { if (index == currentPageState.value) { val itemHref = state.publication.readingOrder[index].href val newLocation = ReflowableWebLocation(itemHref, it) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt index 4697560662..1bacf714a7 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt @@ -21,7 +21,7 @@ import org.readium.navigator.common.OverflowController import org.readium.navigator.common.RenditionState import org.readium.navigator.common.SettingsController import org.readium.navigator.web.css.FontFamilyDeclaration -import org.readium.navigator.web.css.ReadiumCss +import org.readium.navigator.web.css.ReadiumCssInjector import org.readium.navigator.web.css.RsProperties import org.readium.navigator.web.css.buildFontFamilyDeclaration import org.readium.navigator.web.css.update @@ -89,9 +89,9 @@ public class ReflowableWebRenditionState internal constructor( internal val hyperlinkProcessor = HyperlinkProcessor(publication.container) - internal val readiumCss: State = + internal val readiumCssInjector: State = derivedStateOf { - ReadiumCss( + ReadiumCssInjector( assetsBaseHref = assetsBaseHref, readiumCssAssets = RelativeUrl("readium/navigators/web/generated/readium-css/")!!, rsProperties = rsProperties, @@ -118,7 +118,7 @@ public class ReflowableWebRenditionState internal constructor( private val htmlInjector: (Resource, MediaType) -> Resource = { resource, mediaType -> resource.injectHtmlReflowable( charset = mediaType.charset, - readiumCss = readiumCss.value, + readiumCss = readiumCssInjector.value, injectableScript = RelativeUrl("readium/navigators/web/generated/reflowable-injectable-script.js")!!, assetsBaseHref = assetsBaseHref, disableSelection = disableSelection diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/FontFamilyDeclaration.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/FontFamilyDeclaration.kt index 469bc22d8a..1159ac4057 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/FontFamilyDeclaration.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/FontFamilyDeclaration.kt @@ -45,42 +45,7 @@ internal data class FontFaceDeclaration( val sources: List, var fontStyle: FontStyle? = null, var fontWeight: Either>? = null, -) { - - fun links(urlNormalizer: (Url) -> Url): List = - sources - .filter { it.preload } - .map { - """""" - } - - fun toCss(urlNormalizer: (Url) -> Url): String { - val descriptors = buildMap { - set("font-family", """"$fontFamily"""") - - val urls = sources.map { urlNormalizer(it.href) } - val src = urls.joinToString(", ") { """url("$it")""" } - set("src", src) - - fontStyle?.let { set("font-style", it.name.lowercase()) } - - fontWeight?.let { - when (it) { - is Either.Left -> - set("font-weight", it.value.value) - is Either.Right -> - set("font-weight", "${it.value.start} ${it.value.endInclusive}") - } - } - } - - val descriptorList = descriptors - .map { entry -> "${entry.key}: ${entry.value};" } - .joinToString(" ") - - return "@font-face { $descriptorList }" - } -} +) /** * Represents an individual font file. @@ -126,7 +91,6 @@ public data class MutableFontFaceDeclaration internal constructor( private var fontStyle: FontStyle? = null, private var fontWeight: Either>? = null, ) { - /** * Add a source for the font face. * diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCss.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCssInjector.kt similarity index 88% rename from readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCss.kt rename to readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCssInjector.kt index b70ba66fb8..0697bcc4d3 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCss.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCssInjector.kt @@ -27,8 +27,8 @@ import org.readium.r2.shared.util.Either import org.readium.r2.shared.util.RelativeUrl import org.readium.r2.shared.util.Url -internal data class ReadiumCss( - val layout: Layout = Layout(language = null, Layout.Stylesheets.Default, ReadingProgression.LTR), +internal data class ReadiumCssInjector( + val layout: ReadiumCssLayout = ReadiumCssLayout(language = null, ReadiumCssLayout.Stylesheets.Default, ReadingProgression.LTR), val rsProperties: RsProperties = RsProperties(), val userProperties: UserProperties = UserProperties(), val fontFamilyDeclarations: List = emptyList(), @@ -205,9 +205,9 @@ internal data class ReadiumCss( */ private fun injectDir(content: StringBuilder) { val dir = when (layout.stylesheets.htmlDir) { - Layout.HtmlDir.Unspecified -> null - Layout.HtmlDir.Ltr -> "ltr" - Layout.HtmlDir.Rtl -> "rtl" + ReadiumCssLayout.HtmlDir.Unspecified -> null + ReadiumCssLayout.HtmlDir.Ltr -> "ltr" + ReadiumCssLayout.HtmlDir.Rtl -> "rtl" } ?: return // Removes any dir attributes in html/body. @@ -271,13 +271,47 @@ internal data class ReadiumCss( ) + tag.length + 1 } +private fun FontFaceDeclaration.links(urlNormalizer: (Url) -> Url): List = + sources + .filter { it.preload } + .map { + """""" + } + +private fun FontFaceDeclaration.toCss(urlNormalizer: (Url) -> Url): String { + val descriptors = buildMap { + set("font-family", """"$fontFamily"""") + + val urls = sources.map { urlNormalizer(it.href) } + val src = urls.joinToString(", ") { """url("$it")""" } + set("src", src) + + fontStyle?.let { set("font-style", it.name.lowercase()) } + + fontWeight?.let { + when (it) { + is Either.Left -> + set("font-weight", it.value.value) + is Either.Right -> + set("font-weight", "${it.value.start} ${it.value.endInclusive}") + } + } + } + + val descriptorList = descriptors + .map { entry -> "${entry.key}: ${entry.value};" } + .joinToString(" ") + + return "@font-face { $descriptorList }" +} + private val dirRegex = Regex( """(<(?:html|body)[^\>]*)\s+dir=[\"']\w*[\"']""", setOf(RegexOption.IGNORE_CASE, RegexOption.MULTILINE) ) @OptIn(ExperimentalReadiumApi::class) -internal fun ReadiumCss.update(settings: ReflowableWebSettings, useReadiumCssFontSize: Boolean): ReadiumCss { +internal fun ReadiumCssInjector.update(settings: ReflowableWebSettings, useReadiumCssFontSize: Boolean): ReadiumCssInjector { fun resolveFontStack(fontFamily: String): List = buildList { add(fontFamily) @@ -297,7 +331,7 @@ internal fun ReadiumCss.update(settings: ReflowableWebSettings, useReadiumCssFon return with(settings) { copy( - layout = Layout.from(settings), + layout = ReadiumCssLayout.from(settings), rsProperties = rsProperties.copy( pageGutter = Length.Px((rsProperties.pageGutter?.value ?: 20.0) * horizontalMargins) ), diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/Layout.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCssLayout.kt similarity index 96% rename from readium/navigators/web/src/main/java/org/readium/navigator/web/css/Layout.kt rename to readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCssLayout.kt index 36b86cda64..0a1e2c25c3 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/Layout.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCssLayout.kt @@ -18,7 +18,7 @@ import org.readium.r2.shared.util.RelativeUrl * * See https://github.com/readium/readium-css/tree/master/css/dist */ -internal data class Layout( +internal data class ReadiumCssLayout( val language: Language? = null, val stylesheets: Stylesheets = Stylesheets.Default, val readingProgression: ReadingProgression = ReadingProgression.LTR, @@ -54,7 +54,7 @@ internal data class Layout( companion object { @OptIn(ExperimentalReadiumApi::class) - internal fun from(settingsValues: ReflowableWebSettings): Layout { + internal fun from(settingsValues: ReflowableWebSettings): ReadiumCssLayout { val stylesheets = when { settingsValues.verticalText -> Stylesheets.CjkVertical settingsValues.language?.isCjk == true -> Stylesheets.CjkHorizontal @@ -62,7 +62,7 @@ internal data class Layout( else -> Stylesheets.Default } - return Layout( + return ReadiumCssLayout( language = settingsValues.language, readingProgression = settingsValues.readingProgression, stylesheets = stylesheets diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/Properties.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCssProperties.kt similarity index 99% rename from readium/navigators/web/src/main/java/org/readium/navigator/web/css/Properties.kt rename to readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCssProperties.kt index 29e20ab022..fad615b611 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/Properties.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCssProperties.kt @@ -18,7 +18,7 @@ import org.readium.r2.shared.util.Either * Holds a set of Readium CSS properties applied together. */ @ExperimentalReadiumApi -public interface Properties : Cssable { +public interface ReadiumCssProperties : Cssable { public fun toCssProperties(): Map override fun toCss(): String? { @@ -119,7 +119,7 @@ public data class UserProperties( val a11yNormalize: Boolean? = null, val overrides: Map = emptyMap(), -) : Properties { +) : ReadiumCssProperties { override fun toCssProperties(): Map = buildMap { // View mode @@ -266,7 +266,7 @@ public data class RsProperties( val codeFontFamily: List? = null, val overrides: Map = emptyMap(), -) : Properties { +) : ReadiumCssProperties { override fun toCssProperties(): Map = buildMap { // Properties not exposed through RsProperties diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesEditor.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesEditor.kt index 46fa208452..ab613f8184 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesEditor.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesEditor.kt @@ -11,7 +11,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import org.readium.navigator.common.PreferencesEditor -import org.readium.navigator.web.css.Layout +import org.readium.navigator.web.css.ReadiumCssLayout import org.readium.r2.navigator.extensions.format import org.readium.r2.navigator.preferences.Color import org.readium.r2.navigator.preferences.DoubleIncrement @@ -53,7 +53,7 @@ public class ReflowableWebPreferencesEditor internal constructor( private data class State( val preferences: ReflowableWebPreferences, val settings: ReflowableWebSettings, - val layout: Layout, + val layout: ReadiumCssLayout, ) private val settingsResolver: ReflowableWebSettingsResolver = @@ -162,7 +162,7 @@ public class ReflowableWebPreferencesEditor internal constructor( state.settings.hyphens ?: (state.settings.textAlign == TextAlign.JUSTIFY) }, - getIsEffective = { state.layout.stylesheets == Layout.Stylesheets.Default }, + getIsEffective = { state.layout.stylesheets == ReadiumCssLayout.Stylesheets.Default }, updateValue = { value -> updateValues { it.copy(hyphens = value) } } ) @@ -202,7 +202,7 @@ public class ReflowableWebPreferencesEditor internal constructor( RangePreferenceDelegate( getValue = { preferences.letterSpacing }, getEffectiveValue = { state.settings.letterSpacing ?: 0.0 }, - getIsEffective = { state.layout.stylesheets == Layout.Stylesheets.Default }, + getIsEffective = { state.layout.stylesheets == ReadiumCssLayout.Stylesheets.Default }, updateValue = { value -> updateValues { it.copy(letterSpacing = value) } }, supportedRange = 0.0..1.0, progressionStrategy = DoubleIncrement(0.1), @@ -218,7 +218,7 @@ public class ReflowableWebPreferencesEditor internal constructor( PreferenceDelegate( getValue = { preferences.ligatures }, getEffectiveValue = { state.settings.ligatures == true }, - getIsEffective = { state.layout.stylesheets == Layout.Stylesheets.Rtl }, + getIsEffective = { state.layout.stylesheets == ReadiumCssLayout.Stylesheets.Rtl }, updateValue = { value -> updateValues { it.copy(ligatures = value) } } ) @@ -388,7 +388,7 @@ public class ReflowableWebPreferencesEditor internal constructor( RangePreferenceDelegate( getValue = { preferences.wordSpacing }, getEffectiveValue = { state.settings.wordSpacing ?: 0.0 }, - getIsEffective = { state.layout.stylesheets == Layout.Stylesheets.Default }, + getIsEffective = { state.layout.stylesheets == ReadiumCssLayout.Stylesheets.Default }, updateValue = { value -> updateValues { it.copy(wordSpacing = value) } }, supportedRange = 0.0..1.0, progressionStrategy = DoubleIncrement(0.1), @@ -405,18 +405,18 @@ public class ReflowableWebPreferencesEditor internal constructor( private fun ReflowableWebPreferences.toState(): State { val settings = settingsResolver.settings(this) - val layout = Layout.from(settings) + val readiumCssLayout = ReadiumCssLayout.from(settings) return State( preferences = this, settings = settings, - layout = layout + layout = readiumCssLayout ) } private fun isParagraphIndentEffective() = - state.layout.stylesheets in listOf(Layout.Stylesheets.Default, Layout.Stylesheets.Rtl) + state.layout.stylesheets in listOf(ReadiumCssLayout.Stylesheets.Default, ReadiumCssLayout.Stylesheets.Rtl) private fun isTextAlignEffective() = - state.layout.stylesheets in listOf(Layout.Stylesheets.Default, Layout.Stylesheets.Rtl) + state.layout.stylesheets in listOf(ReadiumCssLayout.Stylesheets.Default, ReadiumCssLayout.Stylesheets.Rtl) } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt index 976d549e1b..30e1165b17 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt @@ -13,7 +13,6 @@ import android.view.MotionEvent import android.view.View import androidx.compose.foundation.background import androidx.compose.foundation.gestures.Orientation -import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.pager.PagerState @@ -26,12 +25,10 @@ import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color -import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.unit.DpOffset -import androidx.compose.ui.unit.DpSize import androidx.compose.ui.zIndex import org.readium.navigator.common.TapEvent -import org.readium.navigator.web.css.Layout +import org.readium.navigator.web.css.ReadiumCssLayout import org.readium.navigator.web.css.RsProperties import org.readium.navigator.web.css.UserProperties import org.readium.navigator.web.gestures.NullFling2DBehavior @@ -51,7 +48,6 @@ import org.readium.navigator.web.webview.rememberWebViewState import org.readium.r2.shared.ExperimentalReadiumApi import org.readium.r2.shared.util.AbsoluteUrl import org.readium.r2.shared.util.Url -import timber.log.Timber @SuppressLint("SetJavaScriptEnabled", "ClickableViewAccessibility") @Composable @@ -60,19 +56,18 @@ internal fun ReflowableResource( pagerState: PagerState, publicationBaseUrl: AbsoluteUrl, webViewClient: WebViewClient, - viewportSize: DpSize, backgroundColor: Color, padding: AbsolutePaddingValues, reverseLayout: Boolean, scroll: Boolean, - verticalText: Boolean, + orientation: Orientation, userProperties: UserProperties, rsProperties: RsProperties, - layout: Layout, + readiumCssLayout: ReadiumCssLayout, enableScroll: Boolean, onTap: (TapEvent) -> Unit, onLinkActivated: (Url, String) -> Unit, - onProgessionChange: (Double) -> Unit, + onProgressionChange: (Double) -> Unit, onDocumentResized: () -> Unit, ) { Box( @@ -84,14 +79,8 @@ internal fun ReflowableResource( url = publicationBaseUrl.resolve(resourceState.href).toString() ) - val scrollOrientation = - rememberUpdatedState( - when { - verticalText -> Orientation.Horizontal - scroll -> Orientation.Vertical - else -> Orientation.Horizontal - } - ) + val orientationState = + rememberUpdatedState(orientation) val scriptsLoaded = remember(webViewState.webView) { mutableStateOf(false) } @@ -99,7 +88,8 @@ internal fun ReflowableResource( val contentIsLaidOut = remember(webViewState.webView) { mutableStateOf(false) } - val scrollableState = remember { Scrollable2DState { Offset.Zero } } + val scrollableState = + remember { Scrollable2DState { Offset.Zero } } val documentStateApi = remember(webViewState.webView) { DocumentStateApi( @@ -108,25 +98,23 @@ internal fun ReflowableResource( }, onDocumentLoadedAndSizedDelegate = { webViewState.webView?.apply { - Timber.d("onDocumentLoadedDelegate ${resourceState.index} ${webViewState.webView?.width}") requestLayout() setNextLayoutListener { val scrollController = WebViewScrollController(this) scrollController.moveToProgression( progression = resourceState.progression, scroll = scroll, - orientation = scrollOrientation.value + orientation = orientationState.value ) resourceState.scrollController.value = scrollController setOnScrollChangeListener { view, scrollX, scrollY, oldScrollX, oldScrollY -> - onProgessionChange(scrollController.progression(scrollOrientation.value)) + onProgressionChange(scrollController.progression(orientationState.value)) } contentIsLaidOut.value = true } } }, onDocumentResizedDelegate = { - Timber.d("onDocumentResized ${resourceState.index} ${webViewState.webView?.width}") onDocumentResized.invoke() } ) @@ -178,30 +166,17 @@ internal fun ReflowableResource( ) } - key(layout) { + key(readiumCssLayout) { WebView( modifier = Modifier - // Detect taps on padding - .pointerInput(Unit) { - detectTapGestures( - onTap = { - if (it.x >= 0 && it.y >= 0) { - val offset = DpOffset(x = it.x.toDp(), y = it.y.toDp()) - val event = TapEvent(offset) - onTap(event) - } - } - ) - } .scrollable2D( enabled = enableScroll, state = scrollableState, flingBehavior = NullFling2DBehavior(), reverseDirection = !reverseLayout, - orientation = scrollOrientation.value + orientation = orientationState.value ) .fillMaxSize() - .background(backgroundColor) .absolutePadding(padding), state = webViewState, factory = { RelaxedWebView(it) }, @@ -221,7 +196,7 @@ internal fun ReflowableResource( webview.setOnTouchListener(object : View.OnTouchListener { @SuppressLint("ClickableViewAccessibility") override fun onTouch(view: View, event: MotionEvent): Boolean { - return scrollOrientation.value == Orientation.Horizontal && + return orientationState.value == Orientation.Horizontal && event.action == MotionEvent.ACTION_MOVE } }) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/util/HtmlInjector.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/util/HtmlInjector.kt index e6289670eb..e8491eaccf 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/util/HtmlInjector.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/util/HtmlInjector.kt @@ -7,7 +7,7 @@ package org.readium.navigator.web.util import java.nio.charset.Charset -import org.readium.navigator.web.css.ReadiumCss +import org.readium.navigator.web.css.ReadiumCssInjector import org.readium.r2.shared.ExperimentalReadiumApi import org.readium.r2.shared.util.AbsoluteUrl import org.readium.r2.shared.util.RelativeUrl @@ -51,7 +51,7 @@ internal fun Resource.injectHtml( @OptIn(ExperimentalReadiumApi::class) internal fun Resource.injectHtmlReflowable( charset: Charset?, - readiumCss: ReadiumCss, + readiumCss: ReadiumCssInjector, injectableScript: RelativeUrl, assetsBaseHref: AbsoluteUrl, disableSelection: Boolean, From daef1b50d0605931c376d3a273777ddb343d81cf Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Sun, 13 Apr 2025 18:11:47 +0200 Subject: [PATCH 42/88] Cosmetic changes in fixed layout --- .../navigator/web/FixedWebRendition.kt | 38 ++++++++++++------- .../navigator/web/FixedWebRenditionFactory.kt | 5 ++- .../navigator/web/FixedWebRenditionState.kt | 11 ++---- .../web/fixed/DoubleViewportSpread.kt | 10 ++--- .../web/fixed/SingleViewportSpread.kt | 10 ++--- .../web/fixed/SpreadNestedScrollConnection.kt | 2 +- .../navigator/web/fixed/SpreadWebView.kt | 23 ++++++++--- .../navigator/web/location/LocationTypes.kt | 8 ++-- .../navigator/web/location/LocatorAdapters.kt | 21 +++++----- 9 files changed, 75 insertions(+), 53 deletions(-) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt index 30d5c9ce86..7184349a4c 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt @@ -35,6 +35,7 @@ import org.readium.navigator.common.defaultInputListener import org.readium.navigator.web.fixed.DoubleSpreadState import org.readium.navigator.web.fixed.DoubleViewportSpread import org.readium.navigator.web.fixed.FixedPagingLayoutInfo +import org.readium.navigator.web.fixed.FixedWebPublication import org.readium.navigator.web.fixed.SingleSpreadState import org.readium.navigator.web.fixed.SingleViewportSpread import org.readium.navigator.web.fixed.SpreadScrollState @@ -47,6 +48,7 @@ import org.readium.navigator.web.pager.ScrollDispatcher import org.readium.navigator.web.pager.pagingFlingBehavior import org.readium.navigator.web.util.AbsolutePaddingValues import org.readium.navigator.web.util.DisplayArea +import org.readium.navigator.web.util.HyperlinkProcessor import org.readium.navigator.web.util.WebViewServer import org.readium.r2.navigator.preferences.ReadingProgression import org.readium.r2.shared.ExperimentalReadiumApi @@ -77,6 +79,7 @@ public fun FixedWebRendition( val viewportSize = rememberUpdatedState(DpSize(maxWidth, maxHeight)) val safeDrawingPadding = windowInsets.asAbsolutePaddingValues() + val displayArea = rememberUpdatedState(DisplayArea(viewportSize.value, safeDrawingPadding)) val readingProgression = @@ -85,13 +88,12 @@ public fun FixedWebRendition( val reverseLayout = LocalLayoutDirection.current.toReadingProgression() != readingProgression - // This is barely needed as location could be computed on the state side without any - // data from the layout pass. I keep it so for demonstration purposes of the way the - // reflowable navigator could fit the architecture as well. - val spreadIndex = state.pagerState.currentPage - val itemIndex = state.layoutDelegate.layout.value.pageIndexForSpread(spreadIndex) - val itemHref = state.publication.readingOrder[itemIndex].href - state.updateLocation(FixedWebLocation(itemHref)) + if (state.controller == null) { + val spreadIndex = state.pagerState.currentPage + val itemIndex = state.layoutDelegate.layout.value.pageIndexForSpread(spreadIndex) + val itemHref = state.publication.readingOrder[itemIndex].href + state.initController(location = FixedWebLocation(itemHref)) + } val coroutineScope = rememberCoroutineScope() @@ -157,7 +159,12 @@ public fun FixedWebRendition( onTap = { inputListenerState.value.onTap(it, TapContext(viewportSize.value)) }, onLinkActivated = { url, outerHtml -> coroutineScope.launch { - onLinkActivated(url, outerHtml, state, hyperlinkListenerState.value) + state.hyperlinkProcessor.onLinkActivated( + url = url, + outerHtml = outerHtml, + readingOrder = state.publication.readingOrder, + listener = hyperlinkListenerState.value + ) } }, state = spreadState, @@ -184,7 +191,12 @@ public fun FixedWebRendition( onTap = { inputListenerState.value.onTap(it, TapContext(viewportSize.value)) }, onLinkActivated = { url, outerHtml -> coroutineScope.launch { - onLinkActivated(url, outerHtml, state, hyperlinkListenerState.value) + state.hyperlinkProcessor.onLinkActivated( + url = url, + outerHtml = outerHtml, + readingOrder = state.publication.readingOrder, + listener = hyperlinkListenerState.value + ) } }, state = spreadState, @@ -216,15 +228,15 @@ private fun LayoutDirection.toReadingProgression(): ReadingProgression = } @OptIn(ExperimentalReadiumApi::class) -private suspend fun onLinkActivated( +private suspend fun HyperlinkProcessor.onLinkActivated( url: Url, outerHtml: String, - state: FixedWebRenditionState, + readingOrder: FixedWebPublication.ReadingOrder, listener: HyperlinkListener, ) { val location = HyperlinkLocation(url.removeFragment()) - val isReadingOrder = state.publication.readingOrder.indexOfHref(url.removeFragment()) != null - val context = state.computeHyperlinkContext(url, outerHtml) + val isReadingOrder = readingOrder.indexOfHref(url.removeFragment()) != null + val context = computeLinkContext(url, outerHtml) when { isReadingOrder -> listener.onReadingOrderLinkActivated(location, context) else -> when (url) { diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionFactory.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionFactory.kt index c6dfd1d60c..e4f72f1bed 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionFactory.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionFactory.kt @@ -111,11 +111,14 @@ public class FixedWebRenditionFactory private constructor( val preloads = preloadData() .getOrElse { return Try.failure(it) } + val disableSelection = publication.findService(ContentProtectionService::class) + ?.isRestricted == true + val state = FixedWebRenditionState( application = application, publication = renditionPublication, - isRestricted = publication.findService(ContentProtectionService::class)?.isRestricted ?: false, + disableSelection = disableSelection, initialSettings = initialSettings, initialLocation = initialLocation ?: FixedWebGoLocation(readingOrderItems[0].href), preloadedData = preloads diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionState.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionState.kt index 160b41be79..ec78532b4b 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionState.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionState.kt @@ -14,7 +14,6 @@ import androidx.compose.runtime.State import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.mutableStateOf import org.readium.navigator.common.HyperlinkLocation -import org.readium.navigator.common.LinkContext import org.readium.navigator.common.NavigationController import org.readium.navigator.common.Overflow import org.readium.navigator.common.OverflowController @@ -38,7 +37,6 @@ import org.readium.r2.navigator.preferences.Fit import org.readium.r2.shared.ExperimentalReadiumApi import org.readium.r2.shared.InternalReadiumApi import org.readium.r2.shared.util.RelativeUrl -import org.readium.r2.shared.util.Url import org.readium.r2.shared.util.mediatype.MediaType import org.readium.r2.shared.util.resource.Resource @@ -47,7 +45,7 @@ import org.readium.r2.shared.util.resource.Resource public class FixedWebRenditionState internal constructor( application: Application, internal val publication: FixedWebPublication, - isRestricted: Boolean, + disableSelection: Boolean, initialSettings: FixedWebSettings, initialLocation: FixedWebGoLocation, internal val preloadedData: FixedWebPreloadedData, @@ -77,7 +75,7 @@ public class FixedWebRenditionState internal constructor( charset = mediaType.charset, injectableScript = RelativeUrl("readium/navigators/web/generated/fixed-injectable-script.js")!!, assetsBaseHref = assetsBaseHref, - disableSelection = isRestricted + disableSelection = disableSelection ) } @@ -102,12 +100,9 @@ public class FixedWebRenditionState internal constructor( ) } - internal suspend fun computeHyperlinkContext(originUrl: Url, outerHtml: String): LinkContext? = - hyperlinkProcessor.computeLinkContext(originUrl, outerHtml) - private lateinit var navigationDelegate: NavigationDelegate - internal fun updateLocation(location: FixedWebLocation) { + internal fun initController(location: FixedWebLocation) { initControllerIfNeeded(location) navigationDelegate.updateLocation(location) } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/DoubleViewportSpread.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/DoubleViewportSpread.kt index 2afc108686..7bac4c968f 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/DoubleViewportSpread.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/DoubleViewportSpread.kt @@ -62,21 +62,21 @@ internal fun DoubleViewportSpread( ?.let { FixedDoubleApi(it) } } - layoutApi?.let { api -> - LaunchedEffect(api) { + LaunchedEffect(layoutApi) { + if (layoutApi != null) { snapshotFlow { state.fit.value }.onEach { - api.setFit(state.fit.value) + layoutApi.setFit(state.fit.value) }.launchIn(this) snapshotFlow { state.displayArea.value }.onEach { - api.setDisplayArea(it) + layoutApi.setDisplayArea(it) }.launchIn(this) - api.loadSpread(state.spread) + layoutApi.loadSpread(state.spread) } } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SingleViewportSpread.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SingleViewportSpread.kt index 336f38d0c6..c1543b940c 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SingleViewportSpread.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SingleViewportSpread.kt @@ -62,21 +62,21 @@ internal fun SingleViewportSpread( ?.let { FixedSingleApi(it) } } - layoutApi?.let { api -> - LaunchedEffect(api) { + LaunchedEffect(layoutApi) { + if (layoutApi != null) { snapshotFlow { state.fit.value }.onEach { - api.setFit(it) + layoutApi.setFit(it) }.launchIn(this) snapshotFlow { state.displayArea.value }.onEach { - api.setDisplayArea(it) + layoutApi.setDisplayArea(it) }.launchIn(this) - api.loadSpread(state.spread) + layoutApi.loadSpread(state.spread) } } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadNestedScrollConnection.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadNestedScrollConnection.kt index edc6ad6094..73927107f9 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadNestedScrollConnection.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadNestedScrollConnection.kt @@ -20,7 +20,7 @@ internal class SpreadNestedScrollConnection( private val pagerState: PagerState, private val webviewState: WebViewScrollable2DState, private val scrollController: SpreadScrollState, - private var flingBehavior: Fling2DBehavior, + internal var flingBehavior: Fling2DBehavior, ) : NestedScrollConnection { var consumedHere: Boolean = false diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt index eb719f86e4..4fa0033e9f 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt @@ -33,7 +33,6 @@ import org.readium.navigator.web.webview.WebView import org.readium.navigator.web.webview.WebViewScrollController import org.readium.navigator.web.webview.WebViewScrollable2DState import org.readium.navigator.web.webview.WebViewState -import org.readium.navigator.web.webview.invokeOnReadyToBeDrawn import org.readium.r2.shared.ExperimentalReadiumApi import org.readium.r2.shared.util.AbsoluteUrl @@ -57,14 +56,25 @@ internal fun SpreadWebView( val flingBehavior = Scrollable2DDefaults.flingBehavior() val spreadNestedScrollConnection = - SpreadNestedScrollConnection(spreadIndex, pagerState, scrollableState, spreadScrollState, flingBehavior) + remember(spreadIndex, pagerState, scrollableState, spreadScrollState) { + SpreadNestedScrollConnection( + spreadIndex, + pagerState, + scrollableState, + spreadScrollState, + flingBehavior + ) + } + + spreadNestedScrollConnection.flingBehavior = flingBehavior val documentStateApi = remember(onScriptsLoaded) { DocumentStateApi( onScriptsLoadedDelegate = onScriptsLoaded, onDocumentLoadedAndSizedDelegate = { state.webView?.apply { - invokeOnReadyToBeDrawn { + requestLayout() + setNextLayoutListener { val scrollController = WebViewScrollController(this) spreadScrollState.scrollController.value = scrollController } @@ -74,6 +84,10 @@ internal fun SpreadWebView( ) } + LaunchedEffect(state.webView, documentStateApi) { + state.webView?.let { documentStateApi.registerOnWebView(it) } + } + val gesturesApi = remember(onTap) { val listener = object : GesturesListener { override fun onTap(offset: DpOffset) { @@ -87,8 +101,7 @@ internal fun SpreadWebView( GesturesApi(listener) } - LaunchedEffect(state.webView) { - state.webView?.let { documentStateApi.registerOnWebView(it) } + LaunchedEffect(state.webView, gesturesApi) { state.webView?.let { gesturesApi.registerOnWebView(it) } } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/location/LocationTypes.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/location/LocationTypes.kt index 9e88e206f5..6413c4a74f 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/location/LocationTypes.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/location/LocationTypes.kt @@ -15,10 +15,10 @@ import org.readium.r2.shared.util.Url public data class ReflowableWebGoLocation( val href: Url, val progression: Double? = null, - val cssSelector: String? = null, - val textBefore: String? = null, - val textAfter: String? = null, - val position: Int? = null, + // val cssSelector: String? = null, + // val textBefore: String? = null, + // val textAfter: String? = null, + // val position: Int? = null ) : GoLocation @ExperimentalReadiumApi diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/location/LocatorAdapters.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/location/LocatorAdapters.kt index 47d6be68e2..a0ac8ee41e 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/location/LocatorAdapters.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/location/LocatorAdapters.kt @@ -11,7 +11,6 @@ import org.readium.r2.shared.ExperimentalReadiumApi import org.readium.r2.shared.publication.Link import org.readium.r2.shared.publication.Locator import org.readium.r2.shared.publication.Publication -import org.readium.r2.shared.publication.html.cssSelector import org.readium.r2.shared.publication.indexOfFirstWithHref @ExperimentalReadiumApi @@ -35,6 +34,16 @@ public class ReflowableWebLocatorAdapter internal constructor( private val publication: Publication, ) : LocatorAdapter { + public override fun Locator.toGoLocation(): ReflowableWebGoLocation = + ReflowableWebGoLocation( + href = href, + progression = locations.progression, + // cssSelector = locations.cssSelector, + // textBefore = text.before, + // textAfter = text.highlight?.let { it + text.after } ?: text.after, + // position = locations.position + ) + public override fun ReflowableWebLocation.toLocator(): Locator = publication.locatorFromLink(Link(href))!! .copy( @@ -48,14 +57,4 @@ public class ReflowableWebLocatorAdapter internal constructor( // position = position, // otherLocations = buildMap { cssSelector?.let { put("cssSelector", cssSelector) } } ) - - public override fun Locator.toGoLocation(): ReflowableWebGoLocation = - ReflowableWebGoLocation( - href = href, - progression = locations.progression, - cssSelector = locations.cssSelector, - textBefore = text.before, - textAfter = text.highlight?.let { it + text.after } ?: text.after, - position = locations.position - ) } From 7942a9f4a0757ef1a594ba53301bfb66eeb3df73 Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Wed, 16 Apr 2025 15:57:40 +0200 Subject: [PATCH 43/88] Cosmetic changes --- .../org/readium/navigator/web/FixedWebRenditionState.kt | 4 ++-- .../readium/navigator/web/ReflowableWebRenditionFactory.kt | 2 +- .../java/org/readium/navigator/web/util/HtmlInjector.kt | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionState.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionState.kt index ec78532b4b..7c4f885471 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionState.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionState.kt @@ -30,7 +30,7 @@ import org.readium.navigator.web.util.HyperlinkProcessor import org.readium.navigator.web.util.WebViewClient import org.readium.navigator.web.util.WebViewServer import org.readium.navigator.web.util.WebViewServer.Companion.assetsBaseHref -import org.readium.navigator.web.util.injectHtml +import org.readium.navigator.web.util.injectHtmlFixedLayout import org.readium.r2.navigator.SimpleOverflow import org.readium.r2.navigator.preferences.Axis import org.readium.r2.navigator.preferences.Fit @@ -71,7 +71,7 @@ public class FixedWebRenditionState internal constructor( HyperlinkProcessor(publication.container) private val htmlInjector: (Resource, MediaType) -> Resource = { resource, mediaType -> - resource.injectHtml( + resource.injectHtmlFixedLayout( charset = mediaType.charset, injectableScript = RelativeUrl("readium/navigators/web/generated/fixed-injectable-script.js")!!, assetsBaseHref = assetsBaseHref, diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionFactory.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionFactory.kt index a7535a93b1..76526dd528 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionFactory.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionFactory.kt @@ -45,7 +45,7 @@ public class ReflowableWebRenditionFactory private constructor( defaults: ReflowableWebDefaults = ReflowableWebDefaults(), ): ReflowableWebRenditionFactory? { if (!publication.conformsTo(Publication.Profile.EPUB) || - publication.metadata.presentation.layout != EpubLayout.REFLOWABLE + publication.metadata.presentation.layout == EpubLayout.FIXED ) { return null } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/util/HtmlInjector.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/util/HtmlInjector.kt index e8491eaccf..c13cd5abf1 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/util/HtmlInjector.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/util/HtmlInjector.kt @@ -19,11 +19,11 @@ import org.readium.r2.shared.util.resource.TransformingResource import timber.log.Timber /** - * Injects scripts in the HTML [Resource] receiver. + * Injects scripts for fixed layout publications in the HTML [Resource] receiver. * * @param assetsBaseHref Base URL where and scripts are served. */ -internal fun Resource.injectHtml( +internal fun Resource.injectHtmlFixedLayout( charset: Charset?, injectableScript: RelativeUrl, assetsBaseHref: AbsoluteUrl, @@ -44,7 +44,7 @@ internal fun Resource.injectHtml( } /** - * Injects scripts in the HTML [Resource] receiver. + * Injects scripts for reflowable publications in the HTML [Resource] receiver. * * @param assetsBaseHref Base URL where and scripts are served. */ From 0aced635c2bd142dcada3d821a42831fefaa97c2 Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Fri, 18 Apr 2025 14:00:31 +0200 Subject: [PATCH 44/88] Fix fixed layout scroll after changing preferences --- .../navigator/web/FixedWebRendition.kt | 40 ++++++++++++++----- .../navigator/web/FixedWebRenditionState.kt | 19 +++++---- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt index 7184349a4c..52cbec8bad 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt @@ -14,15 +14,19 @@ import androidx.compose.foundation.layout.displayCutout import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberUpdatedState +import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.LayoutDirection +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import org.readium.navigator.common.HyperlinkListener import org.readium.navigator.common.HyperlinkLocation @@ -88,14 +92,21 @@ public fun FixedWebRendition( val reverseLayout = LocalLayoutDirection.current.toReadingProgression() != readingProgression + val coroutineScope = rememberCoroutineScope() + if (state.controller == null) { - val spreadIndex = state.pagerState.currentPage - val itemIndex = state.layoutDelegate.layout.value.pageIndexForSpread(spreadIndex) - val itemHref = state.publication.readingOrder[itemIndex].href + val itemHref = state.getCurrentHref() state.initController(location = FixedWebLocation(itemHref)) } - val coroutineScope = rememberCoroutineScope() + LaunchedEffect(state) { + snapshotFlow { + state.pagerState.currentPage + }.onEach { + val itemHref = state.getCurrentHref() + state.navigationDelegate.updateLocation(location = FixedWebLocation(itemHref)) + }.launchIn(coroutineScope) + } val inputListenerState = rememberUpdatedState(inputListener) @@ -131,18 +142,31 @@ public fun FixedWebRendition( scrollDispatcher.flingBehavior = flingBehavior + LaunchedEffect(state.layoutDelegate.layout.value, state.controller) { + state.controller?.let { + val currentHref = it.location.value.href + val spreadIndex = checkNotNull(state.layoutDelegate.layout.value.spreadIndexForHref(currentHref)) + state.pagerState.requestScrollToPage(spreadIndex) + } + } + RenditionPager( modifier = Modifier, state = state.pagerState, scrollDispatcher = scrollDispatcher, orientation = Orientation.Horizontal, beyondViewportPageCount = 2, - key = { index -> state.layoutDelegate.layout.value.pageIndexForSpread(index) }, + key = { index -> + val readingProgression = state.layoutDelegate.layout.value.readingProgression + val spread = state.layoutDelegate.layout.value.spreads[index] + val pages = spread.pages.map { it.index } + "$readingProgression $spread $pages" + }, reverseLayout = reverseLayout ) { index -> when (val spread = state.layoutDelegate.layout.value.spreads[index]) { is SingleViewportSpread -> { - val spreadState = remember(state) { + val spreadState = SingleSpreadState( index = index, htmlData = state.preloadedData.fixedSingleContent, @@ -152,7 +176,6 @@ public fun FixedWebRendition( fit = state.layoutDelegate.fit, displayArea = displayArea ) - } SingleViewportSpread( pagerState = state.pagerState, @@ -174,7 +197,7 @@ public fun FixedWebRendition( ) } is DoubleViewportSpread -> { - val spreadState = remember(state) { + val spreadState = DoubleSpreadState( index = index, htmlData = state.preloadedData.fixedDoubleContent, @@ -184,7 +207,6 @@ public fun FixedWebRendition( fit = state.layoutDelegate.fit, displayArea = displayArea ) - } DoubleViewportSpread( pagerState = state.pagerState, diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionState.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionState.kt index 7c4f885471..53aa3b5e70 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionState.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionState.kt @@ -37,6 +37,7 @@ import org.readium.r2.navigator.preferences.Fit import org.readium.r2.shared.ExperimentalReadiumApi import org.readium.r2.shared.InternalReadiumApi import org.readium.r2.shared.util.RelativeUrl +import org.readium.r2.shared.util.Url import org.readium.r2.shared.util.mediatype.MediaType import org.readium.r2.shared.util.resource.Resource @@ -100,18 +101,9 @@ public class FixedWebRenditionState internal constructor( ) } - private lateinit var navigationDelegate: NavigationDelegate + internal lateinit var navigationDelegate: NavigationDelegate internal fun initController(location: FixedWebLocation) { - initControllerIfNeeded(location) - navigationDelegate.updateLocation(location) - } - - private fun initControllerIfNeeded(location: FixedWebLocation) { - if (controller != null) { - return - } - navigationDelegate = NavigationDelegate( pagerState, @@ -124,6 +116,13 @@ public class FixedWebRenditionState internal constructor( navigationDelegate, layoutDelegate ) + navigationDelegate.updateLocation(location) + } + + internal fun getCurrentHref(): Url { + val spreadIndex = pagerState.currentPage + val itemIndex = layoutDelegate.layout.value.pageIndexForSpread(spreadIndex) + return publication.readingOrder[itemIndex].href } } From 4af0f63cf9dfe35b88354dceaca2db75efb9e736 Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Fri, 18 Apr 2025 15:56:22 +0200 Subject: [PATCH 45/88] Fix crash in two columns mode --- .../scripts/src/index-reflowable-injectable.ts | 5 ++++- .../navigators/web/scripts/src/util/columns.ts | 16 +++++++++++++--- .../generated/reflowable-injectable-script.js | 2 +- .../reflowable-injectable-script.js.map | 2 +- 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/readium/navigators/web/scripts/src/index-reflowable-injectable.ts b/readium/navigators/web/scripts/src/index-reflowable-injectable.ts index 52781d5736..bbec440e77 100644 --- a/readium/navigators/web/scripts/src/index-reflowable-injectable.ts +++ b/readium/navigators/web/scripts/src/index-reflowable-injectable.ts @@ -51,7 +51,10 @@ window.addEventListener("load", (event) => { const observer = new ResizeObserver(() => { requestAnimationFrame(() => { - appendVirtualColumnIfNeeded(window) + if (appendVirtualColumnIfNeeded(window)) { + // Column has been added or removed, wait for next resize callback. + return + } const scrollingElement = window.document.scrollingElement diff --git a/readium/navigators/web/scripts/src/util/columns.ts b/readium/navigators/web/scripts/src/util/columns.ts index f945898396..cdeb1915ac 100644 --- a/readium/navigators/web/scripts/src/util/columns.ts +++ b/readium/navigators/web/scripts/src/util/columns.ts @@ -3,21 +3,28 @@ * for proper snapping. This may not be automatically the case if the number of * columns in the resource is not a multiple of the number of columns fitting in the viewport. * To fix this, we insert a blank virtual column at the end of the resource. + * + * Returns if a virtual column has been added or removed. */ -export function appendVirtualColumnIfNeeded(wnd: Window) { +export function appendVirtualColumnIfNeeded(wnd: Window): boolean { + // FIXME: what about scroll mode? const id = "readium-virtual-page" let virtualCol = wnd.document.getElementById(id) if (getColumnCountPerScreen(wnd) !== 2) { if (virtualCol) { virtualCol.remove() + return true + } else { + return false } } else { const documentWidth = wnd.document.scrollingElement!.scrollWidth const colCount = documentWidth / wnd.innerWidth const hasOddColCount = (Math.round(colCount * 2) / 2) % 1 > 0.1 if (hasOddColCount) { - if (virtualCol) virtualCol.remove() - else { + if (virtualCol) { + virtualCol.remove() + } else { virtualCol = wnd.document.createElement("div") virtualCol.setAttribute("id", id) virtualCol.dataset.readium = "true" @@ -25,6 +32,9 @@ export function appendVirtualColumnIfNeeded(wnd: Window) { virtualCol.innerHTML = "​" // zero-width space wnd.document.body.appendChild(virtualCol) } + return true + } else { + return false } } } diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js index 0acda0da6a..16302be211 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js @@ -1,2 +1,2 @@ -!function(){"use strict";const e=new class{constructor(e){this.nativeApi=e}onTap(e){this.nativeApi.onTap(JSON.stringify(e))}onLinkActivated(e,t){this.nativeApi.onLinkActivated(e,t)}}(window.gestures),t={onTap:t=>{const n={x:(t.clientX-visualViewport.offsetLeft)*visualViewport.scale,y:(t.clientY-visualViewport.offsetTop)*visualViewport.scale};e.onTap(n)},onLinkActivated:(t,n)=>{e.onLinkActivated(t,n)}};new class{constructor(e,t){this.window=e,this.listener=t,document.addEventListener("click",(e=>{this.onClick(e)}),!1)}onClick(e){if(e.defaultPrevented)return;const t=this.window.getSelection();if(t&&"Range"==t.type)return;let n;n=e.target instanceof HTMLElement?this.nearestInteractiveElement(e.target):null,n?n instanceof HTMLAnchorElement&&this.listener.onLinkActivated(n.href,n.outerHTML):this.listener.onTap(e),e.stopPropagation(),e.preventDefault()}nearestInteractiveElement(e){return null==e?null:-1!=["a","audio","button","canvas","details","input","label","option","select","submit","textarea","video"].indexOf(e.nodeName.toLowerCase())||e.hasAttribute("contenteditable")&&"false"!=e.getAttribute("contenteditable").toLowerCase()?e:e.parentElement?this.nearestInteractiveElement(e.parentElement):null}}(window,t),Window.prototype.readiumcss=new class{constructor(e){this.document=e}setProperties(e){for(const[t,n]of e)this.setProperty(t,n)}setProperty(e,t){null===t||""===t?this.removeProperty(e):document.documentElement.style.setProperty(e,t,"important")}removeProperty(e){document.documentElement.style.removeProperty(e)}}(window.document),window.documentState.onScriptsLoaded(),window.addEventListener("load",(e=>{let t=!1;new ResizeObserver((()=>{requestAnimationFrame((()=>{!function(e){const t="readium-virtual-page";let n=e.document.getElementById(t);if(2!==function(e){return parseInt(e.getComputedStyle(e.document.documentElement).getPropertyValue("column-count"))}(e))n&&n.remove();else{const o=e.document.scrollingElement.scrollWidth/e.innerWidth;Math.round(2*o)/2%1>.1&&(n?n.remove():(n=e.document.createElement("div"),n.setAttribute("id",t),n.dataset.readium="true",n.style.breakBefore="column",n.innerHTML="​",e.document.body.appendChild(n)))}}(window);const e=window.document.scrollingElement;!t&&(null==e||e.scrollHeight>0||e.scrollWidth>0)?(window.documentState.onDocumentLoadedAndSized(),t=!0):window.documentState.onDocumentResized()}))})).observe(document.body)}))}(); +!function(){"use strict";const e=new class{constructor(e){this.nativeApi=e}onTap(e){this.nativeApi.onTap(JSON.stringify(e))}onLinkActivated(e,t){this.nativeApi.onLinkActivated(e,t)}}(window.gestures),t={onTap:t=>{const n={x:(t.clientX-visualViewport.offsetLeft)*visualViewport.scale,y:(t.clientY-visualViewport.offsetTop)*visualViewport.scale};e.onTap(n)},onLinkActivated:(t,n)=>{e.onLinkActivated(t,n)}};new class{constructor(e,t){this.window=e,this.listener=t,document.addEventListener("click",(e=>{this.onClick(e)}),!1)}onClick(e){if(e.defaultPrevented)return;const t=this.window.getSelection();if(t&&"Range"==t.type)return;let n;n=e.target instanceof HTMLElement?this.nearestInteractiveElement(e.target):null,n?n instanceof HTMLAnchorElement&&this.listener.onLinkActivated(n.href,n.outerHTML):this.listener.onTap(e),e.stopPropagation(),e.preventDefault()}nearestInteractiveElement(e){return null==e?null:-1!=["a","audio","button","canvas","details","input","label","option","select","submit","textarea","video"].indexOf(e.nodeName.toLowerCase())||e.hasAttribute("contenteditable")&&"false"!=e.getAttribute("contenteditable").toLowerCase()?e:e.parentElement?this.nearestInteractiveElement(e.parentElement):null}}(window,t),Window.prototype.readiumcss=new class{constructor(e){this.document=e}setProperties(e){for(const[t,n]of e)this.setProperty(t,n)}setProperty(e,t){null===t||""===t?this.removeProperty(e):document.documentElement.style.setProperty(e,t,"important")}removeProperty(e){document.documentElement.style.removeProperty(e)}}(window.document),window.documentState.onScriptsLoaded(),window.addEventListener("load",(e=>{let t=!1;new ResizeObserver((()=>{requestAnimationFrame((()=>{var e;if(function(e){const t="readium-virtual-page";let n=e.document.getElementById(t);if(2!==function(e){return parseInt(e.getComputedStyle(e.document.documentElement).getPropertyValue("column-count"))}(e))return!!n&&(n.remove(),!0);{const o=e.document.scrollingElement.scrollWidth/e.innerWidth;return!!(Math.round(2*o)/2%1>.1)&&(n?n.remove():(n=e.document.createElement("div"),n.setAttribute("id",t),n.dataset.readium="true",n.style.breakBefore="column",n.innerHTML="​",e.document.body.appendChild(n)),!0)}}(window))return;console.log(`resize ${null===(e=window.document.scrollingElement)||void 0===e?void 0:e.scrollWidth} ${window.innerWidth}`);const n=window.document.scrollingElement;!t&&(null==n||n.scrollHeight>0||n.scrollWidth>0)?(window.documentState.onDocumentLoadedAndSized(),t=!0):window.documentState.onDocumentResized()}))})).observe(document.body)}))}(); //# sourceMappingURL=reflowable-injectable-script.js.map \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map index 1260096914..8018300222 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map @@ -1 +1 @@ -{"version":3,"file":"reflowable-injectable-script.js","mappings":"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","sources":["webpack://readium-js/./src/index-reflowable-injectable.ts","webpack://readium-js/./src/bridge/all-gestures-bridge.ts","webpack://readium-js/./src/common/gestures.ts","webpack://readium-js/./src/bridge/reflowable-css-bridge.ts","webpack://readium-js/./src/util/columns.ts"],"sourcesContent":["//\n// Copyright 2024 Readium Foundation. All rights reserved.\n// Use of this source code is governed by the BSD-style license\n// available in the top-level LICENSE file of the project.\n//\n/**\n * Script loaded by reflowable resources.\n */\nimport { BridgeGesturesAdapter, } from \"./bridge/all-gestures-bridge\";\nimport { CssBridge } from \"./bridge/reflowable-css-bridge\";\nimport { GesturesDetector } from \"./common/gestures\";\nimport { appendVirtualColumnIfNeeded } from \"./util/columns\";\nconst bridgeListener = new BridgeGesturesAdapter(window.gestures);\nconst gesturesListener = {\n onTap: (event) => {\n const tapEvent = {\n x: (event.clientX - visualViewport.offsetLeft) * visualViewport.scale,\n y: (event.clientY - visualViewport.offsetTop) * visualViewport.scale,\n };\n bridgeListener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n bridgeListener.onLinkActivated(href, outerHtml);\n },\n};\nnew GesturesDetector(window, gesturesListener);\nWindow.prototype.readiumcss = new CssBridge(window.document);\nwindow.documentState.onScriptsLoaded();\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nwindow.addEventListener(\"load\", (event) => {\n let documentLoadedFired = false;\n const observer = new ResizeObserver(() => {\n requestAnimationFrame(() => {\n appendVirtualColumnIfNeeded(window);\n const scrollingElement = window.document.scrollingElement;\n if (!documentLoadedFired &&\n (scrollingElement == null ||\n scrollingElement.scrollHeight > 0 ||\n scrollingElement.scrollWidth > 0)) {\n window.documentState.onDocumentLoadedAndSized();\n documentLoadedFired = true;\n }\n else {\n window.documentState.onDocumentResized();\n }\n });\n });\n observer.observe(document.body);\n});\n","export class BridgeGesturesAdapter {\n constructor(gesturesApi) {\n this.nativeApi = gesturesApi;\n }\n onTap(event) {\n this.nativeApi.onTap(JSON.stringify(event));\n }\n onLinkActivated(href, outerHtml) {\n this.nativeApi.onLinkActivated(href, outerHtml);\n }\n}\n","export class GesturesDetector {\n constructor(window, listener) {\n this.window = window;\n this.listener = listener;\n document.addEventListener(\"click\", (event) => {\n this.onClick(event);\n }, false);\n }\n onClick(event) {\n if (event.defaultPrevented) {\n return;\n }\n const selection = this.window.getSelection();\n if (selection && selection.type == \"Range\") {\n // There's an on-going selection, the tap will dismiss it so we don't forward it.\n // selection.type might be None (collapsed) or Caret with a collapsed range\n // when there is not true selection.\n return;\n }\n let nearestElement;\n if (event.target instanceof HTMLElement) {\n nearestElement = this.nearestInteractiveElement(event.target);\n }\n else {\n nearestElement = null;\n }\n if (nearestElement) {\n if (nearestElement instanceof HTMLAnchorElement) {\n this.listener.onLinkActivated(nearestElement.href, nearestElement.outerHTML);\n }\n }\n else {\n this.listener.onTap(event);\n }\n event.stopPropagation();\n event.preventDefault();\n }\n // See. https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling\n nearestInteractiveElement(element) {\n if (element == null) {\n return null;\n }\n const interactiveTags = [\n \"a\",\n \"audio\",\n \"button\",\n \"canvas\",\n \"details\",\n \"input\",\n \"label\",\n \"option\",\n \"select\",\n \"submit\",\n \"textarea\",\n \"video\",\n ];\n if (interactiveTags.indexOf(element.nodeName.toLowerCase()) != -1) {\n return element;\n }\n // Checks whether the element is editable by the user.\n if (element.hasAttribute(\"contenteditable\") &&\n element.getAttribute(\"contenteditable\").toLowerCase() != \"false\") {\n return element;\n }\n // Checks parents recursively because the touch might be for example on an inside a .\n if (element.parentElement) {\n return this.nearestInteractiveElement(element.parentElement);\n }\n return null;\n }\n}\n","export class CssBridge {\n constructor(document) {\n this.document = document;\n }\n setProperties(properties) {\n for (const [key, value] of properties) {\n this.setProperty(key, value);\n }\n }\n // For setting user setting.\n setProperty(key, value) {\n if (value === null || value === \"\") {\n this.removeProperty(key);\n }\n else {\n const root = document.documentElement;\n // The `!important` annotation is added with `setProperty()` because if it's part of the\n // `value`, it will be ignored by the Web View.\n root.style.setProperty(key, value, \"important\");\n }\n }\n // For removing user setting.\n removeProperty(key) {\n const root = document.documentElement;\n root.style.removeProperty(key);\n }\n}\n","/**\n * In paginated mode, the width of each resource must be a multiple of the viewport size\n * for proper snapping. This may not be automatically the case if the number of\n * columns in the resource is not a multiple of the number of columns fitting in the viewport.\n * To fix this, we insert a blank virtual column at the end of the resource.\n */\nexport function appendVirtualColumnIfNeeded(wnd) {\n const id = \"readium-virtual-page\";\n let virtualCol = wnd.document.getElementById(id);\n if (getColumnCountPerScreen(wnd) !== 2) {\n if (virtualCol) {\n virtualCol.remove();\n }\n }\n else {\n const documentWidth = wnd.document.scrollingElement.scrollWidth;\n const colCount = documentWidth / wnd.innerWidth;\n const hasOddColCount = (Math.round(colCount * 2) / 2) % 1 > 0.1;\n if (hasOddColCount) {\n if (virtualCol)\n virtualCol.remove();\n else {\n virtualCol = wnd.document.createElement(\"div\");\n virtualCol.setAttribute(\"id\", id);\n virtualCol.dataset.readium = \"true\";\n virtualCol.style.breakBefore = \"column\";\n virtualCol.innerHTML = \"​\"; // zero-width space\n wnd.document.body.appendChild(virtualCol);\n }\n }\n }\n}\nfunction getColumnCountPerScreen(wnd) {\n return parseInt(wnd\n .getComputedStyle(wnd.document.documentElement)\n .getPropertyValue(\"column-count\"));\n}\n"],"names":["bridgeListener","constructor","gesturesApi","this","nativeApi","onTap","event","JSON","stringify","onLinkActivated","href","outerHtml","window","gestures","gesturesListener","tapEvent","x","clientX","visualViewport","offsetLeft","scale","y","clientY","offsetTop","listener","document","addEventListener","onClick","defaultPrevented","selection","getSelection","type","nearestElement","target","HTMLElement","nearestInteractiveElement","HTMLAnchorElement","outerHTML","stopPropagation","preventDefault","element","indexOf","nodeName","toLowerCase","hasAttribute","getAttribute","parentElement","Window","prototype","readiumcss","setProperties","properties","key","value","setProperty","removeProperty","documentElement","style","documentState","onScriptsLoaded","documentLoadedFired","ResizeObserver","requestAnimationFrame","wnd","id","virtualCol","getElementById","parseInt","getComputedStyle","getPropertyValue","getColumnCountPerScreen","remove","colCount","scrollingElement","scrollWidth","innerWidth","Math","round","createElement","setAttribute","dataset","readium","breakBefore","innerHTML","body","appendChild","appendVirtualColumnIfNeeded","scrollHeight","onDocumentLoadedAndSized","onDocumentResized","observe"],"sourceRoot":""} \ No newline at end of file +{"version":3,"file":"reflowable-injectable-script.js","mappings":"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","sources":["webpack://readium-js/./src/index-reflowable-injectable.ts","webpack://readium-js/./src/bridge/all-gestures-bridge.ts","webpack://readium-js/./src/common/gestures.ts","webpack://readium-js/./src/bridge/reflowable-css-bridge.ts","webpack://readium-js/./src/util/columns.ts"],"sourcesContent":["//\n// Copyright 2024 Readium Foundation. All rights reserved.\n// Use of this source code is governed by the BSD-style license\n// available in the top-level LICENSE file of the project.\n//\n/**\n * Script loaded by reflowable resources.\n */\nimport { BridgeGesturesAdapter, } from \"./bridge/all-gestures-bridge\";\nimport { CssBridge } from \"./bridge/reflowable-css-bridge\";\nimport { GesturesDetector } from \"./common/gestures\";\nimport { appendVirtualColumnIfNeeded } from \"./util/columns\";\nconst bridgeListener = new BridgeGesturesAdapter(window.gestures);\nconst gesturesListener = {\n onTap: (event) => {\n const tapEvent = {\n x: (event.clientX - visualViewport.offsetLeft) * visualViewport.scale,\n y: (event.clientY - visualViewport.offsetTop) * visualViewport.scale,\n };\n bridgeListener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n bridgeListener.onLinkActivated(href, outerHtml);\n },\n};\nnew GesturesDetector(window, gesturesListener);\nWindow.prototype.readiumcss = new CssBridge(window.document);\nwindow.documentState.onScriptsLoaded();\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nwindow.addEventListener(\"load\", (event) => {\n let documentLoadedFired = false;\n const observer = new ResizeObserver(() => {\n requestAnimationFrame(() => {\n var _a;\n if (appendVirtualColumnIfNeeded(window)) {\n // Column has been added or removed, wait for next resize callback.\n return;\n }\n console.log(`resize ${(_a = window.document.scrollingElement) === null || _a === void 0 ? void 0 : _a.scrollWidth} ${window.innerWidth}`);\n const scrollingElement = window.document.scrollingElement;\n if (!documentLoadedFired &&\n (scrollingElement == null ||\n scrollingElement.scrollHeight > 0 ||\n scrollingElement.scrollWidth > 0)) {\n window.documentState.onDocumentLoadedAndSized();\n documentLoadedFired = true;\n }\n else {\n window.documentState.onDocumentResized();\n }\n });\n });\n observer.observe(document.body);\n});\n","export class BridgeGesturesAdapter {\n constructor(gesturesApi) {\n this.nativeApi = gesturesApi;\n }\n onTap(event) {\n this.nativeApi.onTap(JSON.stringify(event));\n }\n onLinkActivated(href, outerHtml) {\n this.nativeApi.onLinkActivated(href, outerHtml);\n }\n}\n","export class GesturesDetector {\n constructor(window, listener) {\n this.window = window;\n this.listener = listener;\n document.addEventListener(\"click\", (event) => {\n this.onClick(event);\n }, false);\n }\n onClick(event) {\n if (event.defaultPrevented) {\n return;\n }\n const selection = this.window.getSelection();\n if (selection && selection.type == \"Range\") {\n // There's an on-going selection, the tap will dismiss it so we don't forward it.\n // selection.type might be None (collapsed) or Caret with a collapsed range\n // when there is not true selection.\n return;\n }\n let nearestElement;\n if (event.target instanceof HTMLElement) {\n nearestElement = this.nearestInteractiveElement(event.target);\n }\n else {\n nearestElement = null;\n }\n if (nearestElement) {\n if (nearestElement instanceof HTMLAnchorElement) {\n this.listener.onLinkActivated(nearestElement.href, nearestElement.outerHTML);\n }\n }\n else {\n this.listener.onTap(event);\n }\n event.stopPropagation();\n event.preventDefault();\n }\n // See. https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling\n nearestInteractiveElement(element) {\n if (element == null) {\n return null;\n }\n const interactiveTags = [\n \"a\",\n \"audio\",\n \"button\",\n \"canvas\",\n \"details\",\n \"input\",\n \"label\",\n \"option\",\n \"select\",\n \"submit\",\n \"textarea\",\n \"video\",\n ];\n if (interactiveTags.indexOf(element.nodeName.toLowerCase()) != -1) {\n return element;\n }\n // Checks whether the element is editable by the user.\n if (element.hasAttribute(\"contenteditable\") &&\n element.getAttribute(\"contenteditable\").toLowerCase() != \"false\") {\n return element;\n }\n // Checks parents recursively because the touch might be for example on an inside a .\n if (element.parentElement) {\n return this.nearestInteractiveElement(element.parentElement);\n }\n return null;\n }\n}\n","export class CssBridge {\n constructor(document) {\n this.document = document;\n }\n setProperties(properties) {\n for (const [key, value] of properties) {\n this.setProperty(key, value);\n }\n }\n // For setting user setting.\n setProperty(key, value) {\n if (value === null || value === \"\") {\n this.removeProperty(key);\n }\n else {\n const root = document.documentElement;\n // The `!important` annotation is added with `setProperty()` because if it's part of the\n // `value`, it will be ignored by the Web View.\n root.style.setProperty(key, value, \"important\");\n }\n }\n // For removing user setting.\n removeProperty(key) {\n const root = document.documentElement;\n root.style.removeProperty(key);\n }\n}\n","/**\n * In paginated mode, the width of each resource must be a multiple of the viewport size\n * for proper snapping. This may not be automatically the case if the number of\n * columns in the resource is not a multiple of the number of columns fitting in the viewport.\n * To fix this, we insert a blank virtual column at the end of the resource.\n *\n * Returns if a virtual column has been added or removed.\n */\nexport function appendVirtualColumnIfNeeded(wnd) {\n // FIXME: what about scroll mode?\n const id = \"readium-virtual-page\";\n let virtualCol = wnd.document.getElementById(id);\n if (getColumnCountPerScreen(wnd) !== 2) {\n if (virtualCol) {\n virtualCol.remove();\n return true;\n }\n else {\n return false;\n }\n }\n else {\n const documentWidth = wnd.document.scrollingElement.scrollWidth;\n const colCount = documentWidth / wnd.innerWidth;\n const hasOddColCount = (Math.round(colCount * 2) / 2) % 1 > 0.1;\n if (hasOddColCount) {\n if (virtualCol) {\n virtualCol.remove();\n }\n else {\n virtualCol = wnd.document.createElement(\"div\");\n virtualCol.setAttribute(\"id\", id);\n virtualCol.dataset.readium = \"true\";\n virtualCol.style.breakBefore = \"column\";\n virtualCol.innerHTML = \"​\"; // zero-width space\n wnd.document.body.appendChild(virtualCol);\n }\n return true;\n }\n else {\n return false;\n }\n }\n}\nfunction getColumnCountPerScreen(wnd) {\n return parseInt(wnd\n .getComputedStyle(wnd.document.documentElement)\n .getPropertyValue(\"column-count\"));\n}\n"],"names":["bridgeListener","constructor","gesturesApi","this","nativeApi","onTap","event","JSON","stringify","onLinkActivated","href","outerHtml","window","gestures","gesturesListener","tapEvent","x","clientX","visualViewport","offsetLeft","scale","y","clientY","offsetTop","listener","document","addEventListener","onClick","defaultPrevented","selection","getSelection","type","nearestElement","target","HTMLElement","nearestInteractiveElement","HTMLAnchorElement","outerHTML","stopPropagation","preventDefault","element","indexOf","nodeName","toLowerCase","hasAttribute","getAttribute","parentElement","Window","prototype","readiumcss","setProperties","properties","key","value","setProperty","removeProperty","documentElement","style","documentState","onScriptsLoaded","documentLoadedFired","ResizeObserver","requestAnimationFrame","_a","wnd","id","virtualCol","getElementById","parseInt","getComputedStyle","getPropertyValue","getColumnCountPerScreen","remove","colCount","scrollingElement","scrollWidth","innerWidth","Math","round","createElement","setAttribute","dataset","readium","breakBefore","innerHTML","body","appendChild","appendVirtualColumnIfNeeded","console","log","scrollHeight","onDocumentLoadedAndSized","onDocumentResized","observe"],"sourceRoot":""} \ No newline at end of file From ce7b8f573edd6b554facf09c4f70a357a2da8649 Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Fri, 18 Apr 2025 16:50:03 +0200 Subject: [PATCH 46/88] Small fixes --- .../src/main/java/org/readium/navigator/web/layout/Layout.kt | 2 +- .../java/org/readium/navigator/web/pager/ScrollDispatcher.kt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/layout/Layout.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/layout/Layout.kt index 5b3ca6feff..3e08e7c089 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/layout/Layout.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/layout/Layout.kt @@ -9,7 +9,7 @@ package org.readium.navigator.web.layout import org.readium.r2.navigator.preferences.ReadingProgression import org.readium.r2.shared.util.Url -internal class Layout( +internal data class Layout( val readingProgression: ReadingProgression, val spreads: List, ) { diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollDispatcher.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollDispatcher.kt index da46a3db35..9425e68ec5 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollDispatcher.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollDispatcher.kt @@ -30,8 +30,8 @@ internal class ScrollDispatcher( internal var flingBehavior: Fling2DBehavior, ) : Scroll2DScope { - override fun scrollBy(available: Offset): Offset { - return -rawScrollBy(-available.mainAxisValue).mainAxisOffset + override fun scrollBy(pixels: Offset): Offset { + return -rawScrollBy(-pixels.mainAxisValue).mainAxisOffset } private fun rawScrollBy(available: Float): Float { From c1d5b1d16fbc4aeccfea7737f73be6fc426f49c0 Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Sun, 20 Apr 2025 16:29:25 +0200 Subject: [PATCH 47/88] Fix scroll issue in fixed layout --- .../scripts/src/bridge/all-document-bridge.ts | 5 --- .../scripts/src/bridge/all-gestures-bridge.ts | 27 ---------------- .../scripts/src/bridge/fixed-double-bridge.ts | 15 +++++++-- .../scripts/src/bridge/fixed-single-bridge.ts | 15 +++++++-- .../web/scripts/src/fixed/area-manager.ts | 1 + .../scripts/src/fixed/double-area-manager.ts | 6 ++++ .../scripts/src/fixed/single-area-manager.ts | 6 ++++ .../web/scripts/src/index-fixed-double.ts | 10 ++---- .../web/scripts/src/index-fixed-single.ts | 10 ++---- .../src/index-reflowable-injectable.ts | 23 +++----------- .../web/generated/fixed-double-script.js | 2 +- .../web/generated/fixed-double-script.js.map | 2 +- .../web/generated/fixed-single-script.js | 2 +- .../web/generated/fixed-single-script.js.map | 2 +- .../generated/reflowable-injectable-script.js | 2 +- .../reflowable-injectable-script.js.map | 2 +- .../navigator/web/FixedWebRendition.kt | 16 +++++++--- .../web/ReflowableWebRenditionState.kt | 2 +- .../web/fixed/DoubleViewportSpread.kt | 2 ++ .../web/fixed/SingleViewportSpread.kt | 6 +++- .../navigator/web/fixed/SpreadWebView.kt | 26 ++++++++++++++++ .../navigator/web/pager/ScrollDispatcher.kt | 31 +++++++++++++++++++ .../web/reflowable/ReflowableResource.kt | 2 +- .../web/webview/WebViewScrollController.kt | 27 +++++++++------- 24 files changed, 147 insertions(+), 95 deletions(-) delete mode 100644 readium/navigators/web/scripts/src/bridge/all-document-bridge.ts delete mode 100644 readium/navigators/web/scripts/src/bridge/all-gestures-bridge.ts diff --git a/readium/navigators/web/scripts/src/bridge/all-document-bridge.ts b/readium/navigators/web/scripts/src/bridge/all-document-bridge.ts deleted file mode 100644 index 0acb0b48d4..0000000000 --- a/readium/navigators/web/scripts/src/bridge/all-document-bridge.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface DocumentBridge { - onScriptsLoaded: () => void - onDocumentLoadedAndSized: () => void - onDocumentResized: () => void -} diff --git a/readium/navigators/web/scripts/src/bridge/all-gestures-bridge.ts b/readium/navigators/web/scripts/src/bridge/all-gestures-bridge.ts deleted file mode 100644 index b6c9530a7e..0000000000 --- a/readium/navigators/web/scripts/src/bridge/all-gestures-bridge.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { AreaManager } from "../fixed/area-manager" - -export interface GesturesBridge { - onTap(event: string): void - onLinkActivated(href: string, outerHtml: string): void -} - -export interface TapEvent { - x: number - y: number -} - -export class BridgeGesturesAdapter implements AreaManager.Listener { - readonly nativeApi: GesturesBridge - - constructor(gesturesApi: GesturesBridge) { - this.nativeApi = gesturesApi - } - - onTap(event: TapEvent): void { - this.nativeApi.onTap(JSON.stringify(event)) - } - - onLinkActivated(href: string, outerHtml: string): void { - this.nativeApi.onLinkActivated(href, outerHtml) - } -} diff --git a/readium/navigators/web/scripts/src/bridge/fixed-double-bridge.ts b/readium/navigators/web/scripts/src/bridge/fixed-double-bridge.ts index b011a24fcc..8072eb4804 100644 --- a/readium/navigators/web/scripts/src/bridge/fixed-double-bridge.ts +++ b/readium/navigators/web/scripts/src/bridge/fixed-double-bridge.ts @@ -1,6 +1,10 @@ import { Insets, Size } from "../common/types" import { DoubleAreaManager } from "../fixed/double-area-manager" -import { GesturesBridge, BridgeGesturesAdapter } from "./all-gestures-bridge" +import { + GesturesBridge, + FixedListenerAdapter, + DocumentBridge, +} from "./all-listener-bridge" import { Fit } from "../util/fit" export class FixedDoubleBridge { @@ -11,9 +15,14 @@ export class FixedDoubleBridge { leftIframe: HTMLIFrameElement, rightIframe: HTMLIFrameElement, metaViewport: HTMLMetaElement, - gestures: GesturesBridge + gesturesBridge: GesturesBridge, + documentBridge: DocumentBridge ) { - const listener = new BridgeGesturesAdapter(gestures) + const listener = new FixedListenerAdapter( + window, + gesturesBridge, + documentBridge + ) this.manager = new DoubleAreaManager( window, leftIframe, diff --git a/readium/navigators/web/scripts/src/bridge/fixed-single-bridge.ts b/readium/navigators/web/scripts/src/bridge/fixed-single-bridge.ts index 97488a7737..6259ff70ef 100644 --- a/readium/navigators/web/scripts/src/bridge/fixed-single-bridge.ts +++ b/readium/navigators/web/scripts/src/bridge/fixed-single-bridge.ts @@ -1,7 +1,11 @@ import { Insets, Size } from "../common/types" import { SingleAreaManager } from "../fixed/single-area-manager" import { Fit } from "../util/fit" -import { GesturesBridge, BridgeGesturesAdapter } from "./all-gestures-bridge" +import { + GesturesBridge, + FixedListenerAdapter, + DocumentBridge, +} from "./all-listener-bridge" export class FixedSingleBridge { private readonly manager: SingleAreaManager @@ -10,9 +14,14 @@ export class FixedSingleBridge { window: Window, iframe: HTMLIFrameElement, metaViewport: HTMLMetaElement, - gestures: GesturesBridge + gesturesBridge: GesturesBridge, + documentBridge: DocumentBridge ) { - const listener = new BridgeGesturesAdapter(gestures) + const listener = new FixedListenerAdapter( + window, + gesturesBridge, + documentBridge + ) this.manager = new SingleAreaManager(window, iframe, metaViewport, listener) } diff --git a/readium/navigators/web/scripts/src/fixed/area-manager.ts b/readium/navigators/web/scripts/src/fixed/area-manager.ts index 92f8d2e524..8f601da0b2 100644 --- a/readium/navigators/web/scripts/src/fixed/area-manager.ts +++ b/readium/navigators/web/scripts/src/fixed/area-manager.ts @@ -4,5 +4,6 @@ export namespace AreaManager { export interface Listener { onTap(event: TapEvent): void onLinkActivated(href: string, outerHtml: string): void + onLayout(): void } } diff --git a/readium/navigators/web/scripts/src/fixed/double-area-manager.ts b/readium/navigators/web/scripts/src/fixed/double-area-manager.ts index 8dc3c0cf7e..72eec96b5f 100644 --- a/readium/navigators/web/scripts/src/fixed/double-area-manager.ts +++ b/readium/navigators/web/scripts/src/fixed/double-area-manager.ts @@ -13,6 +13,8 @@ export class DoubleAreaManager { private readonly rightPage: PageManager + private readonly listener: AreaManager.Listener + private fit: Fit = Fit.Contain private insets: Insets = { top: 0, right: 0, bottom: 0, left: 0 } @@ -28,6 +30,8 @@ export class DoubleAreaManager { metaViewport: HTMLMetaElement, listener: AreaManager.Listener ) { + this.listener = listener + window.addEventListener("message", (event) => { if (!event.ports[0]) { return @@ -188,5 +192,7 @@ export class DoubleAreaManager { this.leftPage.show() this.rightPage.show() + + this.listener.onLayout() } } diff --git a/readium/navigators/web/scripts/src/fixed/single-area-manager.ts b/readium/navigators/web/scripts/src/fixed/single-area-manager.ts index 694e15c835..4fe9e0b8fe 100644 --- a/readium/navigators/web/scripts/src/fixed/single-area-manager.ts +++ b/readium/navigators/web/scripts/src/fixed/single-area-manager.ts @@ -11,6 +11,8 @@ export class SingleAreaManager { private readonly page: PageManager + private readonly listener: AreaManager.Listener + private fit: Fit = Fit.Contain private insets: Insets = { top: 0, right: 0, bottom: 0, left: 0 } @@ -25,6 +27,8 @@ export class SingleAreaManager { metaViewport: HTMLMetaElement, listener: AreaManager.Listener ) { + this.listener = listener + window.addEventListener("message", (event) => { if (event.source === iframe.contentWindow && event.ports[0]) { this.page.setMessagePort(event.ports[0]) @@ -135,5 +139,7 @@ export class SingleAreaManager { this.scale = scale this.page.show() + + this.listener.onLayout() } } diff --git a/readium/navigators/web/scripts/src/index-fixed-double.ts b/readium/navigators/web/scripts/src/index-fixed-double.ts index 7aad79498e..0f7f28ae3b 100644 --- a/readium/navigators/web/scripts/src/index-fixed-double.ts +++ b/readium/navigators/web/scripts/src/index-fixed-double.ts @@ -8,9 +8,8 @@ * Script loaded by the single area HTML wrapper for fixed layout resources. */ -import { GesturesBridge } from "./bridge/all-gestures-bridge" +import { DocumentBridge, GesturesBridge } from "./bridge/all-listener-bridge" import { FixedDoubleBridge } from "./bridge/fixed-double-bridge" -import { DocumentBridge } from "./bridge/all-document-bridge" declare global { interface Window { @@ -33,11 +32,8 @@ Window.prototype.doubleArea = new FixedDoubleBridge( leftIframe, rightIframe, metaViewport, - window.gestures + window.gestures, + window.documentState ) window.documentState.onScriptsLoaded() -// eslint-disable-next-line @typescript-eslint/no-unused-vars -window.addEventListener("load", (event) => { - window.documentState.onDocumentLoadedAndSized() -}) diff --git a/readium/navigators/web/scripts/src/index-fixed-single.ts b/readium/navigators/web/scripts/src/index-fixed-single.ts index a83d0957f2..6c0a11f320 100644 --- a/readium/navigators/web/scripts/src/index-fixed-single.ts +++ b/readium/navigators/web/scripts/src/index-fixed-single.ts @@ -8,8 +8,7 @@ * Script loaded by the single area HTML wrapper for fixed layout resources. */ -import { GesturesBridge } from "./bridge/all-gestures-bridge" -import { DocumentBridge } from "./bridge/all-document-bridge" +import { DocumentBridge, GesturesBridge } from "./bridge/all-listener-bridge" import { FixedSingleBridge } from "./bridge/fixed-single-bridge" declare global { @@ -30,11 +29,8 @@ window.singleArea = new FixedSingleBridge( window, iframe, metaViewport, - window.gestures + window.gestures, + window.documentState ) window.documentState.onScriptsLoaded() -// eslint-disable-next-line @typescript-eslint/no-unused-vars -window.addEventListener("load", (event) => { - window.documentState.onDocumentLoadedAndSized() -}) diff --git a/readium/navigators/web/scripts/src/index-reflowable-injectable.ts b/readium/navigators/web/scripts/src/index-reflowable-injectable.ts index bbec440e77..677baeee65 100644 --- a/readium/navigators/web/scripts/src/index-reflowable-injectable.ts +++ b/readium/navigators/web/scripts/src/index-reflowable-injectable.ts @@ -9,10 +9,10 @@ */ import { - BridgeGesturesAdapter, + ReflowableListenerAdapter, GesturesBridge, -} from "./bridge/all-gestures-bridge" -import { DocumentBridge } from "./bridge/all-document-bridge" +} from "./bridge/all-listener-bridge" +import { DocumentBridge } from "./bridge/all-listener-bridge" import { CssBridge } from "./bridge/reflowable-css-bridge" import { GesturesDetector } from "./common/gestures" import { appendVirtualColumnIfNeeded } from "./util/columns" @@ -25,22 +25,9 @@ declare global { } } -const bridgeListener = new BridgeGesturesAdapter(window.gestures) +const bridgeListener = new ReflowableListenerAdapter(window.gestures) -const gesturesListener = { - onTap: (event: MouseEvent) => { - const tapEvent = { - x: (event.clientX - visualViewport!.offsetLeft) * visualViewport!.scale, - y: (event.clientY - visualViewport!.offsetTop) * visualViewport!.scale, - } - bridgeListener.onTap(tapEvent) - }, - onLinkActivated: (href: string, outerHtml: string) => { - bridgeListener.onLinkActivated(href, outerHtml) - }, -} - -new GesturesDetector(window, gesturesListener) +new GesturesDetector(window, bridgeListener) Window.prototype.readiumcss = new CssBridge(window.document) diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-double-script.js b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-double-script.js index 19c28ab244..7587ebe28a 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-double-script.js +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-double-script.js @@ -1,2 +1,2 @@ -!function(){"use strict";class t{constructor(t,e,i){if(this.margins={top:0,right:0,bottom:0,left:0},!e.contentWindow)throw Error("Iframe argument must have been attached to DOM.");this.listener=i,this.iframe=e}setMessagePort(t){t.onmessage=t=>{this.onMessageFromIframe(t)}}show(){this.iframe.style.display="unset"}hide(){this.iframe.style.display="none"}setMargins(t){this.margins!=t&&(this.iframe.style.marginTop=this.margins.top+"px",this.iframe.style.marginLeft=this.margins.left+"px",this.iframe.style.marginBottom=this.margins.bottom+"px",this.iframe.style.marginRight=this.margins.right+"px")}loadPage(t){this.iframe.src=t}setPlaceholder(t){this.iframe.style.visibility="hidden",this.iframe.style.width=t.width+"px",this.iframe.style.height=t.height+"px",this.size=t}onMessageFromIframe(t){const e=t.data;switch(e.kind){case"contentSize":return this.onContentSizeAvailable(e.size);case"tap":return this.listener.onTap({x:e.x,y:e.y});case"linkActivated":return this.onLinkActivated(e)}}onLinkActivated(t){try{const e=new URL(t.href,this.iframe.src);this.listener.onLinkActivated(e.toString(),t.outerHtml)}catch(t){}}onContentSizeAvailable(t){t&&(this.iframe.style.width=t.width+"px",this.iframe.style.height=t.height+"px",this.size=t,this.listener.onIframeLoaded())}}class e{setInitialScale(t){return this.initialScale=t,this}setMinimumScale(t){return this.minimumScale=t,this}setWidth(t){return this.width=t,this}setHeight(t){return this.height=t,this}build(){const t=[];return this.initialScale&&t.push("initial-scale="+this.initialScale),this.minimumScale&&t.push("minimum-scale="+this.minimumScale),this.width&&t.push("width="+this.width),this.height&&t.push("height="+this.height),t.join(", ")}}class i{constructor(t,e){this.window=t,this.listener=e,document.addEventListener("click",(t=>{this.onClick(t)}),!1)}onClick(t){if(t.defaultPrevented)return;const e=this.window.getSelection();if(e&&"Range"==e.type)return;let i;i=t.target instanceof HTMLElement?this.nearestInteractiveElement(t.target):null,i?i instanceof HTMLAnchorElement&&this.listener.onLinkActivated(i.href,i.outerHTML):this.listener.onTap(t),t.stopPropagation(),t.preventDefault()}nearestInteractiveElement(t){return null==t?null:-1!=["a","audio","button","canvas","details","input","label","option","select","submit","textarea","video"].indexOf(t.nodeName.toLowerCase())||t.hasAttribute("contenteditable")&&"false"!=t.getAttribute("contenteditable").toLowerCase()?t:t.parentElement?this.nearestInteractiveElement(t.parentElement):null}}class s{constructor(e,s,n,a,h){this.fit="contain",this.insets={top:0,right:0,bottom:0,left:0},e.addEventListener("message",(t=>{t.ports[0]&&(t.source===s.contentWindow?this.leftPage.setMessagePort(t.ports[0]):t.source==n.contentWindow&&this.rightPage.setMessagePort(t.ports[0]))})),new i(e,{onTap:t=>{const e={x:(t.clientX-visualViewport.offsetLeft)*visualViewport.scale,y:(t.clientY-visualViewport.offsetTop)*visualViewport.scale};h.onTap(e)},onLinkActivated:t=>{throw Error("No interactive element in the root document.")}});const o={onIframeLoaded:()=>{this.layout()},onTap:t=>{const e=s.getBoundingClientRect(),i={x:(t.x+e.left-visualViewport.offsetLeft)*visualViewport.scale,y:(t.y+e.top-visualViewport.offsetTop)*visualViewport.scale};h.onTap(i)},onLinkActivated:(t,e)=>{h.onLinkActivated(t,e)}},r={onIframeLoaded:()=>{this.layout()},onTap:t=>{const e=n.getBoundingClientRect(),i={x:(t.x+e.left-visualViewport.offsetLeft)*visualViewport.scale,y:(t.y+e.top-visualViewport.offsetTop)*visualViewport.scale};h.onTap(i)},onLinkActivated:(t,e)=>{h.onLinkActivated(t,e)}};this.leftPage=new t(e,s,o),this.rightPage=new t(e,n,r),this.metaViewport=a}loadSpread(t){this.leftPage.hide(),this.rightPage.hide(),this.spread=t,t.left&&this.leftPage.loadPage(t.left),t.right&&this.rightPage.loadPage(t.right)}setViewport(t,e){this.viewport==t&&this.insets==e||(this.viewport=t,this.insets=e,this.layout())}setFit(t){this.fit!=t&&(this.fit=t,this.layout())}layout(){if(!this.viewport||!this.leftPage.size&&this.spread.left||!this.rightPage.size&&this.spread.right)return;const t={top:this.insets.top,right:0,bottom:this.insets.bottom,left:this.insets.left};this.leftPage.setMargins(t);const i={top:this.insets.top,right:this.insets.right,bottom:this.insets.bottom,left:0};this.rightPage.setMargins(i),this.spread.right?this.spread.left||this.leftPage.setPlaceholder(this.rightPage.size):this.rightPage.setPlaceholder(this.leftPage.size);const s=this.leftPage.size.width+this.rightPage.size.width,n=Math.max(this.leftPage.size.height,this.rightPage.size.height),a={width:s,height:n},h={width:this.viewport.width-this.insets.left-this.insets.right,height:this.viewport.height-this.insets.top-this.insets.bottom},o=function(t,e,i){switch(t){case"contain":return function(t,e){const i=e.width/t.width,s=e.height/t.height;return Math.min(i,s)}(e,i);case"width":return function(t,e){return e.width/t.width}(e,i);case"height":return function(t,e){return e.height/t.height}(e,i)}}(this.fit,a,h);this.metaViewport.content=(new e).setInitialScale(o).setMinimumScale(o).setWidth(s).setHeight(n).build(),this.leftPage.show(),this.rightPage.show()}}class n{constructor(t){this.nativeApi=t}onTap(t){this.nativeApi.onTap(JSON.stringify(t))}onLinkActivated(t,e){this.nativeApi.onLinkActivated(t,e)}}const a=document.getElementById("page-left"),h=document.getElementById("page-right"),o=document.querySelector("meta[name=viewport]");Window.prototype.doubleArea=new class{constructor(t,e,i,a,h){const o=new n(h);this.manager=new s(t,e,i,a,o)}loadSpread(t){this.manager.loadSpread(t)}setViewport(t,e,i,s,n,a){const h={width:t,height:e},o={top:i,left:a,bottom:n,right:s};this.manager.setViewport(h,o)}setFit(t){if("contain"!=t&&"width"!=t&&"height"!=t)throw Error(`Invalid fit value: ${t}`);this.manager.setFit(t)}}(window,a,h,o,window.gestures),window.documentState.onScriptsLoaded(),window.addEventListener("load",(t=>{window.documentState.onDocumentLoadedAndSized()}))}(); +!function(){"use strict";class t{constructor(t,e,i){if(this.margins={top:0,right:0,bottom:0,left:0},!e.contentWindow)throw Error("Iframe argument must have been attached to DOM.");this.listener=i,this.iframe=e}setMessagePort(t){t.onmessage=t=>{this.onMessageFromIframe(t)}}show(){this.iframe.style.display="unset"}hide(){this.iframe.style.display="none"}setMargins(t){this.margins!=t&&(this.iframe.style.marginTop=this.margins.top+"px",this.iframe.style.marginLeft=this.margins.left+"px",this.iframe.style.marginBottom=this.margins.bottom+"px",this.iframe.style.marginRight=this.margins.right+"px")}loadPage(t){this.iframe.src=t}setPlaceholder(t){this.iframe.style.visibility="hidden",this.iframe.style.width=t.width+"px",this.iframe.style.height=t.height+"px",this.size=t}onMessageFromIframe(t){const e=t.data;switch(e.kind){case"contentSize":return this.onContentSizeAvailable(e.size);case"tap":return this.listener.onTap({x:e.x,y:e.y});case"linkActivated":return this.onLinkActivated(e)}}onLinkActivated(t){try{const e=new URL(t.href,this.iframe.src);this.listener.onLinkActivated(e.toString(),t.outerHtml)}catch(t){}}onContentSizeAvailable(t){t&&(this.iframe.style.width=t.width+"px",this.iframe.style.height=t.height+"px",this.size=t,this.listener.onIframeLoaded())}}class e{setInitialScale(t){return this.initialScale=t,this}setMinimumScale(t){return this.minimumScale=t,this}setWidth(t){return this.width=t,this}setHeight(t){return this.height=t,this}build(){const t=[];return this.initialScale&&t.push("initial-scale="+this.initialScale),this.minimumScale&&t.push("minimum-scale="+this.minimumScale),this.width&&t.push("width="+this.width),this.height&&t.push("height="+this.height),t.join(", ")}}class i{constructor(t,e){this.window=t,this.listener=e,document.addEventListener("click",(t=>{this.onClick(t)}),!1)}onClick(t){if(t.defaultPrevented)return;const e=this.window.getSelection();if(e&&"Range"==e.type)return;let i;i=t.target instanceof HTMLElement?this.nearestInteractiveElement(t.target):null,i?i instanceof HTMLAnchorElement&&this.listener.onLinkActivated(i.href,i.outerHTML):this.listener.onTap(t),t.stopPropagation(),t.preventDefault()}nearestInteractiveElement(t){return null==t?null:-1!=["a","audio","button","canvas","details","input","label","option","select","submit","textarea","video"].indexOf(t.nodeName.toLowerCase())||t.hasAttribute("contenteditable")&&"false"!=t.getAttribute("contenteditable").toLowerCase()?t:t.parentElement?this.nearestInteractiveElement(t.parentElement):null}}class s{constructor(e,s,n,o,h){this.fit="contain",this.insets={top:0,right:0,bottom:0,left:0},this.listener=h,e.addEventListener("message",(t=>{t.ports[0]&&(t.source===s.contentWindow?this.leftPage.setMessagePort(t.ports[0]):t.source==n.contentWindow&&this.rightPage.setMessagePort(t.ports[0]))})),new i(e,{onTap:t=>{const e={x:(t.clientX-visualViewport.offsetLeft)*visualViewport.scale,y:(t.clientY-visualViewport.offsetTop)*visualViewport.scale};h.onTap(e)},onLinkActivated:t=>{throw Error("No interactive element in the root document.")}});const a={onIframeLoaded:()=>{this.layout()},onTap:t=>{const e=s.getBoundingClientRect(),i={x:(t.x+e.left-visualViewport.offsetLeft)*visualViewport.scale,y:(t.y+e.top-visualViewport.offsetTop)*visualViewport.scale};h.onTap(i)},onLinkActivated:(t,e)=>{h.onLinkActivated(t,e)}},r={onIframeLoaded:()=>{this.layout()},onTap:t=>{const e=n.getBoundingClientRect(),i={x:(t.x+e.left-visualViewport.offsetLeft)*visualViewport.scale,y:(t.y+e.top-visualViewport.offsetTop)*visualViewport.scale};h.onTap(i)},onLinkActivated:(t,e)=>{h.onLinkActivated(t,e)}};this.leftPage=new t(e,s,a),this.rightPage=new t(e,n,r),this.metaViewport=o}loadSpread(t){this.leftPage.hide(),this.rightPage.hide(),this.spread=t,t.left&&this.leftPage.loadPage(t.left),t.right&&this.rightPage.loadPage(t.right)}setViewport(t,e){this.viewport==t&&this.insets==e||(this.viewport=t,this.insets=e,this.layout())}setFit(t){this.fit!=t&&(this.fit=t,this.layout())}layout(){if(!this.viewport||!this.leftPage.size&&this.spread.left||!this.rightPage.size&&this.spread.right)return;const t={top:this.insets.top,right:0,bottom:this.insets.bottom,left:this.insets.left};this.leftPage.setMargins(t);const i={top:this.insets.top,right:this.insets.right,bottom:this.insets.bottom,left:0};this.rightPage.setMargins(i),this.spread.right?this.spread.left||this.leftPage.setPlaceholder(this.rightPage.size):this.rightPage.setPlaceholder(this.leftPage.size);const s=this.leftPage.size.width+this.rightPage.size.width,n=Math.max(this.leftPage.size.height,this.rightPage.size.height),o={width:s,height:n},h={width:this.viewport.width-this.insets.left-this.insets.right,height:this.viewport.height-this.insets.top-this.insets.bottom},a=function(t,e,i){switch(t){case"contain":return function(t,e){const i=e.width/t.width,s=e.height/t.height;return Math.min(i,s)}(e,i);case"width":return function(t,e){return e.width/t.width}(e,i);case"height":return function(t,e){return e.height/t.height}(e,i)}}(this.fit,o,h);this.metaViewport.content=(new e).setInitialScale(a).setMinimumScale(a).setWidth(s).setHeight(n).build(),this.leftPage.show(),this.rightPage.show(),this.listener.onLayout()}}class n{constructor(t,e,i){this.window=t,this.gesturesApi=e,this.documentApi=i,this.resizeObserverAdded=!1,this.documentLoadedFired=!1}onTap(t){this.gesturesApi.onTap(JSON.stringify(t))}onLinkActivated(t,e){this.gesturesApi.onLinkActivated(t,e)}onLayout(){this.resizeObserverAdded||new ResizeObserver((()=>{requestAnimationFrame((()=>{const t=this.window.document.scrollingElement;!this.documentLoadedFired&&(null==t||t.scrollHeight>0||t.scrollWidth>0)?(this.documentApi.onDocumentLoadedAndSized(),this.documentLoadedFired=!0):this.documentApi.onDocumentResized()}))})).observe(this.window.document.body),this.resizeObserverAdded=!0}}const o=document.getElementById("page-left"),h=document.getElementById("page-right"),a=document.querySelector("meta[name=viewport]");Window.prototype.doubleArea=new class{constructor(t,e,i,o,h,a){const r=new n(t,h,a);this.manager=new s(t,e,i,o,r)}loadSpread(t){this.manager.loadSpread(t)}setViewport(t,e,i,s,n,o){const h={width:t,height:e},a={top:i,left:o,bottom:n,right:s};this.manager.setViewport(h,a)}setFit(t){if("contain"!=t&&"width"!=t&&"height"!=t)throw Error(`Invalid fit value: ${t}`);this.manager.setFit(t)}}(window,o,h,a,window.gestures,window.documentState),window.documentState.onScriptsLoaded()}(); //# sourceMappingURL=fixed-double-script.js.map \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-double-script.js.map b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-double-script.js.map index ed6bda5bc7..d9e81fe3a1 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-double-script.js.map +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-double-script.js.map @@ -1 +1 @@ -{"version":3,"file":"fixed-double-script.js","mappings":"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","sources":["webpack://readium-js/./src/fixed/page-manager.ts","webpack://readium-js/./src/util/viewport.ts","webpack://readium-js/./src/common/gestures.ts","webpack://readium-js/./src/fixed/double-area-manager.ts","webpack://readium-js/./src/util/fit.ts","webpack://readium-js/./src/bridge/all-gestures-bridge.ts","webpack://readium-js/./src/index-fixed-double.ts","webpack://readium-js/./src/bridge/fixed-double-bridge.ts"],"sourcesContent":["/** Manages a fixed layout resource embedded in an iframe. */\nexport class PageManager {\n constructor(window, iframe, listener) {\n this.margins = { top: 0, right: 0, bottom: 0, left: 0 };\n if (!iframe.contentWindow) {\n throw Error(\"Iframe argument must have been attached to DOM.\");\n }\n this.listener = listener;\n this.iframe = iframe;\n }\n setMessagePort(messagePort) {\n messagePort.onmessage = (message) => {\n this.onMessageFromIframe(message);\n };\n }\n show() {\n this.iframe.style.display = \"unset\";\n }\n hide() {\n this.iframe.style.display = \"none\";\n }\n /** Sets page margins. */\n setMargins(margins) {\n if (this.margins == margins) {\n return;\n }\n this.iframe.style.marginTop = this.margins.top + \"px\";\n this.iframe.style.marginLeft = this.margins.left + \"px\";\n this.iframe.style.marginBottom = this.margins.bottom + \"px\";\n this.iframe.style.marginRight = this.margins.right + \"px\";\n }\n /** Loads page content. */\n loadPage(url) {\n this.iframe.src = url;\n }\n /** Sets the size of this page without content. */\n setPlaceholder(size) {\n this.iframe.style.visibility = \"hidden\";\n this.iframe.style.width = size.width + \"px\";\n this.iframe.style.height = size.height + \"px\";\n this.size = size;\n }\n onMessageFromIframe(event) {\n const message = event.data;\n switch (message.kind) {\n case \"contentSize\":\n return this.onContentSizeAvailable(message.size);\n case \"tap\":\n return this.listener.onTap({ x: message.x, y: message.y });\n case \"linkActivated\":\n return this.onLinkActivated(message);\n }\n }\n onLinkActivated(message) {\n try {\n const url = new URL(message.href, this.iframe.src);\n this.listener.onLinkActivated(url.toString(), message.outerHtml);\n }\n catch (_a) {\n // Do nothing if url is not valid.\n }\n }\n onContentSizeAvailable(size) {\n if (!size) {\n //FIXME: handle edge case\n return;\n }\n this.iframe.style.width = size.width + \"px\";\n this.iframe.style.height = size.height + \"px\";\n this.size = size;\n this.listener.onIframeLoaded();\n }\n}\n","export class ViewportStringBuilder {\n setInitialScale(scale) {\n this.initialScale = scale;\n return this;\n }\n setMinimumScale(scale) {\n this.minimumScale = scale;\n return this;\n }\n setWidth(width) {\n this.width = width;\n return this;\n }\n setHeight(height) {\n this.height = height;\n return this;\n }\n build() {\n const components = [];\n if (this.initialScale) {\n components.push(\"initial-scale=\" + this.initialScale);\n }\n if (this.minimumScale) {\n components.push(\"minimum-scale=\" + this.minimumScale);\n }\n if (this.width) {\n components.push(\"width=\" + this.width);\n }\n if (this.height) {\n components.push(\"height=\" + this.height);\n }\n return components.join(\", \");\n }\n}\nexport function parseViewportString(viewportString) {\n const regex = /(\\w+) *= *([^\\s,]+)/g;\n const properties = new Map();\n let match;\n while ((match = regex.exec(viewportString))) {\n if (match != null) {\n properties.set(match[1], match[2]);\n }\n }\n const width = parseFloat(properties.get(\"width\"));\n const height = parseFloat(properties.get(\"height\"));\n if (width && height) {\n return { width, height };\n }\n else {\n return undefined;\n }\n}\n","export class GesturesDetector {\n constructor(window, listener) {\n this.window = window;\n this.listener = listener;\n document.addEventListener(\"click\", (event) => {\n this.onClick(event);\n }, false);\n }\n onClick(event) {\n if (event.defaultPrevented) {\n return;\n }\n const selection = this.window.getSelection();\n if (selection && selection.type == \"Range\") {\n // There's an on-going selection, the tap will dismiss it so we don't forward it.\n // selection.type might be None (collapsed) or Caret with a collapsed range\n // when there is not true selection.\n return;\n }\n let nearestElement;\n if (event.target instanceof HTMLElement) {\n nearestElement = this.nearestInteractiveElement(event.target);\n }\n else {\n nearestElement = null;\n }\n if (nearestElement) {\n if (nearestElement instanceof HTMLAnchorElement) {\n this.listener.onLinkActivated(nearestElement.href, nearestElement.outerHTML);\n }\n }\n else {\n this.listener.onTap(event);\n }\n event.stopPropagation();\n event.preventDefault();\n }\n // See. https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling\n nearestInteractiveElement(element) {\n if (element == null) {\n return null;\n }\n const interactiveTags = [\n \"a\",\n \"audio\",\n \"button\",\n \"canvas\",\n \"details\",\n \"input\",\n \"label\",\n \"option\",\n \"select\",\n \"submit\",\n \"textarea\",\n \"video\",\n ];\n if (interactiveTags.indexOf(element.nodeName.toLowerCase()) != -1) {\n return element;\n }\n // Checks whether the element is editable by the user.\n if (element.hasAttribute(\"contenteditable\") &&\n element.getAttribute(\"contenteditable\").toLowerCase() != \"false\") {\n return element;\n }\n // Checks parents recursively because the touch might be for example on an inside a .\n if (element.parentElement) {\n return this.nearestInteractiveElement(element.parentElement);\n }\n return null;\n }\n}\n","import { computeScale } from \"../util/fit\";\nimport { PageManager } from \"./page-manager\";\nimport { ViewportStringBuilder } from \"../util/viewport\";\nimport { GesturesDetector } from \"../common/gestures\";\nexport class DoubleAreaManager {\n constructor(window, leftIframe, rightIframe, metaViewport, listener) {\n this.fit = \"contain\" /* Fit.Contain */;\n this.insets = { top: 0, right: 0, bottom: 0, left: 0 };\n window.addEventListener(\"message\", (event) => {\n if (!event.ports[0]) {\n return;\n }\n if (event.source === leftIframe.contentWindow) {\n this.leftPage.setMessagePort(event.ports[0]);\n }\n else if (event.source == rightIframe.contentWindow) {\n this.rightPage.setMessagePort(event.ports[0]);\n }\n });\n const wrapperGesturesListener = {\n onTap: (event) => {\n const tapEvent = {\n x: (event.clientX - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.clientY - visualViewport.offsetTop) * visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onLinkActivated: (_) => {\n throw Error(\"No interactive element in the root document.\");\n },\n };\n new GesturesDetector(window, wrapperGesturesListener);\n const leftPageListener = {\n onIframeLoaded: () => {\n this.layout();\n },\n onTap: (event) => {\n const boundingRect = leftIframe.getBoundingClientRect();\n const tapEvent = {\n x: (event.x + boundingRect.left - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.y + boundingRect.top - visualViewport.offsetTop) *\n visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n listener.onLinkActivated(href, outerHtml);\n },\n };\n const rightPageListener = {\n onIframeLoaded: () => {\n this.layout();\n },\n onTap: (event) => {\n const boundingRect = rightIframe.getBoundingClientRect();\n const tapEvent = {\n x: (event.x + boundingRect.left - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.y + boundingRect.top - visualViewport.offsetTop) *\n visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n listener.onLinkActivated(href, outerHtml);\n },\n };\n this.leftPage = new PageManager(window, leftIframe, leftPageListener);\n this.rightPage = new PageManager(window, rightIframe, rightPageListener);\n this.metaViewport = metaViewport;\n }\n loadSpread(spread) {\n this.leftPage.hide();\n this.rightPage.hide();\n this.spread = spread;\n if (spread.left) {\n this.leftPage.loadPage(spread.left);\n }\n if (spread.right) {\n this.rightPage.loadPage(spread.right);\n }\n }\n setViewport(size, insets) {\n if (this.viewport == size && this.insets == insets) {\n return;\n }\n this.viewport = size;\n this.insets = insets;\n this.layout();\n }\n setFit(fit) {\n if (this.fit == fit) {\n return;\n }\n this.fit = fit;\n this.layout();\n }\n layout() {\n if (!this.viewport ||\n (!this.leftPage.size && this.spread.left) ||\n (!this.rightPage.size && this.spread.right)) {\n return;\n }\n const leftMargins = {\n top: this.insets.top,\n right: 0,\n bottom: this.insets.bottom,\n left: this.insets.left,\n };\n this.leftPage.setMargins(leftMargins);\n const rightMargins = {\n top: this.insets.top,\n right: this.insets.right,\n bottom: this.insets.bottom,\n left: 0,\n };\n this.rightPage.setMargins(rightMargins);\n if (!this.spread.right) {\n this.rightPage.setPlaceholder(this.leftPage.size);\n }\n else if (!this.spread.left) {\n this.leftPage.setPlaceholder(this.rightPage.size);\n }\n const contentWidth = this.leftPage.size.width + this.rightPage.size.width;\n const contentHeight = Math.max(this.leftPage.size.height, this.rightPage.size.height);\n const contentSize = { width: contentWidth, height: contentHeight };\n const safeDrawingSize = {\n width: this.viewport.width - this.insets.left - this.insets.right,\n height: this.viewport.height - this.insets.top - this.insets.bottom,\n };\n const scale = computeScale(this.fit, contentSize, safeDrawingSize);\n this.metaViewport.content = new ViewportStringBuilder()\n .setInitialScale(scale)\n .setMinimumScale(scale)\n .setWidth(contentWidth)\n .setHeight(contentHeight)\n .build();\n this.leftPage.show();\n this.rightPage.show();\n }\n}\n","export function computeScale(fit, content, container) {\n switch (fit) {\n case \"contain\" /* Fit.Contain */:\n return fitContain(content, container);\n case \"width\" /* Fit.Width */:\n return fitWidth(content, container);\n case \"height\" /* Fit.Height */:\n return fitHeight(content, container);\n }\n}\nfunction fitContain(content, container) {\n const widthRatio = container.width / content.width;\n const heightRatio = container.height / content.height;\n return Math.min(widthRatio, heightRatio);\n}\nfunction fitWidth(content, container) {\n return container.width / content.width;\n}\nfunction fitHeight(content, container) {\n return container.height / content.height;\n}\n","export class BridgeGesturesAdapter {\n constructor(gesturesApi) {\n this.nativeApi = gesturesApi;\n }\n onTap(event) {\n this.nativeApi.onTap(JSON.stringify(event));\n }\n onLinkActivated(href, outerHtml) {\n this.nativeApi.onLinkActivated(href, outerHtml);\n }\n}\n","//\n// Copyright 2024 Readium Foundation. All rights reserved.\n// Use of this source code is governed by the BSD-style license\n// available in the top-level LICENSE file of the project.\n//\nimport { FixedDoubleBridge } from \"./bridge/fixed-double-bridge\";\nconst leftIframe = document.getElementById(\"page-left\");\nconst rightIframe = document.getElementById(\"page-right\");\nconst metaViewport = document.querySelector(\"meta[name=viewport]\");\nWindow.prototype.doubleArea = new FixedDoubleBridge(window, leftIframe, rightIframe, metaViewport, window.gestures);\nwindow.documentState.onScriptsLoaded();\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nwindow.addEventListener(\"load\", (event) => {\n window.documentState.onDocumentLoadedAndSized();\n});\n","import { DoubleAreaManager } from \"../fixed/double-area-manager\";\nimport { BridgeGesturesAdapter } from \"./all-gestures-bridge\";\nexport class FixedDoubleBridge {\n constructor(window, leftIframe, rightIframe, metaViewport, gestures) {\n const listener = new BridgeGesturesAdapter(gestures);\n this.manager = new DoubleAreaManager(window, leftIframe, rightIframe, metaViewport, listener);\n }\n loadSpread(spread) {\n this.manager.loadSpread(spread);\n }\n setViewport(viewporttWidth, viewportHeight, insetTop, insetRight, insetBottom, insetLeft) {\n const viewport = { width: viewporttWidth, height: viewportHeight };\n const insets = {\n top: insetTop,\n left: insetLeft,\n bottom: insetBottom,\n right: insetRight,\n };\n this.manager.setViewport(viewport, insets);\n }\n setFit(fit) {\n if (fit != \"contain\" && fit != \"width\" && fit != \"height\") {\n throw Error(`Invalid fit value: ${fit}`);\n }\n this.manager.setFit(fit);\n }\n}\n"],"names":["PageManager","constructor","window","iframe","listener","this","margins","top","right","bottom","left","contentWindow","Error","setMessagePort","messagePort","onmessage","message","onMessageFromIframe","show","style","display","hide","setMargins","marginTop","marginLeft","marginBottom","marginRight","loadPage","url","src","setPlaceholder","size","visibility","width","height","event","data","kind","onContentSizeAvailable","onTap","x","y","onLinkActivated","URL","href","toString","outerHtml","_a","onIframeLoaded","ViewportStringBuilder","setInitialScale","scale","initialScale","setMinimumScale","minimumScale","setWidth","setHeight","build","components","push","join","GesturesDetector","document","addEventListener","onClick","defaultPrevented","selection","getSelection","type","nearestElement","target","HTMLElement","nearestInteractiveElement","HTMLAnchorElement","outerHTML","stopPropagation","preventDefault","element","indexOf","nodeName","toLowerCase","hasAttribute","getAttribute","parentElement","DoubleAreaManager","leftIframe","rightIframe","metaViewport","fit","insets","ports","source","leftPage","rightPage","tapEvent","clientX","visualViewport","offsetLeft","clientY","offsetTop","_","leftPageListener","layout","boundingRect","getBoundingClientRect","rightPageListener","loadSpread","spread","setViewport","viewport","setFit","leftMargins","rightMargins","contentWidth","contentHeight","Math","max","contentSize","safeDrawingSize","content","container","widthRatio","heightRatio","min","fitContain","fitWidth","fitHeight","computeScale","BridgeGesturesAdapter","gesturesApi","nativeApi","JSON","stringify","getElementById","querySelector","Window","prototype","doubleArea","gestures","manager","viewporttWidth","viewportHeight","insetTop","insetRight","insetBottom","insetLeft","documentState","onScriptsLoaded","onDocumentLoadedAndSized"],"sourceRoot":""} \ No newline at end of file +{"version":3,"file":"fixed-double-script.js","mappings":"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","sources":["webpack://readium-js/./src/fixed/page-manager.ts","webpack://readium-js/./src/util/viewport.ts","webpack://readium-js/./src/common/gestures.ts","webpack://readium-js/./src/fixed/double-area-manager.ts","webpack://readium-js/./src/util/fit.ts","webpack://readium-js/./src/bridge/all-listener-bridge.ts","webpack://readium-js/./src/index-fixed-double.ts","webpack://readium-js/./src/bridge/fixed-double-bridge.ts"],"sourcesContent":["/** Manages a fixed layout resource embedded in an iframe. */\nexport class PageManager {\n constructor(window, iframe, listener) {\n this.margins = { top: 0, right: 0, bottom: 0, left: 0 };\n if (!iframe.contentWindow) {\n throw Error(\"Iframe argument must have been attached to DOM.\");\n }\n this.listener = listener;\n this.iframe = iframe;\n }\n setMessagePort(messagePort) {\n messagePort.onmessage = (message) => {\n this.onMessageFromIframe(message);\n };\n }\n show() {\n this.iframe.style.display = \"unset\";\n }\n hide() {\n this.iframe.style.display = \"none\";\n }\n /** Sets page margins. */\n setMargins(margins) {\n if (this.margins == margins) {\n return;\n }\n this.iframe.style.marginTop = this.margins.top + \"px\";\n this.iframe.style.marginLeft = this.margins.left + \"px\";\n this.iframe.style.marginBottom = this.margins.bottom + \"px\";\n this.iframe.style.marginRight = this.margins.right + \"px\";\n }\n /** Loads page content. */\n loadPage(url) {\n this.iframe.src = url;\n }\n /** Sets the size of this page without content. */\n setPlaceholder(size) {\n this.iframe.style.visibility = \"hidden\";\n this.iframe.style.width = size.width + \"px\";\n this.iframe.style.height = size.height + \"px\";\n this.size = size;\n }\n onMessageFromIframe(event) {\n const message = event.data;\n switch (message.kind) {\n case \"contentSize\":\n return this.onContentSizeAvailable(message.size);\n case \"tap\":\n return this.listener.onTap({ x: message.x, y: message.y });\n case \"linkActivated\":\n return this.onLinkActivated(message);\n }\n }\n onLinkActivated(message) {\n try {\n const url = new URL(message.href, this.iframe.src);\n this.listener.onLinkActivated(url.toString(), message.outerHtml);\n }\n catch (_a) {\n // Do nothing if url is not valid.\n }\n }\n onContentSizeAvailable(size) {\n if (!size) {\n //FIXME: handle edge case\n return;\n }\n this.iframe.style.width = size.width + \"px\";\n this.iframe.style.height = size.height + \"px\";\n this.size = size;\n this.listener.onIframeLoaded();\n }\n}\n","export class ViewportStringBuilder {\n setInitialScale(scale) {\n this.initialScale = scale;\n return this;\n }\n setMinimumScale(scale) {\n this.minimumScale = scale;\n return this;\n }\n setWidth(width) {\n this.width = width;\n return this;\n }\n setHeight(height) {\n this.height = height;\n return this;\n }\n build() {\n const components = [];\n if (this.initialScale) {\n components.push(\"initial-scale=\" + this.initialScale);\n }\n if (this.minimumScale) {\n components.push(\"minimum-scale=\" + this.minimumScale);\n }\n if (this.width) {\n components.push(\"width=\" + this.width);\n }\n if (this.height) {\n components.push(\"height=\" + this.height);\n }\n return components.join(\", \");\n }\n}\nexport function parseViewportString(viewportString) {\n const regex = /(\\w+) *= *([^\\s,]+)/g;\n const properties = new Map();\n let match;\n while ((match = regex.exec(viewportString))) {\n if (match != null) {\n properties.set(match[1], match[2]);\n }\n }\n const width = parseFloat(properties.get(\"width\"));\n const height = parseFloat(properties.get(\"height\"));\n if (width && height) {\n return { width, height };\n }\n else {\n return undefined;\n }\n}\n","export class GesturesDetector {\n constructor(window, listener) {\n this.window = window;\n this.listener = listener;\n document.addEventListener(\"click\", (event) => {\n this.onClick(event);\n }, false);\n }\n onClick(event) {\n if (event.defaultPrevented) {\n return;\n }\n const selection = this.window.getSelection();\n if (selection && selection.type == \"Range\") {\n // There's an on-going selection, the tap will dismiss it so we don't forward it.\n // selection.type might be None (collapsed) or Caret with a collapsed range\n // when there is not true selection.\n return;\n }\n let nearestElement;\n if (event.target instanceof HTMLElement) {\n nearestElement = this.nearestInteractiveElement(event.target);\n }\n else {\n nearestElement = null;\n }\n if (nearestElement) {\n if (nearestElement instanceof HTMLAnchorElement) {\n this.listener.onLinkActivated(nearestElement.href, nearestElement.outerHTML);\n }\n }\n else {\n this.listener.onTap(event);\n }\n event.stopPropagation();\n event.preventDefault();\n }\n // See. https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling\n nearestInteractiveElement(element) {\n if (element == null) {\n return null;\n }\n const interactiveTags = [\n \"a\",\n \"audio\",\n \"button\",\n \"canvas\",\n \"details\",\n \"input\",\n \"label\",\n \"option\",\n \"select\",\n \"submit\",\n \"textarea\",\n \"video\",\n ];\n if (interactiveTags.indexOf(element.nodeName.toLowerCase()) != -1) {\n return element;\n }\n // Checks whether the element is editable by the user.\n if (element.hasAttribute(\"contenteditable\") &&\n element.getAttribute(\"contenteditable\").toLowerCase() != \"false\") {\n return element;\n }\n // Checks parents recursively because the touch might be for example on an inside a .\n if (element.parentElement) {\n return this.nearestInteractiveElement(element.parentElement);\n }\n return null;\n }\n}\n","import { computeScale } from \"../util/fit\";\nimport { PageManager } from \"./page-manager\";\nimport { ViewportStringBuilder } from \"../util/viewport\";\nimport { GesturesDetector } from \"../common/gestures\";\nexport class DoubleAreaManager {\n constructor(window, leftIframe, rightIframe, metaViewport, listener) {\n this.fit = \"contain\" /* Fit.Contain */;\n this.insets = { top: 0, right: 0, bottom: 0, left: 0 };\n this.listener = listener;\n window.addEventListener(\"message\", (event) => {\n if (!event.ports[0]) {\n return;\n }\n if (event.source === leftIframe.contentWindow) {\n this.leftPage.setMessagePort(event.ports[0]);\n }\n else if (event.source == rightIframe.contentWindow) {\n this.rightPage.setMessagePort(event.ports[0]);\n }\n });\n const wrapperGesturesListener = {\n onTap: (event) => {\n const tapEvent = {\n x: (event.clientX - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.clientY - visualViewport.offsetTop) * visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onLinkActivated: (_) => {\n throw Error(\"No interactive element in the root document.\");\n },\n };\n new GesturesDetector(window, wrapperGesturesListener);\n const leftPageListener = {\n onIframeLoaded: () => {\n this.layout();\n },\n onTap: (event) => {\n const boundingRect = leftIframe.getBoundingClientRect();\n const tapEvent = {\n x: (event.x + boundingRect.left - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.y + boundingRect.top - visualViewport.offsetTop) *\n visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n listener.onLinkActivated(href, outerHtml);\n },\n };\n const rightPageListener = {\n onIframeLoaded: () => {\n this.layout();\n },\n onTap: (event) => {\n const boundingRect = rightIframe.getBoundingClientRect();\n const tapEvent = {\n x: (event.x + boundingRect.left - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.y + boundingRect.top - visualViewport.offsetTop) *\n visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n listener.onLinkActivated(href, outerHtml);\n },\n };\n this.leftPage = new PageManager(window, leftIframe, leftPageListener);\n this.rightPage = new PageManager(window, rightIframe, rightPageListener);\n this.metaViewport = metaViewport;\n }\n loadSpread(spread) {\n this.leftPage.hide();\n this.rightPage.hide();\n this.spread = spread;\n if (spread.left) {\n this.leftPage.loadPage(spread.left);\n }\n if (spread.right) {\n this.rightPage.loadPage(spread.right);\n }\n }\n setViewport(size, insets) {\n if (this.viewport == size && this.insets == insets) {\n return;\n }\n this.viewport = size;\n this.insets = insets;\n this.layout();\n }\n setFit(fit) {\n if (this.fit == fit) {\n return;\n }\n this.fit = fit;\n this.layout();\n }\n layout() {\n if (!this.viewport ||\n (!this.leftPage.size && this.spread.left) ||\n (!this.rightPage.size && this.spread.right)) {\n return;\n }\n const leftMargins = {\n top: this.insets.top,\n right: 0,\n bottom: this.insets.bottom,\n left: this.insets.left,\n };\n this.leftPage.setMargins(leftMargins);\n const rightMargins = {\n top: this.insets.top,\n right: this.insets.right,\n bottom: this.insets.bottom,\n left: 0,\n };\n this.rightPage.setMargins(rightMargins);\n if (!this.spread.right) {\n this.rightPage.setPlaceholder(this.leftPage.size);\n }\n else if (!this.spread.left) {\n this.leftPage.setPlaceholder(this.rightPage.size);\n }\n const contentWidth = this.leftPage.size.width + this.rightPage.size.width;\n const contentHeight = Math.max(this.leftPage.size.height, this.rightPage.size.height);\n const contentSize = { width: contentWidth, height: contentHeight };\n const safeDrawingSize = {\n width: this.viewport.width - this.insets.left - this.insets.right,\n height: this.viewport.height - this.insets.top - this.insets.bottom,\n };\n const scale = computeScale(this.fit, contentSize, safeDrawingSize);\n this.metaViewport.content = new ViewportStringBuilder()\n .setInitialScale(scale)\n .setMinimumScale(scale)\n .setWidth(contentWidth)\n .setHeight(contentHeight)\n .build();\n this.leftPage.show();\n this.rightPage.show();\n this.listener.onLayout();\n }\n}\n","export function computeScale(fit, content, container) {\n switch (fit) {\n case \"contain\" /* Fit.Contain */:\n return fitContain(content, container);\n case \"width\" /* Fit.Width */:\n return fitWidth(content, container);\n case \"height\" /* Fit.Height */:\n return fitHeight(content, container);\n }\n}\nfunction fitContain(content, container) {\n const widthRatio = container.width / content.width;\n const heightRatio = container.height / content.height;\n return Math.min(widthRatio, heightRatio);\n}\nfunction fitWidth(content, container) {\n return container.width / content.width;\n}\nfunction fitHeight(content, container) {\n return container.height / content.height;\n}\n","export class ReflowableListenerAdapter {\n constructor(gesturesBridge) {\n this.gesturesBridge = gesturesBridge;\n }\n onTap(event) {\n const tapEvent = {\n x: (event.clientX - visualViewport.offsetLeft) * visualViewport.scale,\n y: (event.clientY - visualViewport.offsetTop) * visualViewport.scale,\n };\n const stringEvent = JSON.stringify(tapEvent);\n this.gesturesBridge.onTap(stringEvent);\n }\n onLinkActivated(href, outerHtml) {\n this.gesturesBridge.onLinkActivated(href, outerHtml);\n }\n}\nexport class FixedListenerAdapter {\n constructor(window, gesturesApi, documentApi) {\n this.window = window;\n this.gesturesApi = gesturesApi;\n this.documentApi = documentApi;\n this.resizeObserverAdded = false;\n this.documentLoadedFired = false;\n }\n onTap(event) {\n this.gesturesApi.onTap(JSON.stringify(event));\n }\n onLinkActivated(href, outerHtml) {\n this.gesturesApi.onLinkActivated(href, outerHtml);\n }\n onLayout() {\n if (!this.resizeObserverAdded) {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const observer = new ResizeObserver(() => {\n requestAnimationFrame(() => {\n const scrollingElement = this.window.document.scrollingElement;\n if (!this.documentLoadedFired &&\n (scrollingElement == null ||\n scrollingElement.scrollHeight > 0 ||\n scrollingElement.scrollWidth > 0)) {\n this.documentApi.onDocumentLoadedAndSized();\n this.documentLoadedFired = true;\n }\n else {\n this.documentApi.onDocumentResized();\n }\n });\n });\n observer.observe(this.window.document.body);\n }\n this.resizeObserverAdded = true;\n }\n}\n","//\n// Copyright 2024 Readium Foundation. All rights reserved.\n// Use of this source code is governed by the BSD-style license\n// available in the top-level LICENSE file of the project.\n//\nimport { FixedDoubleBridge } from \"./bridge/fixed-double-bridge\";\nconst leftIframe = document.getElementById(\"page-left\");\nconst rightIframe = document.getElementById(\"page-right\");\nconst metaViewport = document.querySelector(\"meta[name=viewport]\");\nWindow.prototype.doubleArea = new FixedDoubleBridge(window, leftIframe, rightIframe, metaViewport, window.gestures, window.documentState);\nwindow.documentState.onScriptsLoaded();\n","import { DoubleAreaManager } from \"../fixed/double-area-manager\";\nimport { FixedListenerAdapter, } from \"./all-listener-bridge\";\nexport class FixedDoubleBridge {\n constructor(window, leftIframe, rightIframe, metaViewport, gesturesBridge, documentBridge) {\n const listener = new FixedListenerAdapter(window, gesturesBridge, documentBridge);\n this.manager = new DoubleAreaManager(window, leftIframe, rightIframe, metaViewport, listener);\n }\n loadSpread(spread) {\n this.manager.loadSpread(spread);\n }\n setViewport(viewporttWidth, viewportHeight, insetTop, insetRight, insetBottom, insetLeft) {\n const viewport = { width: viewporttWidth, height: viewportHeight };\n const insets = {\n top: insetTop,\n left: insetLeft,\n bottom: insetBottom,\n right: insetRight,\n };\n this.manager.setViewport(viewport, insets);\n }\n setFit(fit) {\n if (fit != \"contain\" && fit != \"width\" && fit != \"height\") {\n throw Error(`Invalid fit value: ${fit}`);\n }\n this.manager.setFit(fit);\n }\n}\n"],"names":["PageManager","constructor","window","iframe","listener","this","margins","top","right","bottom","left","contentWindow","Error","setMessagePort","messagePort","onmessage","message","onMessageFromIframe","show","style","display","hide","setMargins","marginTop","marginLeft","marginBottom","marginRight","loadPage","url","src","setPlaceholder","size","visibility","width","height","event","data","kind","onContentSizeAvailable","onTap","x","y","onLinkActivated","URL","href","toString","outerHtml","_a","onIframeLoaded","ViewportStringBuilder","setInitialScale","scale","initialScale","setMinimumScale","minimumScale","setWidth","setHeight","build","components","push","join","GesturesDetector","document","addEventListener","onClick","defaultPrevented","selection","getSelection","type","nearestElement","target","HTMLElement","nearestInteractiveElement","HTMLAnchorElement","outerHTML","stopPropagation","preventDefault","element","indexOf","nodeName","toLowerCase","hasAttribute","getAttribute","parentElement","DoubleAreaManager","leftIframe","rightIframe","metaViewport","fit","insets","ports","source","leftPage","rightPage","tapEvent","clientX","visualViewport","offsetLeft","clientY","offsetTop","_","leftPageListener","layout","boundingRect","getBoundingClientRect","rightPageListener","loadSpread","spread","setViewport","viewport","setFit","leftMargins","rightMargins","contentWidth","contentHeight","Math","max","contentSize","safeDrawingSize","content","container","widthRatio","heightRatio","min","fitContain","fitWidth","fitHeight","computeScale","onLayout","FixedListenerAdapter","gesturesApi","documentApi","resizeObserverAdded","documentLoadedFired","JSON","stringify","ResizeObserver","requestAnimationFrame","scrollingElement","scrollHeight","scrollWidth","onDocumentLoadedAndSized","onDocumentResized","observe","body","getElementById","querySelector","Window","prototype","doubleArea","gesturesBridge","documentBridge","manager","viewporttWidth","viewportHeight","insetTop","insetRight","insetBottom","insetLeft","gestures","documentState","onScriptsLoaded"],"sourceRoot":""} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-single-script.js b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-single-script.js index 234cc5afaa..77c7050970 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-single-script.js +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-single-script.js @@ -1,2 +1,2 @@ -!function(){"use strict";class t{constructor(t,e,i){if(this.margins={top:0,right:0,bottom:0,left:0},!e.contentWindow)throw Error("Iframe argument must have been attached to DOM.");this.listener=i,this.iframe=e}setMessagePort(t){t.onmessage=t=>{this.onMessageFromIframe(t)}}show(){this.iframe.style.display="unset"}hide(){this.iframe.style.display="none"}setMargins(t){this.margins!=t&&(this.iframe.style.marginTop=this.margins.top+"px",this.iframe.style.marginLeft=this.margins.left+"px",this.iframe.style.marginBottom=this.margins.bottom+"px",this.iframe.style.marginRight=this.margins.right+"px")}loadPage(t){this.iframe.src=t}setPlaceholder(t){this.iframe.style.visibility="hidden",this.iframe.style.width=t.width+"px",this.iframe.style.height=t.height+"px",this.size=t}onMessageFromIframe(t){const e=t.data;switch(e.kind){case"contentSize":return this.onContentSizeAvailable(e.size);case"tap":return this.listener.onTap({x:e.x,y:e.y});case"linkActivated":return this.onLinkActivated(e)}}onLinkActivated(t){try{const e=new URL(t.href,this.iframe.src);this.listener.onLinkActivated(e.toString(),t.outerHtml)}catch(t){}}onContentSizeAvailable(t){t&&(this.iframe.style.width=t.width+"px",this.iframe.style.height=t.height+"px",this.size=t,this.listener.onIframeLoaded())}}class e{setInitialScale(t){return this.initialScale=t,this}setMinimumScale(t){return this.minimumScale=t,this}setWidth(t){return this.width=t,this}setHeight(t){return this.height=t,this}build(){const t=[];return this.initialScale&&t.push("initial-scale="+this.initialScale),this.minimumScale&&t.push("minimum-scale="+this.minimumScale),this.width&&t.push("width="+this.width),this.height&&t.push("height="+this.height),t.join(", ")}}class i{constructor(t,e){this.window=t,this.listener=e,document.addEventListener("click",(t=>{this.onClick(t)}),!1)}onClick(t){if(t.defaultPrevented)return;const e=this.window.getSelection();if(e&&"Range"==e.type)return;let i;i=t.target instanceof HTMLElement?this.nearestInteractiveElement(t.target):null,i?i instanceof HTMLAnchorElement&&this.listener.onLinkActivated(i.href,i.outerHTML):this.listener.onTap(t),t.stopPropagation(),t.preventDefault()}nearestInteractiveElement(t){return null==t?null:-1!=["a","audio","button","canvas","details","input","label","option","select","submit","textarea","video"].indexOf(t.nodeName.toLowerCase())||t.hasAttribute("contenteditable")&&"false"!=t.getAttribute("contenteditable").toLowerCase()?t:t.parentElement?this.nearestInteractiveElement(t.parentElement):null}}class s{constructor(e,s,n,a){this.fit="contain",this.insets={top:0,right:0,bottom:0,left:0},this.scale=1,e.addEventListener("message",(t=>{t.source===s.contentWindow&&t.ports[0]&&this.page.setMessagePort(t.ports[0])})),new i(e,{onTap:t=>{const e={x:(t.clientX-visualViewport.offsetLeft)*visualViewport.scale,y:(t.clientY-visualViewport.offsetTop)*visualViewport.scale};a.onTap(e)},onLinkActivated:t=>{throw Error("No interactive element in the root document.")}}),this.metaViewport=n;const o={onIframeLoaded:()=>{this.onIframeLoaded()},onTap:t=>{const e=s.getBoundingClientRect(),i={x:(t.x+e.left-visualViewport.offsetLeft)*visualViewport.scale,y:(t.y+e.top-visualViewport.offsetTop)*visualViewport.scale};a.onTap(i)},onLinkActivated:(t,e)=>{a.onLinkActivated(t,e)}};this.page=new t(e,s,o)}setViewport(t,e){this.viewport==t&&this.insets==e||(this.viewport=t,this.insets=e,this.layout())}setFit(t){this.fit!=t&&(this.fit=t,this.layout())}loadResource(t){this.page.hide(),this.page.loadPage(t)}onIframeLoaded(){this.page.size&&this.layout()}layout(){if(!this.page.size||!this.viewport)return;const t={top:this.insets.top,right:this.insets.right,bottom:this.insets.bottom,left:this.insets.left};this.page.setMargins(t);const i={width:this.viewport.width-this.insets.left-this.insets.right,height:this.viewport.height-this.insets.top-this.insets.bottom},s=function(t,e,i){switch(t){case"contain":return function(t,e){const i=e.width/t.width,s=e.height/t.height;return Math.min(i,s)}(e,i);case"width":return function(t,e){return e.width/t.width}(e,i);case"height":return function(t,e){return e.height/t.height}(e,i)}}(this.fit,this.page.size,i);this.metaViewport.content=(new e).setInitialScale(s).setMinimumScale(s).setWidth(this.page.size.width).setHeight(this.page.size.height).build(),this.scale=s,this.page.show()}}class n{constructor(t){this.nativeApi=t}onTap(t){this.nativeApi.onTap(JSON.stringify(t))}onLinkActivated(t,e){this.nativeApi.onLinkActivated(t,e)}}const a=document.getElementById("page"),o=document.querySelector("meta[name=viewport]");window.singleArea=new class{constructor(t,e,i,a){const o=new n(a);this.manager=new s(t,e,i,o)}loadResource(t){this.manager.loadResource(t)}setViewport(t,e,i,s,n,a){const o={width:t,height:e},h={top:i,left:a,bottom:n,right:s};this.manager.setViewport(o,h)}setFit(t){if("contain"!=t&&"width"!=t&&"height"!=t)throw Error(`Invalid fit value: ${t}`);this.manager.setFit(t)}}(window,a,o,window.gestures),window.documentState.onScriptsLoaded(),window.addEventListener("load",(t=>{window.documentState.onDocumentLoadedAndSized()}))}(); +!function(){"use strict";class t{constructor(t,e,i){if(this.margins={top:0,right:0,bottom:0,left:0},!e.contentWindow)throw Error("Iframe argument must have been attached to DOM.");this.listener=i,this.iframe=e}setMessagePort(t){t.onmessage=t=>{this.onMessageFromIframe(t)}}show(){this.iframe.style.display="unset"}hide(){this.iframe.style.display="none"}setMargins(t){this.margins!=t&&(this.iframe.style.marginTop=this.margins.top+"px",this.iframe.style.marginLeft=this.margins.left+"px",this.iframe.style.marginBottom=this.margins.bottom+"px",this.iframe.style.marginRight=this.margins.right+"px")}loadPage(t){this.iframe.src=t}setPlaceholder(t){this.iframe.style.visibility="hidden",this.iframe.style.width=t.width+"px",this.iframe.style.height=t.height+"px",this.size=t}onMessageFromIframe(t){const e=t.data;switch(e.kind){case"contentSize":return this.onContentSizeAvailable(e.size);case"tap":return this.listener.onTap({x:e.x,y:e.y});case"linkActivated":return this.onLinkActivated(e)}}onLinkActivated(t){try{const e=new URL(t.href,this.iframe.src);this.listener.onLinkActivated(e.toString(),t.outerHtml)}catch(t){}}onContentSizeAvailable(t){t&&(this.iframe.style.width=t.width+"px",this.iframe.style.height=t.height+"px",this.size=t,this.listener.onIframeLoaded())}}class e{setInitialScale(t){return this.initialScale=t,this}setMinimumScale(t){return this.minimumScale=t,this}setWidth(t){return this.width=t,this}setHeight(t){return this.height=t,this}build(){const t=[];return this.initialScale&&t.push("initial-scale="+this.initialScale),this.minimumScale&&t.push("minimum-scale="+this.minimumScale),this.width&&t.push("width="+this.width),this.height&&t.push("height="+this.height),t.join(", ")}}class i{constructor(t,e){this.window=t,this.listener=e,document.addEventListener("click",(t=>{this.onClick(t)}),!1)}onClick(t){if(t.defaultPrevented)return;const e=this.window.getSelection();if(e&&"Range"==e.type)return;let i;i=t.target instanceof HTMLElement?this.nearestInteractiveElement(t.target):null,i?i instanceof HTMLAnchorElement&&this.listener.onLinkActivated(i.href,i.outerHTML):this.listener.onTap(t),t.stopPropagation(),t.preventDefault()}nearestInteractiveElement(t){return null==t?null:-1!=["a","audio","button","canvas","details","input","label","option","select","submit","textarea","video"].indexOf(t.nodeName.toLowerCase())||t.hasAttribute("contenteditable")&&"false"!=t.getAttribute("contenteditable").toLowerCase()?t:t.parentElement?this.nearestInteractiveElement(t.parentElement):null}}class s{constructor(e,s,n,o){this.fit="contain",this.insets={top:0,right:0,bottom:0,left:0},this.scale=1,this.listener=o,e.addEventListener("message",(t=>{t.source===s.contentWindow&&t.ports[0]&&this.page.setMessagePort(t.ports[0])})),new i(e,{onTap:t=>{const e={x:(t.clientX-visualViewport.offsetLeft)*visualViewport.scale,y:(t.clientY-visualViewport.offsetTop)*visualViewport.scale};o.onTap(e)},onLinkActivated:t=>{throw Error("No interactive element in the root document.")}}),this.metaViewport=n;const a={onIframeLoaded:()=>{this.onIframeLoaded()},onTap:t=>{const e=s.getBoundingClientRect(),i={x:(t.x+e.left-visualViewport.offsetLeft)*visualViewport.scale,y:(t.y+e.top-visualViewport.offsetTop)*visualViewport.scale};o.onTap(i)},onLinkActivated:(t,e)=>{o.onLinkActivated(t,e)}};this.page=new t(e,s,a)}setViewport(t,e){this.viewport==t&&this.insets==e||(this.viewport=t,this.insets=e,this.layout())}setFit(t){this.fit!=t&&(this.fit=t,this.layout())}loadResource(t){this.page.hide(),this.page.loadPage(t)}onIframeLoaded(){this.page.size&&this.layout()}layout(){if(!this.page.size||!this.viewport)return;const t={top:this.insets.top,right:this.insets.right,bottom:this.insets.bottom,left:this.insets.left};this.page.setMargins(t);const i={width:this.viewport.width-this.insets.left-this.insets.right,height:this.viewport.height-this.insets.top-this.insets.bottom},s=function(t,e,i){switch(t){case"contain":return function(t,e){const i=e.width/t.width,s=e.height/t.height;return Math.min(i,s)}(e,i);case"width":return function(t,e){return e.width/t.width}(e,i);case"height":return function(t,e){return e.height/t.height}(e,i)}}(this.fit,this.page.size,i);this.metaViewport.content=(new e).setInitialScale(s).setMinimumScale(s).setWidth(this.page.size.width).setHeight(this.page.size.height).build(),this.scale=s,this.page.show(),this.listener.onLayout()}}class n{constructor(t,e,i){this.window=t,this.gesturesApi=e,this.documentApi=i,this.resizeObserverAdded=!1,this.documentLoadedFired=!1}onTap(t){this.gesturesApi.onTap(JSON.stringify(t))}onLinkActivated(t,e){this.gesturesApi.onLinkActivated(t,e)}onLayout(){this.resizeObserverAdded||new ResizeObserver((()=>{requestAnimationFrame((()=>{const t=this.window.document.scrollingElement;!this.documentLoadedFired&&(null==t||t.scrollHeight>0||t.scrollWidth>0)?(this.documentApi.onDocumentLoadedAndSized(),this.documentLoadedFired=!0):this.documentApi.onDocumentResized()}))})).observe(this.window.document.body),this.resizeObserverAdded=!0}}const o=document.getElementById("page"),a=document.querySelector("meta[name=viewport]");window.singleArea=new class{constructor(t,e,i,o,a){const h=new n(t,o,a);this.manager=new s(t,e,i,h)}loadResource(t){this.manager.loadResource(t)}setViewport(t,e,i,s,n,o){const a={width:t,height:e},h={top:i,left:o,bottom:n,right:s};this.manager.setViewport(a,h)}setFit(t){if("contain"!=t&&"width"!=t&&"height"!=t)throw Error(`Invalid fit value: ${t}`);this.manager.setFit(t)}}(window,o,a,window.gestures,window.documentState),window.documentState.onScriptsLoaded()}(); //# sourceMappingURL=fixed-single-script.js.map \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-single-script.js.map b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-single-script.js.map index 2a0b119de4..b9a33195ee 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-single-script.js.map +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/fixed-single-script.js.map @@ -1 +1 @@ -{"version":3,"file":"fixed-single-script.js","mappings":"yBACO,MAAMA,EACT,WAAAC,CAAYC,EAAQC,EAAQC,GAExB,GADAC,KAAKC,QAAU,CAAEC,IAAK,EAAGC,MAAO,EAAGC,OAAQ,EAAGC,KAAM,IAC/CP,EAAOQ,cACR,MAAMC,MAAM,mDAEhBP,KAAKD,SAAWA,EAChBC,KAAKF,OAASA,CAClB,CACA,cAAAU,CAAeC,GACXA,EAAYC,UAAaC,IACrBX,KAAKY,oBAAoBD,EAAQ,CAEzC,CACA,IAAAE,GACIb,KAAKF,OAAOgB,MAAMC,QAAU,OAChC,CACA,IAAAC,GACIhB,KAAKF,OAAOgB,MAAMC,QAAU,MAChC,CAEA,UAAAE,CAAWhB,GACHD,KAAKC,SAAWA,IAGpBD,KAAKF,OAAOgB,MAAMI,UAAYlB,KAAKC,QAAQC,IAAM,KACjDF,KAAKF,OAAOgB,MAAMK,WAAanB,KAAKC,QAAQI,KAAO,KACnDL,KAAKF,OAAOgB,MAAMM,aAAepB,KAAKC,QAAQG,OAAS,KACvDJ,KAAKF,OAAOgB,MAAMO,YAAcrB,KAAKC,QAAQE,MAAQ,KACzD,CAEA,QAAAmB,CAASC,GACLvB,KAAKF,OAAO0B,IAAMD,CACtB,CAEA,cAAAE,CAAeC,GACX1B,KAAKF,OAAOgB,MAAMa,WAAa,SAC/B3B,KAAKF,OAAOgB,MAAMc,MAAQF,EAAKE,MAAQ,KACvC5B,KAAKF,OAAOgB,MAAMe,OAASH,EAAKG,OAAS,KACzC7B,KAAK0B,KAAOA,CAChB,CACA,mBAAAd,CAAoBkB,GAChB,MAAMnB,EAAUmB,EAAMC,KACtB,OAAQpB,EAAQqB,MACZ,IAAK,cACD,OAAOhC,KAAKiC,uBAAuBtB,EAAQe,MAC/C,IAAK,MACD,OAAO1B,KAAKD,SAASmC,MAAM,CAAEC,EAAGxB,EAAQwB,EAAGC,EAAGzB,EAAQyB,IAC1D,IAAK,gBACD,OAAOpC,KAAKqC,gBAAgB1B,GAExC,CACA,eAAA0B,CAAgB1B,GACZ,IACI,MAAMY,EAAM,IAAIe,IAAI3B,EAAQ4B,KAAMvC,KAAKF,OAAO0B,KAC9CxB,KAAKD,SAASsC,gBAAgBd,EAAIiB,WAAY7B,EAAQ8B,UAC1D,CACA,MAAOC,GAEP,CACJ,CACA,sBAAAT,CAAuBP,GACdA,IAIL1B,KAAKF,OAAOgB,MAAMc,MAAQF,EAAKE,MAAQ,KACvC5B,KAAKF,OAAOgB,MAAMe,OAASH,EAAKG,OAAS,KACzC7B,KAAK0B,KAAOA,EACZ1B,KAAKD,SAAS4C,iBAClB,ECvEG,MAAMC,EACT,eAAAC,CAAgBC,GAEZ,OADA9C,KAAK+C,aAAeD,EACb9C,IACX,CACA,eAAAgD,CAAgBF,GAEZ,OADA9C,KAAKiD,aAAeH,EACb9C,IACX,CACA,QAAAkD,CAAStB,GAEL,OADA5B,KAAK4B,MAAQA,EACN5B,IACX,CACA,SAAAmD,CAAUtB,GAEN,OADA7B,KAAK6B,OAASA,EACP7B,IACX,CACA,KAAAoD,GACI,MAAMC,EAAa,GAanB,OAZIrD,KAAK+C,cACLM,EAAWC,KAAK,iBAAmBtD,KAAK+C,cAExC/C,KAAKiD,cACLI,EAAWC,KAAK,iBAAmBtD,KAAKiD,cAExCjD,KAAK4B,OACLyB,EAAWC,KAAK,SAAWtD,KAAK4B,OAEhC5B,KAAK6B,QACLwB,EAAWC,KAAK,UAAYtD,KAAK6B,QAE9BwB,EAAWE,KAAK,KAC3B,EChCG,MAAMC,EACT,WAAA5D,CAAYC,EAAQE,GAChBC,KAAKH,OAASA,EACdG,KAAKD,SAAWA,EAChB0D,SAASC,iBAAiB,SAAU5B,IAChC9B,KAAK2D,QAAQ7B,EAAM,IACpB,EACP,CACA,OAAA6B,CAAQ7B,GACJ,GAAIA,EAAM8B,iBACN,OAEJ,MAAMC,EAAY7D,KAAKH,OAAOiE,eAC9B,GAAID,GAA+B,SAAlBA,EAAUE,KAIvB,OAEJ,IAAIC,EAEAA,EADAlC,EAAMmC,kBAAkBC,YACPlE,KAAKmE,0BAA0BrC,EAAMmC,QAGrC,KAEjBD,EACIA,aAA0BI,mBAC1BpE,KAAKD,SAASsC,gBAAgB2B,EAAezB,KAAMyB,EAAeK,WAItErE,KAAKD,SAASmC,MAAMJ,GAExBA,EAAMwC,kBACNxC,EAAMyC,gBACV,CAEA,yBAAAJ,CAA0BK,GACtB,OAAe,MAAXA,EACO,MAgBqD,GAdxC,CACpB,IACA,QACA,SACA,SACA,UACA,QACA,QACA,SACA,SACA,SACA,WACA,SAEgBC,QAAQD,EAAQE,SAASC,gBAIzCH,EAAQI,aAAa,oBACoC,SAAzDJ,EAAQK,aAAa,mBAAmBF,cAJjCH,EAQPA,EAAQM,cACD9E,KAAKmE,0BAA0BK,EAAQM,eAE3C,IACX,ECjEG,MAAMC,EACT,WAAAnF,CAAYC,EAAQC,EAAQkF,EAAcjF,GACtCC,KAAKiF,IAAM,UACXjF,KAAKkF,OAAS,CAAEhF,IAAK,EAAGC,MAAO,EAAGC,OAAQ,EAAGC,KAAM,GACnDL,KAAK8C,MAAQ,EACbjD,EAAO6D,iBAAiB,WAAY5B,IAC5BA,EAAMqD,SAAWrF,EAAOQ,eAAiBwB,EAAMsD,MAAM,IACrDpF,KAAKqF,KAAK7E,eAAesB,EAAMsD,MAAM,GACzC,IAgBJ,IAAI5B,EAAiB3D,EAdW,CAC5BqC,MAAQJ,IACJ,MAAMwD,EAAW,CACbnD,GAAIL,EAAMyD,QAAUC,eAAeC,YAC/BD,eAAe1C,MACnBV,GAAIN,EAAM4D,QAAUF,eAAeG,WAAaH,eAAe1C,OAEnE/C,EAASmC,MAAMoD,EAAS,EAG5BjD,gBAAkBuD,IACd,MAAMrF,MAAM,+CAA+C,IAInEP,KAAKgF,aAAeA,EACpB,MAAMa,EAAe,CACjBlD,eAAgB,KACZ3C,KAAK2C,gBAAgB,EAEzBT,MAAQJ,IACJ,MAAMgE,EAAehG,EAAOiG,wBACtBT,EAAW,CACbnD,GAAIL,EAAMK,EAAI2D,EAAazF,KAAOmF,eAAeC,YAC7CD,eAAe1C,MACnBV,GAAIN,EAAMM,EAAI0D,EAAa5F,IAAMsF,eAAeG,WAC5CH,eAAe1C,OAEvB/C,EAASmC,MAAMoD,EAAS,EAE5BjD,gBAAiB,CAACE,EAAME,KACpB1C,EAASsC,gBAAgBE,EAAME,EAAU,GAGjDzC,KAAKqF,KAAO,IAAI1F,EAAYE,EAAQC,EAAQ+F,EAChD,CACA,WAAAG,CAAYC,EAAUf,GACdlF,KAAKiG,UAAYA,GAAYjG,KAAKkF,QAAUA,IAGhDlF,KAAKiG,SAAWA,EAChBjG,KAAKkF,OAASA,EACdlF,KAAKkG,SACT,CACA,MAAAC,CAAOlB,GACCjF,KAAKiF,KAAOA,IAGhBjF,KAAKiF,IAAMA,EACXjF,KAAKkG,SACT,CACA,YAAAE,CAAa7E,GACTvB,KAAKqF,KAAKrE,OACVhB,KAAKqF,KAAK/D,SAASC,EACvB,CACA,cAAAoB,GACS3C,KAAKqF,KAAK3D,MAIX1B,KAAKkG,QAEb,CACA,MAAAA,GACI,IAAKlG,KAAKqF,KAAK3D,OAAS1B,KAAKiG,SACzB,OAEJ,MAAMhG,EAAU,CACZC,IAAKF,KAAKkF,OAAOhF,IACjBC,MAAOH,KAAKkF,OAAO/E,MACnBC,OAAQJ,KAAKkF,OAAO9E,OACpBC,KAAML,KAAKkF,OAAO7E,MAEtBL,KAAKqF,KAAKpE,WAAWhB,GACrB,MAAMoG,EAAkB,CACpBzE,MAAO5B,KAAKiG,SAASrE,MAAQ5B,KAAKkF,OAAO7E,KAAOL,KAAKkF,OAAO/E,MAC5D0B,OAAQ7B,KAAKiG,SAASpE,OAAS7B,KAAKkF,OAAOhF,IAAMF,KAAKkF,OAAO9E,QAE3D0C,EC5FP,SAAsBmC,EAAKqB,EAASC,GACvC,OAAQtB,GACJ,IAAK,UACD,OAOZ,SAAoBqB,EAASC,GACzB,MAAMC,EAAaD,EAAU3E,MAAQ0E,EAAQ1E,MACvC6E,EAAcF,EAAU1E,OAASyE,EAAQzE,OAC/C,OAAO6E,KAAKC,IAAIH,EAAYC,EAChC,CAXmBG,CAAWN,EAASC,GAC/B,IAAK,QACD,OAUZ,SAAkBD,EAASC,GACvB,OAAOA,EAAU3E,MAAQ0E,EAAQ1E,KACrC,CAZmBiF,CAASP,EAASC,GAC7B,IAAK,SACD,OAWZ,SAAmBD,EAASC,GACxB,OAAOA,EAAU1E,OAASyE,EAAQzE,MACtC,CAbmBiF,CAAUR,EAASC,GAEtC,CDmFsBQ,CAAa/G,KAAKiF,IAAKjF,KAAKqF,KAAK3D,KAAM2E,GACrDrG,KAAKgF,aAAasB,SAAU,IAAI1D,GAC3BC,gBAAgBC,GAChBE,gBAAgBF,GAChBI,SAASlD,KAAKqF,KAAK3D,KAAKE,OACxBuB,UAAUnD,KAAKqF,KAAK3D,KAAKG,QACzBuB,QACLpD,KAAK8C,MAAQA,EACb9C,KAAKqF,KAAKxE,MACd,EErGG,MAAMmG,EACT,WAAApH,CAAYqH,GACRjH,KAAKkH,UAAYD,CACrB,CACA,KAAA/E,CAAMJ,GACF9B,KAAKkH,UAAUhF,MAAMiF,KAAKC,UAAUtF,GACxC,CACA,eAAAO,CAAgBE,EAAME,GAClBzC,KAAKkH,UAAU7E,gBAAgBE,EAAME,EACzC,ECHJ,MAAM3C,EAAS2D,SAAS4D,eAAe,QACjCrC,EAAevB,SAAS6D,cAAc,uBAC5CzH,OAAO0H,WAAa,ICNb,MACH,WAAA3H,CAAYC,EAAQC,EAAQkF,EAAcwC,GACtC,MAAMzH,EAAW,IAAIiH,EAAsBQ,GAC3CxH,KAAKyH,QAAU,IAAI1C,EAAkBlF,EAAQC,EAAQkF,EAAcjF,EACvE,CACA,YAAAqG,CAAa7E,GACTvB,KAAKyH,QAAQrB,aAAa7E,EAC9B,CACA,WAAAyE,CAAY0B,EAAgBC,EAAgBC,EAAUC,EAAYC,EAAaC,GAC3E,MAAM9B,EAAW,CAAErE,MAAO8F,EAAgB7F,OAAQ8F,GAC5CzC,EAAS,CACXhF,IAAK0H,EACLvH,KAAM0H,EACN3H,OAAQ0H,EACR3H,MAAO0H,GAEX7H,KAAKyH,QAAQzB,YAAYC,EAAUf,EACvC,CACA,MAAAiB,CAAOlB,GACH,GAAW,WAAPA,GAA2B,SAAPA,GAAyB,UAAPA,EACtC,MAAM1E,MAAM,sBAAsB0E,KAEtCjF,KAAKyH,QAAQtB,OAAOlB,EACxB,GDjBsCpF,OAAQC,EAAQkF,EAAcnF,OAAO2H,UAC/E3H,OAAOmI,cAAcC,kBAErBpI,OAAO6D,iBAAiB,QAAS5B,IAC7BjC,OAAOmI,cAAcE,0BAA0B,G","sources":["webpack://readium-js/./src/fixed/page-manager.ts","webpack://readium-js/./src/util/viewport.ts","webpack://readium-js/./src/common/gestures.ts","webpack://readium-js/./src/fixed/single-area-manager.ts","webpack://readium-js/./src/util/fit.ts","webpack://readium-js/./src/bridge/all-gestures-bridge.ts","webpack://readium-js/./src/index-fixed-single.ts","webpack://readium-js/./src/bridge/fixed-single-bridge.ts"],"sourcesContent":["/** Manages a fixed layout resource embedded in an iframe. */\nexport class PageManager {\n constructor(window, iframe, listener) {\n this.margins = { top: 0, right: 0, bottom: 0, left: 0 };\n if (!iframe.contentWindow) {\n throw Error(\"Iframe argument must have been attached to DOM.\");\n }\n this.listener = listener;\n this.iframe = iframe;\n }\n setMessagePort(messagePort) {\n messagePort.onmessage = (message) => {\n this.onMessageFromIframe(message);\n };\n }\n show() {\n this.iframe.style.display = \"unset\";\n }\n hide() {\n this.iframe.style.display = \"none\";\n }\n /** Sets page margins. */\n setMargins(margins) {\n if (this.margins == margins) {\n return;\n }\n this.iframe.style.marginTop = this.margins.top + \"px\";\n this.iframe.style.marginLeft = this.margins.left + \"px\";\n this.iframe.style.marginBottom = this.margins.bottom + \"px\";\n this.iframe.style.marginRight = this.margins.right + \"px\";\n }\n /** Loads page content. */\n loadPage(url) {\n this.iframe.src = url;\n }\n /** Sets the size of this page without content. */\n setPlaceholder(size) {\n this.iframe.style.visibility = \"hidden\";\n this.iframe.style.width = size.width + \"px\";\n this.iframe.style.height = size.height + \"px\";\n this.size = size;\n }\n onMessageFromIframe(event) {\n const message = event.data;\n switch (message.kind) {\n case \"contentSize\":\n return this.onContentSizeAvailable(message.size);\n case \"tap\":\n return this.listener.onTap({ x: message.x, y: message.y });\n case \"linkActivated\":\n return this.onLinkActivated(message);\n }\n }\n onLinkActivated(message) {\n try {\n const url = new URL(message.href, this.iframe.src);\n this.listener.onLinkActivated(url.toString(), message.outerHtml);\n }\n catch (_a) {\n // Do nothing if url is not valid.\n }\n }\n onContentSizeAvailable(size) {\n if (!size) {\n //FIXME: handle edge case\n return;\n }\n this.iframe.style.width = size.width + \"px\";\n this.iframe.style.height = size.height + \"px\";\n this.size = size;\n this.listener.onIframeLoaded();\n }\n}\n","export class ViewportStringBuilder {\n setInitialScale(scale) {\n this.initialScale = scale;\n return this;\n }\n setMinimumScale(scale) {\n this.minimumScale = scale;\n return this;\n }\n setWidth(width) {\n this.width = width;\n return this;\n }\n setHeight(height) {\n this.height = height;\n return this;\n }\n build() {\n const components = [];\n if (this.initialScale) {\n components.push(\"initial-scale=\" + this.initialScale);\n }\n if (this.minimumScale) {\n components.push(\"minimum-scale=\" + this.minimumScale);\n }\n if (this.width) {\n components.push(\"width=\" + this.width);\n }\n if (this.height) {\n components.push(\"height=\" + this.height);\n }\n return components.join(\", \");\n }\n}\nexport function parseViewportString(viewportString) {\n const regex = /(\\w+) *= *([^\\s,]+)/g;\n const properties = new Map();\n let match;\n while ((match = regex.exec(viewportString))) {\n if (match != null) {\n properties.set(match[1], match[2]);\n }\n }\n const width = parseFloat(properties.get(\"width\"));\n const height = parseFloat(properties.get(\"height\"));\n if (width && height) {\n return { width, height };\n }\n else {\n return undefined;\n }\n}\n","export class GesturesDetector {\n constructor(window, listener) {\n this.window = window;\n this.listener = listener;\n document.addEventListener(\"click\", (event) => {\n this.onClick(event);\n }, false);\n }\n onClick(event) {\n if (event.defaultPrevented) {\n return;\n }\n const selection = this.window.getSelection();\n if (selection && selection.type == \"Range\") {\n // There's an on-going selection, the tap will dismiss it so we don't forward it.\n // selection.type might be None (collapsed) or Caret with a collapsed range\n // when there is not true selection.\n return;\n }\n let nearestElement;\n if (event.target instanceof HTMLElement) {\n nearestElement = this.nearestInteractiveElement(event.target);\n }\n else {\n nearestElement = null;\n }\n if (nearestElement) {\n if (nearestElement instanceof HTMLAnchorElement) {\n this.listener.onLinkActivated(nearestElement.href, nearestElement.outerHTML);\n }\n }\n else {\n this.listener.onTap(event);\n }\n event.stopPropagation();\n event.preventDefault();\n }\n // See. https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling\n nearestInteractiveElement(element) {\n if (element == null) {\n return null;\n }\n const interactiveTags = [\n \"a\",\n \"audio\",\n \"button\",\n \"canvas\",\n \"details\",\n \"input\",\n \"label\",\n \"option\",\n \"select\",\n \"submit\",\n \"textarea\",\n \"video\",\n ];\n if (interactiveTags.indexOf(element.nodeName.toLowerCase()) != -1) {\n return element;\n }\n // Checks whether the element is editable by the user.\n if (element.hasAttribute(\"contenteditable\") &&\n element.getAttribute(\"contenteditable\").toLowerCase() != \"false\") {\n return element;\n }\n // Checks parents recursively because the touch might be for example on an inside a .\n if (element.parentElement) {\n return this.nearestInteractiveElement(element.parentElement);\n }\n return null;\n }\n}\n","import { computeScale } from \"../util/fit\";\nimport { PageManager } from \"./page-manager\";\nimport { ViewportStringBuilder } from \"../util/viewport\";\nimport { GesturesDetector } from \"../common/gestures\";\nexport class SingleAreaManager {\n constructor(window, iframe, metaViewport, listener) {\n this.fit = \"contain\" /* Fit.Contain */;\n this.insets = { top: 0, right: 0, bottom: 0, left: 0 };\n this.scale = 1;\n window.addEventListener(\"message\", (event) => {\n if (event.source === iframe.contentWindow && event.ports[0]) {\n this.page.setMessagePort(event.ports[0]);\n }\n });\n const wrapperGesturesListener = {\n onTap: (event) => {\n const tapEvent = {\n x: (event.clientX - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.clientY - visualViewport.offsetTop) * visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onLinkActivated: (_) => {\n throw Error(\"No interactive element in the root document.\");\n },\n };\n new GesturesDetector(window, wrapperGesturesListener);\n this.metaViewport = metaViewport;\n const pageListener = {\n onIframeLoaded: () => {\n this.onIframeLoaded();\n },\n onTap: (event) => {\n const boundingRect = iframe.getBoundingClientRect();\n const tapEvent = {\n x: (event.x + boundingRect.left - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.y + boundingRect.top - visualViewport.offsetTop) *\n visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n listener.onLinkActivated(href, outerHtml);\n },\n };\n this.page = new PageManager(window, iframe, pageListener);\n }\n setViewport(viewport, insets) {\n if (this.viewport == viewport && this.insets == insets) {\n return;\n }\n this.viewport = viewport;\n this.insets = insets;\n this.layout();\n }\n setFit(fit) {\n if (this.fit == fit) {\n return;\n }\n this.fit = fit;\n this.layout();\n }\n loadResource(url) {\n this.page.hide();\n this.page.loadPage(url);\n }\n onIframeLoaded() {\n if (!this.page.size) {\n // FIXME: raise error\n }\n else {\n this.layout();\n }\n }\n layout() {\n if (!this.page.size || !this.viewport) {\n return;\n }\n const margins = {\n top: this.insets.top,\n right: this.insets.right,\n bottom: this.insets.bottom,\n left: this.insets.left,\n };\n this.page.setMargins(margins);\n const safeDrawingSize = {\n width: this.viewport.width - this.insets.left - this.insets.right,\n height: this.viewport.height - this.insets.top - this.insets.bottom,\n };\n const scale = computeScale(this.fit, this.page.size, safeDrawingSize);\n this.metaViewport.content = new ViewportStringBuilder()\n .setInitialScale(scale)\n .setMinimumScale(scale)\n .setWidth(this.page.size.width)\n .setHeight(this.page.size.height)\n .build();\n this.scale = scale;\n this.page.show();\n }\n}\n","export function computeScale(fit, content, container) {\n switch (fit) {\n case \"contain\" /* Fit.Contain */:\n return fitContain(content, container);\n case \"width\" /* Fit.Width */:\n return fitWidth(content, container);\n case \"height\" /* Fit.Height */:\n return fitHeight(content, container);\n }\n}\nfunction fitContain(content, container) {\n const widthRatio = container.width / content.width;\n const heightRatio = container.height / content.height;\n return Math.min(widthRatio, heightRatio);\n}\nfunction fitWidth(content, container) {\n return container.width / content.width;\n}\nfunction fitHeight(content, container) {\n return container.height / content.height;\n}\n","export class BridgeGesturesAdapter {\n constructor(gesturesApi) {\n this.nativeApi = gesturesApi;\n }\n onTap(event) {\n this.nativeApi.onTap(JSON.stringify(event));\n }\n onLinkActivated(href, outerHtml) {\n this.nativeApi.onLinkActivated(href, outerHtml);\n }\n}\n","//\n// Copyright 2024 Readium Foundation. All rights reserved.\n// Use of this source code is governed by the BSD-style license\n// available in the top-level LICENSE file of the project.\n//\nimport { FixedSingleBridge } from \"./bridge/fixed-single-bridge\";\nconst iframe = document.getElementById(\"page\");\nconst metaViewport = document.querySelector(\"meta[name=viewport]\");\nwindow.singleArea = new FixedSingleBridge(window, iframe, metaViewport, window.gestures);\nwindow.documentState.onScriptsLoaded();\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nwindow.addEventListener(\"load\", (event) => {\n window.documentState.onDocumentLoadedAndSized();\n});\n","import { SingleAreaManager } from \"../fixed/single-area-manager\";\nimport { BridgeGesturesAdapter } from \"./all-gestures-bridge\";\nexport class FixedSingleBridge {\n constructor(window, iframe, metaViewport, gestures) {\n const listener = new BridgeGesturesAdapter(gestures);\n this.manager = new SingleAreaManager(window, iframe, metaViewport, listener);\n }\n loadResource(url) {\n this.manager.loadResource(url);\n }\n setViewport(viewporttWidth, viewportHeight, insetTop, insetRight, insetBottom, insetLeft) {\n const viewport = { width: viewporttWidth, height: viewportHeight };\n const insets = {\n top: insetTop,\n left: insetLeft,\n bottom: insetBottom,\n right: insetRight,\n };\n this.manager.setViewport(viewport, insets);\n }\n setFit(fit) {\n if (fit != \"contain\" && fit != \"width\" && fit != \"height\") {\n throw Error(`Invalid fit value: ${fit}`);\n }\n this.manager.setFit(fit);\n }\n}\n"],"names":["PageManager","constructor","window","iframe","listener","this","margins","top","right","bottom","left","contentWindow","Error","setMessagePort","messagePort","onmessage","message","onMessageFromIframe","show","style","display","hide","setMargins","marginTop","marginLeft","marginBottom","marginRight","loadPage","url","src","setPlaceholder","size","visibility","width","height","event","data","kind","onContentSizeAvailable","onTap","x","y","onLinkActivated","URL","href","toString","outerHtml","_a","onIframeLoaded","ViewportStringBuilder","setInitialScale","scale","initialScale","setMinimumScale","minimumScale","setWidth","setHeight","build","components","push","join","GesturesDetector","document","addEventListener","onClick","defaultPrevented","selection","getSelection","type","nearestElement","target","HTMLElement","nearestInteractiveElement","HTMLAnchorElement","outerHTML","stopPropagation","preventDefault","element","indexOf","nodeName","toLowerCase","hasAttribute","getAttribute","parentElement","SingleAreaManager","metaViewport","fit","insets","source","ports","page","tapEvent","clientX","visualViewport","offsetLeft","clientY","offsetTop","_","pageListener","boundingRect","getBoundingClientRect","setViewport","viewport","layout","setFit","loadResource","safeDrawingSize","content","container","widthRatio","heightRatio","Math","min","fitContain","fitWidth","fitHeight","computeScale","BridgeGesturesAdapter","gesturesApi","nativeApi","JSON","stringify","getElementById","querySelector","singleArea","gestures","manager","viewporttWidth","viewportHeight","insetTop","insetRight","insetBottom","insetLeft","documentState","onScriptsLoaded","onDocumentLoadedAndSized"],"sourceRoot":""} \ No newline at end of file +{"version":3,"file":"fixed-single-script.js","mappings":"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","sources":["webpack://readium-js/./src/fixed/page-manager.ts","webpack://readium-js/./src/util/viewport.ts","webpack://readium-js/./src/common/gestures.ts","webpack://readium-js/./src/fixed/single-area-manager.ts","webpack://readium-js/./src/util/fit.ts","webpack://readium-js/./src/bridge/all-listener-bridge.ts","webpack://readium-js/./src/index-fixed-single.ts","webpack://readium-js/./src/bridge/fixed-single-bridge.ts"],"sourcesContent":["/** Manages a fixed layout resource embedded in an iframe. */\nexport class PageManager {\n constructor(window, iframe, listener) {\n this.margins = { top: 0, right: 0, bottom: 0, left: 0 };\n if (!iframe.contentWindow) {\n throw Error(\"Iframe argument must have been attached to DOM.\");\n }\n this.listener = listener;\n this.iframe = iframe;\n }\n setMessagePort(messagePort) {\n messagePort.onmessage = (message) => {\n this.onMessageFromIframe(message);\n };\n }\n show() {\n this.iframe.style.display = \"unset\";\n }\n hide() {\n this.iframe.style.display = \"none\";\n }\n /** Sets page margins. */\n setMargins(margins) {\n if (this.margins == margins) {\n return;\n }\n this.iframe.style.marginTop = this.margins.top + \"px\";\n this.iframe.style.marginLeft = this.margins.left + \"px\";\n this.iframe.style.marginBottom = this.margins.bottom + \"px\";\n this.iframe.style.marginRight = this.margins.right + \"px\";\n }\n /** Loads page content. */\n loadPage(url) {\n this.iframe.src = url;\n }\n /** Sets the size of this page without content. */\n setPlaceholder(size) {\n this.iframe.style.visibility = \"hidden\";\n this.iframe.style.width = size.width + \"px\";\n this.iframe.style.height = size.height + \"px\";\n this.size = size;\n }\n onMessageFromIframe(event) {\n const message = event.data;\n switch (message.kind) {\n case \"contentSize\":\n return this.onContentSizeAvailable(message.size);\n case \"tap\":\n return this.listener.onTap({ x: message.x, y: message.y });\n case \"linkActivated\":\n return this.onLinkActivated(message);\n }\n }\n onLinkActivated(message) {\n try {\n const url = new URL(message.href, this.iframe.src);\n this.listener.onLinkActivated(url.toString(), message.outerHtml);\n }\n catch (_a) {\n // Do nothing if url is not valid.\n }\n }\n onContentSizeAvailable(size) {\n if (!size) {\n //FIXME: handle edge case\n return;\n }\n this.iframe.style.width = size.width + \"px\";\n this.iframe.style.height = size.height + \"px\";\n this.size = size;\n this.listener.onIframeLoaded();\n }\n}\n","export class ViewportStringBuilder {\n setInitialScale(scale) {\n this.initialScale = scale;\n return this;\n }\n setMinimumScale(scale) {\n this.minimumScale = scale;\n return this;\n }\n setWidth(width) {\n this.width = width;\n return this;\n }\n setHeight(height) {\n this.height = height;\n return this;\n }\n build() {\n const components = [];\n if (this.initialScale) {\n components.push(\"initial-scale=\" + this.initialScale);\n }\n if (this.minimumScale) {\n components.push(\"minimum-scale=\" + this.minimumScale);\n }\n if (this.width) {\n components.push(\"width=\" + this.width);\n }\n if (this.height) {\n components.push(\"height=\" + this.height);\n }\n return components.join(\", \");\n }\n}\nexport function parseViewportString(viewportString) {\n const regex = /(\\w+) *= *([^\\s,]+)/g;\n const properties = new Map();\n let match;\n while ((match = regex.exec(viewportString))) {\n if (match != null) {\n properties.set(match[1], match[2]);\n }\n }\n const width = parseFloat(properties.get(\"width\"));\n const height = parseFloat(properties.get(\"height\"));\n if (width && height) {\n return { width, height };\n }\n else {\n return undefined;\n }\n}\n","export class GesturesDetector {\n constructor(window, listener) {\n this.window = window;\n this.listener = listener;\n document.addEventListener(\"click\", (event) => {\n this.onClick(event);\n }, false);\n }\n onClick(event) {\n if (event.defaultPrevented) {\n return;\n }\n const selection = this.window.getSelection();\n if (selection && selection.type == \"Range\") {\n // There's an on-going selection, the tap will dismiss it so we don't forward it.\n // selection.type might be None (collapsed) or Caret with a collapsed range\n // when there is not true selection.\n return;\n }\n let nearestElement;\n if (event.target instanceof HTMLElement) {\n nearestElement = this.nearestInteractiveElement(event.target);\n }\n else {\n nearestElement = null;\n }\n if (nearestElement) {\n if (nearestElement instanceof HTMLAnchorElement) {\n this.listener.onLinkActivated(nearestElement.href, nearestElement.outerHTML);\n }\n }\n else {\n this.listener.onTap(event);\n }\n event.stopPropagation();\n event.preventDefault();\n }\n // See. https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling\n nearestInteractiveElement(element) {\n if (element == null) {\n return null;\n }\n const interactiveTags = [\n \"a\",\n \"audio\",\n \"button\",\n \"canvas\",\n \"details\",\n \"input\",\n \"label\",\n \"option\",\n \"select\",\n \"submit\",\n \"textarea\",\n \"video\",\n ];\n if (interactiveTags.indexOf(element.nodeName.toLowerCase()) != -1) {\n return element;\n }\n // Checks whether the element is editable by the user.\n if (element.hasAttribute(\"contenteditable\") &&\n element.getAttribute(\"contenteditable\").toLowerCase() != \"false\") {\n return element;\n }\n // Checks parents recursively because the touch might be for example on an inside a .\n if (element.parentElement) {\n return this.nearestInteractiveElement(element.parentElement);\n }\n return null;\n }\n}\n","import { computeScale } from \"../util/fit\";\nimport { PageManager } from \"./page-manager\";\nimport { ViewportStringBuilder } from \"../util/viewport\";\nimport { GesturesDetector } from \"../common/gestures\";\nexport class SingleAreaManager {\n constructor(window, iframe, metaViewport, listener) {\n this.fit = \"contain\" /* Fit.Contain */;\n this.insets = { top: 0, right: 0, bottom: 0, left: 0 };\n this.scale = 1;\n this.listener = listener;\n window.addEventListener(\"message\", (event) => {\n if (event.source === iframe.contentWindow && event.ports[0]) {\n this.page.setMessagePort(event.ports[0]);\n }\n });\n const wrapperGesturesListener = {\n onTap: (event) => {\n const tapEvent = {\n x: (event.clientX - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.clientY - visualViewport.offsetTop) * visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onLinkActivated: (_) => {\n throw Error(\"No interactive element in the root document.\");\n },\n };\n new GesturesDetector(window, wrapperGesturesListener);\n this.metaViewport = metaViewport;\n const pageListener = {\n onIframeLoaded: () => {\n this.onIframeLoaded();\n },\n onTap: (event) => {\n const boundingRect = iframe.getBoundingClientRect();\n const tapEvent = {\n x: (event.x + boundingRect.left - visualViewport.offsetLeft) *\n visualViewport.scale,\n y: (event.y + boundingRect.top - visualViewport.offsetTop) *\n visualViewport.scale,\n };\n listener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n listener.onLinkActivated(href, outerHtml);\n },\n };\n this.page = new PageManager(window, iframe, pageListener);\n }\n setViewport(viewport, insets) {\n if (this.viewport == viewport && this.insets == insets) {\n return;\n }\n this.viewport = viewport;\n this.insets = insets;\n this.layout();\n }\n setFit(fit) {\n if (this.fit == fit) {\n return;\n }\n this.fit = fit;\n this.layout();\n }\n loadResource(url) {\n this.page.hide();\n this.page.loadPage(url);\n }\n onIframeLoaded() {\n if (!this.page.size) {\n // FIXME: raise error\n }\n else {\n this.layout();\n }\n }\n layout() {\n if (!this.page.size || !this.viewport) {\n return;\n }\n const margins = {\n top: this.insets.top,\n right: this.insets.right,\n bottom: this.insets.bottom,\n left: this.insets.left,\n };\n this.page.setMargins(margins);\n const safeDrawingSize = {\n width: this.viewport.width - this.insets.left - this.insets.right,\n height: this.viewport.height - this.insets.top - this.insets.bottom,\n };\n const scale = computeScale(this.fit, this.page.size, safeDrawingSize);\n this.metaViewport.content = new ViewportStringBuilder()\n .setInitialScale(scale)\n .setMinimumScale(scale)\n .setWidth(this.page.size.width)\n .setHeight(this.page.size.height)\n .build();\n this.scale = scale;\n this.page.show();\n this.listener.onLayout();\n }\n}\n","export function computeScale(fit, content, container) {\n switch (fit) {\n case \"contain\" /* Fit.Contain */:\n return fitContain(content, container);\n case \"width\" /* Fit.Width */:\n return fitWidth(content, container);\n case \"height\" /* Fit.Height */:\n return fitHeight(content, container);\n }\n}\nfunction fitContain(content, container) {\n const widthRatio = container.width / content.width;\n const heightRatio = container.height / content.height;\n return Math.min(widthRatio, heightRatio);\n}\nfunction fitWidth(content, container) {\n return container.width / content.width;\n}\nfunction fitHeight(content, container) {\n return container.height / content.height;\n}\n","export class ReflowableListenerAdapter {\n constructor(gesturesBridge) {\n this.gesturesBridge = gesturesBridge;\n }\n onTap(event) {\n const tapEvent = {\n x: (event.clientX - visualViewport.offsetLeft) * visualViewport.scale,\n y: (event.clientY - visualViewport.offsetTop) * visualViewport.scale,\n };\n const stringEvent = JSON.stringify(tapEvent);\n this.gesturesBridge.onTap(stringEvent);\n }\n onLinkActivated(href, outerHtml) {\n this.gesturesBridge.onLinkActivated(href, outerHtml);\n }\n}\nexport class FixedListenerAdapter {\n constructor(window, gesturesApi, documentApi) {\n this.window = window;\n this.gesturesApi = gesturesApi;\n this.documentApi = documentApi;\n this.resizeObserverAdded = false;\n this.documentLoadedFired = false;\n }\n onTap(event) {\n this.gesturesApi.onTap(JSON.stringify(event));\n }\n onLinkActivated(href, outerHtml) {\n this.gesturesApi.onLinkActivated(href, outerHtml);\n }\n onLayout() {\n if (!this.resizeObserverAdded) {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const observer = new ResizeObserver(() => {\n requestAnimationFrame(() => {\n const scrollingElement = this.window.document.scrollingElement;\n if (!this.documentLoadedFired &&\n (scrollingElement == null ||\n scrollingElement.scrollHeight > 0 ||\n scrollingElement.scrollWidth > 0)) {\n this.documentApi.onDocumentLoadedAndSized();\n this.documentLoadedFired = true;\n }\n else {\n this.documentApi.onDocumentResized();\n }\n });\n });\n observer.observe(this.window.document.body);\n }\n this.resizeObserverAdded = true;\n }\n}\n","//\n// Copyright 2024 Readium Foundation. All rights reserved.\n// Use of this source code is governed by the BSD-style license\n// available in the top-level LICENSE file of the project.\n//\nimport { FixedSingleBridge } from \"./bridge/fixed-single-bridge\";\nconst iframe = document.getElementById(\"page\");\nconst metaViewport = document.querySelector(\"meta[name=viewport]\");\nwindow.singleArea = new FixedSingleBridge(window, iframe, metaViewport, window.gestures, window.documentState);\nwindow.documentState.onScriptsLoaded();\n","import { SingleAreaManager } from \"../fixed/single-area-manager\";\nimport { FixedListenerAdapter, } from \"./all-listener-bridge\";\nexport class FixedSingleBridge {\n constructor(window, iframe, metaViewport, gesturesBridge, documentBridge) {\n const listener = new FixedListenerAdapter(window, gesturesBridge, documentBridge);\n this.manager = new SingleAreaManager(window, iframe, metaViewport, listener);\n }\n loadResource(url) {\n this.manager.loadResource(url);\n }\n setViewport(viewporttWidth, viewportHeight, insetTop, insetRight, insetBottom, insetLeft) {\n const viewport = { width: viewporttWidth, height: viewportHeight };\n const insets = {\n top: insetTop,\n left: insetLeft,\n bottom: insetBottom,\n right: insetRight,\n };\n this.manager.setViewport(viewport, insets);\n }\n setFit(fit) {\n if (fit != \"contain\" && fit != \"width\" && fit != \"height\") {\n throw Error(`Invalid fit value: ${fit}`);\n }\n this.manager.setFit(fit);\n }\n}\n"],"names":["PageManager","constructor","window","iframe","listener","this","margins","top","right","bottom","left","contentWindow","Error","setMessagePort","messagePort","onmessage","message","onMessageFromIframe","show","style","display","hide","setMargins","marginTop","marginLeft","marginBottom","marginRight","loadPage","url","src","setPlaceholder","size","visibility","width","height","event","data","kind","onContentSizeAvailable","onTap","x","y","onLinkActivated","URL","href","toString","outerHtml","_a","onIframeLoaded","ViewportStringBuilder","setInitialScale","scale","initialScale","setMinimumScale","minimumScale","setWidth","setHeight","build","components","push","join","GesturesDetector","document","addEventListener","onClick","defaultPrevented","selection","getSelection","type","nearestElement","target","HTMLElement","nearestInteractiveElement","HTMLAnchorElement","outerHTML","stopPropagation","preventDefault","element","indexOf","nodeName","toLowerCase","hasAttribute","getAttribute","parentElement","SingleAreaManager","metaViewport","fit","insets","source","ports","page","tapEvent","clientX","visualViewport","offsetLeft","clientY","offsetTop","_","pageListener","boundingRect","getBoundingClientRect","setViewport","viewport","layout","setFit","loadResource","safeDrawingSize","content","container","widthRatio","heightRatio","Math","min","fitContain","fitWidth","fitHeight","computeScale","onLayout","FixedListenerAdapter","gesturesApi","documentApi","resizeObserverAdded","documentLoadedFired","JSON","stringify","ResizeObserver","requestAnimationFrame","scrollingElement","scrollHeight","scrollWidth","onDocumentLoadedAndSized","onDocumentResized","observe","body","getElementById","querySelector","singleArea","gesturesBridge","documentBridge","manager","viewporttWidth","viewportHeight","insetTop","insetRight","insetBottom","insetLeft","gestures","documentState","onScriptsLoaded"],"sourceRoot":""} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js index 16302be211..5e4917e958 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js @@ -1,2 +1,2 @@ -!function(){"use strict";const e=new class{constructor(e){this.nativeApi=e}onTap(e){this.nativeApi.onTap(JSON.stringify(e))}onLinkActivated(e,t){this.nativeApi.onLinkActivated(e,t)}}(window.gestures),t={onTap:t=>{const n={x:(t.clientX-visualViewport.offsetLeft)*visualViewport.scale,y:(t.clientY-visualViewport.offsetTop)*visualViewport.scale};e.onTap(n)},onLinkActivated:(t,n)=>{e.onLinkActivated(t,n)}};new class{constructor(e,t){this.window=e,this.listener=t,document.addEventListener("click",(e=>{this.onClick(e)}),!1)}onClick(e){if(e.defaultPrevented)return;const t=this.window.getSelection();if(t&&"Range"==t.type)return;let n;n=e.target instanceof HTMLElement?this.nearestInteractiveElement(e.target):null,n?n instanceof HTMLAnchorElement&&this.listener.onLinkActivated(n.href,n.outerHTML):this.listener.onTap(e),e.stopPropagation(),e.preventDefault()}nearestInteractiveElement(e){return null==e?null:-1!=["a","audio","button","canvas","details","input","label","option","select","submit","textarea","video"].indexOf(e.nodeName.toLowerCase())||e.hasAttribute("contenteditable")&&"false"!=e.getAttribute("contenteditable").toLowerCase()?e:e.parentElement?this.nearestInteractiveElement(e.parentElement):null}}(window,t),Window.prototype.readiumcss=new class{constructor(e){this.document=e}setProperties(e){for(const[t,n]of e)this.setProperty(t,n)}setProperty(e,t){null===t||""===t?this.removeProperty(e):document.documentElement.style.setProperty(e,t,"important")}removeProperty(e){document.documentElement.style.removeProperty(e)}}(window.document),window.documentState.onScriptsLoaded(),window.addEventListener("load",(e=>{let t=!1;new ResizeObserver((()=>{requestAnimationFrame((()=>{var e;if(function(e){const t="readium-virtual-page";let n=e.document.getElementById(t);if(2!==function(e){return parseInt(e.getComputedStyle(e.document.documentElement).getPropertyValue("column-count"))}(e))return!!n&&(n.remove(),!0);{const o=e.document.scrollingElement.scrollWidth/e.innerWidth;return!!(Math.round(2*o)/2%1>.1)&&(n?n.remove():(n=e.document.createElement("div"),n.setAttribute("id",t),n.dataset.readium="true",n.style.breakBefore="column",n.innerHTML="​",e.document.body.appendChild(n)),!0)}}(window))return;console.log(`resize ${null===(e=window.document.scrollingElement)||void 0===e?void 0:e.scrollWidth} ${window.innerWidth}`);const n=window.document.scrollingElement;!t&&(null==n||n.scrollHeight>0||n.scrollWidth>0)?(window.documentState.onDocumentLoadedAndSized(),t=!0):window.documentState.onDocumentResized()}))})).observe(document.body)}))}(); +!function(){"use strict";const e=new class{constructor(e){this.gesturesBridge=e}onTap(e){const t={x:(e.clientX-visualViewport.offsetLeft)*visualViewport.scale,y:(e.clientY-visualViewport.offsetTop)*visualViewport.scale},n=JSON.stringify(t);this.gesturesBridge.onTap(n)}onLinkActivated(e,t){this.gesturesBridge.onLinkActivated(e,t)}}(window.gestures);new class{constructor(e,t){this.window=e,this.listener=t,document.addEventListener("click",(e=>{this.onClick(e)}),!1)}onClick(e){if(e.defaultPrevented)return;const t=this.window.getSelection();if(t&&"Range"==t.type)return;let n;n=e.target instanceof HTMLElement?this.nearestInteractiveElement(e.target):null,n?n instanceof HTMLAnchorElement&&this.listener.onLinkActivated(n.href,n.outerHTML):this.listener.onTap(e),e.stopPropagation(),e.preventDefault()}nearestInteractiveElement(e){return null==e?null:-1!=["a","audio","button","canvas","details","input","label","option","select","submit","textarea","video"].indexOf(e.nodeName.toLowerCase())||e.hasAttribute("contenteditable")&&"false"!=e.getAttribute("contenteditable").toLowerCase()?e:e.parentElement?this.nearestInteractiveElement(e.parentElement):null}}(window,e),Window.prototype.readiumcss=new class{constructor(e){this.document=e}setProperties(e){for(const[t,n]of e)this.setProperty(t,n)}setProperty(e,t){null===t||""===t?this.removeProperty(e):document.documentElement.style.setProperty(e,t,"important")}removeProperty(e){document.documentElement.style.removeProperty(e)}}(window.document),window.documentState.onScriptsLoaded(),window.addEventListener("load",(e=>{let t=!1;new ResizeObserver((()=>{requestAnimationFrame((()=>{if(function(e){const t="readium-virtual-page";let n=e.document.getElementById(t);if(2!==function(e){return parseInt(e.getComputedStyle(e.document.documentElement).getPropertyValue("column-count"))}(e))return!!n&&(n.remove(),!0);{const o=e.document.scrollingElement.scrollWidth/e.innerWidth;return!!(Math.round(2*o)/2%1>.1)&&(n?n.remove():(n=e.document.createElement("div"),n.setAttribute("id",t),n.dataset.readium="true",n.style.breakBefore="column",n.innerHTML="​",e.document.body.appendChild(n)),!0)}}(window))return;const e=window.document.scrollingElement;!t&&(null==e||e.scrollHeight>0||e.scrollWidth>0)?(window.documentState.onDocumentLoadedAndSized(),t=!0):window.documentState.onDocumentResized()}))})).observe(document.body)}))}(); //# sourceMappingURL=reflowable-injectable-script.js.map \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map index 8018300222..0d00777097 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map @@ -1 +1 @@ -{"version":3,"file":"reflowable-injectable-script.js","mappings":"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","sources":["webpack://readium-js/./src/index-reflowable-injectable.ts","webpack://readium-js/./src/bridge/all-gestures-bridge.ts","webpack://readium-js/./src/common/gestures.ts","webpack://readium-js/./src/bridge/reflowable-css-bridge.ts","webpack://readium-js/./src/util/columns.ts"],"sourcesContent":["//\n// Copyright 2024 Readium Foundation. All rights reserved.\n// Use of this source code is governed by the BSD-style license\n// available in the top-level LICENSE file of the project.\n//\n/**\n * Script loaded by reflowable resources.\n */\nimport { BridgeGesturesAdapter, } from \"./bridge/all-gestures-bridge\";\nimport { CssBridge } from \"./bridge/reflowable-css-bridge\";\nimport { GesturesDetector } from \"./common/gestures\";\nimport { appendVirtualColumnIfNeeded } from \"./util/columns\";\nconst bridgeListener = new BridgeGesturesAdapter(window.gestures);\nconst gesturesListener = {\n onTap: (event) => {\n const tapEvent = {\n x: (event.clientX - visualViewport.offsetLeft) * visualViewport.scale,\n y: (event.clientY - visualViewport.offsetTop) * visualViewport.scale,\n };\n bridgeListener.onTap(tapEvent);\n },\n onLinkActivated: (href, outerHtml) => {\n bridgeListener.onLinkActivated(href, outerHtml);\n },\n};\nnew GesturesDetector(window, gesturesListener);\nWindow.prototype.readiumcss = new CssBridge(window.document);\nwindow.documentState.onScriptsLoaded();\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nwindow.addEventListener(\"load\", (event) => {\n let documentLoadedFired = false;\n const observer = new ResizeObserver(() => {\n requestAnimationFrame(() => {\n var _a;\n if (appendVirtualColumnIfNeeded(window)) {\n // Column has been added or removed, wait for next resize callback.\n return;\n }\n console.log(`resize ${(_a = window.document.scrollingElement) === null || _a === void 0 ? void 0 : _a.scrollWidth} ${window.innerWidth}`);\n const scrollingElement = window.document.scrollingElement;\n if (!documentLoadedFired &&\n (scrollingElement == null ||\n scrollingElement.scrollHeight > 0 ||\n scrollingElement.scrollWidth > 0)) {\n window.documentState.onDocumentLoadedAndSized();\n documentLoadedFired = true;\n }\n else {\n window.documentState.onDocumentResized();\n }\n });\n });\n observer.observe(document.body);\n});\n","export class BridgeGesturesAdapter {\n constructor(gesturesApi) {\n this.nativeApi = gesturesApi;\n }\n onTap(event) {\n this.nativeApi.onTap(JSON.stringify(event));\n }\n onLinkActivated(href, outerHtml) {\n this.nativeApi.onLinkActivated(href, outerHtml);\n }\n}\n","export class GesturesDetector {\n constructor(window, listener) {\n this.window = window;\n this.listener = listener;\n document.addEventListener(\"click\", (event) => {\n this.onClick(event);\n }, false);\n }\n onClick(event) {\n if (event.defaultPrevented) {\n return;\n }\n const selection = this.window.getSelection();\n if (selection && selection.type == \"Range\") {\n // There's an on-going selection, the tap will dismiss it so we don't forward it.\n // selection.type might be None (collapsed) or Caret with a collapsed range\n // when there is not true selection.\n return;\n }\n let nearestElement;\n if (event.target instanceof HTMLElement) {\n nearestElement = this.nearestInteractiveElement(event.target);\n }\n else {\n nearestElement = null;\n }\n if (nearestElement) {\n if (nearestElement instanceof HTMLAnchorElement) {\n this.listener.onLinkActivated(nearestElement.href, nearestElement.outerHTML);\n }\n }\n else {\n this.listener.onTap(event);\n }\n event.stopPropagation();\n event.preventDefault();\n }\n // See. https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling\n nearestInteractiveElement(element) {\n if (element == null) {\n return null;\n }\n const interactiveTags = [\n \"a\",\n \"audio\",\n \"button\",\n \"canvas\",\n \"details\",\n \"input\",\n \"label\",\n \"option\",\n \"select\",\n \"submit\",\n \"textarea\",\n \"video\",\n ];\n if (interactiveTags.indexOf(element.nodeName.toLowerCase()) != -1) {\n return element;\n }\n // Checks whether the element is editable by the user.\n if (element.hasAttribute(\"contenteditable\") &&\n element.getAttribute(\"contenteditable\").toLowerCase() != \"false\") {\n return element;\n }\n // Checks parents recursively because the touch might be for example on an inside a .\n if (element.parentElement) {\n return this.nearestInteractiveElement(element.parentElement);\n }\n return null;\n }\n}\n","export class CssBridge {\n constructor(document) {\n this.document = document;\n }\n setProperties(properties) {\n for (const [key, value] of properties) {\n this.setProperty(key, value);\n }\n }\n // For setting user setting.\n setProperty(key, value) {\n if (value === null || value === \"\") {\n this.removeProperty(key);\n }\n else {\n const root = document.documentElement;\n // The `!important` annotation is added with `setProperty()` because if it's part of the\n // `value`, it will be ignored by the Web View.\n root.style.setProperty(key, value, \"important\");\n }\n }\n // For removing user setting.\n removeProperty(key) {\n const root = document.documentElement;\n root.style.removeProperty(key);\n }\n}\n","/**\n * In paginated mode, the width of each resource must be a multiple of the viewport size\n * for proper snapping. This may not be automatically the case if the number of\n * columns in the resource is not a multiple of the number of columns fitting in the viewport.\n * To fix this, we insert a blank virtual column at the end of the resource.\n *\n * Returns if a virtual column has been added or removed.\n */\nexport function appendVirtualColumnIfNeeded(wnd) {\n // FIXME: what about scroll mode?\n const id = \"readium-virtual-page\";\n let virtualCol = wnd.document.getElementById(id);\n if (getColumnCountPerScreen(wnd) !== 2) {\n if (virtualCol) {\n virtualCol.remove();\n return true;\n }\n else {\n return false;\n }\n }\n else {\n const documentWidth = wnd.document.scrollingElement.scrollWidth;\n const colCount = documentWidth / wnd.innerWidth;\n const hasOddColCount = (Math.round(colCount * 2) / 2) % 1 > 0.1;\n if (hasOddColCount) {\n if (virtualCol) {\n virtualCol.remove();\n }\n else {\n virtualCol = wnd.document.createElement(\"div\");\n virtualCol.setAttribute(\"id\", id);\n virtualCol.dataset.readium = \"true\";\n virtualCol.style.breakBefore = \"column\";\n virtualCol.innerHTML = \"​\"; // zero-width space\n wnd.document.body.appendChild(virtualCol);\n }\n return true;\n }\n else {\n return false;\n }\n }\n}\nfunction getColumnCountPerScreen(wnd) {\n return parseInt(wnd\n .getComputedStyle(wnd.document.documentElement)\n .getPropertyValue(\"column-count\"));\n}\n"],"names":["bridgeListener","constructor","gesturesApi","this","nativeApi","onTap","event","JSON","stringify","onLinkActivated","href","outerHtml","window","gestures","gesturesListener","tapEvent","x","clientX","visualViewport","offsetLeft","scale","y","clientY","offsetTop","listener","document","addEventListener","onClick","defaultPrevented","selection","getSelection","type","nearestElement","target","HTMLElement","nearestInteractiveElement","HTMLAnchorElement","outerHTML","stopPropagation","preventDefault","element","indexOf","nodeName","toLowerCase","hasAttribute","getAttribute","parentElement","Window","prototype","readiumcss","setProperties","properties","key","value","setProperty","removeProperty","documentElement","style","documentState","onScriptsLoaded","documentLoadedFired","ResizeObserver","requestAnimationFrame","_a","wnd","id","virtualCol","getElementById","parseInt","getComputedStyle","getPropertyValue","getColumnCountPerScreen","remove","colCount","scrollingElement","scrollWidth","innerWidth","Math","round","createElement","setAttribute","dataset","readium","breakBefore","innerHTML","body","appendChild","appendVirtualColumnIfNeeded","console","log","scrollHeight","onDocumentLoadedAndSized","onDocumentResized","observe"],"sourceRoot":""} \ No newline at end of file +{"version":3,"file":"reflowable-injectable-script.js","mappings":"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","sources":["webpack://readium-js/./src/index-reflowable-injectable.ts","webpack://readium-js/./src/bridge/all-listener-bridge.ts","webpack://readium-js/./src/common/gestures.ts","webpack://readium-js/./src/bridge/reflowable-css-bridge.ts","webpack://readium-js/./src/util/columns.ts"],"sourcesContent":["//\n// Copyright 2024 Readium Foundation. All rights reserved.\n// Use of this source code is governed by the BSD-style license\n// available in the top-level LICENSE file of the project.\n//\n/**\n * Script loaded by reflowable resources.\n */\nimport { ReflowableListenerAdapter, } from \"./bridge/all-listener-bridge\";\nimport { CssBridge } from \"./bridge/reflowable-css-bridge\";\nimport { GesturesDetector } from \"./common/gestures\";\nimport { appendVirtualColumnIfNeeded } from \"./util/columns\";\nconst bridgeListener = new ReflowableListenerAdapter(window.gestures);\nnew GesturesDetector(window, bridgeListener);\nWindow.prototype.readiumcss = new CssBridge(window.document);\nwindow.documentState.onScriptsLoaded();\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nwindow.addEventListener(\"load\", (event) => {\n let documentLoadedFired = false;\n const observer = new ResizeObserver(() => {\n requestAnimationFrame(() => {\n if (appendVirtualColumnIfNeeded(window)) {\n // Column has been added or removed, wait for next resize callback.\n return;\n }\n const scrollingElement = window.document.scrollingElement;\n if (!documentLoadedFired &&\n (scrollingElement == null ||\n scrollingElement.scrollHeight > 0 ||\n scrollingElement.scrollWidth > 0)) {\n window.documentState.onDocumentLoadedAndSized();\n documentLoadedFired = true;\n }\n else {\n window.documentState.onDocumentResized();\n }\n });\n });\n observer.observe(document.body);\n});\n","export class ReflowableListenerAdapter {\n constructor(gesturesBridge) {\n this.gesturesBridge = gesturesBridge;\n }\n onTap(event) {\n const tapEvent = {\n x: (event.clientX - visualViewport.offsetLeft) * visualViewport.scale,\n y: (event.clientY - visualViewport.offsetTop) * visualViewport.scale,\n };\n const stringEvent = JSON.stringify(tapEvent);\n this.gesturesBridge.onTap(stringEvent);\n }\n onLinkActivated(href, outerHtml) {\n this.gesturesBridge.onLinkActivated(href, outerHtml);\n }\n}\nexport class FixedListenerAdapter {\n constructor(window, gesturesApi, documentApi) {\n this.window = window;\n this.gesturesApi = gesturesApi;\n this.documentApi = documentApi;\n this.resizeObserverAdded = false;\n this.documentLoadedFired = false;\n }\n onTap(event) {\n this.gesturesApi.onTap(JSON.stringify(event));\n }\n onLinkActivated(href, outerHtml) {\n this.gesturesApi.onLinkActivated(href, outerHtml);\n }\n onLayout() {\n if (!this.resizeObserverAdded) {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const observer = new ResizeObserver(() => {\n requestAnimationFrame(() => {\n const scrollingElement = this.window.document.scrollingElement;\n if (!this.documentLoadedFired &&\n (scrollingElement == null ||\n scrollingElement.scrollHeight > 0 ||\n scrollingElement.scrollWidth > 0)) {\n this.documentApi.onDocumentLoadedAndSized();\n this.documentLoadedFired = true;\n }\n else {\n this.documentApi.onDocumentResized();\n }\n });\n });\n observer.observe(this.window.document.body);\n }\n this.resizeObserverAdded = true;\n }\n}\n","export class GesturesDetector {\n constructor(window, listener) {\n this.window = window;\n this.listener = listener;\n document.addEventListener(\"click\", (event) => {\n this.onClick(event);\n }, false);\n }\n onClick(event) {\n if (event.defaultPrevented) {\n return;\n }\n const selection = this.window.getSelection();\n if (selection && selection.type == \"Range\") {\n // There's an on-going selection, the tap will dismiss it so we don't forward it.\n // selection.type might be None (collapsed) or Caret with a collapsed range\n // when there is not true selection.\n return;\n }\n let nearestElement;\n if (event.target instanceof HTMLElement) {\n nearestElement = this.nearestInteractiveElement(event.target);\n }\n else {\n nearestElement = null;\n }\n if (nearestElement) {\n if (nearestElement instanceof HTMLAnchorElement) {\n this.listener.onLinkActivated(nearestElement.href, nearestElement.outerHTML);\n }\n }\n else {\n this.listener.onTap(event);\n }\n event.stopPropagation();\n event.preventDefault();\n }\n // See. https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling\n nearestInteractiveElement(element) {\n if (element == null) {\n return null;\n }\n const interactiveTags = [\n \"a\",\n \"audio\",\n \"button\",\n \"canvas\",\n \"details\",\n \"input\",\n \"label\",\n \"option\",\n \"select\",\n \"submit\",\n \"textarea\",\n \"video\",\n ];\n if (interactiveTags.indexOf(element.nodeName.toLowerCase()) != -1) {\n return element;\n }\n // Checks whether the element is editable by the user.\n if (element.hasAttribute(\"contenteditable\") &&\n element.getAttribute(\"contenteditable\").toLowerCase() != \"false\") {\n return element;\n }\n // Checks parents recursively because the touch might be for example on an inside a .\n if (element.parentElement) {\n return this.nearestInteractiveElement(element.parentElement);\n }\n return null;\n }\n}\n","export class CssBridge {\n constructor(document) {\n this.document = document;\n }\n setProperties(properties) {\n for (const [key, value] of properties) {\n this.setProperty(key, value);\n }\n }\n // For setting user setting.\n setProperty(key, value) {\n if (value === null || value === \"\") {\n this.removeProperty(key);\n }\n else {\n const root = document.documentElement;\n // The `!important` annotation is added with `setProperty()` because if it's part of the\n // `value`, it will be ignored by the Web View.\n root.style.setProperty(key, value, \"important\");\n }\n }\n // For removing user setting.\n removeProperty(key) {\n const root = document.documentElement;\n root.style.removeProperty(key);\n }\n}\n","/**\n * In paginated mode, the width of each resource must be a multiple of the viewport size\n * for proper snapping. This may not be automatically the case if the number of\n * columns in the resource is not a multiple of the number of columns fitting in the viewport.\n * To fix this, we insert a blank virtual column at the end of the resource.\n *\n * Returns if a virtual column has been added or removed.\n */\nexport function appendVirtualColumnIfNeeded(wnd) {\n // FIXME: what about scroll mode?\n const id = \"readium-virtual-page\";\n let virtualCol = wnd.document.getElementById(id);\n if (getColumnCountPerScreen(wnd) !== 2) {\n if (virtualCol) {\n virtualCol.remove();\n return true;\n }\n else {\n return false;\n }\n }\n else {\n const documentWidth = wnd.document.scrollingElement.scrollWidth;\n const colCount = documentWidth / wnd.innerWidth;\n const hasOddColCount = (Math.round(colCount * 2) / 2) % 1 > 0.1;\n if (hasOddColCount) {\n if (virtualCol) {\n virtualCol.remove();\n }\n else {\n virtualCol = wnd.document.createElement(\"div\");\n virtualCol.setAttribute(\"id\", id);\n virtualCol.dataset.readium = \"true\";\n virtualCol.style.breakBefore = \"column\";\n virtualCol.innerHTML = \"​\"; // zero-width space\n wnd.document.body.appendChild(virtualCol);\n }\n return true;\n }\n else {\n return false;\n }\n }\n}\nfunction getColumnCountPerScreen(wnd) {\n return parseInt(wnd\n .getComputedStyle(wnd.document.documentElement)\n .getPropertyValue(\"column-count\"));\n}\n"],"names":["bridgeListener","constructor","gesturesBridge","this","onTap","event","tapEvent","x","clientX","visualViewport","offsetLeft","scale","y","clientY","offsetTop","stringEvent","JSON","stringify","onLinkActivated","href","outerHtml","window","gestures","listener","document","addEventListener","onClick","defaultPrevented","selection","getSelection","type","nearestElement","target","HTMLElement","nearestInteractiveElement","HTMLAnchorElement","outerHTML","stopPropagation","preventDefault","element","indexOf","nodeName","toLowerCase","hasAttribute","getAttribute","parentElement","Window","prototype","readiumcss","setProperties","properties","key","value","setProperty","removeProperty","documentElement","style","documentState","onScriptsLoaded","documentLoadedFired","ResizeObserver","requestAnimationFrame","wnd","id","virtualCol","getElementById","parseInt","getComputedStyle","getPropertyValue","getColumnCountPerScreen","remove","colCount","scrollingElement","scrollWidth","innerWidth","Math","round","createElement","setAttribute","dataset","readium","breakBefore","innerHTML","body","appendChild","appendVirtualColumnIfNeeded","scrollHeight","onDocumentLoadedAndSized","onDocumentResized","observe"],"sourceRoot":""} \ No newline at end of file diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt index 52cbec8bad..639085fa4d 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt @@ -92,8 +92,6 @@ public fun FixedWebRendition( val reverseLayout = LocalLayoutDirection.current.toReadingProgression() != readingProgression - val coroutineScope = rememberCoroutineScope() - if (state.controller == null) { val itemHref = state.getCurrentHref() state.initController(location = FixedWebLocation(itemHref)) @@ -105,9 +103,11 @@ public fun FixedWebRendition( }.onEach { val itemHref = state.getCurrentHref() state.navigationDelegate.updateLocation(location = FixedWebLocation(itemHref)) - }.launchIn(coroutineScope) + }.launchIn(this) } + val coroutineScope = rememberCoroutineScope() + val inputListenerState = rememberUpdatedState(inputListener) val hyperlinkListenerState = rememberUpdatedState(hyperlinkListener) @@ -160,10 +160,16 @@ public fun FixedWebRendition( val readingProgression = state.layoutDelegate.layout.value.readingProgression val spread = state.layoutDelegate.layout.value.spreads[index] val pages = spread.pages.map { it.index } - "$readingProgression $spread $pages" + val fit = state.layoutDelegate.fit.value + "$readingProgression $spread $pages $fit" }, reverseLayout = reverseLayout ) { index -> + val initialProgression = when { + index < state.pagerState.currentPage -> 1.0 + else -> 0.0 + } + when (val spread = state.layoutDelegate.layout.value.spreads[index]) { is SingleViewportSpread -> { val spreadState = @@ -179,6 +185,7 @@ public fun FixedWebRendition( SingleViewportSpread( pagerState = state.pagerState, + progression = initialProgression, onTap = { inputListenerState.value.onTap(it, TapContext(viewportSize.value)) }, onLinkActivated = { url, outerHtml -> coroutineScope.launch { @@ -210,6 +217,7 @@ public fun FixedWebRendition( DoubleViewportSpread( pagerState = state.pagerState, + progression = initialProgression, onTap = { inputListenerState.value.onTap(it, TapContext(viewportSize.value)) }, onLinkActivated = { url, outerHtml -> coroutineScope.launch { diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt index 1bacf714a7..b29815e3bd 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt @@ -313,7 +313,7 @@ internal class ReflowableNavigationDelegate( private fun WebViewScrollController.moveToProgression(progression: Double) { moveToProgression( progression = progression, - scroll = overflow.value.scroll, + snap = !overflow.value.scroll, orientation = overflow.value.axis.toOrientation() ) } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/DoubleViewportSpread.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/DoubleViewportSpread.kt index 7bac4c968f..fc47c4dc48 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/DoubleViewportSpread.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/DoubleViewportSpread.kt @@ -37,6 +37,7 @@ import org.readium.r2.shared.util.Url internal fun DoubleViewportSpread( pagerState: PagerState, scrollState: SpreadScrollState, + progression: Double, onTap: (TapEvent) -> Unit, onLinkActivated: (Url, String) -> Unit, state: DoubleSpreadState, @@ -85,6 +86,7 @@ internal fun DoubleViewportSpread( pagerState = pagerState, state = webViewState, spreadScrollState = scrollState, + progression = progression, client = state.webViewClient, onTap = onTap, onLinkActivated = { url, outerHtml -> diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SingleViewportSpread.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SingleViewportSpread.kt index c1543b940c..8f58a74d0c 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SingleViewportSpread.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SingleViewportSpread.kt @@ -36,10 +36,11 @@ import org.readium.r2.shared.util.Url @Composable internal fun SingleViewportSpread( pagerState: PagerState, + scrollState: SpreadScrollState, + progression: Double, onTap: (TapEvent) -> Unit, onLinkActivated: (Url, String) -> Unit, state: SingleSpreadState, - scrollState: SpreadScrollState, backgroundColor: Color, reverseScrollDirection: Boolean, ) { @@ -76,6 +77,8 @@ internal fun SingleViewportSpread( layoutApi.setDisplayArea(it) }.launchIn(this) + layoutApi.setFit(state.fit.value) + layoutApi.setDisplayArea(state.displayArea.value) layoutApi.loadSpread(state.spread) } } @@ -86,6 +89,7 @@ internal fun SingleViewportSpread( state = webViewState, spreadScrollState = scrollState, client = state.webViewClient, + progression = progression, onTap = onTap, onLinkActivated = { url, outerHtml -> onLinkActivated( diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt index 4fa0033e9f..a66fcf11fc 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt @@ -8,10 +8,14 @@ package org.readium.navigator.web.fixed import android.annotation.SuppressLint import android.view.View +import androidx.compose.foundation.background +import androidx.compose.foundation.gestures.Orientation +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.pager.PagerState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset @@ -19,6 +23,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.unit.DpOffset +import androidx.compose.ui.zIndex import org.readium.navigator.common.TapEvent import org.readium.navigator.web.gestures.NullFling2DBehavior import org.readium.navigator.web.gestures.Scrollable2DDefaults @@ -44,6 +49,7 @@ internal fun SpreadWebView( spreadIndex: Int, state: WebViewState, spreadScrollState: SpreadScrollState, + progression: Double, client: WebViewClient, onScriptsLoaded: () -> Unit, onTap: (TapEvent) -> Unit, @@ -68,6 +74,9 @@ internal fun SpreadWebView( spreadNestedScrollConnection.flingBehavior = flingBehavior + val contentIsLaidOut = + remember(scrollableState.webView) { mutableStateOf(false) } + val documentStateApi = remember(onScriptsLoaded) { DocumentStateApi( onScriptsLoadedDelegate = onScriptsLoaded, @@ -76,7 +85,13 @@ internal fun SpreadWebView( requestLayout() setNextLayoutListener { val scrollController = WebViewScrollController(this) + scrollController.moveToProgression( + progression = progression, + snap = true, + orientation = Orientation.Horizontal + ) spreadScrollState.scrollController.value = scrollController + contentIsLaidOut.value = true } } }, @@ -105,6 +120,17 @@ internal fun SpreadWebView( state.webView?.let { gesturesApi.registerOnWebView(it) } } + // Hide content before initial position is settled + if (!contentIsLaidOut.value) { + Box( + modifier = Modifier + .background(backgroundColor) + .zIndex(1f) + .fillMaxSize(), + content = {} + ) + } + WebView( state = state, factory = { RelaxedWebView(it) }, diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollDispatcher.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollDispatcher.kt index 9425e68ec5..b01e059d2a 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollDispatcher.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollDispatcher.kt @@ -42,6 +42,26 @@ internal class ScrollDispatcher( val lastPage = pagerState.layoutInfo.visiblePagesInfo.last() + if (firstPage == lastPage) { + // Set the page that will become visible to the right scroll position. + when { + available > 0 -> { + val prevPage = (firstPage.index - 1).takeIf { it >= 0 } + prevPage?.let { + val success = scrollWebviewToEdge(prevPage, end = true) + if (!success) return available + } + } + else -> { + val nextPage = (firstPage.index + 1).takeIf { it < resourceStates.size } + nextPage?.let { + val success = scrollWebviewToEdge(nextPage, end = false) + if (!success) return available + } + } + } + } + val firstTargetPage = when { available >= 0 -> lastPage else -> firstPage @@ -96,6 +116,17 @@ internal class ScrollDispatcher( } } + private fun scrollWebviewToEdge(targetPage: Int, end: Boolean): Boolean { + val scrollController = resourceStates[targetPage].scrollController.value + ?: return false + scrollController.moveToProgression( + progression = if (end) 1.0 else 0.0, + snap = false, + orientation = pagerOrientation + ) + return true + } + private fun consumeInWebview(targetPage: Int, available: Float): Float { val scrollController = resourceStates[targetPage].scrollController.value ?: return available // WebView is not ready, consume everything. diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt index 30e1165b17..674fb1797d 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt @@ -103,7 +103,7 @@ internal fun ReflowableResource( val scrollController = WebViewScrollController(this) scrollController.moveToProgression( progression = resourceState.progression, - scroll = scroll, + snap = !scroll, orientation = orientationState.value ) resourceState.scrollController.value = scrollController diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollController.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollController.kt index 5ccade1487..fc09b8f985 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollController.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollController.kt @@ -94,20 +94,23 @@ internal class WebViewScrollController( fun moveToProgression( progression: Double, - scroll: Boolean, + snap: Boolean, orientation: Orientation, ) { - when (scroll) { - true -> { - webView.scrollToProgression( - progression = progression, - scrollOrientation = orientation - ) - } - false -> { - webView.scrollToProgression(progression, Orientation.Horizontal) - val offset = webView.scrollX % webView.width - webView.scrollBy(-offset, 0) + webView.scrollToProgression( + progression = progression, + scrollOrientation = orientation + ) + if (snap) { + when (orientation) { + Orientation.Vertical -> { + val offset = webView.scrollY % webView.height + webView.scrollBy(0, -offset) + } + Orientation.Horizontal -> { + val offset = webView.scrollX % webView.width + webView.scrollBy(-offset, 0) + } } } } From d74659c763d4657614c1585ef0a9a72a638be1a3 Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Sun, 20 Apr 2025 20:18:08 +0200 Subject: [PATCH 48/88] Commit missing file --- .../scripts/src/bridge/all-listener-bridge.ts | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 readium/navigators/web/scripts/src/bridge/all-listener-bridge.ts diff --git a/readium/navigators/web/scripts/src/bridge/all-listener-bridge.ts b/readium/navigators/web/scripts/src/bridge/all-listener-bridge.ts new file mode 100644 index 0000000000..1e4edddf76 --- /dev/null +++ b/readium/navigators/web/scripts/src/bridge/all-listener-bridge.ts @@ -0,0 +1,91 @@ +import { GesturesListener } from "../common/gestures" +import { AreaManager } from "../fixed/area-manager" + +export interface GesturesBridge { + onTap(event: string): void + onLinkActivated(href: string, outerHtml: string): void +} + +export interface TapEvent { + x: number + y: number +} + +export interface DocumentBridge { + onScriptsLoaded: () => void + onDocumentLoadedAndSized: () => void + onDocumentResized: () => void +} + +export class ReflowableListenerAdapter implements GesturesListener { + readonly gesturesBridge: GesturesBridge + + constructor(gesturesBridge: GesturesBridge) { + this.gesturesBridge = gesturesBridge + } + + onTap(event: MouseEvent) { + const tapEvent = { + x: (event.clientX - visualViewport!.offsetLeft) * visualViewport!.scale, + y: (event.clientY - visualViewport!.offsetTop) * visualViewport!.scale, + } + const stringEvent = JSON.stringify(tapEvent) + this.gesturesBridge.onTap(stringEvent) + } + onLinkActivated(href: string, outerHtml: string) { + this.gesturesBridge.onLinkActivated(href, outerHtml) + } +} + +export class FixedListenerAdapter implements AreaManager.Listener { + readonly gesturesApi: GesturesBridge + readonly documentApi: DocumentBridge + readonly window: Window + resizeObserverAdded: boolean + documentLoadedFired: boolean + + constructor( + window: Window, + gesturesApi: GesturesBridge, + documentApi: DocumentBridge + ) { + this.window = window + this.gesturesApi = gesturesApi + this.documentApi = documentApi + this.resizeObserverAdded = false + this.documentLoadedFired = false + } + + onTap(event: TapEvent): void { + this.gesturesApi.onTap(JSON.stringify(event)) + } + + onLinkActivated(href: string, outerHtml: string): void { + this.gesturesApi.onLinkActivated(href, outerHtml) + } + + onLayout(): void { + if (!this.resizeObserverAdded) { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const observer = new ResizeObserver(() => { + requestAnimationFrame(() => { + const scrollingElement = this.window.document.scrollingElement + + if ( + !this.documentLoadedFired && + (scrollingElement == null || + scrollingElement.scrollHeight > 0 || + scrollingElement.scrollWidth > 0) + ) { + this.documentApi.onDocumentLoadedAndSized() + this.documentLoadedFired = true + } else { + this.documentApi.onDocumentResized() + } + }) + }) + observer.observe(this.window.document.body) + } + this.resizeObserverAdded = true + } +} From 3e507fd078ee32deed71ff207827d9f691e25251 Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Thu, 24 Apr 2025 21:23:00 +0200 Subject: [PATCH 49/88] Simplify scroll dispatching by directly using ScrollableState and FlingBehavior --- .../navigator/web/FixedWebRendition.kt | 57 +++++----- .../navigator/web/ReflowableWebRendition.kt | 45 +++----- .../web/fixed/SpreadNestedScrollConnection.kt | 41 +++---- .../navigator/web/fixed/SpreadWebView.kt | 34 +----- ...lingBehavior.kt => PagingFlingBehavior.kt} | 0 .../navigator/web/pager/RenditionPager.kt | 56 ++++------ ...lDispatcher.kt => RenditionScrollState.kt} | 100 ++++++++++-------- .../web/reflowable/ReflowableResource.kt | 17 +-- .../navigator/web/util/LayoutDirection.kt | 22 ++++ .../web/webview/WebViewScrollController.kt | 58 ++++++---- .../web/webview/WebViewScrollable2DState.kt | 96 ----------------- 11 files changed, 206 insertions(+), 320 deletions(-) rename readium/navigators/web/src/main/java/org/readium/navigator/web/pager/{FlingBehavior.kt => PagingFlingBehavior.kt} (100%) rename readium/navigators/web/src/main/java/org/readium/navigator/web/pager/{ScrollDispatcher.kt => RenditionScrollState.kt} (71%) create mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/util/LayoutDirection.kt delete mode 100644 readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollable2DState.kt diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt index 639085fa4d..fea350163c 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt @@ -21,6 +21,7 @@ import androidx.compose.runtime.rememberUpdatedState import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.unit.DpSize @@ -42,19 +43,21 @@ import org.readium.navigator.web.fixed.FixedPagingLayoutInfo import org.readium.navigator.web.fixed.FixedWebPublication import org.readium.navigator.web.fixed.SingleSpreadState import org.readium.navigator.web.fixed.SingleViewportSpread +import org.readium.navigator.web.fixed.SpreadNestedScrollConnection import org.readium.navigator.web.fixed.SpreadScrollState +import org.readium.navigator.web.gestures.Scrollable2DDefaults import org.readium.navigator.web.gestures.toFling2DBehavior import org.readium.navigator.web.layout.DoubleViewportSpread import org.readium.navigator.web.layout.SingleViewportSpread import org.readium.navigator.web.location.FixedWebLocation import org.readium.navigator.web.pager.RenditionPager -import org.readium.navigator.web.pager.ScrollDispatcher +import org.readium.navigator.web.pager.RenditionScrollState import org.readium.navigator.web.pager.pagingFlingBehavior import org.readium.navigator.web.util.AbsolutePaddingValues import org.readium.navigator.web.util.DisplayArea import org.readium.navigator.web.util.HyperlinkProcessor import org.readium.navigator.web.util.WebViewServer -import org.readium.r2.navigator.preferences.ReadingProgression +import org.readium.navigator.web.util.toLayoutDirection import org.readium.r2.shared.ExperimentalReadiumApi import org.readium.r2.shared.util.AbsoluteUrl import org.readium.r2.shared.util.RelativeUrl @@ -86,11 +89,9 @@ public fun FixedWebRendition( val displayArea = rememberUpdatedState(DisplayArea(viewportSize.value, safeDrawingPadding)) - val readingProgression = - state.layoutDelegate.settings.value.readingProgression - - val reverseLayout = - LocalLayoutDirection.current.toReadingProgression() != readingProgression + val layoutDirection = state.layoutDelegate.settings.value + .readingProgression + .toLayoutDirection() if (state.controller == null) { val itemHref = state.getCurrentHref() @@ -132,16 +133,13 @@ public fun FixedWebRendition( }.toFling2DBehavior(Orientation.Horizontal) val scrollDispatcher = remember(state, scrollStates) { - ScrollDispatcher( + RenditionScrollState( pagerState = state.pagerState, - resourceStates = scrollStates, - flingBehavior = flingBehavior, + pageStates = scrollStates, pagerOrientation = Orientation.Horizontal, ) } - scrollDispatcher.flingBehavior = flingBehavior - LaunchedEffect(state.layoutDelegate.layout.value, state.controller) { state.controller?.let { val currentHref = it.location.value.href @@ -150,12 +148,30 @@ public fun FixedWebRendition( } } + val readyToScroll = ((state.pagerState.currentPage - 2)..(state.pagerState.currentPage + 2)).toList() + .mapNotNull { scrollStates.getOrNull(it) } + .all { it.scrollController.value != null } + + val spreadFlingBehavior = Scrollable2DDefaults.flingBehavior() + + val spreadNestedScrollConnection = + remember(state.pagerState, scrollStates) { + SpreadNestedScrollConnection( + pagerState = state.pagerState, + resourceStates = scrollStates, + flingBehavior = spreadFlingBehavior + ) + } + RenditionPager( - modifier = Modifier, + modifier = Modifier.nestedScroll(spreadNestedScrollConnection), state = state.pagerState, - scrollDispatcher = scrollDispatcher, + scrollState = scrollDispatcher, + flingBehavior = flingBehavior, orientation = Orientation.Horizontal, beyondViewportPageCount = 2, + layoutDirection = layoutDirection, + enableScroll = readyToScroll, key = { index -> val readingProgression = state.layoutDelegate.layout.value.readingProgression val spread = state.layoutDelegate.layout.value.spreads[index] @@ -163,7 +179,6 @@ public fun FixedWebRendition( val fit = state.layoutDelegate.fit.value "$readingProgression $spread $pages $fit" }, - reverseLayout = reverseLayout ) { index -> val initialProgression = when { index < state.pagerState.currentPage -> 1.0 @@ -200,7 +215,7 @@ public fun FixedWebRendition( state = spreadState, scrollState = scrollStates[index], backgroundColor = backgroundColor, - reverseScrollDirection = !reverseLayout + reverseScrollDirection = layoutDirection == LayoutDirection.Ltr ) } is DoubleViewportSpread -> { @@ -212,7 +227,7 @@ public fun FixedWebRendition( webViewClient = state.webViewClient, spread = spread, fit = state.layoutDelegate.fit, - displayArea = displayArea + displayArea = displayArea, ) DoubleViewportSpread( @@ -232,7 +247,7 @@ public fun FixedWebRendition( state = spreadState, scrollState = scrollStates[index], backgroundColor = backgroundColor, - reverseScrollDirection = !reverseLayout + reverseScrollDirection = layoutDirection == LayoutDirection.Ltr ) } } @@ -251,12 +266,6 @@ private fun WindowInsets.asAbsolutePaddingValues(): AbsolutePaddingValues { return AbsolutePaddingValues(top = top, right = right, bottom = bottom, left = left) } -private fun LayoutDirection.toReadingProgression(): ReadingProgression = - when (this) { - LayoutDirection.Ltr -> ReadingProgression.LTR - LayoutDirection.Rtl -> ReadingProgression.RTL - } - @OptIn(ExperimentalReadiumApi::class) private suspend fun HyperlinkProcessor.onLinkActivated( url: Url, diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt index 954f8d1a59..a0e3bf17ec 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt @@ -26,10 +26,8 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.unit.DpOffset import androidx.compose.ui.unit.DpSize -import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import kotlinx.coroutines.launch import org.readium.navigator.common.HyperlinkListener @@ -44,7 +42,7 @@ import org.readium.navigator.common.defaultInputListener import org.readium.navigator.web.gestures.toFling2DBehavior import org.readium.navigator.web.location.ReflowableWebLocation import org.readium.navigator.web.pager.RenditionPager -import org.readium.navigator.web.pager.ScrollDispatcher +import org.readium.navigator.web.pager.RenditionScrollState import org.readium.navigator.web.pager.pagingFlingBehavior import org.readium.navigator.web.reflowable.ReflowablePagingLayoutInfo import org.readium.navigator.web.reflowable.ReflowableResource @@ -52,7 +50,7 @@ import org.readium.navigator.web.reflowable.ReflowableWebPublication import org.readium.navigator.web.util.AbsolutePaddingValues import org.readium.navigator.web.util.HyperlinkProcessor import org.readium.navigator.web.util.WebViewServer -import org.readium.r2.navigator.preferences.ReadingProgression +import org.readium.navigator.web.util.toLayoutDirection import org.readium.r2.shared.ExperimentalReadiumApi import org.readium.r2.shared.util.AbsoluteUrl import org.readium.r2.shared.util.RelativeUrl @@ -79,12 +77,6 @@ public fun ReflowableWebRendition( ) { val viewportSize = rememberUpdatedState(DpSize(maxWidth, maxHeight)) - val readingProgression = - state.layoutDelegate.overflow.value.readingProgression - - val reverseLayout = - LocalLayoutDirection.current.toReadingProgression() != readingProgression - val coroutineScope = rememberCoroutineScope() val resourcePadding = @@ -124,15 +116,13 @@ public fun ReflowableWebRendition( }.toFling2DBehavior(state.layoutDelegate.orientation) val scrollDispatcher = remember(state) { - ScrollDispatcher( + RenditionScrollState( pagerState = state.pagerState, - resourceStates = state.resourceStates, - flingBehavior = flingBehavior, + pageStates = state.resourceStates, pagerOrientation = state.layoutDelegate.orientation, ) } - scrollDispatcher.flingBehavior = flingBehavior scrollDispatcher.pagerOrientation = state.layoutDelegate.orientation val backgroundColor = Color( @@ -144,6 +134,13 @@ public fun ReflowableWebRendition( val hyperlinkListenerState = rememberUpdatedState(hyperlinkListener) + val layoutDirection = + state.layoutDelegate.overflow.value.readingProgression.toLayoutDirection() + + val readyToScroll = ((currentPageState.value - 2)..(currentPageState.value + 2)).toList() + .mapNotNull { state.resourceStates.getOrNull(it) } + .all { it.scrollController.value != null } + RenditionPager( modifier = Modifier // Apply background on padding @@ -162,15 +159,13 @@ public fun ReflowableWebRendition( } .windowInsetsPadding(windowInsets), state = state.pagerState, - scrollDispatcher = scrollDispatcher, + scrollState = scrollDispatcher, + flingBehavior = flingBehavior, beyondViewportPageCount = 3, - reverseLayout = reverseLayout, - orientation = state.layoutDelegate.orientation + layoutDirection = layoutDirection, + orientation = state.layoutDelegate.orientation, + enableScroll = readyToScroll ) { index -> - val readyToScroll = ((index - 2)..(index + 2)).toList() - .mapNotNull { state.resourceStates.getOrNull(it) } - .all { it.scrollController.value != null } - ReflowableResource( resourceState = state.resourceStates[index], pagerState = state.pagerState, @@ -178,7 +173,7 @@ public fun ReflowableWebRendition( webViewClient = state.webViewClient, backgroundColor = backgroundColor, padding = resourcePadding, - reverseLayout = reverseLayout, + layoutDirection = layoutDirection, scroll = state.layoutDelegate.settings.value.scroll, orientation = state.layoutDelegate.orientation, rsProperties = state.readiumCssInjector.value.rsProperties, @@ -213,12 +208,6 @@ public fun ReflowableWebRendition( } } -private fun LayoutDirection.toReadingProgression(): ReadingProgression = - when (this) { - LayoutDirection.Ltr -> ReadingProgression.LTR - LayoutDirection.Rtl -> ReadingProgression.RTL - } - @OptIn(ExperimentalReadiumApi::class) private suspend fun HyperlinkProcessor.onLinkActivated( url: Url, diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadNestedScrollConnection.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadNestedScrollConnection.kt index 73927107f9..3120830755 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadNestedScrollConnection.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadNestedScrollConnection.kt @@ -13,20 +13,17 @@ import androidx.compose.ui.input.nestedscroll.NestedScrollSource import androidx.compose.ui.unit.Velocity import kotlin.math.abs import org.readium.navigator.web.gestures.Fling2DBehavior -import org.readium.navigator.web.webview.WebViewScrollable2DState +import org.readium.navigator.web.pager.PageScrollState internal class SpreadNestedScrollConnection( - private val spreadIndex: Int, private val pagerState: PagerState, - private val webviewState: WebViewScrollable2DState, - private val scrollController: SpreadScrollState, - internal var flingBehavior: Fling2DBehavior, + private val resourceStates: List, + private val flingBehavior: Fling2DBehavior, ) : NestedScrollConnection { var consumedHere: Boolean = false - override fun onPostScroll( - consumed: Offset, + override fun onPreScroll( available: Offset, source: NestedScrollSource, ): Offset { @@ -34,21 +31,23 @@ internal class SpreadNestedScrollConnection( return Offset.Zero } - if (!pagerShowsOnlyThisSpread()) { + if (!pagerShowsOnlyOneSpread()) { // Let the main dispatcher scroll only horizontally. return Offset.Zero } - val scrollController = scrollController.scrollController.value + val scrollController = resourceStates[pagerState.currentPage].scrollController.value ?: return available consumedHere = true - return -scrollController.scrollBy(-available) + val consumed = -scrollController.scrollBy(-available) + + // Let the main dispatcher consume what's left on the horizontal axis. + return consumed } - override suspend fun onPostFling( - consumed: Velocity, + override suspend fun onPreFling( available: Velocity, ): Velocity { var velocityLeft = available @@ -56,8 +55,10 @@ internal class SpreadNestedScrollConnection( // The main dispatcher will do a fling in any case. We restrain ourselves from // doing one here if that of the main dispatcher will be significant to prevent // strange visual behaviors. - if (consumedHere && pagerShowsOnlyThisSpread()) { - webviewState.scroll { + if (consumedHere && pagerShowsOnlyOneSpread()) { + val scrollController = resourceStates[pagerState.currentPage].scrollController.value + ?: return available + scrollController.scroll { velocityLeft = with(flingBehavior) { -performFling(-velocityLeft) } } } @@ -70,13 +71,13 @@ internal class SpreadNestedScrollConnection( ) } - private fun pagerShowsOnlyThisSpread(): Boolean { + private fun pagerShowsOnlyOneSpread(): Boolean { val visiblePages = pagerState.layoutInfo.visiblePagesInfo - val otherPages = visiblePages.filter { it.index != spreadIndex } - val mostlyThis = otherPages.all { abs(it.offset) > 0.95 * pagerState.layoutInfo.pageSize } - if (mostlyThis) { - pagerState.requestScrollToPage(spreadIndex) + val otherPages = visiblePages.filter { it.index != pagerState.currentPage } + val mostlyCurrent = otherPages.all { abs(it.offset) > 0.95 * pagerState.layoutInfo.pageSize } + if (mostlyCurrent) { + pagerState.requestScrollToPage(pagerState.currentPage) } - return mostlyThis + return mostlyCurrent } } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt index a66fcf11fc..a7f3fc8e70 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt @@ -18,17 +18,11 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier -import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.toArgb -import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.unit.DpOffset import androidx.compose.ui.zIndex import org.readium.navigator.common.TapEvent -import org.readium.navigator.web.gestures.NullFling2DBehavior -import org.readium.navigator.web.gestures.Scrollable2DDefaults -import org.readium.navigator.web.gestures.Scrollable2DState -import org.readium.navigator.web.gestures.scrollable2D import org.readium.navigator.web.util.WebViewClient import org.readium.navigator.web.webapi.DocumentStateApi import org.readium.navigator.web.webapi.GesturesApi @@ -36,7 +30,6 @@ import org.readium.navigator.web.webapi.GesturesListener import org.readium.navigator.web.webview.RelaxedWebView import org.readium.navigator.web.webview.WebView import org.readium.navigator.web.webview.WebViewScrollController -import org.readium.navigator.web.webview.WebViewScrollable2DState import org.readium.navigator.web.webview.WebViewState import org.readium.r2.shared.ExperimentalReadiumApi import org.readium.r2.shared.util.AbsoluteUrl @@ -57,25 +50,8 @@ internal fun SpreadWebView( backgroundColor: Color, reverseScrollDirection: Boolean, ) { - val scrollableState = remember { WebViewScrollable2DState() } - - val flingBehavior = Scrollable2DDefaults.flingBehavior() - - val spreadNestedScrollConnection = - remember(spreadIndex, pagerState, scrollableState, spreadScrollState) { - SpreadNestedScrollConnection( - spreadIndex, - pagerState, - scrollableState, - spreadScrollState, - flingBehavior - ) - } - - spreadNestedScrollConnection.flingBehavior = flingBehavior - val contentIsLaidOut = - remember(scrollableState.webView) { mutableStateOf(false) } + remember { mutableStateOf(false) } val documentStateApi = remember(onScriptsLoaded) { DocumentStateApi( @@ -135,16 +111,9 @@ internal fun SpreadWebView( state = state, factory = { RelaxedWebView(it) }, modifier = Modifier - .nestedScroll(spreadNestedScrollConnection) - .scrollable2D( - state = Scrollable2DState { Offset.Zero }, - reverseDirection = reverseScrollDirection, - flingBehavior = NullFling2DBehavior() - ) .fillMaxSize(), client = client, onCreated = { webview -> - scrollableState.webView = webview webview.settings.javaScriptEnabled = true webview.settings.setSupportZoom(true) webview.settings.builtInZoomControls = true @@ -158,7 +127,6 @@ internal fun SpreadWebView( }, onDispose = { spreadScrollState.scrollController.value = null - scrollableState.webView = null } ) } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/FlingBehavior.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/PagingFlingBehavior.kt similarity index 100% rename from readium/navigators/web/src/main/java/org/readium/navigator/web/pager/FlingBehavior.kt rename to readium/navigators/web/src/main/java/org/readium/navigator/web/pager/PagingFlingBehavior.kt diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/RenditionPager.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/RenditionPager.kt index 525bd935c3..26afa8d106 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/RenditionPager.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/RenditionPager.kt @@ -15,31 +15,35 @@ import androidx.compose.foundation.pager.PagerState import androidx.compose.foundation.pager.VerticalPager import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.geometry.Offset import androidx.compose.ui.input.nestedscroll.NestedScrollConnection -import androidx.compose.ui.input.nestedscroll.NestedScrollSource -import androidx.compose.ui.input.nestedscroll.nestedScroll -import androidx.compose.ui.unit.Velocity +import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.unit.LayoutDirection +import org.readium.navigator.web.gestures.Fling2DBehavior +import org.readium.navigator.web.gestures.Scrollable2DState +import org.readium.navigator.web.gestures.scrollable2D @Composable internal fun RenditionPager( modifier: Modifier = Modifier, state: PagerState, - scrollDispatcher: ScrollDispatcher, + scrollState: Scrollable2DState, + flingBehavior: Fling2DBehavior, orientation: Orientation, - reverseLayout: Boolean, + layoutDirection: LayoutDirection, + enableScroll: Boolean = true, beyondViewportPageCount: Int, key: ((index: Int) -> Any)? = null, pageContent: @Composable PagerScope.(Int) -> Unit, ) { - // A nested scroll connection is the only way to get separate drag and fling events - // from the scrollable modifiers. So we catch all events in the "post phase" and pass them to - // the provided ScrollDispatcher for processing. - val scrollDispatcherNestedScrollConnection = - ScrollDispatcherNestedScrollConnection(scrollDispatcher) - val modifier = modifier - .nestedScroll(scrollDispatcherNestedScrollConnection) + .scrollable2D( + enabled = enableScroll, + state = scrollState, + flingBehavior = flingBehavior, + reverseDirection = layoutDirection == LayoutDirection.Ltr || + orientation == Orientation.Vertical, + orientation = null + ) // Disable built-in pager behavior as it is not suitable. val pageNestedScrollConnection = NullNestedScrollConnection @@ -56,7 +60,7 @@ internal fun RenditionPager( flingBehavior = flingBehavior, userScrollEnabled = userScrollEnabled, key = key, - reverseLayout = reverseLayout, + reverseLayout = layoutDirection != LocalLayoutDirection.current, pageNestedScrollConnection = pageNestedScrollConnection, pageContent = pageContent ) @@ -68,7 +72,7 @@ internal fun RenditionPager( flingBehavior = flingBehavior, userScrollEnabled = userScrollEnabled, key = key, - reverseLayout = reverseLayout, + reverseLayout = false, pageNestedScrollConnection = pageNestedScrollConnection, pageContent = pageContent ) @@ -77,28 +81,6 @@ internal fun RenditionPager( private object NullNestedScrollConnection : NestedScrollConnection -private class ScrollDispatcherNestedScrollConnection( - private val scrollDispatcher: ScrollDispatcher, -) : NestedScrollConnection { - - override fun onPostScroll( - consumed: Offset, - available: Offset, - source: NestedScrollSource, - ): Offset { - if (source == NestedScrollSource.UserInput) { - scrollDispatcher.onScroll(available) - } - - return available - } - - override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity { - scrollDispatcher.onFling(available) - return available - } -} - private object NullTargetedFlingBehavior : TargetedFlingBehavior { override suspend fun ScrollScope.performFling( diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollDispatcher.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/RenditionScrollState.kt similarity index 71% rename from readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollDispatcher.kt rename to readium/navigators/web/src/main/java/org/readium/navigator/web/pager/RenditionScrollState.kt index b01e059d2a..dfd99e38a9 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/ScrollDispatcher.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/RenditionScrollState.kt @@ -6,15 +6,18 @@ package org.readium.navigator.web.pager +import androidx.compose.foundation.MutatePriority +import androidx.compose.foundation.MutatorMutex import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.pager.PagerState import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.unit.Velocity import androidx.compose.ui.util.fastCoerceAtLeast import androidx.compose.ui.util.fastCoerceAtMost -import org.readium.navigator.web.gestures.Fling2DBehavior +import kotlinx.coroutines.coroutineScope import org.readium.navigator.web.gestures.Scroll2DScope +import org.readium.navigator.web.gestures.Scrollable2DState import org.readium.navigator.web.webview.WebViewScrollController import timber.log.Timber @@ -23,17 +26,17 @@ internal interface PageScrollState { val scrollController: MutableState } -internal class ScrollDispatcher( +internal class RenditionScrollState( private val pagerState: PagerState, - private val resourceStates: List, + private val pageStates: List, internal var pagerOrientation: Orientation, - internal var flingBehavior: Fling2DBehavior, -) : Scroll2DScope { - - override fun scrollBy(pixels: Offset): Offset { - return -rawScrollBy(-pixels.mainAxisValue).mainAxisOffset - } +) : Scrollable2DState { + /* + * To favour natural reasoning, this function applies reverse scrolling: + * - a positive delta makes scrolling left + * - a negative delta makes scrolling right + */ private fun rawScrollBy(available: Float): Float { Timber.d("scrollBy available $available") var deltaLeft = available @@ -53,7 +56,7 @@ internal class ScrollDispatcher( } } else -> { - val nextPage = (firstPage.index + 1).takeIf { it < resourceStates.size } + val nextPage = (firstPage.index + 1).takeIf { it < pageStates.size } nextPage?.let { val success = scrollWebviewToEdge(nextPage, end = false) if (!success) return available @@ -117,7 +120,7 @@ internal class ScrollDispatcher( } private fun scrollWebviewToEdge(targetPage: Int, end: Boolean): Boolean { - val scrollController = resourceStates[targetPage].scrollController.value + val scrollController = pageStates[targetPage].scrollController.value ?: return false scrollController.moveToProgression( progression = if (end) 1.0 else 0.0, @@ -128,42 +131,12 @@ internal class ScrollDispatcher( } private fun consumeInWebview(targetPage: Int, available: Float): Float { - val scrollController = resourceStates[targetPage].scrollController.value + val scrollController = pageStates[targetPage].scrollController.value ?: return available // WebView is not ready, consume everything. return -scrollController.scrollBy(-available.mainAxisOffset).mainAxisValue } - fun onScroll(available: Offset): Offset { - Timber.d("onScroll ${available.x}") - return -scrollBy(-available) - } - - suspend fun onFling(available: Velocity): Velocity { - Timber.d("onFling ${available.x}") - var velocityLeft = available - pagerState.scroll { - with(flingBehavior) { - with(this@ScrollDispatcher) { - velocityLeft = -performFling(-velocityLeft) - } - } - } - - return Velocity( - x = if ((available.x - velocityLeft.x).isNaN()) { - available.x - } else { - available.x - velocityLeft.x - }, - y = if ((available.y - velocityLeft.y).isNaN()) { - available.y - } else { - available.y - velocityLeft.y - } - ) - } - fun onDocumentResized(index: Int) { val firstPage = pagerState.layoutInfo.visiblePagesInfo.first() @@ -173,7 +146,7 @@ internal class ScrollDispatcher( return } - val scrollController = resourceStates[index].scrollController.value!! + val scrollController = pageStates[index].scrollController.value!! val scrolled = scrollController.scrollToEnd(pagerOrientation) if (scrolled > 0) { rawScrollBy(scrolled.toFloat()) @@ -190,4 +163,43 @@ internal class ScrollDispatcher( Orientation.Vertical -> Offset(0f, this) Orientation.Horizontal -> Offset(this, 0f) } + + private val scrollScope: Scroll2DScope = object : Scroll2DScope { + override fun scrollBy(pixels: Offset): Offset { + val coercedPixels = Offset( + x = if (pixels.x.isNaN()) 0f else pixels.x, + y = if (pixels.y.isNaN()) 0f else pixels.y + ) + if (coercedPixels == Offset.Zero) return Offset.Zero + val delta = -rawScrollBy(-coercedPixels.mainAxisValue).mainAxisOffset + return delta + } + } + + private val scrollMutex = MutatorMutex() + + private val isScrollingState = mutableStateOf(false) + + override suspend fun scroll( + scrollPriority: MutatePriority, + block: suspend Scroll2DScope.() -> Unit, + ): Unit = coroutineScope { + pagerState.scroll(scrollPriority) { + scrollMutex.mutateWith(scrollScope, scrollPriority) { + isScrollingState.value = true + try { + block() + } finally { + isScrollingState.value = false + } + } + } + } + + override fun dispatchRawDelta(delta: Offset): Offset { + return -rawScrollBy(-delta.mainAxisValue).mainAxisOffset + } + + override val isScrollInProgress: Boolean + get() = isScrollingState.value || pagerState.isScrollInProgress } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt index 674fb1797d..efa6064db0 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt @@ -23,17 +23,14 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Modifier -import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.DpOffset +import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.zIndex import org.readium.navigator.common.TapEvent import org.readium.navigator.web.css.ReadiumCssLayout import org.readium.navigator.web.css.RsProperties import org.readium.navigator.web.css.UserProperties -import org.readium.navigator.web.gestures.NullFling2DBehavior -import org.readium.navigator.web.gestures.Scrollable2DState -import org.readium.navigator.web.gestures.scrollable2D import org.readium.navigator.web.util.AbsolutePaddingValues import org.readium.navigator.web.util.WebViewClient import org.readium.navigator.web.util.absolutePadding @@ -58,9 +55,9 @@ internal fun ReflowableResource( webViewClient: WebViewClient, backgroundColor: Color, padding: AbsolutePaddingValues, - reverseLayout: Boolean, scroll: Boolean, orientation: Orientation, + layoutDirection: LayoutDirection, userProperties: UserProperties, rsProperties: RsProperties, readiumCssLayout: ReadiumCssLayout, @@ -88,9 +85,6 @@ internal fun ReflowableResource( val contentIsLaidOut = remember(webViewState.webView) { mutableStateOf(false) } - val scrollableState = - remember { Scrollable2DState { Offset.Zero } } - val documentStateApi = remember(webViewState.webView) { DocumentStateApi( onScriptsLoadedDelegate = { @@ -169,13 +163,6 @@ internal fun ReflowableResource( key(readiumCssLayout) { WebView( modifier = Modifier - .scrollable2D( - enabled = enableScroll, - state = scrollableState, - flingBehavior = NullFling2DBehavior(), - reverseDirection = !reverseLayout, - orientation = orientationState.value - ) .fillMaxSize() .absolutePadding(padding), state = webViewState, diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/util/LayoutDirection.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/util/LayoutDirection.kt new file mode 100644 index 0000000000..a3ae9e7f5e --- /dev/null +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/util/LayoutDirection.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2024 Readium Foundation. All rights reserved. + * Use of this source code is governed by the BSD-style license + * available in the top-level LICENSE file of the project. + */ + +package org.readium.navigator.web.util + +import androidx.compose.ui.unit.LayoutDirection +import org.readium.r2.navigator.preferences.ReadingProgression + +internal fun LayoutDirection.toReadingProgression(): ReadingProgression = + when (this) { + LayoutDirection.Ltr -> ReadingProgression.LTR + LayoutDirection.Rtl -> ReadingProgression.RTL + } + +internal fun ReadingProgression.toLayoutDirection(): LayoutDirection = + when (this) { + ReadingProgression.LTR -> LayoutDirection.Ltr + ReadingProgression.RTL -> LayoutDirection.Rtl + } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollController.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollController.kt index fc09b8f985..925d760d2b 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollController.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollController.kt @@ -1,3 +1,9 @@ +/* + * Copyright 2024 Readium Foundation. All rights reserved. + * Use of this source code is governed by the BSD-style license + * available in the top-level LICENSE file of the project. + */ + package org.readium.navigator.web.webview import androidx.compose.foundation.gestures.Orientation @@ -7,10 +13,12 @@ import androidx.compose.ui.util.fastCoerceAtMost import androidx.compose.ui.util.fastRoundToInt import kotlin.math.ceil import kotlin.math.floor +import org.readium.navigator.web.gestures.DefaultScrollable2DState +import org.readium.navigator.web.gestures.Scrollable2DState internal class WebViewScrollController( private val webView: RelaxedWebView, -) { +) : Scrollable2DState by DefaultScrollable2DState({ webView.scrollBy(it) }) { val scrollX: Int get() = webView.scrollX @@ -52,26 +60,7 @@ internal class WebViewScrollController( } fun scrollBy(delta: Offset): Offset { - val coercedX = - if (delta.x < 0) { - delta.x.fastCoerceAtLeast(-webView.scrollX.toFloat()) - } else { - delta.x.fastCoerceAtMost((webView.maxScrollX - webView.scrollX).toFloat()) - } - - val coercedY = - if (delta.y < 0) { - delta.y.fastCoerceAtLeast((-webView.scrollY.toFloat())) - } else { - delta.y.fastCoerceAtMost((webView.maxScrollY - webView.scrollY).toFloat()) - } - - val roundedX = coercedX.fastRoundToInt() - - val roundedY = coercedY.fastRoundToInt() - - webView.scrollBy(roundedX, roundedY) - return Offset(coercedX, coercedY) + return webView.scrollBy(delta) } fun scrollToEnd(scrollOrientation: Orientation): Int { @@ -118,9 +107,9 @@ internal class WebViewScrollController( private fun RelaxedWebView.scrollToProgression(progression: Double, scrollOrientation: Orientation) { if (scrollOrientation == Orientation.Horizontal) { - scrollTo(floor(progression * maxScrollX).toInt(), 0) + scrollTo(floor(progression * maxScrollX).toInt(), scrollY) } else { - scrollTo(0, ceil(progression * maxScrollY).toInt()) + scrollTo(scrollX, ceil(progression * maxScrollY).toInt()) } } @@ -128,3 +117,26 @@ private fun RelaxedWebView.progression(orientation: Orientation) = when (orienta Orientation.Vertical -> scrollY / maxScrollY.toDouble() Orientation.Horizontal -> scrollX / maxScrollX.toDouble() } + +private fun RelaxedWebView.scrollBy(delta: Offset): Offset { + val coercedX = + if (delta.x < 0) { + delta.x.fastCoerceAtLeast(-scrollX.toFloat()) + } else { + delta.x.fastCoerceAtMost((maxScrollX - scrollX).toFloat()) + } + + val coercedY = + if (delta.y < 0) { + delta.y.fastCoerceAtLeast((-scrollY.toFloat())) + } else { + delta.y.fastCoerceAtMost((maxScrollY - scrollY).toFloat()) + } + + val roundedX = coercedX.fastRoundToInt() + + val roundedY = coercedY.fastRoundToInt() + + scrollBy(roundedX, roundedY) + return Offset(coercedX, coercedY) +} diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollable2DState.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollable2DState.kt deleted file mode 100644 index 5209555089..0000000000 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollable2DState.kt +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2024 Readium Foundation. All rights reserved. - * Use of this source code is governed by the BSD-style license - * available in the top-level LICENSE file of the project. - */ - -package org.readium.navigator.web.webview - -import androidx.compose.ui.geometry.Offset -import kotlin.math.abs -import kotlin.math.ceil -import kotlin.math.sign -import org.readium.navigator.web.gestures.DefaultScrollable2DState -import org.readium.navigator.web.gestures.Scrollable2DState -import org.readium.r2.shared.util.Url -import timber.log.Timber - -internal class WebViewScrollable2DState private constructor( - private val webViewDeltaDispatcher: WebViewDeltaDispatcher, -) : Scrollable2DState by DefaultScrollable2DState(webViewDeltaDispatcher::onDelta) { - - constructor(href: Url? = null) : this(WebViewDeltaDispatcher(href)) - - var webView: RelaxedWebView? - get() = - webViewDeltaDispatcher.webView - set(value) { - webViewDeltaDispatcher.webView = value - } - - val canMoveLeft: Boolean get() = - webView?.let { it.scrollX > it.width / 2 } == true - - val canMoveRight: Boolean get() = - webView?.let { (it.maxScrollX - it.scrollX) > it.width / 2 } == true - - val canMoveTop: Boolean get() = - webView?.let { it.scrollY > it.width / 2 } == true - - val canMoveBottom: Boolean get() = - webView?.let { (it.maxScrollY - it.scrollY) > it.width / 2 } == true - - fun moveLeft() { - webView?.let { it.scrollBy(-it.width, 0) } - } - - fun moveRight() { - webView?.let { it.scrollBy(it.width, 0) } - } - - fun moveTop() { - webView?.let { it.scrollBy(0, -it.width) } - } - - fun moveBottom() { - webView?.let { it.scrollBy(0, it.width) } - } -} - -private class WebViewDeltaDispatcher(private val href: Url? = null) { - - var webView: RelaxedWebView? = null - - fun onDelta(delta: Offset): Offset { - val webViewNow = webView ?: return Offset.Zero - - val currentX = webViewNow.scrollX - val currentY = webViewNow.scrollY - val maxX = webViewNow.maxScrollX - val maxY = webViewNow.maxScrollY - - Timber.d("Dispatching $delta to Webview $href current $currentX max $maxX") - - // Consume slightly more than delta if we have to because - // we don't want the pager to consume any rounding error - val newX = (currentX + sign(delta.x) * ceil(abs(delta.x))).toInt().coerceIn(0, maxX) - val newY = (currentY + sign(delta.y) * ceil(abs(delta.y))).toInt().coerceIn(0, maxY) - webViewNow.scrollTo(newX, newY) - - // Fake that we never consume more than delta - val consumedX = -(currentX - webViewNow.scrollX).toFloat().coerceAbsAtMost(abs(delta.x)) - val consumedY = -(currentY - webViewNow.scrollY).toFloat().coerceAbsAtMost(abs(delta.y)) - val consumed = Offset(consumedX, consumedY) - - return consumed - } - - private fun Float.coerceAbsAtMost(maxValue: Float): Float { - require(maxValue >= 0) - return if (this > 0) { - this.coerceAtMost(maxValue) - } else { - this.coerceAtLeast(-maxValue) - } - } -} From 78381a9b444f795f0670172e1bb807fe42d002a8 Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Sat, 26 Apr 2025 14:13:28 +0200 Subject: [PATCH 50/88] Various big cosmetic changes --- .../navigator/common/HyperlinkListener.kt | 42 ++++++--- .../readium/navigator/common/InputListener.kt | 33 ++++--- .../navigator/common/RenditionState.kt | 5 ++ .../readium/navigator/demo/reader/ReaderUi.kt | 42 ++++----- .../navigator/web/FixedWebRendition.kt | 13 +-- .../navigator/web/FixedWebRenditionFactory.kt | 18 ++-- .../navigator/web/FixedWebRenditionState.kt | 26 +++--- .../navigator/web/ReflowableWebRendition.kt | 82 +++++++----------- .../web/ReflowableWebRenditionFactory.kt | 18 ++-- .../web/ReflowableWebRenditionState.kt | 85 ++++++++++--------- .../web/pager/RenditionScrollState.kt | 11 ++- .../web/reflowable/ReflowableResource.kt | 19 ++--- .../{LayoutDirection.kt => ComposeTypes.kt} | 7 ++ .../navigator/web/util/WebViewClient.kt | 11 --- 14 files changed, 210 insertions(+), 202 deletions(-) rename readium/navigators/web/src/main/java/org/readium/navigator/web/util/{LayoutDirection.kt => ComposeTypes.kt} (75%) diff --git a/readium/navigators/common/src/main/java/org/readium/navigator/common/HyperlinkListener.kt b/readium/navigators/common/src/main/java/org/readium/navigator/common/HyperlinkListener.kt index 28741083a8..4195a1fa17 100644 --- a/readium/navigators/common/src/main/java/org/readium/navigator/common/HyperlinkListener.kt +++ b/readium/navigators/common/src/main/java/org/readium/navigator/common/HyperlinkListener.kt @@ -7,6 +7,7 @@ package org.readium.navigator.common import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch @@ -43,7 +44,7 @@ public data class FootnoteContext( ) : LinkContext @ExperimentalReadiumApi -public class NullHyperlinkListener : HyperlinkListener { +private class NullHyperlinkListener : HyperlinkListener { override fun onReadingOrderLinkActivated(location: HyperlinkLocation, context: LinkContext?) { } @@ -63,20 +64,37 @@ public class NullHyperlinkListener : HyperlinkListener { @ExperimentalReadiumApi @Composable public fun defaultHyperlinkListener( - controller: NavigationController, - shouldFollowReadingOrderLink: (HyperlinkLocation, LinkContext?) -> Boolean = { _, _ -> true }, - onNonLinearLinkActivated: (HyperlinkLocation, LinkContext?) -> Unit = { _, _ -> }, - onExternalLinkActivated: (AbsoluteUrl, LinkContext?) -> Unit = { _, _ -> }, + controller: NavigationController?, + shouldFollowReadingOrderLink: (NavigationController).(HyperlinkLocation, LinkContext?) -> Boolean = { _, _ -> true }, + onNonLinearLinkActivated: (NavigationController).(HyperlinkLocation, LinkContext?) -> Unit = { _, _ -> }, + onExternalLinkActivated: (NavigationController).(AbsoluteUrl, LinkContext?) -> Unit = { _, _ -> }, ): HyperlinkListener { val coroutineScope = rememberCoroutineScope() - return DefaultHyperlinkListener( - coroutineScope = coroutineScope, - controller = controller, - shouldFollowReadingOrderLink = shouldFollowReadingOrderLink, - onNonLinearLinkActivatedDelegate = onNonLinearLinkActivated, - onExternalLinkActivatedDelegate = onExternalLinkActivated - ) + return remember( + controller, + shouldFollowReadingOrderLink, + onNonLinearLinkActivated, + onExternalLinkActivated + ) { + if (controller == null) { + NullHyperlinkListener() + } else { + DefaultHyperlinkListener( + coroutineScope = coroutineScope, + controller = controller, + shouldFollowReadingOrderLink = { link, context -> + controller.shouldFollowReadingOrderLink(link, context) + }, + onNonLinearLinkActivatedDelegate = { link, context -> + controller.onNonLinearLinkActivated(link, context) + }, + onExternalLinkActivatedDelegate = { url, context -> + controller.onExternalLinkActivated(url, context) + } + ) + } + } } @ExperimentalReadiumApi diff --git a/readium/navigators/common/src/main/java/org/readium/navigator/common/InputListener.kt b/readium/navigators/common/src/main/java/org/readium/navigator/common/InputListener.kt index 5c6f99eba0..ce1e7c0852 100644 --- a/readium/navigators/common/src/main/java/org/readium/navigator/common/InputListener.kt +++ b/readium/navigators/common/src/main/java/org/readium/navigator/common/InputListener.kt @@ -7,6 +7,7 @@ package org.readium.navigator.common import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.DpOffset @@ -45,7 +46,7 @@ public data class TapContext( ) @ExperimentalReadiumApi -public class NullInputListener : InputListener { +private class NullInputListener : InputListener { override fun onTap(event: TapEvent, context: TapContext) { } } @@ -53,7 +54,7 @@ public class NullInputListener : InputListener { @ExperimentalReadiumApi @Composable public fun defaultInputListener( - controller: OverflowController, + controller: OverflowController?, fallbackListener: InputListener? = null, tapEdges: Set = setOf( DirectionalNavigationAdapter.TapEdge.Horizontal @@ -66,17 +67,23 @@ public fun defaultInputListener( ): InputListener { val coroutineScope = rememberCoroutineScope() - return DefaultInputListener( - coroutineScope, - fallbackListener, - controller, - tapEdges, - handleTapsWhileScrolling, - minimumHorizontalEdgeSize, - horizontalEdgeThresholdPercent, - minimumVerticalEdgeSize, - verticalEdgeThresholdPercent - ) + return remember(controller) { + if (controller == null) { + NullInputListener() + } else { + DefaultInputListener( + coroutineScope, + fallbackListener, + controller, + tapEdges, + handleTapsWhileScrolling, + minimumHorizontalEdgeSize, + horizontalEdgeThresholdPercent, + minimumVerticalEdgeSize, + verticalEdgeThresholdPercent + ) + } + } } @OptIn(ExperimentalReadiumApi::class) diff --git a/readium/navigators/common/src/main/java/org/readium/navigator/common/RenditionState.kt b/readium/navigators/common/src/main/java/org/readium/navigator/common/RenditionState.kt index a07f866910..0e9de6177e 100644 --- a/readium/navigators/common/src/main/java/org/readium/navigator/common/RenditionState.kt +++ b/readium/navigators/common/src/main/java/org/readium/navigator/common/RenditionState.kt @@ -6,13 +6,18 @@ package org.readium.navigator.common +import androidx.compose.runtime.Stable import org.readium.r2.shared.ExperimentalReadiumApi /** * The state of the rendition, giving access to a [NavigationController] after the first composition. */ @ExperimentalReadiumApi +@Stable public interface RenditionState> { + /** + * The rendition controller if available. This property must be observable. + */ public val controller: N? } diff --git a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/reader/ReaderUi.kt b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/reader/ReaderUi.kt index 03b3f31362..cc558cf64b 100644 --- a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/reader/ReaderUi.kt +++ b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/reader/ReaderUi.kt @@ -41,7 +41,6 @@ import org.readium.navigator.common.InputListener import org.readium.navigator.common.Location import org.readium.navigator.common.LocatorAdapter import org.readium.navigator.common.NavigationController -import org.readium.navigator.common.NullHyperlinkListener import org.readium.navigator.common.OverflowController import org.readium.navigator.common.PreferencesEditor import org.readium.navigator.common.RenditionState @@ -141,33 +140,24 @@ fun > Reader( } val inputListener = - if (controllerNow == null) { - fallbackInputListener - } else { - (controllerNow as? OverflowController)?.let { - defaultInputListener( - controller = it, - fallbackListener = fallbackInputListener - ) - } ?: fallbackInputListener - } + (controllerNow as? OverflowController)?.let { + defaultInputListener( + controller = it, + fallbackListener = fallbackInputListener + ) + } ?: fallbackInputListener + + val context = LocalContext.current val hyperlinkListener = - if (controllerNow == null) { - NullHyperlinkListener() - } else { - val context = LocalContext.current - val onFollowingLink = { navigationHistory.value += controllerNow.location.value } - - defaultHyperlinkListener( - controller = controllerNow, - shouldFollowReadingOrderLink = { _, _ -> - onFollowingLink() - true - }, - onExternalLinkActivated = { url, _ -> launchWebBrowser(context, url.toUri()) } - ) - } + defaultHyperlinkListener( + controller = controllerNow, + shouldFollowReadingOrderLink = { _, _ -> + navigationHistory.value += location.value + true + }, + onExternalLinkActivated = { url, _ -> launchWebBrowser(context, url.toUri()) } + ) when (readerState.renditionState) { is FixedWebRenditionState -> { diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt index fea350163c..33a96d464b 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt @@ -32,8 +32,6 @@ import kotlinx.coroutines.launch import org.readium.navigator.common.HyperlinkListener import org.readium.navigator.common.HyperlinkLocation import org.readium.navigator.common.InputListener -import org.readium.navigator.common.NullHyperlinkListener -import org.readium.navigator.common.NullInputListener import org.readium.navigator.common.TapContext import org.readium.navigator.common.defaultHyperlinkListener import org.readium.navigator.common.defaultInputListener @@ -71,13 +69,8 @@ public fun FixedWebRendition( modifier: Modifier = Modifier, windowInsets: WindowInsets = WindowInsets.displayCutout, backgroundColor: Color = MaterialTheme.colorScheme.background, - inputListener: InputListener = state.controller - ?.let { defaultInputListener(controller = it) } - ?: NullInputListener(), - hyperlinkListener: HyperlinkListener = - state.controller - ?.let { defaultHyperlinkListener(controller = it) } - ?: NullHyperlinkListener(), + inputListener: InputListener = defaultInputListener(state.controller), + hyperlinkListener: HyperlinkListener = defaultHyperlinkListener(controller = state.controller), ) { BoxWithConstraints( modifier = modifier.fillMaxSize(), @@ -136,7 +129,7 @@ public fun FixedWebRendition( RenditionScrollState( pagerState = state.pagerState, pageStates = scrollStates, - pagerOrientation = Orientation.Horizontal, + overflow = state.layoutDelegate.overflow ) } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionFactory.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionFactory.kt index e4f72f1bed..7895b890c6 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionFactory.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionFactory.kt @@ -28,7 +28,7 @@ import org.readium.r2.shared.publication.Publication import org.readium.r2.shared.publication.epub.EpubLayout import org.readium.r2.shared.publication.presentation.page import org.readium.r2.shared.publication.presentation.presentation -import org.readium.r2.shared.publication.services.ContentProtectionService +import org.readium.r2.shared.publication.services.isProtected import org.readium.r2.shared.util.ThrowableError import org.readium.r2.shared.util.Try import org.readium.r2.shared.util.getOrElse @@ -87,6 +87,8 @@ public class FixedWebRenditionFactory private constructor( initialLocation: FixedWebGoLocation? = null, readingOrder: List = publication.readingOrder, ): Try { + // TODO: enable apps not to disable selection when publication is protected + val readingOrderItems = readingOrder.map { ReadingOrderItem( href = it.url(), @@ -95,7 +97,7 @@ public class FixedWebRenditionFactory private constructor( ) } - val otherResources = publication.resources.map { + val resourceItems = (publication.readingOrder - readingOrder + publication.resources).map { OtherItem( href = it.url(), mediaType = it.mediaType @@ -104,24 +106,24 @@ public class FixedWebRenditionFactory private constructor( val renditionPublication = FixedWebPublication( readingOrder = ReadingOrder(readingOrderItems), - otherResources = otherResources, + otherResources = resourceItems, container = publication.container ) val preloads = preloadData() .getOrElse { return Try.failure(it) } - val disableSelection = publication.findService(ContentProtectionService::class) - ?.isRestricted == true + val initialLocation = initialLocation + ?: FixedWebGoLocation(readingOrderItems[0].href) val state = FixedWebRenditionState( application = application, publication = renditionPublication, - disableSelection = disableSelection, initialSettings = initialSettings, - initialLocation = initialLocation ?: FixedWebGoLocation(readingOrderItems[0].href), - preloadedData = preloads + initialLocation = initialLocation, + preloadedData = preloads, + disableSelection = publication.isProtected, ) return Try.success(state) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionState.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionState.kt index 53aa3b5e70..afdc08b4dc 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionState.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionState.kt @@ -31,6 +31,7 @@ import org.readium.navigator.web.util.WebViewClient import org.readium.navigator.web.util.WebViewServer import org.readium.navigator.web.util.WebViewServer.Companion.assetsBaseHref import org.readium.navigator.web.util.injectHtmlFixedLayout +import org.readium.r2.navigator.OverflowableNavigator import org.readium.r2.navigator.SimpleOverflow import org.readium.r2.navigator.preferences.Axis import org.readium.r2.navigator.preferences.Fit @@ -108,7 +109,7 @@ public class FixedWebRenditionState internal constructor( NavigationDelegate( pagerState, layoutDelegate.layout, - layoutDelegate.settings, + layoutDelegate.overflow, location ) controllerState.value = @@ -140,7 +141,7 @@ internal data class FixedWebPreloadedData( val fixedDoubleContent: String, ) -@OptIn(ExperimentalReadiumApi::class) +@OptIn(ExperimentalReadiumApi::class, InternalReadiumApi::class) internal class LayoutDelegate( readingOrder: ReadingOrder, initialSettings: FixedWebSettings, @@ -152,6 +153,16 @@ internal class LayoutDelegate( override val settings: MutableState = mutableStateOf(initialSettings) + val overflow: State = derivedStateOf { + with(settings.value) { + SimpleOverflow( + readingProgression = readingProgression, + scroll = false, + axis = Axis.HORIZONTAL + ) + } + } + val layout: State = derivedStateOf { val spreads = layoutResolver.layout(settings.value) @@ -166,7 +177,7 @@ internal class LayoutDelegate( internal class NavigationDelegate( private val pagerState: PagerState, private val layout: State, - private val settings: State, + override val overflow: State, initialLocation: FixedWebLocation, ) : NavigationController, OverflowController { @@ -193,15 +204,6 @@ internal class NavigationDelegate( goTo(FixedWebGoLocation(location.href)) } - override val overflow: State = - derivedStateOf { - SimpleOverflow( - settings.value.readingProgression, - false, - Axis.HORIZONTAL - ) - } - override val canMoveForward: Boolean get() = pagerState.currentPage < layout.value.spreads.size - 1 diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt index a0e3bf17ec..826df32df6 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt @@ -22,10 +22,12 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.DpOffset import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp @@ -33,8 +35,6 @@ import kotlinx.coroutines.launch import org.readium.navigator.common.HyperlinkListener import org.readium.navigator.common.HyperlinkLocation import org.readium.navigator.common.InputListener -import org.readium.navigator.common.NullHyperlinkListener -import org.readium.navigator.common.NullInputListener import org.readium.navigator.common.TapContext import org.readium.navigator.common.TapEvent import org.readium.navigator.common.defaultHyperlinkListener @@ -42,7 +42,6 @@ import org.readium.navigator.common.defaultInputListener import org.readium.navigator.web.gestures.toFling2DBehavior import org.readium.navigator.web.location.ReflowableWebLocation import org.readium.navigator.web.pager.RenditionPager -import org.readium.navigator.web.pager.RenditionScrollState import org.readium.navigator.web.pager.pagingFlingBehavior import org.readium.navigator.web.reflowable.ReflowablePagingLayoutInfo import org.readium.navigator.web.reflowable.ReflowableResource @@ -63,13 +62,8 @@ public fun ReflowableWebRendition( state: ReflowableWebRenditionState, modifier: Modifier = Modifier, windowInsets: WindowInsets = WindowInsets.displayCutout, - inputListener: InputListener = state.controller - ?.let { defaultInputListener(controller = it) } - ?: NullInputListener(), - hyperlinkListener: HyperlinkListener = - state.controller - ?.let { defaultHyperlinkListener(controller = it) } - ?: NullHyperlinkListener(), + inputListener: InputListener = defaultInputListener(state.controller), + hyperlinkListener: HyperlinkListener = defaultHyperlinkListener(state.controller), ) { BoxWithConstraints( modifier = modifier.fillMaxSize(), @@ -91,18 +85,6 @@ public fun ReflowableWebRendition( } } - val currentPageState = remember(state) { derivedStateOf { state.pagerState.currentPage } } - - if (state.controller == null) { - // Initialize controller. In the future, that should require access to a ready WebView. - state.initController( - location = ReflowableWebLocation( - href = state.publication.readingOrder.items[currentPageState.value].href, - progression = state.resourceStates[currentPageState.value].progression - ) - ) - } - val flingBehavior = if (state.layoutDelegate.overflow.value.scroll) { ScrollableDefaults.flingBehavior() } else { @@ -115,16 +97,6 @@ public fun ReflowableWebRendition( ) }.toFling2DBehavior(state.layoutDelegate.orientation) - val scrollDispatcher = remember(state) { - RenditionScrollState( - pagerState = state.pagerState, - pageStates = state.resourceStates, - pagerOrientation = state.layoutDelegate.orientation, - ) - } - - scrollDispatcher.pagerOrientation = state.layoutDelegate.orientation - val backgroundColor = Color( state.layoutDelegate.settings.value.backgroundColor?.int ?: state.layoutDelegate.settings.value.theme.backgroundColor @@ -137,9 +109,17 @@ public fun ReflowableWebRendition( val layoutDirection = state.layoutDelegate.overflow.value.readingProgression.toLayoutDirection() - val readyToScroll = ((currentPageState.value - 2)..(currentPageState.value + 2)).toList() - .mapNotNull { state.resourceStates.getOrNull(it) } - .all { it.scrollController.value != null } + val currentPageState = remember(state) { derivedStateOf { state.pagerState.currentPage } } + + if (state.controller == null) { + // Initialize controller. In the future, that should require access to a ready WebView. + state.initController( + location = ReflowableWebLocation( + href = state.publication.readingOrder.items[currentPageState.value].href, + progression = state.resourceStates[currentPageState.value].progression + ) + ) + } RenditionPager( modifier = Modifier @@ -148,27 +128,19 @@ public fun ReflowableWebRendition( // Detect taps on padding .pointerInput(Unit) { detectTapGestures( - onTap = { - if (it.x >= 0 && it.y >= 0) { - val offset = DpOffset(x = it.x.toDp(), y = it.y.toDp()) - val event = TapEvent(offset) - inputListenerState.value.onTap(event, TapContext(viewportSize.value)) - } - } + onTap = { onTapOnPadding(it, viewportSize.value, inputListenerState.value) } ) } .windowInsetsPadding(windowInsets), state = state.pagerState, - scrollState = scrollDispatcher, + scrollState = state.scrollState, flingBehavior = flingBehavior, beyondViewportPageCount = 3, layoutDirection = layoutDirection, orientation = state.layoutDelegate.orientation, - enableScroll = readyToScroll ) { index -> ReflowableResource( resourceState = state.resourceStates[index], - pagerState = state.pagerState, publicationBaseUrl = WebViewServer.publicationBaseHref, webViewClient = state.webViewClient, backgroundColor = backgroundColor, @@ -176,10 +148,7 @@ public fun ReflowableWebRendition( layoutDirection = layoutDirection, scroll = state.layoutDelegate.settings.value.scroll, orientation = state.layoutDelegate.orientation, - rsProperties = state.readiumCssInjector.value.rsProperties, - userProperties = state.readiumCssInjector.value.userProperties, - readiumCssLayout = state.readiumCssInjector.value.layout, - enableScroll = readyToScroll, + readiumCssInjector = state.readiumCssInjector.value, onTap = { tapEvent -> inputListenerState.value.onTap(tapEvent, TapContext(viewportSize.value)) }, @@ -201,13 +170,26 @@ public fun ReflowableWebRendition( } }, onDocumentResized = { - scrollDispatcher.onDocumentResized(index) + state.scrollState.onDocumentResized(index) } ) } } } +@OptIn(ExperimentalReadiumApi::class) +private fun (Density).onTapOnPadding( + offset: Offset, + viewportSize: DpSize, + listener: InputListener, +) { + if (offset.x >= 0 && offset.y >= 0) { + val offset = DpOffset(x = offset.x.toDp(), y = offset.y.toDp()) + val event = TapEvent(offset) + listener.onTap(event, TapContext(viewportSize)) + } +} + @OptIn(ExperimentalReadiumApi::class) private suspend fun HyperlinkProcessor.onLinkActivated( url: Url, diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionFactory.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionFactory.kt index 76526dd528..847360fe66 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionFactory.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionFactory.kt @@ -7,6 +7,7 @@ package org.readium.navigator.web import android.app.Application +import org.readium.navigator.web.css.RsProperties import org.readium.navigator.web.location.ReflowableWebGoLocation import org.readium.navigator.web.location.ReflowableWebLocatorAdapter import org.readium.navigator.web.preferences.ReflowableWebDefaults @@ -20,7 +21,7 @@ import org.readium.r2.shared.publication.Link import org.readium.r2.shared.publication.Publication import org.readium.r2.shared.publication.epub.EpubLayout import org.readium.r2.shared.publication.presentation.presentation -import org.readium.r2.shared.publication.services.ContentProtectionService +import org.readium.r2.shared.publication.services.isProtected import org.readium.r2.shared.util.Try /** @@ -78,6 +79,9 @@ public class ReflowableWebRenditionFactory private constructor( initialLocation: ReflowableWebGoLocation? = null, readingOrder: List = publication.readingOrder, ): Try { + // TODO: support font family declarations and reading system properties + // TODO: enable apps not to disable selection when publication is protected + val readingOrderItems = readingOrder.map { ReflowableWebPublication.Item( href = it.url(), @@ -85,7 +89,7 @@ public class ReflowableWebRenditionFactory private constructor( ) } - val otherResources = publication.resources.map { + val resourceItems = (publication.readingOrder - readingOrder + publication.resources).map { ReflowableWebPublication.Item( href = it.url(), mediaType = it.mediaType @@ -94,24 +98,22 @@ public class ReflowableWebRenditionFactory private constructor( val renditionPublication = ReflowableWebPublication( readingOrder = ReflowableWebPublication.ReadingOrder(readingOrderItems), - otherResources = otherResources, + otherResources = resourceItems, container = publication.container ) val initialLocation = initialLocation ?: ReflowableWebGoLocation(readingOrderItems[0].href) - val disableSelection = publication.findService(ContentProtectionService::class) - ?.isRestricted == true - val state = ReflowableWebRenditionState( application = application, publication = renditionPublication, initialSettings = initialSettings, initialLocation = initialLocation, - fontFamilyDeclarations = emptyList(), // FIXME: pass font family declarations - disableSelection = disableSelection + rsProperties = RsProperties(), + fontFamilyDeclarations = emptyList(), + disableSelection = publication.isProtected ) return Try.success(state) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt index b29815e3bd..2f2c9263bc 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt @@ -27,6 +27,7 @@ import org.readium.navigator.web.css.buildFontFamilyDeclaration import org.readium.navigator.web.css.update import org.readium.navigator.web.location.ReflowableWebGoLocation import org.readium.navigator.web.location.ReflowableWebLocation +import org.readium.navigator.web.pager.RenditionScrollState import org.readium.navigator.web.preferences.ReflowableWebSettings import org.readium.navigator.web.reflowable.ReflowableResourceState import org.readium.navigator.web.reflowable.ReflowableWebPublication @@ -35,6 +36,7 @@ import org.readium.navigator.web.util.WebViewClient import org.readium.navigator.web.util.WebViewServer import org.readium.navigator.web.util.WebViewServer.Companion.assetsBaseHref import org.readium.navigator.web.util.injectHtmlReflowable +import org.readium.navigator.web.util.toOrientation import org.readium.navigator.web.webview.WebViewScrollController import org.readium.r2.navigator.SimpleOverflow import org.readium.r2.navigator.preferences.Axis @@ -53,7 +55,7 @@ public class ReflowableWebRenditionState internal constructor( internal val publication: ReflowableWebPublication, initialSettings: ReflowableWebSettings, initialLocation: ReflowableWebGoLocation, - private val rsProperties: RsProperties = RsProperties(), + private val rsProperties: RsProperties, fontFamilyDeclarations: List, disableSelection: Boolean, ) : RenditionState { @@ -64,7 +66,7 @@ public class ReflowableWebRenditionState internal constructor( private val controllerState: MutableState = mutableStateOf(null) - private val initialIndex = publication.readingOrder + private val initialResource = publication.readingOrder .indexOfHref(initialLocation.href) ?: 0 @@ -74,8 +76,8 @@ public class ReflowableWebRenditionState internal constructor( index = index, href = item.href, progression = when { - index < initialIndex -> 1.0 - index > initialIndex -> 0.0 + index < initialResource -> 1.0 + index > initialResource -> 0.0 else -> initialLocation.progression ?: 0.0 } ) @@ -86,6 +88,19 @@ public class ReflowableWebRenditionState internal constructor( initialSettings ) + internal val pagerState: PagerState = + PagerState( + currentPage = initialResource, + pageCount = { publication.readingOrder.size } + ) + + internal val scrollState: RenditionScrollState = + RenditionScrollState( + pagerState = pagerState, + pageStates = resourceStates, + overflow = layoutDelegate.overflow, + ) + internal val hyperlinkProcessor = HyperlinkProcessor(publication.container) @@ -95,8 +110,7 @@ public class ReflowableWebRenditionState internal constructor( assetsBaseHref = assetsBaseHref, readiumCssAssets = RelativeUrl("readium/navigators/web/generated/readium-css/")!!, rsProperties = rsProperties, - fontFamilyDeclarations = - buildList { + fontFamilyDeclarations = buildList { addAll(fontFamilyDeclarations) add( buildFontFamilyDeclaration( @@ -115,35 +129,30 @@ public class ReflowableWebRenditionState internal constructor( ) } - private val htmlInjector: (Resource, MediaType) -> Resource = { resource, mediaType -> - resource.injectHtmlReflowable( - charset = mediaType.charset, - readiumCss = readiumCssInjector.value, - injectableScript = RelativeUrl("readium/navigators/web/generated/reflowable-injectable-script.js")!!, - assetsBaseHref = assetsBaseHref, - disableSelection = disableSelection - ) - } + internal val webViewClient: WebViewClient = run { + val htmlInjector: (Resource, MediaType) -> Resource = { resource, mediaType -> + resource.injectHtmlReflowable( + charset = mediaType.charset, + readiumCss = readiumCssInjector.value, + injectableScript = RelativeUrl("readium/navigators/web/generated/reflowable-injectable-script.js")!!, + assetsBaseHref = assetsBaseHref, + disableSelection = disableSelection + ) + } - internal val webViewServer = - WebViewServer( - application = application, - container = publication.container, - mediaTypes = publication.mediaTypes, - errorPage = RelativeUrl("readium/navigators/web/error.xhtml")!!, - htmlInjector = htmlInjector, - servedAssets = listOf("readium/.*"), - onResourceLoadFailed = { _, _ -> } - ) + val webViewServer = + WebViewServer( + application = application, + container = publication.container, + mediaTypes = publication.mediaTypes, + errorPage = RelativeUrl("readium/navigators/web/error.xhtml")!!, + htmlInjector = htmlInjector, + servedAssets = listOf("readium/.*"), + onResourceLoadFailed = { _, _ -> } // TODO: pass errors to the app + ) - internal val webViewClient: WebViewClient = WebViewClient(webViewServer) - - internal val pagerState: PagerState = - PagerState( - currentPage = initialIndex, - pageCount = { publication.readingOrder.size } - ) + } private lateinit var navigationDelegate: ReflowableNavigationDelegate @@ -222,7 +231,7 @@ internal class ReflowableNavigationDelegate( locationMutable override suspend fun goTo(location: HyperlinkLocation) { - goTo(ReflowableWebGoLocation(location.href)) + goTo(ReflowableWebGoLocation(location.href)) // TODO: use fragment } override suspend fun goTo(location: ReflowableWebGoLocation) { @@ -230,6 +239,8 @@ internal class ReflowableNavigationDelegate( pagerState.scrollToPage(resourceIndex) location.progression?.let { // FIXME: goTo returns before the move has completed. resourceStates[resourceIndex].progression = it + // If the scrollController is not available yet, progression will be applied + // when it becomes available. resourceStates[resourceIndex].scrollController.value?.moveToProgression(it) } } @@ -240,8 +251,9 @@ internal class ReflowableNavigationDelegate( // This information is not available when the WebView has not yet been composed or laid out. // We assume that the best UI behavior would be to have a possible forward button disabled - // and then return false when we can't tell. + // and return false when we can't tell. override val canMoveForward: Boolean + // FIXME: should we really return true when we're not ready yet to move forward? get() = pagerState.currentPage < readingOrder.items.size - 1 || run { val currentResourceState = resourceStates[pagerState.currentPage] val scrollController = currentResourceState.scrollController.value ?: return false @@ -318,8 +330,3 @@ internal class ReflowableNavigationDelegate( ) } } - -private fun Axis.toOrientation() = when (this) { - Axis.HORIZONTAL -> Orientation.Horizontal - Axis.VERTICAL -> Orientation.Vertical -} diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/RenditionScrollState.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/RenditionScrollState.kt index dfd99e38a9..3372dc25c5 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/RenditionScrollState.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/RenditionScrollState.kt @@ -4,6 +4,8 @@ * available in the top-level LICENSE file of the project. */ +@file:OptIn(ExperimentalReadiumApi::class) + package org.readium.navigator.web.pager import androidx.compose.foundation.MutatePriority @@ -11,6 +13,7 @@ import androidx.compose.foundation.MutatorMutex import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.pager.PagerState import androidx.compose.runtime.MutableState +import androidx.compose.runtime.State import androidx.compose.runtime.mutableStateOf import androidx.compose.ui.geometry.Offset import androidx.compose.ui.util.fastCoerceAtLeast @@ -18,7 +21,10 @@ import androidx.compose.ui.util.fastCoerceAtMost import kotlinx.coroutines.coroutineScope import org.readium.navigator.web.gestures.Scroll2DScope import org.readium.navigator.web.gestures.Scrollable2DState +import org.readium.navigator.web.util.toOrientation import org.readium.navigator.web.webview.WebViewScrollController +import org.readium.r2.navigator.OverflowableNavigator +import org.readium.r2.shared.ExperimentalReadiumApi import timber.log.Timber internal interface PageScrollState { @@ -29,9 +35,12 @@ internal interface PageScrollState { internal class RenditionScrollState( private val pagerState: PagerState, private val pageStates: List, - internal var pagerOrientation: Orientation, + private val overflow: State, ) : Scrollable2DState { + private val pagerOrientation: Orientation get() = + overflow.value.axis.toOrientation() + /* * To favour natural reasoning, this function applies reverse scrolling: * - a positive delta makes scrolling left diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt index efa6064db0..9a6ad60369 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt @@ -15,7 +15,6 @@ import androidx.compose.foundation.background import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.pager.PagerState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.key @@ -28,9 +27,7 @@ import androidx.compose.ui.unit.DpOffset import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.zIndex import org.readium.navigator.common.TapEvent -import org.readium.navigator.web.css.ReadiumCssLayout -import org.readium.navigator.web.css.RsProperties -import org.readium.navigator.web.css.UserProperties +import org.readium.navigator.web.css.ReadiumCssInjector import org.readium.navigator.web.util.AbsolutePaddingValues import org.readium.navigator.web.util.WebViewClient import org.readium.navigator.web.util.absolutePadding @@ -50,7 +47,6 @@ import org.readium.r2.shared.util.Url @Composable internal fun ReflowableResource( resourceState: ReflowableResourceState, - pagerState: PagerState, publicationBaseUrl: AbsoluteUrl, webViewClient: WebViewClient, backgroundColor: Color, @@ -58,10 +54,7 @@ internal fun ReflowableResource( scroll: Boolean, orientation: Orientation, layoutDirection: LayoutDirection, - userProperties: UserProperties, - rsProperties: RsProperties, - readiumCssLayout: ReadiumCssLayout, - enableScroll: Boolean, + readiumCssInjector: ReadiumCssInjector, onTap: (TapEvent) -> Unit, onLinkActivated: (Url, String) -> Unit, onProgressionChange: (Double) -> Unit, @@ -124,8 +117,9 @@ internal fun ReflowableResource( ?.let { CssApi(it) } } - LaunchedEffect(cssApi, rsProperties, userProperties) { - cssApi?.setProperties(userProperties, rsProperties) + LaunchedEffect(cssApi, readiumCssInjector) { + cssApi?.setProperties(readiumCssInjector.userProperties, readiumCssInjector.rsProperties) + // FIXME: resource is laid out again, so we should apply progression again } val gesturesApi = remember(onTap, onLinkActivated) { @@ -160,7 +154,8 @@ internal fun ReflowableResource( ) } - key(readiumCssLayout) { + // Recreate WebView when Readium CSS layout changes because injected stuff depends on it + key(readiumCssInjector.layout) { WebView( modifier = Modifier .fillMaxSize() diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/util/LayoutDirection.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/util/ComposeTypes.kt similarity index 75% rename from readium/navigators/web/src/main/java/org/readium/navigator/web/util/LayoutDirection.kt rename to readium/navigators/web/src/main/java/org/readium/navigator/web/util/ComposeTypes.kt index a3ae9e7f5e..11e4ddf9fd 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/util/LayoutDirection.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/util/ComposeTypes.kt @@ -6,7 +6,9 @@ package org.readium.navigator.web.util +import androidx.compose.foundation.gestures.Orientation import androidx.compose.ui.unit.LayoutDirection +import org.readium.r2.navigator.preferences.Axis import org.readium.r2.navigator.preferences.ReadingProgression internal fun LayoutDirection.toReadingProgression(): ReadingProgression = @@ -20,3 +22,8 @@ internal fun ReadingProgression.toLayoutDirection(): LayoutDirection = ReadingProgression.LTR -> LayoutDirection.Ltr ReadingProgression.RTL -> LayoutDirection.Rtl } + +internal fun Axis.toOrientation() = when (this) { + Axis.HORIZONTAL -> Orientation.Horizontal + Axis.VERTICAL -> Orientation.Vertical +} diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/util/WebViewClient.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/util/WebViewClient.kt index bb64c6e84c..2b4be265ec 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/util/WebViewClient.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/util/WebViewClient.kt @@ -9,12 +9,9 @@ package org.readium.navigator.web.util import android.webkit.WebResourceRequest import android.webkit.WebResourceResponse import android.webkit.WebView -import androidx.webkit.WebViewCompat -import androidx.webkit.WebViewFeature internal class WebViewClient( private val webViewServer: WebViewServer, - private val onPageFinishedDelegate: (() -> Unit)? = null, ) : android.webkit.WebViewClient() { override fun shouldInterceptRequest( @@ -23,12 +20,4 @@ internal class WebViewClient( ): WebResourceResponse? { return webViewServer.shouldInterceptRequest(request) } - - override fun onPageFinished(view: WebView, url: String?) { - if (WebViewFeature.isFeatureSupported(WebViewFeature.VISUAL_STATE_CALLBACK)) { - WebViewCompat.postVisualStateCallback(view, 0) { - onPageFinishedDelegate?.invoke() - } - } - } } From 35a7411e55c2a3d9793f90b0f97232037bfe2b9c Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Sun, 27 Apr 2025 20:30:48 +0200 Subject: [PATCH 51/88] Fix scroll behavior in RTL mode --- .../navigator/web/FixedWebRendition.kt | 304 +++++++++--------- .../navigator/web/ReflowableWebRendition.kt | 190 +++++------ .../web/ReflowableWebRenditionState.kt | 56 ++-- .../navigator/web/css/ReadiumCssInjector.kt | 8 +- .../web/fixed/DoubleViewportSpread.kt | 5 +- .../web/fixed/FixedPagingLayoutInfo.kt | 8 +- .../web/fixed/SingleViewportSpread.kt | 5 +- .../navigator/web/fixed/SpreadWebView.kt | 6 +- .../navigator/web/pager/RenditionPager.kt | 8 +- .../web/pager/RenditionScrollState.kt | 129 +++++--- .../reflowable/ReflowablePagingLayoutInfo.kt | 55 ++-- .../web/reflowable/ReflowableResource.kt | 10 +- .../web/webview/WebViewScrollController.kt | 100 +++++- 13 files changed, 505 insertions(+), 379 deletions(-) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt index 33a96d464b..a552700ff6 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt @@ -14,6 +14,7 @@ import androidx.compose.foundation.layout.displayCutout import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope @@ -25,7 +26,6 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.unit.DpSize -import androidx.compose.ui.unit.LayoutDirection import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch @@ -72,176 +72,192 @@ public fun FixedWebRendition( inputListener: InputListener = defaultInputListener(state.controller), hyperlinkListener: HyperlinkListener = defaultHyperlinkListener(controller = state.controller), ) { - BoxWithConstraints( - modifier = modifier.fillMaxSize(), - propagateMinConstraints = true - ) { - val viewportSize = rememberUpdatedState(DpSize(maxWidth, maxHeight)) + val layoutDirection = + state.layoutDelegate.overflow.value.readingProgression.toLayoutDirection() - val safeDrawingPadding = windowInsets.asAbsolutePaddingValues() + CompositionLocalProvider(LocalLayoutDirection provides layoutDirection) { + BoxWithConstraints( + modifier = modifier.fillMaxSize(), + propagateMinConstraints = true + ) { + val viewportSize = rememberUpdatedState(DpSize(maxWidth, maxHeight)) - val displayArea = rememberUpdatedState(DisplayArea(viewportSize.value, safeDrawingPadding)) + val safeDrawingPadding = windowInsets.asAbsolutePaddingValues() - val layoutDirection = state.layoutDelegate.settings.value - .readingProgression - .toLayoutDirection() + val displayArea = + rememberUpdatedState(DisplayArea(viewportSize.value, safeDrawingPadding)) - if (state.controller == null) { - val itemHref = state.getCurrentHref() - state.initController(location = FixedWebLocation(itemHref)) - } - - LaunchedEffect(state) { - snapshotFlow { - state.pagerState.currentPage - }.onEach { + if (state.controller == null) { val itemHref = state.getCurrentHref() - state.navigationDelegate.updateLocation(location = FixedWebLocation(itemHref)) - }.launchIn(this) - } + state.initController(location = FixedWebLocation(itemHref)) + } - val coroutineScope = rememberCoroutineScope() + LaunchedEffect(state) { + snapshotFlow { + state.pagerState.currentPage + }.onEach { + val itemHref = state.getCurrentHref() + state.navigationDelegate.updateLocation(location = FixedWebLocation(itemHref)) + }.launchIn(this) + } - val inputListenerState = rememberUpdatedState(inputListener) + val coroutineScope = rememberCoroutineScope() - val hyperlinkListenerState = rememberUpdatedState(hyperlinkListener) + val inputListenerState = rememberUpdatedState(inputListener) - val density = LocalDensity.current + val hyperlinkListenerState = rememberUpdatedState(hyperlinkListener) - val scrollStates = remember(state, state.layoutDelegate.layout.value) { - state.layoutDelegate.layout.value.spreads - .map { SpreadScrollState() } - } + val density = LocalDensity.current - val flingBehavior = run { - val pagingLayoutInfo = remember(state, scrollStates) { - FixedPagingLayoutInfo( - pagerState = state.pagerState, - pageStates = scrollStates, - orientation = Orientation.Horizontal, - density = density - ) + val scrollStates = remember(state, state.layoutDelegate.layout.value) { + state.layoutDelegate.layout.value.spreads + .map { SpreadScrollState() } } - pagingFlingBehavior(pagingLayoutInfo) - }.toFling2DBehavior(Orientation.Horizontal) - val scrollDispatcher = remember(state, scrollStates) { - RenditionScrollState( - pagerState = state.pagerState, - pageStates = scrollStates, - overflow = state.layoutDelegate.overflow - ) - } - - LaunchedEffect(state.layoutDelegate.layout.value, state.controller) { - state.controller?.let { - val currentHref = it.location.value.href - val spreadIndex = checkNotNull(state.layoutDelegate.layout.value.spreadIndexForHref(currentHref)) - state.pagerState.requestScrollToPage(spreadIndex) - } - } - - val readyToScroll = ((state.pagerState.currentPage - 2)..(state.pagerState.currentPage + 2)).toList() - .mapNotNull { scrollStates.getOrNull(it) } - .all { it.scrollController.value != null } - - val spreadFlingBehavior = Scrollable2DDefaults.flingBehavior() + val flingBehavior = run { + val pagingLayoutInfo = remember(state, scrollStates, layoutDirection) { + FixedPagingLayoutInfo( + pagerState = state.pagerState, + pageStates = scrollStates, + orientation = Orientation.Horizontal, + direction = layoutDirection, + density = density + ) + } + pagingFlingBehavior(pagingLayoutInfo) + }.toFling2DBehavior(Orientation.Horizontal) - val spreadNestedScrollConnection = - remember(state.pagerState, scrollStates) { - SpreadNestedScrollConnection( + val scrollDispatcher = remember(state, scrollStates) { + RenditionScrollState( pagerState = state.pagerState, - resourceStates = scrollStates, - flingBehavior = spreadFlingBehavior + pageStates = scrollStates, + overflow = state.layoutDelegate.overflow ) } - RenditionPager( - modifier = Modifier.nestedScroll(spreadNestedScrollConnection), - state = state.pagerState, - scrollState = scrollDispatcher, - flingBehavior = flingBehavior, - orientation = Orientation.Horizontal, - beyondViewportPageCount = 2, - layoutDirection = layoutDirection, - enableScroll = readyToScroll, - key = { index -> - val readingProgression = state.layoutDelegate.layout.value.readingProgression - val spread = state.layoutDelegate.layout.value.spreads[index] - val pages = spread.pages.map { it.index } - val fit = state.layoutDelegate.fit.value - "$readingProgression $spread $pages $fit" - }, - ) { index -> - val initialProgression = when { - index < state.pagerState.currentPage -> 1.0 - else -> 0.0 + LaunchedEffect(state.layoutDelegate.layout.value, state.controller) { + state.controller?.let { + val currentHref = it.location.value.href + val spreadIndex = checkNotNull( + state.layoutDelegate.layout.value.spreadIndexForHref(currentHref) + ) + state.pagerState.requestScrollToPage(spreadIndex) + } } - when (val spread = state.layoutDelegate.layout.value.spreads[index]) { - is SingleViewportSpread -> { - val spreadState = - SingleSpreadState( - index = index, - htmlData = state.preloadedData.fixedSingleContent, - publicationBaseUrl = WebViewServer.publicationBaseHref, - webViewClient = state.webViewClient, - spread = spread, - fit = state.layoutDelegate.fit, - displayArea = displayArea - ) + val readyToScroll = + ((state.pagerState.currentPage - 2)..(state.pagerState.currentPage + 2)).toList() + .mapNotNull { scrollStates.getOrNull(it) } + .all { it.scrollController.value != null } + + val spreadFlingBehavior = Scrollable2DDefaults.flingBehavior() - SingleViewportSpread( + val spreadNestedScrollConnection = + remember(state.pagerState, scrollStates) { + SpreadNestedScrollConnection( pagerState = state.pagerState, - progression = initialProgression, - onTap = { inputListenerState.value.onTap(it, TapContext(viewportSize.value)) }, - onLinkActivated = { url, outerHtml -> - coroutineScope.launch { - state.hyperlinkProcessor.onLinkActivated( - url = url, - outerHtml = outerHtml, - readingOrder = state.publication.readingOrder, - listener = hyperlinkListenerState.value - ) - } - }, - state = spreadState, - scrollState = scrollStates[index], - backgroundColor = backgroundColor, - reverseScrollDirection = layoutDirection == LayoutDirection.Ltr + resourceStates = scrollStates, + flingBehavior = spreadFlingBehavior ) } - is DoubleViewportSpread -> { - val spreadState = - DoubleSpreadState( - index = index, - htmlData = state.preloadedData.fixedDoubleContent, - publicationBaseUrl = WebViewServer.publicationBaseHref, - webViewClient = state.webViewClient, - spread = spread, - fit = state.layoutDelegate.fit, - displayArea = displayArea, + + RenditionPager( + modifier = Modifier.nestedScroll(spreadNestedScrollConnection), + state = state.pagerState, + scrollState = scrollDispatcher, + flingBehavior = flingBehavior, + orientation = Orientation.Horizontal, + beyondViewportPageCount = 2, + enableScroll = readyToScroll, + key = { index -> + val readingProgression = state.layoutDelegate.layout.value.readingProgression + val spread = state.layoutDelegate.layout.value.spreads[index] + val pages = spread.pages.map { it.index } + val fit = state.layoutDelegate.fit.value + "$readingProgression $spread $pages $fit" + }, + ) { index -> + val initialProgression = when { + index < state.pagerState.currentPage -> 1.0 + else -> 0.0 + } + + when (val spread = state.layoutDelegate.layout.value.spreads[index]) { + is SingleViewportSpread -> { + val spreadState = + SingleSpreadState( + index = index, + htmlData = state.preloadedData.fixedSingleContent, + publicationBaseUrl = WebViewServer.publicationBaseHref, + webViewClient = state.webViewClient, + spread = spread, + fit = state.layoutDelegate.fit, + displayArea = displayArea + ) + + SingleViewportSpread( + pagerState = state.pagerState, + progression = initialProgression, + layoutDirection = layoutDirection, + onTap = { + inputListenerState.value.onTap( + it, + TapContext(viewportSize.value) + ) + }, + onLinkActivated = { url, outerHtml -> + coroutineScope.launch { + state.hyperlinkProcessor.onLinkActivated( + url = url, + outerHtml = outerHtml, + readingOrder = state.publication.readingOrder, + listener = hyperlinkListenerState.value + ) + } + }, + state = spreadState, + scrollState = scrollStates[index], + backgroundColor = backgroundColor ) + } - DoubleViewportSpread( - pagerState = state.pagerState, - progression = initialProgression, - onTap = { inputListenerState.value.onTap(it, TapContext(viewportSize.value)) }, - onLinkActivated = { url, outerHtml -> - coroutineScope.launch { - state.hyperlinkProcessor.onLinkActivated( - url = url, - outerHtml = outerHtml, - readingOrder = state.publication.readingOrder, - listener = hyperlinkListenerState.value + is DoubleViewportSpread -> { + val spreadState = + DoubleSpreadState( + index = index, + htmlData = state.preloadedData.fixedDoubleContent, + publicationBaseUrl = WebViewServer.publicationBaseHref, + webViewClient = state.webViewClient, + spread = spread, + fit = state.layoutDelegate.fit, + displayArea = displayArea, + ) + + DoubleViewportSpread( + pagerState = state.pagerState, + progression = initialProgression, + layoutDirection = layoutDirection, + onTap = { + inputListenerState.value.onTap( + it, + TapContext(viewportSize.value) ) - } - }, - state = spreadState, - scrollState = scrollStates[index], - backgroundColor = backgroundColor, - reverseScrollDirection = layoutDirection == LayoutDirection.Ltr - ) + }, + onLinkActivated = { url, outerHtml -> + coroutineScope.launch { + state.hyperlinkProcessor.onLinkActivated( + url = url, + outerHtml = outerHtml, + readingOrder = state.publication.readingOrder, + listener = hyperlinkListenerState.value + ) + } + }, + state = spreadState, + scrollState = scrollStates[index], + backgroundColor = backgroundColor + ) + } } } } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt index 826df32df6..fb03ed63b7 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt @@ -17,6 +17,7 @@ import androidx.compose.foundation.layout.displayCutout import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope @@ -27,6 +28,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.DpOffset import androidx.compose.ui.unit.DpSize @@ -65,114 +67,116 @@ public fun ReflowableWebRendition( inputListener: InputListener = defaultInputListener(state.controller), hyperlinkListener: HyperlinkListener = defaultHyperlinkListener(state.controller), ) { - BoxWithConstraints( - modifier = modifier.fillMaxSize(), - propagateMinConstraints = true - ) { - val viewportSize = rememberUpdatedState(DpSize(maxWidth, maxHeight)) + val layoutDirection = + state.layoutDelegate.overflow.value.readingProgression.toLayoutDirection() - val coroutineScope = rememberCoroutineScope() + CompositionLocalProvider(LocalLayoutDirection provides layoutDirection) { + BoxWithConstraints( + modifier = modifier.fillMaxSize(), + propagateMinConstraints = true + ) { + val viewportSize = rememberUpdatedState(DpSize(maxWidth, maxHeight)) - val resourcePadding = - if (state.layoutDelegate.overflow.value.scroll) { - AbsolutePaddingValues() - } else { - when (LocalConfiguration.current.orientation) { - Configuration.ORIENTATION_LANDSCAPE -> - AbsolutePaddingValues(vertical = 20.dp) - else -> - AbsolutePaddingValues(vertical = 40.dp) + val coroutineScope = rememberCoroutineScope() + + val resourcePadding = + if (state.layoutDelegate.overflow.value.scroll) { + AbsolutePaddingValues() + } else { + when (LocalConfiguration.current.orientation) { + Configuration.ORIENTATION_LANDSCAPE -> + AbsolutePaddingValues(vertical = 20.dp) + else -> + AbsolutePaddingValues(vertical = 40.dp) + } } - } - val flingBehavior = if (state.layoutDelegate.overflow.value.scroll) { - ScrollableDefaults.flingBehavior() - } else { - pagingFlingBehavior( - ReflowablePagingLayoutInfo( - pagerState = state.pagerState, - resourceStates = state.resourceStates, - density = LocalDensity.current + val flingBehavior = if (state.layoutDelegate.overflow.value.scroll) { + ScrollableDefaults.flingBehavior() + } else { + pagingFlingBehavior( + ReflowablePagingLayoutInfo( + pagerState = state.pagerState, + pageStates = state.resourceStates, + density = LocalDensity.current, + direction = layoutDirection + ) ) - ) - }.toFling2DBehavior(state.layoutDelegate.orientation) - - val backgroundColor = Color( - state.layoutDelegate.settings.value.backgroundColor?.int - ?: state.layoutDelegate.settings.value.theme.backgroundColor - ) + }.toFling2DBehavior(state.layoutDelegate.orientation) - val inputListenerState = rememberUpdatedState(inputListener) + val backgroundColor = Color( + state.layoutDelegate.settings.value.backgroundColor?.int + ?: state.layoutDelegate.settings.value.theme.backgroundColor + ) - val hyperlinkListenerState = rememberUpdatedState(hyperlinkListener) + val inputListenerState = rememberUpdatedState(inputListener) - val layoutDirection = - state.layoutDelegate.overflow.value.readingProgression.toLayoutDirection() + val hyperlinkListenerState = rememberUpdatedState(hyperlinkListener) - val currentPageState = remember(state) { derivedStateOf { state.pagerState.currentPage } } + val currentPageState = remember(state) { derivedStateOf { state.pagerState.currentPage } } - if (state.controller == null) { - // Initialize controller. In the future, that should require access to a ready WebView. - state.initController( - location = ReflowableWebLocation( - href = state.publication.readingOrder.items[currentPageState.value].href, - progression = state.resourceStates[currentPageState.value].progression + if (state.controller == null) { + // Initialize controller. In the future, that should require access to a ready WebView. + state.initController( + location = ReflowableWebLocation( + href = state.publication.readingOrder.items[currentPageState.value].href, + progression = state.resourceStates[currentPageState.value].progression + ) ) - ) - } + } - RenditionPager( - modifier = Modifier - // Apply background on padding - .background(backgroundColor) - // Detect taps on padding - .pointerInput(Unit) { - detectTapGestures( - onTap = { onTapOnPadding(it, viewportSize.value, inputListenerState.value) } - ) - } - .windowInsetsPadding(windowInsets), - state = state.pagerState, - scrollState = state.scrollState, - flingBehavior = flingBehavior, - beyondViewportPageCount = 3, - layoutDirection = layoutDirection, - orientation = state.layoutDelegate.orientation, - ) { index -> - ReflowableResource( - resourceState = state.resourceStates[index], - publicationBaseUrl = WebViewServer.publicationBaseHref, - webViewClient = state.webViewClient, - backgroundColor = backgroundColor, - padding = resourcePadding, - layoutDirection = layoutDirection, - scroll = state.layoutDelegate.settings.value.scroll, - orientation = state.layoutDelegate.orientation, - readiumCssInjector = state.readiumCssInjector.value, - onTap = { tapEvent -> - inputListenerState.value.onTap(tapEvent, TapContext(viewportSize.value)) - }, - onLinkActivated = { url, outerHtml -> - coroutineScope.launch { - state.hyperlinkProcessor.onLinkActivated( - url = url, - outerHtml = outerHtml, - readingOrder = state.publication.readingOrder, - listener = hyperlinkListenerState.value + RenditionPager( + modifier = Modifier + // Apply background on padding + .background(backgroundColor) + // Detect taps on padding + .pointerInput(Unit) { + detectTapGestures( + onTap = { onTapOnPadding(it, viewportSize.value, inputListenerState.value) } ) } - }, - onProgressionChange = { - if (index == currentPageState.value) { - val itemHref = state.publication.readingOrder[index].href - val newLocation = ReflowableWebLocation(itemHref, it) - state.updateLocation(newLocation) + .windowInsetsPadding(windowInsets), + state = state.pagerState, + scrollState = state.scrollState, + flingBehavior = flingBehavior, + beyondViewportPageCount = 3, + orientation = state.layoutDelegate.orientation, + ) { index -> + ReflowableResource( + resourceState = state.resourceStates[index], + publicationBaseUrl = WebViewServer.publicationBaseHref, + webViewClient = state.webViewClient, + backgroundColor = backgroundColor, + padding = resourcePadding, + layoutDirection = layoutDirection, + scroll = state.layoutDelegate.settings.value.scroll, + orientation = state.layoutDelegate.orientation, + readiumCssInjector = state.readiumCssInjector.value, + onTap = { tapEvent -> + inputListenerState.value.onTap(tapEvent, TapContext(viewportSize.value)) + }, + onLinkActivated = { url, outerHtml -> + coroutineScope.launch { + state.hyperlinkProcessor.onLinkActivated( + url = url, + outerHtml = outerHtml, + readingOrder = state.publication.readingOrder, + listener = hyperlinkListenerState.value + ) + } + }, + onProgressionChange = { + if (index == currentPageState.value) { + val itemHref = state.publication.readingOrder[index].href + val newLocation = ReflowableWebLocation(itemHref, it) + state.updateLocation(newLocation) + } + }, + onDocumentResized = { + state.scrollState.onDocumentResized(index) } - }, - onDocumentResized = { - state.scrollState.onDocumentResized(index) - } - ) + ) + } } } } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt index 2f2c9263bc..746c3790cd 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRenditionState.kt @@ -24,7 +24,7 @@ import org.readium.navigator.web.css.FontFamilyDeclaration import org.readium.navigator.web.css.ReadiumCssInjector import org.readium.navigator.web.css.RsProperties import org.readium.navigator.web.css.buildFontFamilyDeclaration -import org.readium.navigator.web.css.update +import org.readium.navigator.web.css.withSettings import org.readium.navigator.web.location.ReflowableWebGoLocation import org.readium.navigator.web.location.ReflowableWebLocation import org.readium.navigator.web.pager.RenditionScrollState @@ -36,12 +36,12 @@ import org.readium.navigator.web.util.WebViewClient import org.readium.navigator.web.util.WebViewServer import org.readium.navigator.web.util.WebViewServer.Companion.assetsBaseHref import org.readium.navigator.web.util.injectHtmlReflowable +import org.readium.navigator.web.util.toLayoutDirection import org.readium.navigator.web.util.toOrientation import org.readium.navigator.web.webview.WebViewScrollController import org.readium.r2.navigator.SimpleOverflow import org.readium.r2.navigator.preferences.Axis import org.readium.r2.navigator.preferences.FontFamily -import org.readium.r2.navigator.preferences.ReadingProgression import org.readium.r2.shared.ExperimentalReadiumApi import org.readium.r2.shared.InternalReadiumApi import org.readium.r2.shared.util.RelativeUrl @@ -123,9 +123,8 @@ public class ReflowableWebRenditionState internal constructor( } ) } - ).update( + ).withSettings( settings = layoutDelegate.settings.value, - useReadiumCssFontSize = true ) } @@ -288,45 +287,34 @@ internal class ReflowableNavigationDelegate( } private fun WebViewScrollController.moveForward() = - when (overflow.value.scroll) { - true -> moveBottom() - false -> when (overflow.value.readingProgression) { - ReadingProgression.LTR -> moveRight() - ReadingProgression.RTL -> moveLeft() - } - } + moveForward( + orientation = overflow.value.axis.toOrientation(), + direction = overflow.value.readingProgression.toLayoutDirection() + ) private fun WebViewScrollController.moveBackward() = - when (overflow.value.scroll) { - true -> moveTop() - false -> when (overflow.value.readingProgression) { - ReadingProgression.LTR -> moveLeft() - ReadingProgression.RTL -> moveRight() - } - } + moveBackward( + orientation = overflow.value.axis.toOrientation(), + direction = overflow.value.readingProgression.toLayoutDirection() + ) private fun WebViewScrollController.canMoveForward(): Boolean = - when (overflow.value.scroll) { - true -> canMoveBottom - false -> when (overflow.value.readingProgression) { - ReadingProgression.LTR -> canMoveRight - ReadingProgression.RTL -> canMoveLeft - } - } - + canMoveForward( + orientation = overflow.value.axis.toOrientation(), + direction = overflow.value.readingProgression.toLayoutDirection() + ) private fun WebViewScrollController.canMoveBackward(): Boolean = - when (overflow.value.scroll) { - true -> canMoveTop - false -> when (overflow.value.readingProgression) { - ReadingProgression.LTR -> canMoveLeft - ReadingProgression.RTL -> canMoveRight - } - } + canMoveBackward( + orientation = overflow.value.axis.toOrientation(), + direction = overflow.value.readingProgression.toLayoutDirection() + ) + private fun WebViewScrollController.moveToProgression(progression: Double) { moveToProgression( progression = progression, snap = !overflow.value.scroll, - orientation = overflow.value.axis.toOrientation() + orientation = overflow.value.axis.toOrientation(), + direction = overflow.value.readingProgression.toLayoutDirection() ) } } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCssInjector.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCssInjector.kt index 0697bcc4d3..f39d451b59 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCssInjector.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCssInjector.kt @@ -311,7 +311,7 @@ private val dirRegex = Regex( ) @OptIn(ExperimentalReadiumApi::class) -internal fun ReadiumCssInjector.update(settings: ReflowableWebSettings, useReadiumCssFontSize: Boolean): ReadiumCssInjector { +internal fun ReadiumCssInjector.withSettings(settings: ReflowableWebSettings): ReadiumCssInjector { fun resolveFontStack(fontFamily: String): List = buildList { add(fontFamily) @@ -352,11 +352,7 @@ internal fun ReadiumCssInjector.update(settings: ReflowableWebSettings, useReadi backgroundColor = backgroundColor?.toCss(), fontOverride = (fontFamily != null || textNormalization), fontFamily = fontFamily?.toCss(), - fontSize = if (useReadiumCssFontSize) { - Length.Percent(fontSize) - } else { - null - }, + fontSize = Length.Percent(fontSize), textAlign = when (textAlign) { TextAlign.JUSTIFY -> CssTextAlign.JUSTIFY TextAlign.LEFT -> CssTextAlign.LEFT diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/DoubleViewportSpread.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/DoubleViewportSpread.kt index fc47c4dc48..977c00daf2 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/DoubleViewportSpread.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/DoubleViewportSpread.kt @@ -19,6 +19,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.LayoutDirection import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import org.readium.navigator.common.TapEvent @@ -38,11 +39,11 @@ internal fun DoubleViewportSpread( pagerState: PagerState, scrollState: SpreadScrollState, progression: Double, + layoutDirection: LayoutDirection, onTap: (TapEvent) -> Unit, onLinkActivated: (Url, String) -> Unit, state: DoubleSpreadState, backgroundColor: Color, - reverseScrollDirection: Boolean, ) { Box( modifier = Modifier.fillMaxSize(), @@ -87,6 +88,7 @@ internal fun DoubleViewportSpread( state = webViewState, spreadScrollState = scrollState, progression = progression, + layoutDirection = layoutDirection, client = state.webViewClient, onTap = onTap, onLinkActivated = { url, outerHtml -> @@ -97,7 +99,6 @@ internal fun DoubleViewportSpread( }, backgroundColor = backgroundColor, onScriptsLoaded = { scriptsLoaded.value = true }, - reverseScrollDirection = reverseScrollDirection ) } } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/FixedPagingLayoutInfo.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/FixedPagingLayoutInfo.kt index 30bf1853d9..c6884862a1 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/FixedPagingLayoutInfo.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/FixedPagingLayoutInfo.kt @@ -10,6 +10,7 @@ import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.pager.PagerState import androidx.compose.ui.geometry.Offset import androidx.compose.ui.unit.Density +import androidx.compose.ui.unit.LayoutDirection import org.readium.navigator.web.pager.PageScrollState import org.readium.navigator.web.pager.PagingLayoutInfo @@ -17,6 +18,7 @@ internal class FixedPagingLayoutInfo( private val pagerState: PagerState, private val pageStates: List, override val orientation: Orientation, + private val direction: LayoutDirection, override val density: Density, ) : PagingLayoutInfo { @@ -30,21 +32,21 @@ internal class FixedPagingLayoutInfo( get() = Offset.Zero override val reverseLayout: Boolean get() = - false + direction == LayoutDirection.Rtl override val canScrollForward: Boolean get() = pagerState.layoutInfo.visiblePagesInfo.last() .let { pageInfo -> pageInfo.index < pagerState.pageCount - 1 || pageInfo.offset > 0 } || run { val lastResourceState = pageStates[pagerState.pageCount - 1] val scrollController = lastResourceState.scrollController.value ?: return false - return scrollController.canMoveRight + scrollController.canMoveForward(orientation, direction) } override val canScrollBackward: Boolean get() = pagerState.layoutInfo.visiblePagesInfo.first() .let { pageInfo -> pageInfo.index > 0 || pageInfo.offset < 0 } || run { val scrollController = pageStates[0].scrollController.value ?: return false - return scrollController.canMoveLeft + return scrollController.canMoveBackward(orientation, direction) } override val visiblePageOffsets: List diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SingleViewportSpread.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SingleViewportSpread.kt index 8f58a74d0c..b108a7212b 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SingleViewportSpread.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SingleViewportSpread.kt @@ -19,6 +19,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.LayoutDirection import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import org.readium.navigator.common.TapEvent @@ -38,11 +39,11 @@ internal fun SingleViewportSpread( pagerState: PagerState, scrollState: SpreadScrollState, progression: Double, + layoutDirection: LayoutDirection, onTap: (TapEvent) -> Unit, onLinkActivated: (Url, String) -> Unit, state: SingleSpreadState, backgroundColor: Color, - reverseScrollDirection: Boolean, ) { Box( modifier = Modifier.fillMaxSize(), @@ -99,7 +100,7 @@ internal fun SingleViewportSpread( }, backgroundColor = backgroundColor, onScriptsLoaded = { scriptsLoaded.value = true }, - reverseScrollDirection = reverseScrollDirection + layoutDirection = layoutDirection ) } } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt index a7f3fc8e70..4c2c4451d9 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt @@ -21,6 +21,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.unit.DpOffset +import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.zIndex import org.readium.navigator.common.TapEvent import org.readium.navigator.web.util.WebViewClient @@ -42,13 +43,13 @@ internal fun SpreadWebView( spreadIndex: Int, state: WebViewState, spreadScrollState: SpreadScrollState, + layoutDirection: LayoutDirection, progression: Double, client: WebViewClient, onScriptsLoaded: () -> Unit, onTap: (TapEvent) -> Unit, onLinkActivated: (AbsoluteUrl, String) -> Unit, backgroundColor: Color, - reverseScrollDirection: Boolean, ) { val contentIsLaidOut = remember { mutableStateOf(false) } @@ -64,7 +65,8 @@ internal fun SpreadWebView( scrollController.moveToProgression( progression = progression, snap = true, - orientation = Orientation.Horizontal + orientation = Orientation.Horizontal, + direction = layoutDirection ) spreadScrollState.scrollController.value = scrollController contentIsLaidOut.value = true diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/RenditionPager.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/RenditionPager.kt index 26afa8d106..51577d2e34 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/RenditionPager.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/RenditionPager.kt @@ -29,7 +29,6 @@ internal fun RenditionPager( scrollState: Scrollable2DState, flingBehavior: Fling2DBehavior, orientation: Orientation, - layoutDirection: LayoutDirection, enableScroll: Boolean = true, beyondViewportPageCount: Int, key: ((index: Int) -> Any)? = null, @@ -40,9 +39,8 @@ internal fun RenditionPager( enabled = enableScroll, state = scrollState, flingBehavior = flingBehavior, - reverseDirection = layoutDirection == LayoutDirection.Ltr || - orientation == Orientation.Vertical, - orientation = null + reverseDirection = orientation == Orientation.Vertical || + LocalLayoutDirection.current == LayoutDirection.Ltr ) // Disable built-in pager behavior as it is not suitable. @@ -60,7 +58,7 @@ internal fun RenditionPager( flingBehavior = flingBehavior, userScrollEnabled = userScrollEnabled, key = key, - reverseLayout = layoutDirection != LocalLayoutDirection.current, + reverseLayout = false, pageNestedScrollConnection = pageNestedScrollConnection, pageContent = pageContent ) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/RenditionScrollState.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/RenditionScrollState.kt index 3372dc25c5..0f4069c58f 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/RenditionScrollState.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/RenditionScrollState.kt @@ -16,11 +16,12 @@ import androidx.compose.runtime.MutableState import androidx.compose.runtime.State import androidx.compose.runtime.mutableStateOf import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.util.fastCoerceAtLeast -import androidx.compose.ui.util.fastCoerceAtMost +import androidx.compose.ui.unit.LayoutDirection +import androidx.compose.ui.util.fastCoerceIn import kotlinx.coroutines.coroutineScope import org.readium.navigator.web.gestures.Scroll2DScope import org.readium.navigator.web.gestures.Scrollable2DState +import org.readium.navigator.web.util.toLayoutDirection import org.readium.navigator.web.util.toOrientation import org.readium.navigator.web.webview.WebViewScrollController import org.readium.r2.navigator.OverflowableNavigator @@ -38,16 +39,23 @@ internal class RenditionScrollState( private val overflow: State, ) : Scrollable2DState { - private val pagerOrientation: Orientation get() = + private val orientation: Orientation get() = overflow.value.axis.toOrientation() + private val direction: LayoutDirection get() = + overflow.value.readingProgression.toLayoutDirection() + + private val reverseLayout get() = + orientation == Orientation.Horizontal && direction == LayoutDirection.Rtl + /* - * To favour natural reasoning, this function applies reverse scrolling: - * - a positive delta makes scrolling left - * - a negative delta makes scrolling right + * To ease the reasoning, this function applies reverse scrolling: + * - a positive delta (finger moved to the right) makes the viewport scrolling left + * - a negative delta (finger moved to the left) makes the viewport scrolling right */ - private fun rawScrollBy(available: Float): Float { + private fun dispatchRawDelta(available: Float): Float { Timber.d("scrollBy available $available") + Timber.d("visiblePages ${pagerState.layoutInfo.visiblePagesInfo.map { it.index to it.offset }}") var deltaLeft = available val firstPage = pagerState.layoutInfo.visiblePagesInfo.first() @@ -58,60 +66,57 @@ internal class RenditionScrollState( // Set the page that will become visible to the right scroll position. when { available > 0 -> { - val prevPage = (firstPage.index - 1).takeIf { it >= 0 } + val prevPage = pageOnTheLeftOrTop(firstPage.index) prevPage?.let { - val success = scrollWebviewToEdge(prevPage, end = true) + val success = scrollWebviewToEdge(prevPage, max = true) if (!success) return available } } else -> { - val nextPage = (firstPage.index + 1).takeIf { it < pageStates.size } + val nextPage = pageOnTheRightOrBottom(firstPage.index) nextPage?.let { - val success = scrollWebviewToEdge(nextPage, end = false) + val success = scrollWebviewToEdge(nextPage, max = false) if (!success) return available } } } } - val firstTargetPage = when { + var firstTargetPage = when { available >= 0 -> lastPage else -> firstPage } - val secondTargetPage = when { + var secondTargetPage = when { available >= 0 -> firstPage else -> lastPage } + if (reverseLayout) { + val temp = firstTargetPage + firstTargetPage = secondTargetPage + secondTargetPage = temp + } + val consumedInFirst = consumeInWebview(firstTargetPage.index, deltaLeft) deltaLeft -= consumedInFirst Timber.d("consumed $consumedInFirst in ${firstTargetPage.index}") - val availableForPager = - if (firstPage.index == lastPage.index) { - when { - deltaLeft > 0 -> - deltaLeft.fastCoerceAtMost(pagerState.layoutInfo.pageSize.toFloat()) - deltaLeft < 0 -> - deltaLeft.coerceAtLeast(-pagerState.layoutInfo.pageSize.toFloat()) - else -> - 0f - } - } else { - when { - deltaLeft > 0 -> { - deltaLeft.fastCoerceAtMost(-firstPage.offset.toFloat()) - } - deltaLeft < 0 -> { - deltaLeft.fastCoerceAtLeast(-lastPage.offset.toFloat()) - } - else -> - 0f - } - } + val pageSize = pagerState.layoutInfo.pageSize.toFloat() + + val availableForPager = when { + firstPage.index == lastPage.index -> + deltaLeft.fastCoerceIn(-pageSize, pageSize) + reverseLayout -> + deltaLeft.fastCoerceIn(firstPage.offset.toFloat(), lastPage.offset.toFloat()) + else -> + deltaLeft.fastCoerceIn(-lastPage.offset.toFloat(), -firstPage.offset.toFloat()) + } + + val consumedInPager = pagerState.dispatchRawDelta( + delta = availableForPager.reverseIfNeeded(reverseLayout) + ).reverseIfNeeded(reverseLayout) - val consumedInPager = -pagerState.dispatchRawDelta(-availableForPager) deltaLeft -= consumedInPager Timber.d("consumed $consumedInPager in pager") @@ -124,18 +129,19 @@ internal class RenditionScrollState( return when (deltaLeft) { 0f -> available available -> 0f - else -> rawScrollBy(deltaLeft) + else -> dispatchRawDelta(deltaLeft) } } - private fun scrollWebviewToEdge(targetPage: Int, end: Boolean): Boolean { + private fun scrollWebviewToEdge(targetPage: Int, max: Boolean): Boolean { val scrollController = pageStates[targetPage].scrollController.value ?: return false - scrollController.moveToProgression( - progression = if (end) 1.0 else 0.0, - snap = false, - orientation = pagerOrientation - ) + Timber.d("scrolling to edge $targetPage max = $max $orientation $direction") + if (max) { + scrollController.scrollToMax(orientation) + } else { + scrollController.scrollToMin(orientation) + } return true } @@ -146,29 +152,49 @@ internal class RenditionScrollState( return -scrollController.scrollBy(-available.mainAxisOffset).mainAxisValue } + private fun pageOnTheLeftOrTop(index: Int): Int? = + if (reverseLayout) { + (index + 1).takeIf { it < pageStates.size } + } else { + (index - 1).takeIf { it >= 0 } + } + + private fun pageOnTheRightOrBottom(index: Int): Int? = + if (reverseLayout) { + (index - 1).takeIf { it >= 0 } + } else { + (index + 1).takeIf { it < pageStates.size } + } + + private fun Float.reverseIfNeeded(reverseLayout: Boolean): Float = + if (reverseLayout) this else -this + fun onDocumentResized(index: Int) { val firstPage = pagerState.layoutInfo.visiblePagesInfo.first() val lastPage = pagerState.layoutInfo.visiblePagesInfo.last() - if (firstPage == lastPage || firstPage.index != index) { + if (firstPage == lastPage || + firstPage.index != index && direction == LayoutDirection.Ltr || + lastPage.index != index && direction == LayoutDirection.Rtl + ) { return } val scrollController = pageStates[index].scrollController.value!! - val scrolled = scrollController.scrollToEnd(pagerOrientation) + val scrolled = scrollController.scrollToMax(orientation) if (scrolled > 0) { - rawScrollBy(scrolled.toFloat()) + dispatchRawDelta(scrolled.toFloat()) } } - private val Offset.mainAxisValue: Float get() = when (pagerOrientation) { + private val Offset.mainAxisValue: Float get() = when (orientation) { Orientation.Vertical -> y Orientation.Horizontal -> x } private val Float.mainAxisOffset: Offset - get() = when (pagerOrientation) { + get() = when (orientation) { Orientation.Vertical -> Offset(0f, this) Orientation.Horizontal -> Offset(this, 0f) } @@ -180,8 +206,9 @@ internal class RenditionScrollState( y = if (pixels.y.isNaN()) 0f else pixels.y ) if (coercedPixels == Offset.Zero) return Offset.Zero - val delta = -rawScrollBy(-coercedPixels.mainAxisValue).mainAxisOffset - return delta + val delta = coercedPixels.mainAxisValue.reverseIfNeeded(reverseLayout) + val consumed = dispatchRawDelta(delta).reverseIfNeeded(reverseLayout).mainAxisOffset + return consumed } } @@ -206,7 +233,7 @@ internal class RenditionScrollState( } override fun dispatchRawDelta(delta: Offset): Offset { - return -rawScrollBy(-delta.mainAxisValue).mainAxisOffset + return dispatchRawDelta(delta.mainAxisValue).mainAxisOffset } override val isScrollInProgress: Boolean diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowablePagingLayoutInfo.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowablePagingLayoutInfo.kt index 6947e9b457..6f3a6d08ed 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowablePagingLayoutInfo.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowablePagingLayoutInfo.kt @@ -10,17 +10,18 @@ import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.pager.PagerState import androidx.compose.ui.geometry.Offset import androidx.compose.ui.unit.Density +import androidx.compose.ui.unit.LayoutDirection import org.readium.navigator.web.pager.PagingLayoutInfo import timber.log.Timber internal class ReflowablePagingLayoutInfo( private val pagerState: PagerState, - private val resourceStates: List, + private val pageStates: List, + private val direction: LayoutDirection, override val density: Density, ) : PagingLayoutInfo { - override val orientation: Orientation = - Orientation.Horizontal + override val orientation: Orientation = Orientation.Horizontal override val pageSize: Int get() = pagerState.layoutInfo.pageSize @@ -32,21 +33,21 @@ internal class ReflowablePagingLayoutInfo( get() = Offset.Zero override val reverseLayout: Boolean get() = - false + direction == LayoutDirection.Rtl && orientation == Orientation.Horizontal override val canScrollForward: Boolean get() = pagerState.layoutInfo.visiblePagesInfo.last() .let { pageInfo -> pageInfo.index < pagerState.pageCount - 1 || pageInfo.offset > 0 } || run { - val lastResourceState = resourceStates[pagerState.pageCount - 1] + val lastResourceState = pageStates[pagerState.pageCount - 1] val scrollController = lastResourceState.scrollController.value ?: return false - return scrollController.canMoveRight + return scrollController.canMoveForward(orientation, direction) } override val canScrollBackward: Boolean get() = pagerState.layoutInfo.visiblePagesInfo.first() .let { pageInfo -> pageInfo.index > 0 || pageInfo.offset < 0 } || run { - val scrollController = resourceStates[0].scrollController.value ?: return false - return scrollController.canMoveLeft + val scrollController = pageStates[0].scrollController.value ?: return false + return scrollController.canMoveBackward(orientation, direction) } override val visiblePageOffsets: List @@ -54,8 +55,8 @@ internal class ReflowablePagingLayoutInfo( val pagerVisible = pagerState.layoutInfo.visiblePagesInfo .map { it.index to it.offset } val webViewVisible = pagerVisible.map { - resourceStates[it.first].scrollController.value?.scrollX to - resourceStates[it.first].scrollController.value?.maxScrollX + pageStates[it.first].scrollController.value?.scrollX to + pageStates[it.first].scrollController.value?.maxScrollX } Timber.d("pager $pagerVisible webview $webViewVisible") @@ -65,18 +66,30 @@ internal class ReflowablePagingLayoutInfo( if (firstPage.index == lastPage.index) { val index = firstPage.index - val scrollController = resourceStates[index].scrollController.value!! - add(-scrollController.scrollX % pageSize) - add(-scrollController.scrollX % pageSize + pageSize) - Timber.d("visiblePageOffsets if $this") + val scrollController = pageStates[index].scrollController.value!! + if (direction == LayoutDirection.Ltr) { + add(-scrollController.scrollX % pageSize) + add(-scrollController.scrollX % pageSize + pageSize) + } else { + add(scrollController.scrollX % pageSize - pageSize) + add(scrollController.scrollX % pageSize) + } + Timber.d("visiblePageOffsets if $this pageSize $pageSize") } else { - val firstScrollController = resourceStates[firstPage.index].scrollController.value!! - val lastScrollController = resourceStates[lastPage.index].scrollController.value!! - // To get to the left bound, we first need to scroll the last visible page to zero. - add(lastPage.offset - pageSize - lastScrollController.scrollX) - // To get to the right bound, we first need to scroll the first visible page - // as far as possible. - add(lastPage.offset + firstScrollController.maxScrollX - firstScrollController.scrollX) + val firstScrollController = pageStates[firstPage.index].scrollController.value!! + val lastScrollController = pageStates[lastPage.index].scrollController.value!! + if (direction == LayoutDirection.Ltr) { + // To get to the left bound, we first need to scroll the last visible page to zero. + add(lastPage.offset - pageSize - lastScrollController.scrollX) + // To get to the right bound, we first need to scroll the first visible page + // as far as possible. + add(lastPage.offset + firstScrollController.maxScrollX - firstScrollController.scrollX) + } else { + // To get to the right bound, we first need to scroll the last visible page as far as possible. + add(lastPage.offset - pageSize + lastScrollController.maxScrollX - lastScrollController.scrollX) + // To get to the left bound, we first need to scroll the first visible page to zero. + add(lastPage.offset - firstScrollController.scrollX) + } Timber.d("visiblePageOffsets else $this") } } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt index 9a6ad60369..cef4822bdd 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt @@ -72,6 +72,9 @@ internal fun ReflowableResource( val orientationState = rememberUpdatedState(orientation) + val directionState = + rememberUpdatedState(layoutDirection) + val scriptsLoaded = remember(webViewState.webView) { mutableStateOf(false) } @@ -91,11 +94,14 @@ internal fun ReflowableResource( scrollController.moveToProgression( progression = resourceState.progression, snap = !scroll, - orientation = orientationState.value + orientation = orientationState.value, + direction = layoutDirection ) resourceState.scrollController.value = scrollController setOnScrollChangeListener { view, scrollX, scrollY, oldScrollX, oldScrollY -> - onProgressionChange(scrollController.progression(orientationState.value)) + onProgressionChange( + scrollController.progression(orientationState.value, directionState.value) + ) } contentIsLaidOut.value = true } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollController.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollController.kt index 925d760d2b..7d94ec4bbb 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollController.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollController.kt @@ -8,11 +8,11 @@ package org.readium.navigator.web.webview import androidx.compose.foundation.gestures.Orientation import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.util.fastCoerceAtLeast import androidx.compose.ui.util.fastCoerceAtMost import androidx.compose.ui.util.fastRoundToInt -import kotlin.math.ceil -import kotlin.math.floor +import kotlin.math.roundToInt import org.readium.navigator.web.gestures.DefaultScrollable2DState import org.readium.navigator.web.gestures.Scrollable2DState @@ -63,8 +63,24 @@ internal class WebViewScrollController( return webView.scrollBy(delta) } - fun scrollToEnd(scrollOrientation: Orientation): Int { - return when (scrollOrientation) { + fun scrollToMin(orientation: Orientation): Int { + return when (orientation) { + Orientation.Vertical -> { + val delta = -scrollY + webView.scrollBy(0, delta) + delta + } + + Orientation.Horizontal -> { + val delta = -scrollX + webView.scrollBy(delta, 0) + delta + } + } + } + + fun scrollToMax(orientation: Orientation): Int { + return when (orientation) { Orientation.Vertical -> { val delta = webView.maxScrollY - scrollY webView.scrollBy(0, delta) @@ -78,17 +94,19 @@ internal class WebViewScrollController( } } - fun progression(scrollOrientation: Orientation) = - webView.progression(scrollOrientation) + fun progression(orientation: Orientation, direction: LayoutDirection) = + webView.progression(orientation, direction) fun moveToProgression( progression: Double, snap: Boolean, orientation: Orientation, + direction: LayoutDirection, ) { webView.scrollToProgression( progression = progression, - scrollOrientation = orientation + orientation = orientation, + direction = direction ) if (snap) { when (orientation) { @@ -103,19 +121,73 @@ internal class WebViewScrollController( } } } + + fun moveForward(orientation: Orientation, direction: LayoutDirection) = + when (orientation) { + Orientation.Vertical -> moveBottom() + Orientation.Horizontal -> when (direction) { + LayoutDirection.Ltr -> moveRight() + LayoutDirection.Rtl -> moveLeft() + } + } + + fun moveBackward(orientation: Orientation, direction: LayoutDirection) = + when (orientation) { + Orientation.Vertical -> moveTop() + Orientation.Horizontal -> when (direction) { + LayoutDirection.Ltr -> moveLeft() + LayoutDirection.Rtl -> moveRight() + } + } + + fun canMoveForward(orientation: Orientation, direction: LayoutDirection): Boolean = + when (orientation) { + Orientation.Vertical -> canMoveBottom + Orientation.Horizontal -> when (direction) { + LayoutDirection.Ltr -> canMoveRight + LayoutDirection.Rtl -> canMoveLeft + } + } + + fun canMoveBackward(orientation: Orientation, direction: LayoutDirection): Boolean = + when (orientation) { + Orientation.Vertical -> canMoveTop + Orientation.Horizontal -> when (direction) { + LayoutDirection.Ltr -> canMoveLeft + LayoutDirection.Rtl -> canMoveRight + } + } } -private fun RelaxedWebView.scrollToProgression(progression: Double, scrollOrientation: Orientation) { - if (scrollOrientation == Orientation.Horizontal) { - scrollTo(floor(progression * maxScrollX).toInt(), scrollY) - } else { - scrollTo(scrollX, ceil(progression * maxScrollY).toInt()) +private fun RelaxedWebView.scrollToProgression( + progression: Double, + orientation: Orientation, + direction: LayoutDirection, +) { + when (orientation) { + Orientation.Vertical -> { + scrollTo(scrollX, progression.roundToInt() * maxScrollY.toInt()) + } + Orientation.Horizontal -> when (direction) { + LayoutDirection.Ltr -> { + scrollTo(progression.roundToInt() * maxScrollX, scrollY) + } + LayoutDirection.Rtl -> { + scrollTo((1 - progression).roundToInt() * maxScrollX, scrollY) + } + } } } -private fun RelaxedWebView.progression(orientation: Orientation) = when (orientation) { +private fun RelaxedWebView.progression( + orientation: Orientation, + direction: LayoutDirection, +) = when (orientation) { Orientation.Vertical -> scrollY / maxScrollY.toDouble() - Orientation.Horizontal -> scrollX / maxScrollX.toDouble() + Orientation.Horizontal -> when (direction) { + LayoutDirection.Ltr -> scrollX / maxScrollX.toDouble() + LayoutDirection.Rtl -> 1 - scrollX / maxScrollX.toDouble() + } } private fun RelaxedWebView.scrollBy(delta: Offset): Offset { From 2b8d47b8e817041e17d85710c8bde8da601354a2 Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Fri, 2 May 2025 12:28:43 +0200 Subject: [PATCH 52/88] Refactoring + fix thread safety in webapis --- .../src/index-reflowable-injectable.ts | 20 ++-- .../generated/reflowable-injectable-script.js | 2 +- .../reflowable-injectable-script.js.map | 2 +- .../navigator/web/FixedWebRendition.kt | 20 ++-- .../navigator/web/FixedWebRenditionState.kt | 7 -- .../navigator/web/ReflowableWebRendition.kt | 25 +++-- .../navigator/web/fixed/SpreadWebView.kt | 63 ++++++------ .../web/pager/RenditionScrollState.kt | 2 + .../reflowable/ReflowablePagingLayoutInfo.kt | 6 +- .../web/reflowable/ReflowableResource.kt | 99 ++++++++++--------- .../navigator/web/webapi/DocumentStateApi.kt | 20 +++- .../navigator/web/webapi/GesturesApi.kt | 20 +++- .../web/webview/WebViewScrollController.kt | 3 + 13 files changed, 164 insertions(+), 125 deletions(-) diff --git a/readium/navigators/web/scripts/src/index-reflowable-injectable.ts b/readium/navigators/web/scripts/src/index-reflowable-injectable.ts index 677baeee65..8efec31e77 100644 --- a/readium/navigators/web/scripts/src/index-reflowable-injectable.ts +++ b/readium/navigators/web/scripts/src/index-reflowable-injectable.ts @@ -43,14 +43,18 @@ window.addEventListener("load", (event) => { return } - const scrollingElement = window.document.scrollingElement - - if ( - !documentLoadedFired && - (scrollingElement == null || - scrollingElement.scrollHeight > 0 || - scrollingElement.scrollWidth > 0) - ) { + if (!documentLoadedFired) { + const scrollingElement = window.document.scrollingElement + + if ( + scrollingElement != null && + scrollingElement.scrollHeight == 0 && + scrollingElement.scrollWidth == 0 + ) { + // Document is not sized yet + return + } + window.documentState.onDocumentLoadedAndSized() documentLoadedFired = true } else { diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js index 5e4917e958..df2e9c5ab5 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js @@ -1,2 +1,2 @@ -!function(){"use strict";const e=new class{constructor(e){this.gesturesBridge=e}onTap(e){const t={x:(e.clientX-visualViewport.offsetLeft)*visualViewport.scale,y:(e.clientY-visualViewport.offsetTop)*visualViewport.scale},n=JSON.stringify(t);this.gesturesBridge.onTap(n)}onLinkActivated(e,t){this.gesturesBridge.onLinkActivated(e,t)}}(window.gestures);new class{constructor(e,t){this.window=e,this.listener=t,document.addEventListener("click",(e=>{this.onClick(e)}),!1)}onClick(e){if(e.defaultPrevented)return;const t=this.window.getSelection();if(t&&"Range"==t.type)return;let n;n=e.target instanceof HTMLElement?this.nearestInteractiveElement(e.target):null,n?n instanceof HTMLAnchorElement&&this.listener.onLinkActivated(n.href,n.outerHTML):this.listener.onTap(e),e.stopPropagation(),e.preventDefault()}nearestInteractiveElement(e){return null==e?null:-1!=["a","audio","button","canvas","details","input","label","option","select","submit","textarea","video"].indexOf(e.nodeName.toLowerCase())||e.hasAttribute("contenteditable")&&"false"!=e.getAttribute("contenteditable").toLowerCase()?e:e.parentElement?this.nearestInteractiveElement(e.parentElement):null}}(window,e),Window.prototype.readiumcss=new class{constructor(e){this.document=e}setProperties(e){for(const[t,n]of e)this.setProperty(t,n)}setProperty(e,t){null===t||""===t?this.removeProperty(e):document.documentElement.style.setProperty(e,t,"important")}removeProperty(e){document.documentElement.style.removeProperty(e)}}(window.document),window.documentState.onScriptsLoaded(),window.addEventListener("load",(e=>{let t=!1;new ResizeObserver((()=>{requestAnimationFrame((()=>{if(function(e){const t="readium-virtual-page";let n=e.document.getElementById(t);if(2!==function(e){return parseInt(e.getComputedStyle(e.document.documentElement).getPropertyValue("column-count"))}(e))return!!n&&(n.remove(),!0);{const o=e.document.scrollingElement.scrollWidth/e.innerWidth;return!!(Math.round(2*o)/2%1>.1)&&(n?n.remove():(n=e.document.createElement("div"),n.setAttribute("id",t),n.dataset.readium="true",n.style.breakBefore="column",n.innerHTML="​",e.document.body.appendChild(n)),!0)}}(window))return;const e=window.document.scrollingElement;!t&&(null==e||e.scrollHeight>0||e.scrollWidth>0)?(window.documentState.onDocumentLoadedAndSized(),t=!0):window.documentState.onDocumentResized()}))})).observe(document.body)}))}(); +!function(){"use strict";const e=new class{constructor(e){this.gesturesBridge=e}onTap(e){const t={x:(e.clientX-visualViewport.offsetLeft)*visualViewport.scale,y:(e.clientY-visualViewport.offsetTop)*visualViewport.scale},n=JSON.stringify(t);this.gesturesBridge.onTap(n)}onLinkActivated(e,t){this.gesturesBridge.onLinkActivated(e,t)}}(window.gestures);new class{constructor(e,t){this.window=e,this.listener=t,document.addEventListener("click",(e=>{this.onClick(e)}),!1)}onClick(e){if(e.defaultPrevented)return;const t=this.window.getSelection();if(t&&"Range"==t.type)return;let n;n=e.target instanceof HTMLElement?this.nearestInteractiveElement(e.target):null,n?n instanceof HTMLAnchorElement&&this.listener.onLinkActivated(n.href,n.outerHTML):this.listener.onTap(e),e.stopPropagation(),e.preventDefault()}nearestInteractiveElement(e){return null==e?null:-1!=["a","audio","button","canvas","details","input","label","option","select","submit","textarea","video"].indexOf(e.nodeName.toLowerCase())||e.hasAttribute("contenteditable")&&"false"!=e.getAttribute("contenteditable").toLowerCase()?e:e.parentElement?this.nearestInteractiveElement(e.parentElement):null}}(window,e),Window.prototype.readiumcss=new class{constructor(e){this.document=e}setProperties(e){for(const[t,n]of e)this.setProperty(t,n)}setProperty(e,t){null===t||""===t?this.removeProperty(e):document.documentElement.style.setProperty(e,t,"important")}removeProperty(e){document.documentElement.style.removeProperty(e)}}(window.document),window.documentState.onScriptsLoaded(),window.addEventListener("load",(e=>{let t=!1;new ResizeObserver((()=>{requestAnimationFrame((()=>{if(!function(e){const t="readium-virtual-page";let n=e.document.getElementById(t);if(2!==function(e){return parseInt(e.getComputedStyle(e.document.documentElement).getPropertyValue("column-count"))}(e))return!!n&&(n.remove(),!0);{const o=e.document.scrollingElement.scrollWidth/e.innerWidth;return!!(Math.round(2*o)/2%1>.1)&&(n?n.remove():(n=e.document.createElement("div"),n.setAttribute("id",t),n.dataset.readium="true",n.style.breakBefore="column",n.innerHTML="​",e.document.body.appendChild(n)),!0)}}(window))if(t)window.documentState.onDocumentResized();else{const e=window.document.scrollingElement;if(null!=e&&0==e.scrollHeight&&0==e.scrollWidth)return;window.documentState.onDocumentLoadedAndSized(),t=!0}}))})).observe(document.body)}))}(); //# sourceMappingURL=reflowable-injectable-script.js.map \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map index 0d00777097..2bca1b35a7 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js.map @@ -1 +1 @@ -{"version":3,"file":"reflowable-injectable-script.js","mappings":"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","sources":["webpack://readium-js/./src/index-reflowable-injectable.ts","webpack://readium-js/./src/bridge/all-listener-bridge.ts","webpack://readium-js/./src/common/gestures.ts","webpack://readium-js/./src/bridge/reflowable-css-bridge.ts","webpack://readium-js/./src/util/columns.ts"],"sourcesContent":["//\n// Copyright 2024 Readium Foundation. All rights reserved.\n// Use of this source code is governed by the BSD-style license\n// available in the top-level LICENSE file of the project.\n//\n/**\n * Script loaded by reflowable resources.\n */\nimport { ReflowableListenerAdapter, } from \"./bridge/all-listener-bridge\";\nimport { CssBridge } from \"./bridge/reflowable-css-bridge\";\nimport { GesturesDetector } from \"./common/gestures\";\nimport { appendVirtualColumnIfNeeded } from \"./util/columns\";\nconst bridgeListener = new ReflowableListenerAdapter(window.gestures);\nnew GesturesDetector(window, bridgeListener);\nWindow.prototype.readiumcss = new CssBridge(window.document);\nwindow.documentState.onScriptsLoaded();\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nwindow.addEventListener(\"load\", (event) => {\n let documentLoadedFired = false;\n const observer = new ResizeObserver(() => {\n requestAnimationFrame(() => {\n if (appendVirtualColumnIfNeeded(window)) {\n // Column has been added or removed, wait for next resize callback.\n return;\n }\n const scrollingElement = window.document.scrollingElement;\n if (!documentLoadedFired &&\n (scrollingElement == null ||\n scrollingElement.scrollHeight > 0 ||\n scrollingElement.scrollWidth > 0)) {\n window.documentState.onDocumentLoadedAndSized();\n documentLoadedFired = true;\n }\n else {\n window.documentState.onDocumentResized();\n }\n });\n });\n observer.observe(document.body);\n});\n","export class ReflowableListenerAdapter {\n constructor(gesturesBridge) {\n this.gesturesBridge = gesturesBridge;\n }\n onTap(event) {\n const tapEvent = {\n x: (event.clientX - visualViewport.offsetLeft) * visualViewport.scale,\n y: (event.clientY - visualViewport.offsetTop) * visualViewport.scale,\n };\n const stringEvent = JSON.stringify(tapEvent);\n this.gesturesBridge.onTap(stringEvent);\n }\n onLinkActivated(href, outerHtml) {\n this.gesturesBridge.onLinkActivated(href, outerHtml);\n }\n}\nexport class FixedListenerAdapter {\n constructor(window, gesturesApi, documentApi) {\n this.window = window;\n this.gesturesApi = gesturesApi;\n this.documentApi = documentApi;\n this.resizeObserverAdded = false;\n this.documentLoadedFired = false;\n }\n onTap(event) {\n this.gesturesApi.onTap(JSON.stringify(event));\n }\n onLinkActivated(href, outerHtml) {\n this.gesturesApi.onLinkActivated(href, outerHtml);\n }\n onLayout() {\n if (!this.resizeObserverAdded) {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const observer = new ResizeObserver(() => {\n requestAnimationFrame(() => {\n const scrollingElement = this.window.document.scrollingElement;\n if (!this.documentLoadedFired &&\n (scrollingElement == null ||\n scrollingElement.scrollHeight > 0 ||\n scrollingElement.scrollWidth > 0)) {\n this.documentApi.onDocumentLoadedAndSized();\n this.documentLoadedFired = true;\n }\n else {\n this.documentApi.onDocumentResized();\n }\n });\n });\n observer.observe(this.window.document.body);\n }\n this.resizeObserverAdded = true;\n }\n}\n","export class GesturesDetector {\n constructor(window, listener) {\n this.window = window;\n this.listener = listener;\n document.addEventListener(\"click\", (event) => {\n this.onClick(event);\n }, false);\n }\n onClick(event) {\n if (event.defaultPrevented) {\n return;\n }\n const selection = this.window.getSelection();\n if (selection && selection.type == \"Range\") {\n // There's an on-going selection, the tap will dismiss it so we don't forward it.\n // selection.type might be None (collapsed) or Caret with a collapsed range\n // when there is not true selection.\n return;\n }\n let nearestElement;\n if (event.target instanceof HTMLElement) {\n nearestElement = this.nearestInteractiveElement(event.target);\n }\n else {\n nearestElement = null;\n }\n if (nearestElement) {\n if (nearestElement instanceof HTMLAnchorElement) {\n this.listener.onLinkActivated(nearestElement.href, nearestElement.outerHTML);\n }\n }\n else {\n this.listener.onTap(event);\n }\n event.stopPropagation();\n event.preventDefault();\n }\n // See. https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling\n nearestInteractiveElement(element) {\n if (element == null) {\n return null;\n }\n const interactiveTags = [\n \"a\",\n \"audio\",\n \"button\",\n \"canvas\",\n \"details\",\n \"input\",\n \"label\",\n \"option\",\n \"select\",\n \"submit\",\n \"textarea\",\n \"video\",\n ];\n if (interactiveTags.indexOf(element.nodeName.toLowerCase()) != -1) {\n return element;\n }\n // Checks whether the element is editable by the user.\n if (element.hasAttribute(\"contenteditable\") &&\n element.getAttribute(\"contenteditable\").toLowerCase() != \"false\") {\n return element;\n }\n // Checks parents recursively because the touch might be for example on an inside a .\n if (element.parentElement) {\n return this.nearestInteractiveElement(element.parentElement);\n }\n return null;\n }\n}\n","export class CssBridge {\n constructor(document) {\n this.document = document;\n }\n setProperties(properties) {\n for (const [key, value] of properties) {\n this.setProperty(key, value);\n }\n }\n // For setting user setting.\n setProperty(key, value) {\n if (value === null || value === \"\") {\n this.removeProperty(key);\n }\n else {\n const root = document.documentElement;\n // The `!important` annotation is added with `setProperty()` because if it's part of the\n // `value`, it will be ignored by the Web View.\n root.style.setProperty(key, value, \"important\");\n }\n }\n // For removing user setting.\n removeProperty(key) {\n const root = document.documentElement;\n root.style.removeProperty(key);\n }\n}\n","/**\n * In paginated mode, the width of each resource must be a multiple of the viewport size\n * for proper snapping. This may not be automatically the case if the number of\n * columns in the resource is not a multiple of the number of columns fitting in the viewport.\n * To fix this, we insert a blank virtual column at the end of the resource.\n *\n * Returns if a virtual column has been added or removed.\n */\nexport function appendVirtualColumnIfNeeded(wnd) {\n // FIXME: what about scroll mode?\n const id = \"readium-virtual-page\";\n let virtualCol = wnd.document.getElementById(id);\n if (getColumnCountPerScreen(wnd) !== 2) {\n if (virtualCol) {\n virtualCol.remove();\n return true;\n }\n else {\n return false;\n }\n }\n else {\n const documentWidth = wnd.document.scrollingElement.scrollWidth;\n const colCount = documentWidth / wnd.innerWidth;\n const hasOddColCount = (Math.round(colCount * 2) / 2) % 1 > 0.1;\n if (hasOddColCount) {\n if (virtualCol) {\n virtualCol.remove();\n }\n else {\n virtualCol = wnd.document.createElement(\"div\");\n virtualCol.setAttribute(\"id\", id);\n virtualCol.dataset.readium = \"true\";\n virtualCol.style.breakBefore = \"column\";\n virtualCol.innerHTML = \"​\"; // zero-width space\n wnd.document.body.appendChild(virtualCol);\n }\n return true;\n }\n else {\n return false;\n }\n }\n}\nfunction getColumnCountPerScreen(wnd) {\n return parseInt(wnd\n .getComputedStyle(wnd.document.documentElement)\n .getPropertyValue(\"column-count\"));\n}\n"],"names":["bridgeListener","constructor","gesturesBridge","this","onTap","event","tapEvent","x","clientX","visualViewport","offsetLeft","scale","y","clientY","offsetTop","stringEvent","JSON","stringify","onLinkActivated","href","outerHtml","window","gestures","listener","document","addEventListener","onClick","defaultPrevented","selection","getSelection","type","nearestElement","target","HTMLElement","nearestInteractiveElement","HTMLAnchorElement","outerHTML","stopPropagation","preventDefault","element","indexOf","nodeName","toLowerCase","hasAttribute","getAttribute","parentElement","Window","prototype","readiumcss","setProperties","properties","key","value","setProperty","removeProperty","documentElement","style","documentState","onScriptsLoaded","documentLoadedFired","ResizeObserver","requestAnimationFrame","wnd","id","virtualCol","getElementById","parseInt","getComputedStyle","getPropertyValue","getColumnCountPerScreen","remove","colCount","scrollingElement","scrollWidth","innerWidth","Math","round","createElement","setAttribute","dataset","readium","breakBefore","innerHTML","body","appendChild","appendVirtualColumnIfNeeded","scrollHeight","onDocumentLoadedAndSized","onDocumentResized","observe"],"sourceRoot":""} \ No newline at end of file +{"version":3,"file":"reflowable-injectable-script.js","mappings":"yBAYA,MAAMA,EAAiB,ICZhB,MACH,WAAAC,CAAYC,GACRC,KAAKD,eAAiBA,CAC1B,CACA,KAAAE,CAAMC,GACF,MAAMC,EAAW,CACbC,GAAIF,EAAMG,QAAUC,eAAeC,YAAcD,eAAeE,MAChEC,GAAIP,EAAMQ,QAAUJ,eAAeK,WAAaL,eAAeE,OAE7DI,EAAcC,KAAKC,UAAUX,GACnCH,KAAKD,eAAeE,MAAMW,EAC9B,CACA,eAAAG,CAAgBC,EAAMC,GAClBjB,KAAKD,eAAegB,gBAAgBC,EAAMC,EAC9C,GDFiDC,OAAOC,UAC5D,IEbO,MACH,WAAArB,CAAYoB,EAAQE,GAChBpB,KAAKkB,OAASA,EACdlB,KAAKoB,SAAWA,EAChBC,SAASC,iBAAiB,SAAUpB,IAChCF,KAAKuB,QAAQrB,EAAM,IACpB,EACP,CACA,OAAAqB,CAAQrB,GACJ,GAAIA,EAAMsB,iBACN,OAEJ,MAAMC,EAAYzB,KAAKkB,OAAOQ,eAC9B,GAAID,GAA+B,SAAlBA,EAAUE,KAIvB,OAEJ,IAAIC,EAEAA,EADA1B,EAAM2B,kBAAkBC,YACP9B,KAAK+B,0BAA0B7B,EAAM2B,QAGrC,KAEjBD,EACIA,aAA0BI,mBAC1BhC,KAAKoB,SAASL,gBAAgBa,EAAeZ,KAAMY,EAAeK,WAItEjC,KAAKoB,SAASnB,MAAMC,GAExBA,EAAMgC,kBACNhC,EAAMiC,gBACV,CAEA,yBAAAJ,CAA0BK,GACtB,OAAe,MAAXA,EACO,MAgBqD,GAdxC,CACpB,IACA,QACA,SACA,SACA,UACA,QACA,QACA,SACA,SACA,SACA,WACA,SAEgBC,QAAQD,EAAQE,SAASC,gBAIzCH,EAAQI,aAAa,oBACoC,SAAzDJ,EAAQK,aAAa,mBAAmBF,cAJjCH,EAQPA,EAAQM,cACD1C,KAAK+B,0BAA0BK,EAAQM,eAE3C,IACX,GFxDiBxB,OAAQrB,GAC7B8C,OAAOC,UAAUC,WAAa,IGdvB,MACH,WAAA/C,CAAYuB,GACRrB,KAAKqB,SAAWA,CACpB,CACA,aAAAyB,CAAcC,GACV,IAAK,MAAOC,EAAKC,KAAUF,EACvB/C,KAAKkD,YAAYF,EAAKC,EAE9B,CAEA,WAAAC,CAAYF,EAAKC,GACC,OAAVA,GAA4B,KAAVA,EAClBjD,KAAKmD,eAAeH,GAGP3B,SAAS+B,gBAGjBC,MAAMH,YAAYF,EAAKC,EAAO,YAE3C,CAEA,cAAAE,CAAeH,GACE3B,SAAS+B,gBACjBC,MAAMF,eAAeH,EAC9B,GHXwC9B,OAAOG,UACnDH,OAAOoC,cAAcC,kBAErBrC,OAAOI,iBAAiB,QAASpB,IAC7B,IAAIsD,GAAsB,EACT,IAAIC,gBAAe,KAChCC,uBAAsB,KAClB,IIbL,SAAqCC,GAExC,MAAMC,EAAK,uBACX,IAAIC,EAAaF,EAAItC,SAASyC,eAAeF,GAC7C,GAAqC,IAgCzC,SAAiCD,GAC7B,OAAOI,SAASJ,EACXK,iBAAiBL,EAAItC,SAAS+B,iBAC9Ba,iBAAiB,gBAC1B,CApCQC,CAAwBP,GACxB,QAAIE,IACAA,EAAWM,UACJ,GAMV,CACD,MACMC,EADgBT,EAAItC,SAASgD,iBAAiBC,YACnBX,EAAIY,WAErC,SADwBC,KAAKC,MAAiB,EAAXL,GAAgB,EAAK,EAAI,MAEpDP,EACAA,EAAWM,UAGXN,EAAaF,EAAItC,SAASqD,cAAc,OACxCb,EAAWc,aAAa,KAAMf,GAC9BC,EAAWe,QAAQC,QAAU,OAC7BhB,EAAWR,MAAMyB,YAAc,SAC/BjB,EAAWkB,UAAY,UACvBpB,EAAItC,SAAS2D,KAAKC,YAAYpB,KAE3B,EAKf,CACJ,CJtBgBqB,CAA4BhE,QAIhC,GAAKsC,EAYDtC,OAAOoC,cAAc6B,wBAZC,CACtB,MAAMd,EAAmBnD,OAAOG,SAASgD,iBACzC,GAAwB,MAApBA,GACiC,GAAjCA,EAAiBe,cACe,GAAhCf,EAAiBC,YAEjB,OAEJpD,OAAOoC,cAAc+B,2BACrB7B,GAAsB,CAC1B,CAGA,GACF,IAEG8B,QAAQjE,SAAS2D,KAAK,G","sources":["webpack://readium-js/./src/index-reflowable-injectable.ts","webpack://readium-js/./src/bridge/all-listener-bridge.ts","webpack://readium-js/./src/common/gestures.ts","webpack://readium-js/./src/bridge/reflowable-css-bridge.ts","webpack://readium-js/./src/util/columns.ts"],"sourcesContent":["//\n// Copyright 2024 Readium Foundation. All rights reserved.\n// Use of this source code is governed by the BSD-style license\n// available in the top-level LICENSE file of the project.\n//\n/**\n * Script loaded by reflowable resources.\n */\nimport { ReflowableListenerAdapter, } from \"./bridge/all-listener-bridge\";\nimport { CssBridge } from \"./bridge/reflowable-css-bridge\";\nimport { GesturesDetector } from \"./common/gestures\";\nimport { appendVirtualColumnIfNeeded } from \"./util/columns\";\nconst bridgeListener = new ReflowableListenerAdapter(window.gestures);\nnew GesturesDetector(window, bridgeListener);\nWindow.prototype.readiumcss = new CssBridge(window.document);\nwindow.documentState.onScriptsLoaded();\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nwindow.addEventListener(\"load\", (event) => {\n let documentLoadedFired = false;\n const observer = new ResizeObserver(() => {\n requestAnimationFrame(() => {\n if (appendVirtualColumnIfNeeded(window)) {\n // Column has been added or removed, wait for next resize callback.\n return;\n }\n if (!documentLoadedFired) {\n const scrollingElement = window.document.scrollingElement;\n if (scrollingElement != null &&\n scrollingElement.scrollHeight == 0 &&\n scrollingElement.scrollWidth == 0) {\n // Document is not sized yet\n return;\n }\n window.documentState.onDocumentLoadedAndSized();\n documentLoadedFired = true;\n }\n else {\n window.documentState.onDocumentResized();\n }\n });\n });\n observer.observe(document.body);\n});\n","export class ReflowableListenerAdapter {\n constructor(gesturesBridge) {\n this.gesturesBridge = gesturesBridge;\n }\n onTap(event) {\n const tapEvent = {\n x: (event.clientX - visualViewport.offsetLeft) * visualViewport.scale,\n y: (event.clientY - visualViewport.offsetTop) * visualViewport.scale,\n };\n const stringEvent = JSON.stringify(tapEvent);\n this.gesturesBridge.onTap(stringEvent);\n }\n onLinkActivated(href, outerHtml) {\n this.gesturesBridge.onLinkActivated(href, outerHtml);\n }\n}\nexport class FixedListenerAdapter {\n constructor(window, gesturesApi, documentApi) {\n this.window = window;\n this.gesturesApi = gesturesApi;\n this.documentApi = documentApi;\n this.resizeObserverAdded = false;\n this.documentLoadedFired = false;\n }\n onTap(event) {\n this.gesturesApi.onTap(JSON.stringify(event));\n }\n onLinkActivated(href, outerHtml) {\n this.gesturesApi.onLinkActivated(href, outerHtml);\n }\n onLayout() {\n if (!this.resizeObserverAdded) {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const observer = new ResizeObserver(() => {\n requestAnimationFrame(() => {\n const scrollingElement = this.window.document.scrollingElement;\n if (!this.documentLoadedFired &&\n (scrollingElement == null ||\n scrollingElement.scrollHeight > 0 ||\n scrollingElement.scrollWidth > 0)) {\n this.documentApi.onDocumentLoadedAndSized();\n this.documentLoadedFired = true;\n }\n else {\n this.documentApi.onDocumentResized();\n }\n });\n });\n observer.observe(this.window.document.body);\n }\n this.resizeObserverAdded = true;\n }\n}\n","export class GesturesDetector {\n constructor(window, listener) {\n this.window = window;\n this.listener = listener;\n document.addEventListener(\"click\", (event) => {\n this.onClick(event);\n }, false);\n }\n onClick(event) {\n if (event.defaultPrevented) {\n return;\n }\n const selection = this.window.getSelection();\n if (selection && selection.type == \"Range\") {\n // There's an on-going selection, the tap will dismiss it so we don't forward it.\n // selection.type might be None (collapsed) or Caret with a collapsed range\n // when there is not true selection.\n return;\n }\n let nearestElement;\n if (event.target instanceof HTMLElement) {\n nearestElement = this.nearestInteractiveElement(event.target);\n }\n else {\n nearestElement = null;\n }\n if (nearestElement) {\n if (nearestElement instanceof HTMLAnchorElement) {\n this.listener.onLinkActivated(nearestElement.href, nearestElement.outerHTML);\n }\n }\n else {\n this.listener.onTap(event);\n }\n event.stopPropagation();\n event.preventDefault();\n }\n // See. https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling\n nearestInteractiveElement(element) {\n if (element == null) {\n return null;\n }\n const interactiveTags = [\n \"a\",\n \"audio\",\n \"button\",\n \"canvas\",\n \"details\",\n \"input\",\n \"label\",\n \"option\",\n \"select\",\n \"submit\",\n \"textarea\",\n \"video\",\n ];\n if (interactiveTags.indexOf(element.nodeName.toLowerCase()) != -1) {\n return element;\n }\n // Checks whether the element is editable by the user.\n if (element.hasAttribute(\"contenteditable\") &&\n element.getAttribute(\"contenteditable\").toLowerCase() != \"false\") {\n return element;\n }\n // Checks parents recursively because the touch might be for example on an inside a .\n if (element.parentElement) {\n return this.nearestInteractiveElement(element.parentElement);\n }\n return null;\n }\n}\n","export class CssBridge {\n constructor(document) {\n this.document = document;\n }\n setProperties(properties) {\n for (const [key, value] of properties) {\n this.setProperty(key, value);\n }\n }\n // For setting user setting.\n setProperty(key, value) {\n if (value === null || value === \"\") {\n this.removeProperty(key);\n }\n else {\n const root = document.documentElement;\n // The `!important` annotation is added with `setProperty()` because if it's part of the\n // `value`, it will be ignored by the Web View.\n root.style.setProperty(key, value, \"important\");\n }\n }\n // For removing user setting.\n removeProperty(key) {\n const root = document.documentElement;\n root.style.removeProperty(key);\n }\n}\n","/**\n * In paginated mode, the width of each resource must be a multiple of the viewport size\n * for proper snapping. This may not be automatically the case if the number of\n * columns in the resource is not a multiple of the number of columns fitting in the viewport.\n * To fix this, we insert a blank virtual column at the end of the resource.\n *\n * Returns if a virtual column has been added or removed.\n */\nexport function appendVirtualColumnIfNeeded(wnd) {\n // FIXME: what about scroll mode?\n const id = \"readium-virtual-page\";\n let virtualCol = wnd.document.getElementById(id);\n if (getColumnCountPerScreen(wnd) !== 2) {\n if (virtualCol) {\n virtualCol.remove();\n return true;\n }\n else {\n return false;\n }\n }\n else {\n const documentWidth = wnd.document.scrollingElement.scrollWidth;\n const colCount = documentWidth / wnd.innerWidth;\n const hasOddColCount = (Math.round(colCount * 2) / 2) % 1 > 0.1;\n if (hasOddColCount) {\n if (virtualCol) {\n virtualCol.remove();\n }\n else {\n virtualCol = wnd.document.createElement(\"div\");\n virtualCol.setAttribute(\"id\", id);\n virtualCol.dataset.readium = \"true\";\n virtualCol.style.breakBefore = \"column\";\n virtualCol.innerHTML = \"​\"; // zero-width space\n wnd.document.body.appendChild(virtualCol);\n }\n return true;\n }\n else {\n return false;\n }\n }\n}\nfunction getColumnCountPerScreen(wnd) {\n return parseInt(wnd\n .getComputedStyle(wnd.document.documentElement)\n .getPropertyValue(\"column-count\"));\n}\n"],"names":["bridgeListener","constructor","gesturesBridge","this","onTap","event","tapEvent","x","clientX","visualViewport","offsetLeft","scale","y","clientY","offsetTop","stringEvent","JSON","stringify","onLinkActivated","href","outerHtml","window","gestures","listener","document","addEventListener","onClick","defaultPrevented","selection","getSelection","type","nearestElement","target","HTMLElement","nearestInteractiveElement","HTMLAnchorElement","outerHTML","stopPropagation","preventDefault","element","indexOf","nodeName","toLowerCase","hasAttribute","getAttribute","parentElement","Window","prototype","readiumcss","setProperties","properties","key","value","setProperty","removeProperty","documentElement","style","documentState","onScriptsLoaded","documentLoadedFired","ResizeObserver","requestAnimationFrame","wnd","id","virtualCol","getElementById","parseInt","getComputedStyle","getPropertyValue","getColumnCountPerScreen","remove","colCount","scrollingElement","scrollWidth","innerWidth","Math","round","createElement","setAttribute","dataset","readium","breakBefore","innerHTML","body","appendChild","appendVirtualColumnIfNeeded","onDocumentResized","scrollHeight","onDocumentLoadedAndSized","observe"],"sourceRoot":""} \ No newline at end of file diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt index a552700ff6..6bba5c7c2d 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRendition.kt @@ -87,17 +87,22 @@ public fun FixedWebRendition( val displayArea = rememberUpdatedState(DisplayArea(viewportSize.value, safeDrawingPadding)) + fun currentLocation(): FixedWebLocation { + val spreadIndex = state.pagerState.currentPage + val itemIndex = state.layoutDelegate.layout.value.pageIndexForSpread(spreadIndex) + val href = state.publication.readingOrder[itemIndex].href + return FixedWebLocation(href) + } + if (state.controller == null) { - val itemHref = state.getCurrentHref() - state.initController(location = FixedWebLocation(itemHref)) + state.initController(location = currentLocation()) } LaunchedEffect(state) { snapshotFlow { state.pagerState.currentPage }.onEach { - val itemHref = state.getCurrentHref() - state.navigationDelegate.updateLocation(location = FixedWebLocation(itemHref)) + state.navigationDelegate.updateLocation(currentLocation()) }.launchIn(this) } @@ -145,11 +150,6 @@ public fun FixedWebRendition( } } - val readyToScroll = - ((state.pagerState.currentPage - 2)..(state.pagerState.currentPage + 2)).toList() - .mapNotNull { scrollStates.getOrNull(it) } - .all { it.scrollController.value != null } - val spreadFlingBehavior = Scrollable2DDefaults.flingBehavior() val spreadNestedScrollConnection = @@ -168,7 +168,7 @@ public fun FixedWebRendition( flingBehavior = flingBehavior, orientation = Orientation.Horizontal, beyondViewportPageCount = 2, - enableScroll = readyToScroll, + enableScroll = true, key = { index -> val readingProgression = state.layoutDelegate.layout.value.readingProgression val spread = state.layoutDelegate.layout.value.spreads[index] diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionState.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionState.kt index afdc08b4dc..40d2f2dc91 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionState.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/FixedWebRenditionState.kt @@ -38,7 +38,6 @@ import org.readium.r2.navigator.preferences.Fit import org.readium.r2.shared.ExperimentalReadiumApi import org.readium.r2.shared.InternalReadiumApi import org.readium.r2.shared.util.RelativeUrl -import org.readium.r2.shared.util.Url import org.readium.r2.shared.util.mediatype.MediaType import org.readium.r2.shared.util.resource.Resource @@ -119,12 +118,6 @@ public class FixedWebRenditionState internal constructor( ) navigationDelegate.updateLocation(location) } - - internal fun getCurrentHref(): Url { - val spreadIndex = pagerState.currentPage - val itemIndex = layoutDelegate.layout.value.pageIndexForSpread(spreadIndex) - return publication.readingOrder[itemIndex].href - } } @ExperimentalReadiumApi diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt index fb03ed63b7..a1296a86e1 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/ReflowableWebRendition.kt @@ -18,10 +18,12 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberUpdatedState +import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color @@ -33,6 +35,8 @@ import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.DpOffset import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import org.readium.navigator.common.HyperlinkListener import org.readium.navigator.common.HyperlinkLocation @@ -115,14 +119,23 @@ public fun ReflowableWebRendition( val currentPageState = remember(state) { derivedStateOf { state.pagerState.currentPage } } + fun currentLocation() = + ReflowableWebLocation( + href = state.publication.readingOrder.items[currentPageState.value].href, + progression = state.resourceStates[currentPageState.value].progression + ) + if (state.controller == null) { // Initialize controller. In the future, that should require access to a ready WebView. - state.initController( - location = ReflowableWebLocation( - href = state.publication.readingOrder.items[currentPageState.value].href, - progression = state.resourceStates[currentPageState.value].progression - ) - ) + state.initController(location = currentLocation()) + } + + LaunchedEffect(state) { + snapshotFlow { + state.pagerState.currentPage + }.onEach { + state.updateLocation(currentLocation()) + }.launchIn(this) } RenditionPager( diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt index 4c2c4451d9..b5c75a3129 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/fixed/SpreadWebView.kt @@ -34,6 +34,7 @@ import org.readium.navigator.web.webview.WebViewScrollController import org.readium.navigator.web.webview.WebViewState import org.readium.r2.shared.ExperimentalReadiumApi import org.readium.r2.shared.util.AbsoluteUrl +import timber.log.Timber @OptIn(ExperimentalReadiumApi::class) @SuppressLint("SetJavaScriptEnabled") @@ -54,14 +55,32 @@ internal fun SpreadWebView( val contentIsLaidOut = remember { mutableStateOf(false) } - val documentStateApi = remember(onScriptsLoaded) { - DocumentStateApi( - onScriptsLoadedDelegate = onScriptsLoaded, - onDocumentLoadedAndSizedDelegate = { - state.webView?.apply { - requestLayout() - setNextLayoutListener { - val scrollController = WebViewScrollController(this) + LaunchedEffect(state.webView, onTap, onLinkActivated) { + state.webView?.let { webView -> + val listener = object : GesturesListener { + override fun onTap(offset: DpOffset) { + onTap(TapEvent(offset)) + } + + override fun onLinkActivated(href: AbsoluteUrl, outerHtml: String) { + onLinkActivated(href, outerHtml) + } + } + + GesturesApi(webView, listener) + } + } + + LaunchedEffect(state.webView, onScriptsLoaded, spreadScrollState, contentIsLaidOut) { + state.webView?.let { webView -> + DocumentStateApi( + webView = webView, + onScriptsLoadedDelegate = onScriptsLoaded, + onDocumentLoadedAndSizedDelegate = { + Timber.d("spread $spreadIndex onDocumentLoadedAndSized") + webView.requestLayout() + webView.setNextLayoutListener { + val scrollController = WebViewScrollController(webView) scrollController.moveToProgression( progression = progression, snap = true, @@ -71,31 +90,12 @@ internal fun SpreadWebView( spreadScrollState.scrollController.value = scrollController contentIsLaidOut.value = true } + }, + onDocumentResizedDelegate = { + Timber.d("spread $spreadIndex onDocumentResizedAndSized") } - }, - onDocumentResizedDelegate = {} - ) - } - - LaunchedEffect(state.webView, documentStateApi) { - state.webView?.let { documentStateApi.registerOnWebView(it) } - } - - val gesturesApi = remember(onTap) { - val listener = object : GesturesListener { - override fun onTap(offset: DpOffset) { - onTap(TapEvent(offset)) - } - - override fun onLinkActivated(href: AbsoluteUrl, outerHtml: String) { - onLinkActivated(href, outerHtml) - } + ) } - GesturesApi(listener) - } - - LaunchedEffect(state.webView, gesturesApi) { - state.webView?.let { gesturesApi.registerOnWebView(it) } } // Hide content before initial position is settled @@ -129,6 +129,7 @@ internal fun SpreadWebView( }, onDispose = { spreadScrollState.scrollController.value = null + Timber.d("spread disposing $spreadIndex") } ) } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/RenditionScrollState.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/RenditionScrollState.kt index 0f4069c58f..850f074a87 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/RenditionScrollState.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/pager/RenditionScrollState.kt @@ -62,6 +62,8 @@ internal class RenditionScrollState( val lastPage = pagerState.layoutInfo.visiblePagesInfo.last() + // This should not be needed if all WebViews are properly initialized at suitable scroll + // positions and any discontinuous move through the publication adjusts those positions. if (firstPage == lastPage) { // Set the page that will become visible to the right scroll position. when { diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowablePagingLayoutInfo.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowablePagingLayoutInfo.kt index 6f3a6d08ed..0015a356ed 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowablePagingLayoutInfo.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowablePagingLayoutInfo.kt @@ -66,7 +66,7 @@ internal class ReflowablePagingLayoutInfo( if (firstPage.index == lastPage.index) { val index = firstPage.index - val scrollController = pageStates[index].scrollController.value!! + val scrollController = pageStates[index].scrollController.value ?: return emptyList() if (direction == LayoutDirection.Ltr) { add(-scrollController.scrollX % pageSize) add(-scrollController.scrollX % pageSize + pageSize) @@ -76,8 +76,8 @@ internal class ReflowablePagingLayoutInfo( } Timber.d("visiblePageOffsets if $this pageSize $pageSize") } else { - val firstScrollController = pageStates[firstPage.index].scrollController.value!! - val lastScrollController = pageStates[lastPage.index].scrollController.value!! + val firstScrollController = pageStates[firstPage.index].scrollController.value ?: return emptyList() + val lastScrollController = pageStates[lastPage.index].scrollController.value ?: return emptyList() if (direction == LayoutDirection.Ltr) { // To get to the left bound, we first need to scroll the last visible page to zero. add(lastPage.offset - pageSize - lastScrollController.scrollX) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt index cef4822bdd..f9be3ad823 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt @@ -42,6 +42,7 @@ import org.readium.navigator.web.webview.rememberWebViewState import org.readium.r2.shared.ExperimentalReadiumApi import org.readium.r2.shared.util.AbsoluteUrl import org.readium.r2.shared.util.Url +import timber.log.Timber @SuppressLint("SetJavaScriptEnabled", "ClickableViewAccessibility") @Composable @@ -81,16 +82,41 @@ internal fun ReflowableResource( val contentIsLaidOut = remember(webViewState.webView) { mutableStateOf(false) } - val documentStateApi = remember(webViewState.webView) { - DocumentStateApi( - onScriptsLoadedDelegate = { - scriptsLoaded.value = true - }, - onDocumentLoadedAndSizedDelegate = { - webViewState.webView?.apply { - requestLayout() - setNextLayoutListener { - val scrollController = WebViewScrollController(this) + val cssApi = remember(webViewState.webView) { mutableStateOf(null) } + + LaunchedEffect(webViewState.webView, onTap, onLinkActivated) { + webViewState.webView?.let { webView -> + GesturesApi( + webView = webView, + listener = DelegatingGesturesListener( + onTapDelegate = { offset -> + val shiftedOffset = DpOffset( + x = offset.x + padding.left, + y = offset.y + padding.top + ) + onTap(TapEvent(shiftedOffset)) + }, + onLinkActivatedDelegate = { href, outerHtml -> + onLinkActivated(publicationBaseUrl.relativize(href), outerHtml) + } + ) + ) + } + } + + LaunchedEffect(webViewState.webView, scriptsLoaded, cssApi, resourceState, contentIsLaidOut) { + webViewState.webView?.let { webView -> + DocumentStateApi( + webView = webView, + onScriptsLoadedDelegate = { + scriptsLoaded.value = true + cssApi.value = CssApi(webView) + }, + onDocumentLoadedAndSizedDelegate = { + Timber.d("resource ${resourceState.index} onDocumentLoadedAndResized") + webView.requestLayout() + webView.setNextLayoutListener { + val scrollController = WebViewScrollController(webView) scrollController.moveToProgression( progression = resourceState.progression, snap = !scroll, @@ -98,55 +124,29 @@ internal fun ReflowableResource( direction = layoutDirection ) resourceState.scrollController.value = scrollController - setOnScrollChangeListener { view, scrollX, scrollY, oldScrollX, oldScrollY -> + Timber.d("resource ${resourceState.index} ready to scroll") + webView.setOnScrollChangeListener { view, scrollX, scrollY, oldScrollX, oldScrollY -> onProgressionChange( - scrollController.progression(orientationState.value, directionState.value) + scrollController.progression( + orientationState.value, + directionState.value + ) ) } contentIsLaidOut.value = true } - } - }, - onDocumentResizedDelegate = { - onDocumentResized.invoke() - } - ) - } - - LaunchedEffect(webViewState.webView, documentStateApi) { - webViewState.webView?.let { documentStateApi.registerOnWebView(it) } - } - - val cssApi = remember(webViewState.webView, scriptsLoaded.value) { - webViewState.webView - .takeIf { scriptsLoaded.value } - ?.let { CssApi(it) } - } - - LaunchedEffect(cssApi, readiumCssInjector) { - cssApi?.setProperties(readiumCssInjector.userProperties, readiumCssInjector.rsProperties) - // FIXME: resource is laid out again, so we should apply progression again - } - - val gesturesApi = remember(onTap, onLinkActivated) { - GesturesApi( - DelegatingGesturesListener( - onTapDelegate = { offset -> - val shiftedOffset = DpOffset( - x = offset.x + padding.left, - y = offset.y + padding.top - ) - onTap(TapEvent(shiftedOffset)) }, - onLinkActivatedDelegate = { href, outerHtml -> - onLinkActivated(publicationBaseUrl.relativize(href), outerHtml) + onDocumentResizedDelegate = { + Timber.d("resource ${resourceState.index} onDocumentResized") + onDocumentResized.invoke() } ) - ) + } } - LaunchedEffect(webViewState.webView, gesturesApi) { - webViewState.webView?.let { gesturesApi.registerOnWebView(it) } + LaunchedEffect(cssApi.value, readiumCssInjector) { + cssApi.value?.setProperties(readiumCssInjector.userProperties, readiumCssInjector.rsProperties) + // FIXME: resource is laid out again, so we should apply progression again } // Hide content before initial position is settled @@ -191,6 +191,7 @@ internal fun ReflowableResource( }, onDispose = { resourceState.scrollController.value = null + Timber.d("resource ${resourceState.index} disposed") } ) } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/webapi/DocumentStateApi.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/webapi/DocumentStateApi.kt index c170bcdab9..4a3d785900 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/webapi/DocumentStateApi.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/webapi/DocumentStateApi.kt @@ -8,29 +8,41 @@ package org.readium.navigator.web.webapi import android.webkit.JavascriptInterface import android.webkit.WebView +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.MainScope +import kotlinx.coroutines.launch internal class DocumentStateApi( + webView: WebView, private val onScriptsLoadedDelegate: () -> Unit, private val onDocumentLoadedAndSizedDelegate: () -> Unit, private val onDocumentResizedDelegate: () -> Unit, ) { + private val coroutineScope: CoroutineScope = + MainScope() - fun registerOnWebView(webView: WebView) { + init { webView.addJavascriptInterface(this, "documentState") } @JavascriptInterface fun onScriptsLoaded() { - onScriptsLoadedDelegate.invoke() + coroutineScope.launch { + onScriptsLoadedDelegate.invoke() + } } @JavascriptInterface fun onDocumentLoadedAndSized() { - onDocumentLoadedAndSizedDelegate.invoke() + coroutineScope.launch { + onDocumentLoadedAndSizedDelegate.invoke() + } } @JavascriptInterface fun onDocumentResized() { - onDocumentResizedDelegate.invoke() + coroutineScope.launch { + onDocumentResizedDelegate.invoke() + } } } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/webapi/GesturesApi.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/webapi/GesturesApi.kt index 9e7ab2e0d9..598114a600 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/webapi/GesturesApi.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/webapi/GesturesApi.kt @@ -9,6 +9,9 @@ package org.readium.navigator.web.webapi import android.webkit.WebView import androidx.compose.ui.unit.DpOffset import androidx.compose.ui.unit.dp +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.MainScope +import kotlinx.coroutines.launch import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json import org.readium.r2.shared.util.AbsoluteUrl @@ -38,23 +41,30 @@ internal interface GesturesListener { } internal class GesturesApi( + webView: WebView, private val listener: GesturesListener, ) { + private val coroutineScope: CoroutineScope = + MainScope() - fun registerOnWebView(webView: WebView) { + init { webView.addJavascriptInterface(this, "gestures") } @android.webkit.JavascriptInterface fun onTap(eventJson: String) { - val tapEvent = Json.decodeFromString(eventJson) - listener.onTap(DpOffset(tapEvent.x.dp, tapEvent.y.dp)) + coroutineScope.launch { + val tapEvent = Json.decodeFromString(eventJson) + listener.onTap(DpOffset(tapEvent.x.dp, tapEvent.y.dp)) + } } @android.webkit.JavascriptInterface fun onLinkActivated(href: String, outerHtml: String) { - val url = AbsoluteUrl(href) ?: return - listener.onLinkActivated(url, outerHtml) + coroutineScope.launch { + val url = AbsoluteUrl(href) ?: return@launch + listener.onLinkActivated(url, outerHtml) + } } } diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollController.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollController.kt index 7d94ec4bbb..f7411d543f 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollController.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/WebViewScrollController.kt @@ -103,6 +103,9 @@ internal class WebViewScrollController( orientation: Orientation, direction: LayoutDirection, ) { + check(webView.height != 0) + check(webView.width != 0) + webView.scrollToProgression( progression = progression, orientation = orientation, From 0c77906dbe0ec8f2dad48a66db780c5ee351b381 Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Fri, 30 May 2025 13:56:10 +0200 Subject: [PATCH 53/88] Update Readium CSS to 2.0.0-beta-13 --- readium/navigators/web/scripts/package.json | 10 +- readium/navigators/web/scripts/pnpm-lock.yaml | 64 +++---- .../readium-css/ReadiumCSS-after.css | 176 +++++++++++------- .../readium-css/ReadiumCSS-before.css | 2 +- .../readium-css/ReadiumCSS-default.css | 2 +- .../cjk-horizontal/ReadiumCSS-after.css | 159 +++++++++++----- .../cjk-horizontal/ReadiumCSS-before.css | 2 +- .../cjk-horizontal/ReadiumCSS-default.css | 2 +- .../cjk-vertical/ReadiumCSS-after.css | 159 +++++++++++----- .../cjk-vertical/ReadiumCSS-before.css | 4 +- .../cjk-vertical/ReadiumCSS-default.css | 2 +- .../readium-css/rtl/ReadiumCSS-after.css | 159 +++++++++++----- .../readium-css/rtl/ReadiumCSS-before.css | 2 +- .../readium-css/rtl/ReadiumCSS-default.css | 2 +- .../navigator/web/css/ReadiumCssInjector.kt | 15 +- .../navigator/web/css/ReadiumCssProperties.kt | 13 +- .../ReflowableWebPreferencesEditor.kt | 6 +- 17 files changed, 500 insertions(+), 279 deletions(-) diff --git a/readium/navigators/web/scripts/package.json b/readium/navigators/web/scripts/package.json index 880982a7fc..c3a745bc8b 100644 --- a/readium/navigators/web/scripts/package.json +++ b/readium/navigators/web/scripts/package.json @@ -16,18 +16,18 @@ "Android >= 4" ], "devDependencies": { - "copy-webpack-plugin": "^12.0.2", "@babel/core": "^7.23.0", "@babel/preset-env": "^7.22.20", - "babel-loader": "^8.3.0", - "eslint": "^8.57.0", + "@readium/css": "2.0.0-beta.13", "@typescript-eslint/eslint-plugin": "^8.3.0", "@typescript-eslint/parser": "^8.3.0", + "babel-loader": "^8.3.0", + "copy-webpack-plugin": "^12.0.2", + "eslint": "^8.57.0", "prettier": "2.3.1", "vite": "^5.4.1", "webpack": "^5.88.2", - "webpack-cli": "^5.1.4", - "@readium/css": "2.0.0-beta.7" + "webpack-cli": "^5.1.4" }, "dependencies": { "approx-string-match": "^1.1.0", diff --git a/readium/navigators/web/scripts/pnpm-lock.yaml b/readium/navigators/web/scripts/pnpm-lock.yaml index 59ffbe0c86..7e9d5a3046 100644 --- a/readium/navigators/web/scripts/pnpm-lock.yaml +++ b/readium/navigators/web/scripts/pnpm-lock.yaml @@ -22,7 +22,7 @@ dependencies: version: 4.0.10 ts-loader: specifier: ^9.5.1 - version: 9.5.1(typescript@5.5.4)(webpack@5.88.2) + version: 9.5.1(typescript@5.8.3)(webpack@5.88.2) devDependencies: '@babel/core': @@ -32,14 +32,14 @@ devDependencies: specifier: ^7.22.20 version: 7.22.20(@babel/core@7.23.0) '@readium/css': - specifier: 2.0.0-beta.7 - version: 2.0.0-beta.7 + specifier: 2.0.0-beta.13 + version: 2.0.0-beta.13 '@typescript-eslint/eslint-plugin': specifier: ^8.3.0 - version: 8.3.0(@typescript-eslint/parser@8.3.0)(eslint@8.57.0)(typescript@5.5.4) + version: 8.3.0(@typescript-eslint/parser@8.3.0)(eslint@8.57.0)(typescript@5.8.3) '@typescript-eslint/parser': specifier: ^8.3.0 - version: 8.3.0(eslint@8.57.0)(typescript@5.5.4) + version: 8.3.0(eslint@8.57.0)(typescript@5.8.3) babel-loader: specifier: ^8.3.0 version: 8.3.0(@babel/core@7.23.0)(webpack@5.88.2) @@ -1553,8 +1553,8 @@ packages: fastq: 1.17.1 dev: true - /@readium/css@2.0.0-beta.7: - resolution: {integrity: sha512-OoHrhc2/f38o1Qj+y2k9upS6YI2K+hhoItVfJdzVLpXDFWdtY7vA7vqbTLAvICzbrrU3q983OfyEHX8JTYQ14g==} + /@readium/css@2.0.0-beta.13: + resolution: {integrity: sha512-45WweTkywrRmPiaKE0gCKOxyMJjCyNzv/FG4H31vxeOdmGpZXeoQSpK7jm5DGnrlCUHUPQzkLSwJtNJhXBY3AQ==} dev: true /@rollup/rollup-android-arm-eabi@4.20.0: @@ -1715,7 +1715,7 @@ packages: /@types/node@20.8.2: resolution: {integrity: sha512-Vvycsc9FQdwhxE3y3DzeIxuEJbWGDsnrxvMADzTDF/lcdR9/K+AQIeAghTQsHtotg/q0j3WEOYS/jQgSdWue3w==} - /@typescript-eslint/eslint-plugin@8.3.0(@typescript-eslint/parser@8.3.0)(eslint@8.57.0)(typescript@5.5.4): + /@typescript-eslint/eslint-plugin@8.3.0(@typescript-eslint/parser@8.3.0)(eslint@8.57.0)(typescript@5.8.3): resolution: {integrity: sha512-FLAIn63G5KH+adZosDYiutqkOkYEx0nvcwNNfJAf+c7Ae/H35qWwTYvPZUKFj5AS+WfHG/WJJfWnDnyNUlp8UA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: @@ -1727,22 +1727,22 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.11.0 - '@typescript-eslint/parser': 8.3.0(eslint@8.57.0)(typescript@5.5.4) + '@typescript-eslint/parser': 8.3.0(eslint@8.57.0)(typescript@5.8.3) '@typescript-eslint/scope-manager': 8.3.0 - '@typescript-eslint/type-utils': 8.3.0(eslint@8.57.0)(typescript@5.5.4) - '@typescript-eslint/utils': 8.3.0(eslint@8.57.0)(typescript@5.5.4) + '@typescript-eslint/type-utils': 8.3.0(eslint@8.57.0)(typescript@5.8.3) + '@typescript-eslint/utils': 8.3.0(eslint@8.57.0)(typescript@5.8.3) '@typescript-eslint/visitor-keys': 8.3.0 eslint: 8.57.0 graphemer: 1.4.0 ignore: 5.3.2 natural-compare: 1.4.0 - ts-api-utils: 1.3.0(typescript@5.5.4) - typescript: 5.5.4 + ts-api-utils: 1.3.0(typescript@5.8.3) + typescript: 5.8.3 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/parser@8.3.0(eslint@8.57.0)(typescript@5.5.4): + /@typescript-eslint/parser@8.3.0(eslint@8.57.0)(typescript@5.8.3): resolution: {integrity: sha512-h53RhVyLu6AtpUzVCYLPhZGL5jzTD9fZL+SYf/+hYOx2bDkyQXztXSc4tbvKYHzfMXExMLiL9CWqJmVz6+78IQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: @@ -1754,11 +1754,11 @@ packages: dependencies: '@typescript-eslint/scope-manager': 8.3.0 '@typescript-eslint/types': 8.3.0 - '@typescript-eslint/typescript-estree': 8.3.0(typescript@5.5.4) + '@typescript-eslint/typescript-estree': 8.3.0(typescript@5.8.3) '@typescript-eslint/visitor-keys': 8.3.0 debug: 4.3.4 eslint: 8.57.0 - typescript: 5.5.4 + typescript: 5.8.3 transitivePeerDependencies: - supports-color dev: true @@ -1771,7 +1771,7 @@ packages: '@typescript-eslint/visitor-keys': 8.3.0 dev: true - /@typescript-eslint/type-utils@8.3.0(eslint@8.57.0)(typescript@5.5.4): + /@typescript-eslint/type-utils@8.3.0(eslint@8.57.0)(typescript@5.8.3): resolution: {integrity: sha512-wrV6qh//nLbfXZQoj32EXKmwHf4b7L+xXLrP3FZ0GOUU72gSvLjeWUl5J5Ue5IwRxIV1TfF73j/eaBapxx99Lg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: @@ -1780,11 +1780,11 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 8.3.0(typescript@5.5.4) - '@typescript-eslint/utils': 8.3.0(eslint@8.57.0)(typescript@5.5.4) + '@typescript-eslint/typescript-estree': 8.3.0(typescript@5.8.3) + '@typescript-eslint/utils': 8.3.0(eslint@8.57.0)(typescript@5.8.3) debug: 4.3.4 - ts-api-utils: 1.3.0(typescript@5.5.4) - typescript: 5.5.4 + ts-api-utils: 1.3.0(typescript@5.8.3) + typescript: 5.8.3 transitivePeerDependencies: - eslint - supports-color @@ -1795,7 +1795,7 @@ packages: engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dev: true - /@typescript-eslint/typescript-estree@8.3.0(typescript@5.5.4): + /@typescript-eslint/typescript-estree@8.3.0(typescript@5.8.3): resolution: {integrity: sha512-Mq7FTHl0R36EmWlCJWojIC1qn/ZWo2YiWYc1XVtasJ7FIgjo0MVv9rZWXEE7IK2CGrtwe1dVOxWwqXUdNgfRCA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: @@ -1811,13 +1811,13 @@ packages: is-glob: 4.0.3 minimatch: 9.0.5 semver: 7.6.3 - ts-api-utils: 1.3.0(typescript@5.5.4) - typescript: 5.5.4 + ts-api-utils: 1.3.0(typescript@5.8.3) + typescript: 5.8.3 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/utils@8.3.0(eslint@8.57.0)(typescript@5.5.4): + /@typescript-eslint/utils@8.3.0(eslint@8.57.0)(typescript@5.8.3): resolution: {integrity: sha512-F77WwqxIi/qGkIGOGXNBLV7nykwfjLsdauRB/DOFPdv6LTF3BHHkBpq81/b5iMPSF055oO2BiivDJV4ChvNtXA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: @@ -1826,7 +1826,7 @@ packages: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) '@typescript-eslint/scope-manager': 8.3.0 '@typescript-eslint/types': 8.3.0 - '@typescript-eslint/typescript-estree': 8.3.0(typescript@5.5.4) + '@typescript-eslint/typescript-estree': 8.3.0(typescript@5.8.3) eslint: 8.57.0 transitivePeerDependencies: - supports-color @@ -3765,16 +3765,16 @@ packages: dependencies: is-number: 7.0.0 - /ts-api-utils@1.3.0(typescript@5.5.4): + /ts-api-utils@1.3.0(typescript@5.8.3): resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} engines: {node: '>=16'} peerDependencies: typescript: '>=4.2.0' dependencies: - typescript: 5.5.4 + typescript: 5.8.3 dev: true - /ts-loader@9.5.1(typescript@5.5.4)(webpack@5.88.2): + /ts-loader@9.5.1(typescript@5.8.3)(webpack@5.88.2): resolution: {integrity: sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg==} engines: {node: '>=12.0.0'} peerDependencies: @@ -3786,7 +3786,7 @@ packages: micromatch: 4.0.7 semver: 7.5.4 source-map: 0.7.4 - typescript: 5.5.4 + typescript: 5.8.3 webpack: 5.88.2(webpack-cli@5.1.4) dev: false @@ -3840,8 +3840,8 @@ packages: is-typed-array: 1.1.12 dev: false - /typescript@5.5.4: - resolution: {integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==} + /typescript@5.8.3: + resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} engines: {node: '>=14.17'} hasBin: true diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-after.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-after.css index 0e153a3e17..9feb56ecef 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-after.css +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-after.css @@ -1,5 +1,5 @@ /* - * Readium CSS (v. 2.0.0-beta.7) + * Readium CSS (v. 2.0.0-beta.13) * Developers: Jiminy Panoz * Copyright (c) 2017. Readium Foundation. All rights reserved. * Use of this source code is governed by a BSD-style license which is detailed in the @@ -56,9 +56,7 @@ min-height:100vh; padding:0 !important; margin:0 !important; - font-size:100% !important; - -webkit-text-size-adjust:none; - text-size-adjust:none; + font-size:1rem !important; box-sizing:border-box; -webkit-touch-callout:none; } @@ -358,40 +356,33 @@ body{ font-family:var(--USER__fontFamily) !important; } -:root[style*="readium-font-on"][style*="--USER__fontFamily"] *:not(code):not(var):not(kbd):not(samp){ - font-family:inherit !important; +:root[style*="readium-font-on"][style*="--USER__fontFamily"] *{ + font-family:revert !important; } :root[style*="readium-font-on"][style*="AccessibleDfA"]{ font-family:AccessibleDfA, Verdana, Tahoma, "Trebuchet MS", sans-serif !important; - --RS__lineHeightCompensation:1.167; } :root[style*="readium-font-on"][style*="IA Writer Duospace"]{ font-family:"IA Writer Duospace", Menlo, "DejaVu Sans Mono", "Bitstream Vera Sans Mono", Courier, monospace !important; - --RS__lineHeightCompensation:1.167; -} - -:root[style*="readium-font-on"][style*="readium-a11y-on"]{ - font-family:var(--USER__fontFamily) !important; - --RS__lineHeightCompensation:1.167; } :root[style*="readium-font-on"][style*="AccessibleDfA"],:root[style*="readium-font-on"][style*="IA Writer Duospace"], -:root[style*="readium-font-on"][style*="readium-a11y-on"]{ +:root[style*="readium-a11y-on"]{ font-style:normal !important; font-weight:normal !important; } :root[style*="readium-font-on"][style*="AccessibleDfA"] *:not(code):not(var):not(kbd):not(samp),:root[style*="readium-font-on"][style*="IA Writer Duospace"] *:not(code):not(var):not(kbd):not(samp), -:root[style*="readium-font-on"][style*="readium-a11y-on"] *:not(code):not(var):not(kbd):not(samp){ +:root[style*="readium-a11y-on"] *:not(code):not(var):not(kbd):not(samp){ font-family:inherit !important; font-style:inherit !important; font-weight:inherit !important; } :root[style*="readium-font-on"][style*="AccessibleDfA"] *,:root[style*="readium-font-on"][style*="IA Writer Duospace"] *, -:root[style*="readium-font-on"][style*="readium-a11y-on"] *{ +:root[style*="readium-a11y-on"] *{ text-decoration:none !important; font-variant-caps:normal !important; font-variant-numeric:normal !important; @@ -399,15 +390,15 @@ body{ } :root[style*="readium-font-on"][style*="AccessibleDfA"] sup,:root[style*="readium-font-on"][style*="IA Writer Duospace"] sup, -:root[style*="readium-font-on"][style*="readium-a11y-on"] sup, +:root[style*="readium-a11y-on"] sup, :root[style*="readium-font-on"][style*="AccessibleDfA"] sub, :root[style*="readium-font-on"][style*="IA Writer Duospace"] sub, -:root[style*="readium-font-on"][style*="readium-a11y-on"] sub{ +:root[style*="readium-a11y-on"] sub{ font-size:1rem !important; vertical-align:baseline !important; } -:root[style*="--USER__fontSize"] body{ +:root:not([style*="readium-deprecatedFontSize-on"])[style*="--USER__fontSize"] body{ zoom:var(--USER__fontSize) !important; } @@ -418,6 +409,10 @@ body{ } } +:root[style*="readium-deprecatedFontSize-on"][style*="--USER__fontSize"]{ + font-size:var(--USER__fontSize) !important; +} + :root[style*="--USER__lineHeight"]{ line-height:var(--USER__lineHeight) !important; } @@ -545,59 +540,114 @@ body{ filter:invert(100%) !important; } -@supports not (zoom: 1){ +:root[style*="readium-normalize-on"]{ + --USER__typeScale:1.2; +} - :root[style*="readium-normalize-on"]{ - --USER__typeScale:1.2; - } +:root[style*="readium-normalize-on"] p, +:root[style*="readium-normalize-on"] li, +:root[style*="readium-normalize-on"] div, +:root[style*="readium-normalize-on"] pre, +:root[style*="readium-normalize-on"] dd{ + font-size:1rem !important; +} - :root[style*="readium-normalize-on"] p, - :root[style*="readium-normalize-on"] li, - :root[style*="readium-normalize-on"] div, - :root[style*="readium-normalize-on"] pre, - :root[style*="readium-normalize-on"] dd{ - font-size:1rem !important; - } +:root[style*="readium-normalize-on"] h1{ + font-size:1.75rem !important; + font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important; +} - :root[style*="readium-normalize-on"] h1{ - font-size:1.75rem !important; - font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important; - } +:root[style*="readium-normalize-on"] h2{ + font-size:1.5rem !important; + font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important; +} - :root[style*="readium-normalize-on"] h2{ - font-size:1.5rem !important; - font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important; - } +:root[style*="readium-normalize-on"] h3{ + font-size:1.25rem !important; + font-size:calc(1rem * var(--USER__typeScale)) !important; +} - :root[style*="readium-normalize-on"] h3{ - font-size:1.25rem !important; - font-size:calc(1rem * var(--USER__typeScale)) !important; - } +:root[style*="readium-normalize-on"] h4, +:root[style*="readium-normalize-on"] h5, +:root[style*="readium-normalize-on"] h6{ + font-size:1rem !important; +} - :root[style*="readium-normalize-on"] h4, - :root[style*="readium-normalize-on"] h5, - :root[style*="readium-normalize-on"] h6{ - font-size:1rem !important; - } +:root[style*="readium-normalize-on"] small{ + font-size:smaller !important; +} - :root[style*="readium-normalize-on"] small{ - font-size:smaller !important; - } +:root[style*="readium-normalize-on"] sub, +:root[style*="readium-normalize-on"] sup{ + font-size:67.5% !important; +} - :root[style*="readium-normalize-on"] sub, - :root[style*="readium-normalize-on"] sup{ - font-size:67.5% !important; - } +:root[style*="readium-normalize-on"][style*="--USER__typeScale"] h1{ + font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important; +} - :root[style*="readium-normalize-on"][style*="--USER__typeScale"] h1{ - font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important; - } +:root[style*="readium-normalize-on"][style*="--USER__typeScale"] h2{ + font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important; +} - :root[style*="readium-normalize-on"][style*="--USER__typeScale"] h2{ - font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important; - } +:root[style*="readium-normalize-on"][style*="--USER__typeScale"] h3{ + font-size:calc(1rem * var(--USER__typeScale)) !important; +} - :root[style*="readium-normalize-on"][style*="--USER__typeScale"] h3{ - font-size:calc(1rem * var(--USER__typeScale)) !important; - } +:root[style*="readium-iPadOSPatch-on"] body{ + -webkit-text-size-adjust:none; +} + +:root[style*="readium-iPadOSPatch-on"] p, +:root[style*="readium-iPadOSPatch-on"] h1, +:root[style*="readium-iPadOSPatch-on"] h2, +:root[style*="readium-iPadOSPatch-on"] h3, +:root[style*="readium-iPadOSPatch-on"] h4, +:root[style*="readium-iPadOSPatch-on"] h5, +:root[style*="readium-iPadOSPatch-on"] h6, +:root[style*="readium-iPadOSPatch-on"] li, +:root[style*="readium-iPadOSPatch-on"] th, +:root[style*="readium-iPadOSPatch-on"] td, +:root[style*="readium-iPadOSPatch-on"] dt, +:root[style*="readium-iPadOSPatch-on"] dd, +:root[style*="readium-iPadOSPatch-on"] pre, +:root[style*="readium-iPadOSPatch-on"] address, +:root[style*="readium-iPadOSPatch-on"] details, +:root[style*="readium-iPadOSPatch-on"] summary, +:root[style*="readium-iPadOSPatch-on"] figcaption, +:root[style*="readium-iPadOSPatch-on"] div:not(:has(p, h1, h2, h3, h4, h5, h6, li, th, td, dt, dd, pre, address, aside, details, figcaption, summary)), +:root[style*="readium-iPadOSPatch-on"] aside:not(:has(p, h1, h2, h3, h4, h5, h6, li, th, td, dt, dd, pre, address, aside, details, figcaption, summary)){ + -webkit-text-zoom:reset; +} + +:root[style*="readium-iPadOSPatch-on"] abbr, +:root[style*="readium-iPadOSPatch-on"] b, +:root[style*="readium-iPadOSPatch-on"] bdi, +:root[style*="readium-iPadOSPatch-on"] bdo, +:root[style*="readium-iPadOSPatch-on"] cite, +:root[style*="readium-iPadOSPatch-on"] code, +:root[style*="readium-iPadOSPatch-on"] dfn, +:root[style*="readium-iPadOSPatch-on"] em, +:root[style*="readium-iPadOSPatch-on"] i, +:root[style*="readium-iPadOSPatch-on"] kbd, +:root[style*="readium-iPadOSPatch-on"] mark, +:root[style*="readium-iPadOSPatch-on"] q, +:root[style*="readium-iPadOSPatch-on"] rp, +:root[style*="readium-iPadOSPatch-on"] rt, +:root[style*="readium-iPadOSPatch-on"] ruby, +:root[style*="readium-iPadOSPatch-on"] s, +:root[style*="readium-iPadOSPatch-on"] samp, +:root[style*="readium-iPadOSPatch-on"] small, +:root[style*="readium-iPadOSPatch-on"] span, +:root[style*="readium-iPadOSPatch-on"] strong, +:root[style*="readium-iPadOSPatch-on"] sub, +:root[style*="readium-iPadOSPatch-on"] sup, +:root[style*="readium-iPadOSPatch-on"] time, +:root[style*="readium-iPadOSPatch-on"] u, +:root[style*="readium-iPadOSPatch-on"] var{ + -webkit-text-zoom:normal; +} + +:root[style*="readium-iPadOSPatch-on"] p:not(:has(b, cite, em, i, q, s, small, span, strong)):first-line{ + -webkit-text-zoom:normal; } \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-before.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-before.css index a98ae32ae0..0cc5938f7b 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-before.css +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-before.css @@ -1,5 +1,5 @@ /* - * Readium CSS (v. 2.0.0-beta.7) + * Readium CSS (v. 2.0.0-beta.13) * Developers: Jiminy Panoz * Copyright (c) 2017. Readium Foundation. All rights reserved. * Use of this source code is governed by a BSD-style license which is detailed in the diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-default.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-default.css index 02e4e80c11..c05d1d8ec8 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-default.css +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/ReadiumCSS-default.css @@ -1,5 +1,5 @@ /* - * Readium CSS (v. 2.0.0-beta.7) + * Readium CSS (v. 2.0.0-beta.13) * Developers: Jiminy Panoz * Copyright (c) 2017. Readium Foundation. All rights reserved. * Use of this source code is governed by a BSD-style license which is detailed in the diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-horizontal/ReadiumCSS-after.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-horizontal/ReadiumCSS-after.css index 7706672a46..a43234fc65 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-horizontal/ReadiumCSS-after.css +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-horizontal/ReadiumCSS-after.css @@ -1,5 +1,5 @@ /* - * Readium CSS (v. 2.0.0-beta.7) + * Readium CSS (v. 2.0.0-beta.13) * Developers: Jiminy Panoz * Copyright (c) 2017. Readium Foundation. All rights reserved. * Use of this source code is governed by a BSD-style license which is detailed in the @@ -56,9 +56,7 @@ min-height:100vh; padding:0 !important; margin:0 !important; - font-size:100% !important; - -webkit-text-size-adjust:none; - text-size-adjust:none; + font-size:1rem !important; box-sizing:border-box; -webkit-touch-callout:none; } @@ -324,11 +322,11 @@ body{ font-family:var(--USER__fontFamily) !important; } -:root[style*="readium-font-on"][style*="--USER__fontFamily"] *:not(code):not(var):not(kbd):not(samp){ - font-family:inherit !important; +:root[style*="readium-font-on"][style*="--USER__fontFamily"] *{ + font-family:revert !important; } -:root[style*="--USER__fontSize"] body{ +:root:not([style*="readium-deprecatedFontSize-on"])[style*="--USER__fontSize"] body{ zoom:var(--USER__fontSize) !important; } @@ -339,6 +337,10 @@ body{ } } +:root[style*="readium-deprecatedFontSize-on"][style*="--USER__fontSize"]{ + font-size:var(--USER__fontSize) !important; +} + :root[style*="--USER__lineHeight"]{ line-height:var(--USER__lineHeight) !important; } @@ -448,59 +450,114 @@ body{ filter:invert(100%) !important; } -@supports not (zoom: 1){ +:root[style*="readium-normalize-on"]{ + --USER__typeScale:1.2; +} - :root[style*="readium-normalize-on"]{ - --USER__typeScale:1.2; - } +:root[style*="readium-normalize-on"] p, +:root[style*="readium-normalize-on"] li, +:root[style*="readium-normalize-on"] div, +:root[style*="readium-normalize-on"] pre, +:root[style*="readium-normalize-on"] dd{ + font-size:1rem !important; +} - :root[style*="readium-normalize-on"] p, - :root[style*="readium-normalize-on"] li, - :root[style*="readium-normalize-on"] div, - :root[style*="readium-normalize-on"] pre, - :root[style*="readium-normalize-on"] dd{ - font-size:1rem !important; - } +:root[style*="readium-normalize-on"] h1{ + font-size:1.75rem !important; + font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important; +} - :root[style*="readium-normalize-on"] h1{ - font-size:1.75rem !important; - font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important; - } +:root[style*="readium-normalize-on"] h2{ + font-size:1.5rem !important; + font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important; +} - :root[style*="readium-normalize-on"] h2{ - font-size:1.5rem !important; - font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important; - } +:root[style*="readium-normalize-on"] h3{ + font-size:1.25rem !important; + font-size:calc(1rem * var(--USER__typeScale)) !important; +} - :root[style*="readium-normalize-on"] h3{ - font-size:1.25rem !important; - font-size:calc(1rem * var(--USER__typeScale)) !important; - } +:root[style*="readium-normalize-on"] h4, +:root[style*="readium-normalize-on"] h5, +:root[style*="readium-normalize-on"] h6{ + font-size:1rem !important; +} - :root[style*="readium-normalize-on"] h4, - :root[style*="readium-normalize-on"] h5, - :root[style*="readium-normalize-on"] h6{ - font-size:1rem !important; - } +:root[style*="readium-normalize-on"] small{ + font-size:smaller !important; +} - :root[style*="readium-normalize-on"] small{ - font-size:smaller !important; - } +:root[style*="readium-normalize-on"] sub, +:root[style*="readium-normalize-on"] sup{ + font-size:67.5% !important; +} - :root[style*="readium-normalize-on"] sub, - :root[style*="readium-normalize-on"] sup{ - font-size:67.5% !important; - } +:root[style*="readium-normalize-on"][style*="--USER__typeScale"] h1{ + font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important; +} - :root[style*="readium-normalize-on"][style*="--USER__typeScale"] h1{ - font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important; - } +:root[style*="readium-normalize-on"][style*="--USER__typeScale"] h2{ + font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important; +} - :root[style*="readium-normalize-on"][style*="--USER__typeScale"] h2{ - font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important; - } +:root[style*="readium-normalize-on"][style*="--USER__typeScale"] h3{ + font-size:calc(1rem * var(--USER__typeScale)) !important; +} - :root[style*="readium-normalize-on"][style*="--USER__typeScale"] h3{ - font-size:calc(1rem * var(--USER__typeScale)) !important; - } +:root[style*="readium-iPadOSPatch-on"] body{ + -webkit-text-size-adjust:none; +} + +:root[style*="readium-iPadOSPatch-on"] p, +:root[style*="readium-iPadOSPatch-on"] h1, +:root[style*="readium-iPadOSPatch-on"] h2, +:root[style*="readium-iPadOSPatch-on"] h3, +:root[style*="readium-iPadOSPatch-on"] h4, +:root[style*="readium-iPadOSPatch-on"] h5, +:root[style*="readium-iPadOSPatch-on"] h6, +:root[style*="readium-iPadOSPatch-on"] li, +:root[style*="readium-iPadOSPatch-on"] th, +:root[style*="readium-iPadOSPatch-on"] td, +:root[style*="readium-iPadOSPatch-on"] dt, +:root[style*="readium-iPadOSPatch-on"] dd, +:root[style*="readium-iPadOSPatch-on"] pre, +:root[style*="readium-iPadOSPatch-on"] address, +:root[style*="readium-iPadOSPatch-on"] details, +:root[style*="readium-iPadOSPatch-on"] summary, +:root[style*="readium-iPadOSPatch-on"] figcaption, +:root[style*="readium-iPadOSPatch-on"] div:not(:has(p, h1, h2, h3, h4, h5, h6, li, th, td, dt, dd, pre, address, aside, details, figcaption, summary)), +:root[style*="readium-iPadOSPatch-on"] aside:not(:has(p, h1, h2, h3, h4, h5, h6, li, th, td, dt, dd, pre, address, aside, details, figcaption, summary)){ + -webkit-text-zoom:reset; +} + +:root[style*="readium-iPadOSPatch-on"] abbr, +:root[style*="readium-iPadOSPatch-on"] b, +:root[style*="readium-iPadOSPatch-on"] bdi, +:root[style*="readium-iPadOSPatch-on"] bdo, +:root[style*="readium-iPadOSPatch-on"] cite, +:root[style*="readium-iPadOSPatch-on"] code, +:root[style*="readium-iPadOSPatch-on"] dfn, +:root[style*="readium-iPadOSPatch-on"] em, +:root[style*="readium-iPadOSPatch-on"] i, +:root[style*="readium-iPadOSPatch-on"] kbd, +:root[style*="readium-iPadOSPatch-on"] mark, +:root[style*="readium-iPadOSPatch-on"] q, +:root[style*="readium-iPadOSPatch-on"] rp, +:root[style*="readium-iPadOSPatch-on"] rt, +:root[style*="readium-iPadOSPatch-on"] ruby, +:root[style*="readium-iPadOSPatch-on"] s, +:root[style*="readium-iPadOSPatch-on"] samp, +:root[style*="readium-iPadOSPatch-on"] small, +:root[style*="readium-iPadOSPatch-on"] span, +:root[style*="readium-iPadOSPatch-on"] strong, +:root[style*="readium-iPadOSPatch-on"] sub, +:root[style*="readium-iPadOSPatch-on"] sup, +:root[style*="readium-iPadOSPatch-on"] time, +:root[style*="readium-iPadOSPatch-on"] u, +:root[style*="readium-iPadOSPatch-on"] var{ + -webkit-text-zoom:normal; +} + +:root[style*="readium-iPadOSPatch-on"] p:not(:has(b, cite, em, i, q, s, small, span, strong)):first-line{ + -webkit-text-zoom:normal; } \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-horizontal/ReadiumCSS-before.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-horizontal/ReadiumCSS-before.css index b7009eac49..9358959302 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-horizontal/ReadiumCSS-before.css +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-horizontal/ReadiumCSS-before.css @@ -1,5 +1,5 @@ /* - * Readium CSS (v. 2.0.0-beta.7) + * Readium CSS (v. 2.0.0-beta.13) * Developers: Jiminy Panoz * Copyright (c) 2017. Readium Foundation. All rights reserved. * Use of this source code is governed by a BSD-style license which is detailed in the diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-horizontal/ReadiumCSS-default.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-horizontal/ReadiumCSS-default.css index 9e84d5e5ab..c1954250a3 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-horizontal/ReadiumCSS-default.css +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-horizontal/ReadiumCSS-default.css @@ -1,5 +1,5 @@ /* - * Readium CSS (v. 2.0.0-beta.7) + * Readium CSS (v. 2.0.0-beta.13) * Developers: Jiminy Panoz * Copyright (c) 2017. Readium Foundation. All rights reserved. * Use of this source code is governed by a BSD-style license which is detailed in the diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-vertical/ReadiumCSS-after.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-vertical/ReadiumCSS-after.css index 4e89486f99..958fbca96d 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-vertical/ReadiumCSS-after.css +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-vertical/ReadiumCSS-after.css @@ -1,5 +1,5 @@ /* - * Readium CSS (v. 2.0.0-beta.7) + * Readium CSS (v. 2.0.0-beta.13) * Developers: Jiminy Panoz * Copyright (c) 2017. Readium Foundation. All rights reserved. * Use of this source code is governed by a BSD-style license which is detailed in the @@ -56,9 +56,7 @@ min-height:100vh; padding:0 !important; margin:0 !important; - font-size:100% !important; - -webkit-text-size-adjust:none; - text-size-adjust:none; + font-size:1rem !important; box-sizing:border-box; hanging-punctuation:last allow-end; @@ -312,11 +310,11 @@ body{ font-family:var(--USER__fontFamily) !important; } -:root[style*="readium-font-on"][style*="--USER__fontFamily"] *:not(code):not(var):not(kbd):not(samp){ - font-family:inherit !important; +:root[style*="readium-font-on"][style*="--USER__fontFamily"] *{ + font-family:revert !important; } -:root[style*="--USER__fontSize"] body{ +:root:not([style*="readium-deprecatedFontSize-on"])[style*="--USER__fontSize"] body{ zoom:var(--USER__fontSize) !important; } @@ -327,6 +325,10 @@ body{ } } +:root[style*="readium-deprecatedFontSize-on"][style*="--USER__fontSize"]{ + font-size:var(--USER__fontSize) !important; +} + :root[style*="--USER__lineHeight"]{ line-height:var(--USER__lineHeight) !important; } @@ -436,59 +438,114 @@ body{ filter:invert(100%) !important; } -@supports not (zoom: 1){ +:root[style*="readium-normalize-on"]{ + --USER__typeScale:1.2; +} - :root[style*="readium-normalize-on"]{ - --USER__typeScale:1.2; - } +:root[style*="readium-normalize-on"] p, +:root[style*="readium-normalize-on"] li, +:root[style*="readium-normalize-on"] div, +:root[style*="readium-normalize-on"] pre, +:root[style*="readium-normalize-on"] dd{ + font-size:1rem !important; +} - :root[style*="readium-normalize-on"] p, - :root[style*="readium-normalize-on"] li, - :root[style*="readium-normalize-on"] div, - :root[style*="readium-normalize-on"] pre, - :root[style*="readium-normalize-on"] dd{ - font-size:1rem !important; - } +:root[style*="readium-normalize-on"] h1{ + font-size:1.75rem !important; + font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important; +} - :root[style*="readium-normalize-on"] h1{ - font-size:1.75rem !important; - font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important; - } +:root[style*="readium-normalize-on"] h2{ + font-size:1.5rem !important; + font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important; +} - :root[style*="readium-normalize-on"] h2{ - font-size:1.5rem !important; - font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important; - } +:root[style*="readium-normalize-on"] h3{ + font-size:1.25rem !important; + font-size:calc(1rem * var(--USER__typeScale)) !important; +} - :root[style*="readium-normalize-on"] h3{ - font-size:1.25rem !important; - font-size:calc(1rem * var(--USER__typeScale)) !important; - } +:root[style*="readium-normalize-on"] h4, +:root[style*="readium-normalize-on"] h5, +:root[style*="readium-normalize-on"] h6{ + font-size:1rem !important; +} - :root[style*="readium-normalize-on"] h4, - :root[style*="readium-normalize-on"] h5, - :root[style*="readium-normalize-on"] h6{ - font-size:1rem !important; - } +:root[style*="readium-normalize-on"] small{ + font-size:smaller !important; +} - :root[style*="readium-normalize-on"] small{ - font-size:smaller !important; - } +:root[style*="readium-normalize-on"] sub, +:root[style*="readium-normalize-on"] sup{ + font-size:67.5% !important; +} - :root[style*="readium-normalize-on"] sub, - :root[style*="readium-normalize-on"] sup{ - font-size:67.5% !important; - } +:root[style*="readium-normalize-on"][style*="--USER__typeScale"] h1{ + font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important; +} - :root[style*="readium-normalize-on"][style*="--USER__typeScale"] h1{ - font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important; - } +:root[style*="readium-normalize-on"][style*="--USER__typeScale"] h2{ + font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important; +} - :root[style*="readium-normalize-on"][style*="--USER__typeScale"] h2{ - font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important; - } +:root[style*="readium-normalize-on"][style*="--USER__typeScale"] h3{ + font-size:calc(1rem * var(--USER__typeScale)) !important; +} - :root[style*="readium-normalize-on"][style*="--USER__typeScale"] h3{ - font-size:calc(1rem * var(--USER__typeScale)) !important; - } +:root[style*="readium-iPadOSPatch-on"] body{ + -webkit-text-size-adjust:none; +} + +:root[style*="readium-iPadOSPatch-on"] p, +:root[style*="readium-iPadOSPatch-on"] h1, +:root[style*="readium-iPadOSPatch-on"] h2, +:root[style*="readium-iPadOSPatch-on"] h3, +:root[style*="readium-iPadOSPatch-on"] h4, +:root[style*="readium-iPadOSPatch-on"] h5, +:root[style*="readium-iPadOSPatch-on"] h6, +:root[style*="readium-iPadOSPatch-on"] li, +:root[style*="readium-iPadOSPatch-on"] th, +:root[style*="readium-iPadOSPatch-on"] td, +:root[style*="readium-iPadOSPatch-on"] dt, +:root[style*="readium-iPadOSPatch-on"] dd, +:root[style*="readium-iPadOSPatch-on"] pre, +:root[style*="readium-iPadOSPatch-on"] address, +:root[style*="readium-iPadOSPatch-on"] details, +:root[style*="readium-iPadOSPatch-on"] summary, +:root[style*="readium-iPadOSPatch-on"] figcaption, +:root[style*="readium-iPadOSPatch-on"] div:not(:has(p, h1, h2, h3, h4, h5, h6, li, th, td, dt, dd, pre, address, aside, details, figcaption, summary)), +:root[style*="readium-iPadOSPatch-on"] aside:not(:has(p, h1, h2, h3, h4, h5, h6, li, th, td, dt, dd, pre, address, aside, details, figcaption, summary)){ + -webkit-text-zoom:reset; +} + +:root[style*="readium-iPadOSPatch-on"] abbr, +:root[style*="readium-iPadOSPatch-on"] b, +:root[style*="readium-iPadOSPatch-on"] bdi, +:root[style*="readium-iPadOSPatch-on"] bdo, +:root[style*="readium-iPadOSPatch-on"] cite, +:root[style*="readium-iPadOSPatch-on"] code, +:root[style*="readium-iPadOSPatch-on"] dfn, +:root[style*="readium-iPadOSPatch-on"] em, +:root[style*="readium-iPadOSPatch-on"] i, +:root[style*="readium-iPadOSPatch-on"] kbd, +:root[style*="readium-iPadOSPatch-on"] mark, +:root[style*="readium-iPadOSPatch-on"] q, +:root[style*="readium-iPadOSPatch-on"] rp, +:root[style*="readium-iPadOSPatch-on"] rt, +:root[style*="readium-iPadOSPatch-on"] ruby, +:root[style*="readium-iPadOSPatch-on"] s, +:root[style*="readium-iPadOSPatch-on"] samp, +:root[style*="readium-iPadOSPatch-on"] small, +:root[style*="readium-iPadOSPatch-on"] span, +:root[style*="readium-iPadOSPatch-on"] strong, +:root[style*="readium-iPadOSPatch-on"] sub, +:root[style*="readium-iPadOSPatch-on"] sup, +:root[style*="readium-iPadOSPatch-on"] time, +:root[style*="readium-iPadOSPatch-on"] u, +:root[style*="readium-iPadOSPatch-on"] var{ + -webkit-text-zoom:normal; +} + +:root[style*="readium-iPadOSPatch-on"] p:not(:has(b, cite, em, i, q, s, small, span, strong)):first-line{ + -webkit-text-zoom:normal; } \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-vertical/ReadiumCSS-before.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-vertical/ReadiumCSS-before.css index 259f835576..0072752b1a 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-vertical/ReadiumCSS-before.css +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-vertical/ReadiumCSS-before.css @@ -1,5 +1,5 @@ /* - * Readium CSS (v. 2.0.0-beta.7) + * Readium CSS (v. 2.0.0-beta.13) * Developers: Jiminy Panoz * Copyright (c) 2017. Readium Foundation. All rights reserved. * Use of this source code is governed by a BSD-style license which is detailed in the @@ -377,7 +377,7 @@ ruby > rt, ruby > rp{ --RS__boxSizingTable:border-box; } -a, h1, h2, h3, h4, h5, h6{ +a, a span, span a, h1, h2, h3, h4, h5, h6{ word-wrap:break-word; } diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-vertical/ReadiumCSS-default.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-vertical/ReadiumCSS-default.css index 4ee9de4600..08e7b95fd6 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-vertical/ReadiumCSS-default.css +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-vertical/ReadiumCSS-default.css @@ -1,5 +1,5 @@ /* - * Readium CSS (v. 2.0.0-beta.7) + * Readium CSS (v. 2.0.0-beta.13) * Developers: Jiminy Panoz * Copyright (c) 2017. Readium Foundation. All rights reserved. * Use of this source code is governed by a BSD-style license which is detailed in the diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/rtl/ReadiumCSS-after.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/rtl/ReadiumCSS-after.css index 1f37e37a9a..2d9b79405c 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/rtl/ReadiumCSS-after.css +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/rtl/ReadiumCSS-after.css @@ -1,5 +1,5 @@ /* - * Readium CSS (v. 2.0.0-beta.7) + * Readium CSS (v. 2.0.0-beta.13) * Developers: Jiminy Panoz * Copyright (c) 2017. Readium Foundation. All rights reserved. * Use of this source code is governed by a BSD-style license which is detailed in the @@ -56,9 +56,7 @@ min-height:100vh; padding:0 !important; margin:0 !important; - font-size:100% !important; - -webkit-text-size-adjust:none; - text-size-adjust:none; + font-size:1rem !important; box-sizing:border-box; -webkit-touch-callout:none; } @@ -338,11 +336,11 @@ body{ font-family:var(--USER__fontFamily) !important; } -:root[style*="readium-font-on"][style*="--USER__fontFamily"] *:not(code):not(var):not(kbd):not(samp){ - font-family:inherit !important; +:root[style*="readium-font-on"][style*="--USER__fontFamily"] *{ + font-family:revert !important; } -:root[style*="--USER__fontSize"] body{ +:root:not([style*="readium-deprecatedFontSize-on"])[style*="--USER__fontSize"] body{ zoom:var(--USER__fontSize) !important; } @@ -353,6 +351,10 @@ body{ } } +:root[style*="readium-deprecatedFontSize-on"][style*="--USER__fontSize"]{ + font-size:var(--USER__fontSize) !important; +} + :root[style*="--USER__lineHeight"]{ line-height:var(--USER__lineHeight) !important; } @@ -473,59 +475,114 @@ body{ filter:invert(100%) !important; } -@supports not (zoom: 1){ +:root[style*="readium-normalize-on"]{ + --USER__typeScale:1.2; +} - :root[style*="readium-normalize-on"]{ - --USER__typeScale:1.2; - } +:root[style*="readium-normalize-on"] p, +:root[style*="readium-normalize-on"] li, +:root[style*="readium-normalize-on"] div, +:root[style*="readium-normalize-on"] pre, +:root[style*="readium-normalize-on"] dd{ + font-size:1rem !important; +} - :root[style*="readium-normalize-on"] p, - :root[style*="readium-normalize-on"] li, - :root[style*="readium-normalize-on"] div, - :root[style*="readium-normalize-on"] pre, - :root[style*="readium-normalize-on"] dd{ - font-size:1rem !important; - } +:root[style*="readium-normalize-on"] h1{ + font-size:1.75rem !important; + font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important; +} - :root[style*="readium-normalize-on"] h1{ - font-size:1.75rem !important; - font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important; - } +:root[style*="readium-normalize-on"] h2{ + font-size:1.5rem !important; + font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important; +} - :root[style*="readium-normalize-on"] h2{ - font-size:1.5rem !important; - font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important; - } +:root[style*="readium-normalize-on"] h3{ + font-size:1.25rem !important; + font-size:calc(1rem * var(--USER__typeScale)) !important; +} - :root[style*="readium-normalize-on"] h3{ - font-size:1.25rem !important; - font-size:calc(1rem * var(--USER__typeScale)) !important; - } +:root[style*="readium-normalize-on"] h4, +:root[style*="readium-normalize-on"] h5, +:root[style*="readium-normalize-on"] h6{ + font-size:1rem !important; +} - :root[style*="readium-normalize-on"] h4, - :root[style*="readium-normalize-on"] h5, - :root[style*="readium-normalize-on"] h6{ - font-size:1rem !important; - } +:root[style*="readium-normalize-on"] small{ + font-size:smaller !important; +} - :root[style*="readium-normalize-on"] small{ - font-size:smaller !important; - } +:root[style*="readium-normalize-on"] sub, +:root[style*="readium-normalize-on"] sup{ + font-size:67.5% !important; +} - :root[style*="readium-normalize-on"] sub, - :root[style*="readium-normalize-on"] sup{ - font-size:67.5% !important; - } +:root[style*="readium-normalize-on"][style*="--USER__typeScale"] h1{ + font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important; +} - :root[style*="readium-normalize-on"][style*="--USER__typeScale"] h1{ - font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important; - } +:root[style*="readium-normalize-on"][style*="--USER__typeScale"] h2{ + font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important; +} - :root[style*="readium-normalize-on"][style*="--USER__typeScale"] h2{ - font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important; - } +:root[style*="readium-normalize-on"][style*="--USER__typeScale"] h3{ + font-size:calc(1rem * var(--USER__typeScale)) !important; +} - :root[style*="readium-normalize-on"][style*="--USER__typeScale"] h3{ - font-size:calc(1rem * var(--USER__typeScale)) !important; - } +:root[style*="readium-iPadOSPatch-on"] body{ + -webkit-text-size-adjust:none; +} + +:root[style*="readium-iPadOSPatch-on"] p, +:root[style*="readium-iPadOSPatch-on"] h1, +:root[style*="readium-iPadOSPatch-on"] h2, +:root[style*="readium-iPadOSPatch-on"] h3, +:root[style*="readium-iPadOSPatch-on"] h4, +:root[style*="readium-iPadOSPatch-on"] h5, +:root[style*="readium-iPadOSPatch-on"] h6, +:root[style*="readium-iPadOSPatch-on"] li, +:root[style*="readium-iPadOSPatch-on"] th, +:root[style*="readium-iPadOSPatch-on"] td, +:root[style*="readium-iPadOSPatch-on"] dt, +:root[style*="readium-iPadOSPatch-on"] dd, +:root[style*="readium-iPadOSPatch-on"] pre, +:root[style*="readium-iPadOSPatch-on"] address, +:root[style*="readium-iPadOSPatch-on"] details, +:root[style*="readium-iPadOSPatch-on"] summary, +:root[style*="readium-iPadOSPatch-on"] figcaption, +:root[style*="readium-iPadOSPatch-on"] div:not(:has(p, h1, h2, h3, h4, h5, h6, li, th, td, dt, dd, pre, address, aside, details, figcaption, summary)), +:root[style*="readium-iPadOSPatch-on"] aside:not(:has(p, h1, h2, h3, h4, h5, h6, li, th, td, dt, dd, pre, address, aside, details, figcaption, summary)){ + -webkit-text-zoom:reset; +} + +:root[style*="readium-iPadOSPatch-on"] abbr, +:root[style*="readium-iPadOSPatch-on"] b, +:root[style*="readium-iPadOSPatch-on"] bdi, +:root[style*="readium-iPadOSPatch-on"] bdo, +:root[style*="readium-iPadOSPatch-on"] cite, +:root[style*="readium-iPadOSPatch-on"] code, +:root[style*="readium-iPadOSPatch-on"] dfn, +:root[style*="readium-iPadOSPatch-on"] em, +:root[style*="readium-iPadOSPatch-on"] i, +:root[style*="readium-iPadOSPatch-on"] kbd, +:root[style*="readium-iPadOSPatch-on"] mark, +:root[style*="readium-iPadOSPatch-on"] q, +:root[style*="readium-iPadOSPatch-on"] rp, +:root[style*="readium-iPadOSPatch-on"] rt, +:root[style*="readium-iPadOSPatch-on"] ruby, +:root[style*="readium-iPadOSPatch-on"] s, +:root[style*="readium-iPadOSPatch-on"] samp, +:root[style*="readium-iPadOSPatch-on"] small, +:root[style*="readium-iPadOSPatch-on"] span, +:root[style*="readium-iPadOSPatch-on"] strong, +:root[style*="readium-iPadOSPatch-on"] sub, +:root[style*="readium-iPadOSPatch-on"] sup, +:root[style*="readium-iPadOSPatch-on"] time, +:root[style*="readium-iPadOSPatch-on"] u, +:root[style*="readium-iPadOSPatch-on"] var{ + -webkit-text-zoom:normal; +} + +:root[style*="readium-iPadOSPatch-on"] p:not(:has(b, cite, em, i, q, s, small, span, strong)):first-line{ + -webkit-text-zoom:normal; } \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/rtl/ReadiumCSS-before.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/rtl/ReadiumCSS-before.css index b7009eac49..9358959302 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/rtl/ReadiumCSS-before.css +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/rtl/ReadiumCSS-before.css @@ -1,5 +1,5 @@ /* - * Readium CSS (v. 2.0.0-beta.7) + * Readium CSS (v. 2.0.0-beta.13) * Developers: Jiminy Panoz * Copyright (c) 2017. Readium Foundation. All rights reserved. * Use of this source code is governed by a BSD-style license which is detailed in the diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/rtl/ReadiumCSS-default.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/rtl/ReadiumCSS-default.css index a77057515e..c54777b89b 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/rtl/ReadiumCSS-default.css +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/rtl/ReadiumCSS-default.css @@ -1,5 +1,5 @@ /* - * Readium CSS (v. 2.0.0-beta.7) + * Readium CSS (v. 2.0.0-beta.13) * Developers: Jiminy Panoz * Copyright (c) 2017. Readium Foundation. All rights reserved. * Use of this source code is governed by a BSD-style license which is detailed in the diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCssInjector.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCssInjector.kt index f39d451b59..6ae2571efb 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCssInjector.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCssInjector.kt @@ -350,9 +350,10 @@ internal fun ReadiumCssInjector.withSettings(settings: ReflowableWebSettings): R invertImages = imageFilter == ImageFilter.INVERT, textColor = textColor?.toCss(), backgroundColor = backgroundColor?.toCss(), - fontOverride = (fontFamily != null || textNormalization), + fontOverride = true, // we don't need this guard, fontFamily = fontFamily?.toCss(), fontSize = Length.Percent(fontSize), + fontWeight = fontWeight?.let { (FontWeight.NORMAL.value * it).toInt().coerceIn(1, 1000) }, textAlign = when (textAlign) { TextAlign.JUSTIFY -> CssTextAlign.JUSTIFY TextAlign.LEFT -> CssTextAlign.LEFT @@ -369,11 +370,13 @@ internal fun ReadiumCssInjector.withSettings(settings: ReflowableWebSettings): R ligatures = ligatures?.let { if (it) Ligatures.COMMON else Ligatures.NONE }, a11yNormalize = textNormalization, overrides = mapOf( - "font-weight" to - if (fontWeight != null) { - (FontWeight.NORMAL.value * fontWeight).toInt().coerceIn(1, 1000).toString() - } else { - "" + "writing-mode" to // See https://github.com/readium/css/issues/180 + when (verticalText) { + false -> "horizontal-tb" + true -> when (readingProgression) { + ReadingProgression.LTR -> "vertical-lr" + ReadingProgression.RTL -> "vertical-rl" + } } ) ) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCssProperties.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCssProperties.kt index fad615b611..d944e39238 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCssProperties.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCssProperties.kt @@ -58,27 +58,24 @@ public interface ReadiumCssProperties : Cssable { * remove the required flag. Requires: fontOverride * @param fontSize Increasing and decreasing the root font-size. It will serve as a reference * for the cascade. To reset, remove the required flag. + * @param fontWeight Increasing and decreasing the text boldness. Requires: fontOverride * @param lineLength Increasing and decreasing the line length. * @param textAlign The alignment (text-align) the user prefers. It impacts body, li, and p - * which are not children of blockquote and figcaption. Requires: advancedSettings + * which are not children of blockquote and figcaption. * @param lineHeight Increasing and decreasing leading (line-height). It impacts body, p, li and * div. Recommended values: a range from 1 to 2. Increments are left to implementers’ judgment. - * Requires: advancedSettings * @param paraSpacing The vertical margins (margin-top and margin-bottom) for paragraphs. * Recommended values: a range from 0 to 2rem. Increments are left to implementers’ - * judgment. Requires: advancedSettings = true + * judgment. * @param paraIndent The text-indent for paragraphs. Recommended values: a range from 0 to 3rem. * Increments are left to implementers’ judgment. Requires: advancedSettings * @param wordSpacing Increasing space between words (word-spacing, related to a11y). * Recommended values: a range from 0 to 1rem. Increments are left to implementers’ judgment. - * Requires: advancedSettings * @param letterSpacing Increasing space between letters (letter-spacing, related to a11y). * Recommended values: a range from 0 to 0.5rem. Increments are left to implementers’ - * judgment. Requires: advancedSettings + * judgment. * @param bodyHyphens Enabling and disabling hyphenation. It impacts body, p, li, div and dd. - * Requires: advancedSettings * @param ligatures Enabling and disabling ligatures in Arabic (related to a11y). - * Requires: advancedSettings * @param a11yNormalize It impacts font style, weight and variant, text decoration, super and * subscripts. Requires: fontOverride */ @@ -103,6 +100,7 @@ public data class UserProperties( val fontOverride: Boolean? = null, val fontFamily: List? = null, val fontSize: Length? = null, + val fontWeight: Int? = null, val lineLength: Length? = null, // Advanced settings @@ -141,6 +139,7 @@ public data class UserProperties( putCss("--USER__fontOverride", flag("font", fontOverride)) putCss("--USER__fontFamily", fontFamily) putCss("--USER__fontSize", fontSize) + putCss("--USER__fontWeight", fontWeight) putCss("--USER__lineLength", lineLength) putCss("--USER__textAlign", textAlign) lineHeight diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesEditor.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesEditor.kt index ab613f8184..85165ee1ee 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesEditor.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesEditor.kt @@ -167,15 +167,13 @@ public class ReflowableWebPreferencesEditor internal constructor( ) /** - * Filter applied to images in dark theme. - * - * Only effective when the [theme] is set to [Theme.DARK]. + * Filter applied to images. */ public val imageFilter: EnumPreference = EnumPreferenceDelegate( getValue = { preferences.imageFilter }, getEffectiveValue = { state.settings.imageFilter }, - getIsEffective = { state.settings.theme == Theme.DARK }, + getIsEffective = { true }, updateValue = { value -> updateValues { it.copy(imageFilter = value) } }, supportedValues = listOf(ImageFilter.DARKEN, ImageFilter.INVERT) ) From 1b594c39996d4018e091373657e40fd0088f70c9 Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Fri, 30 May 2025 14:02:24 +0200 Subject: [PATCH 54/88] Make Readium CSS stuff internal --- .../readium/navigator/web/css/ReadiumCssProperties.kt | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCssProperties.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCssProperties.kt index d944e39238..246af2982a 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCssProperties.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/css/ReadiumCssProperties.kt @@ -17,9 +17,8 @@ import org.readium.r2.shared.util.Either /** * Holds a set of Readium CSS properties applied together. */ -@ExperimentalReadiumApi -public interface ReadiumCssProperties : Cssable { - public fun toCssProperties(): Map +internal interface ReadiumCssProperties : Cssable { + fun toCssProperties(): Map override fun toCss(): String? { val props = toCssProperties() @@ -79,8 +78,7 @@ public interface ReadiumCssProperties : Cssable { * @param a11yNormalize It impacts font style, weight and variant, text decoration, super and * subscripts. Requires: fontOverride */ -@ExperimentalReadiumApi -public data class UserProperties( +internal data class UserProperties( // View mode val view: View? = null, @@ -213,8 +211,7 @@ public data class UserProperties( * @param codeFontFamily The typeface for code snippets. * The value can be another variable e.g. var(-RS__monospaceTf). */ -@ExperimentalReadiumApi -public data class RsProperties( +internal data class RsProperties( // Pagination val colWidth: Length? = null, val colCount: Int? = null, From 245790e21f469d6a7fdfdb999a391175c00980f8 Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Fri, 30 May 2025 14:23:35 +0200 Subject: [PATCH 55/88] Fix multi columns and allow more than two columns --- .../demo/preferences/UserPreferences.kt | 7 +- .../src/index-reflowable-injectable.ts | 42 +++++++++--- .../web/scripts/src/util/columns.ts | 68 +++++++++++-------- .../generated/reflowable-injectable-script.js | 2 +- .../reflowable-injectable-script.js.map | 2 +- .../ReflowableWebPreferencesEditor.kt | 41 +++++------ .../web/reflowable/ReflowableResource.kt | 4 +- .../web/webview/ComposableWebView.kt | 1 - 8 files changed, 98 insertions(+), 69 deletions(-) diff --git a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/preferences/UserPreferences.kt b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/preferences/UserPreferences.kt index bbbd67976f..7ca40a1030 100644 --- a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/preferences/UserPreferences.kt +++ b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/preferences/UserPreferences.kt @@ -197,7 +197,7 @@ private fun FixedLayoutUserPreferences( @Composable private fun ReflowableUserPreferences( backgroundColor: Preference? = null, - columnCount: EnumPreference? = null, + columnCount: RangePreference? = null, fontFamily: Preference? = null, fontSize: RangePreference? = null, fontWeight: RangePreference? = null, @@ -253,10 +253,9 @@ private fun ReflowableUserPreferences( } if (columnCount != null) { - ButtonGroupItem( + StepperItem( title = "Columns", - preference = columnCount, - formatValue = Int::toString + preference = columnCount ) } diff --git a/readium/navigators/web/scripts/src/index-reflowable-injectable.ts b/readium/navigators/web/scripts/src/index-reflowable-injectable.ts index 8efec31e77..5fb1192086 100644 --- a/readium/navigators/web/scripts/src/index-reflowable-injectable.ts +++ b/readium/navigators/web/scripts/src/index-reflowable-injectable.ts @@ -32,29 +32,49 @@ new GesturesDetector(window, bridgeListener) Window.prototype.readiumcss = new CssBridge(window.document) window.documentState.onScriptsLoaded() + +document.addEventListener("DOMContentLoaded", () => { + // Setups the `viewport` meta tag to disable overview. + const meta = document.createElement("meta") + meta.setAttribute("name", "viewport") + meta.setAttribute( + "content", + "width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, shrink-to-fit=no" + ) + document.head.appendChild(meta) +}) + // eslint-disable-next-line @typescript-eslint/no-unused-vars window.addEventListener("load", (event) => { let documentLoadedFired = false const observer = new ResizeObserver(() => { + let colCountFixed = false + requestAnimationFrame(() => { - if (appendVirtualColumnIfNeeded(window)) { - // Column has been added or removed, wait for next resize callback. + const scrollingElement = window.document.scrollingElement + const scrollingElementEmpty = + scrollingElement == null || + (scrollingElement.scrollHeight == 0 && + scrollingElement.scrollWidth == 0) + + if (!documentLoadedFired && scrollingElementEmpty) { + // Document is not sized yet return } - if (!documentLoadedFired) { - const scrollingElement = window.document.scrollingElement - - if ( - scrollingElement != null && - scrollingElement.scrollHeight == 0 && - scrollingElement.scrollWidth == 0 - ) { - // Document is not sized yet + if (!colCountFixed && !scrollingElementEmpty) { + const colChanged = appendVirtualColumnIfNeeded(window) + colCountFixed = true + if (colChanged) { + // Column number has changed, wait for next resize callback. return } + } + colCountFixed = false + + if (!documentLoadedFired) { window.documentState.onDocumentLoadedAndSized() documentLoadedFired = true } else { diff --git a/readium/navigators/web/scripts/src/util/columns.ts b/readium/navigators/web/scripts/src/util/columns.ts index cdeb1915ac..a116b346d0 100644 --- a/readium/navigators/web/scripts/src/util/columns.ts +++ b/readium/navigators/web/scripts/src/util/columns.ts @@ -1,42 +1,50 @@ /** * In paginated mode, the width of each resource must be a multiple of the viewport size * for proper snapping. This may not be automatically the case if the number of - * columns in the resource is not a multiple of the number of columns fitting in the viewport. + * columns in the resource is not a multiple of the number of columns displayed in the viewport. * To fix this, we insert a blank virtual column at the end of the resource. * - * Returns if a virtual column has been added or removed. + * Returns if the column number has changed. */ export function appendVirtualColumnIfNeeded(wnd: Window): boolean { - // FIXME: what about scroll mode? - const id = "readium-virtual-page" - let virtualCol = wnd.document.getElementById(id) - if (getColumnCountPerScreen(wnd) !== 2) { - if (virtualCol) { - virtualCol.remove() - return true - } else { - return false - } - } else { - const documentWidth = wnd.document.scrollingElement!.scrollWidth - const colCount = documentWidth / wnd.innerWidth - const hasOddColCount = (Math.round(colCount * 2) / 2) % 1 > 0.1 - if (hasOddColCount) { - if (virtualCol) { - virtualCol.remove() - } else { - virtualCol = wnd.document.createElement("div") - virtualCol.setAttribute("id", id) - virtualCol.dataset.readium = "true" - virtualCol.style.breakBefore = "column" - virtualCol.innerHTML = "​" // zero-width space - wnd.document.body.appendChild(virtualCol) - } - return true - } else { - return false + const virtualCols = wnd.document.querySelectorAll( + "div[id^='readium-virtual-page']" + ) + const virtualColsCount = virtualCols.length + + // Remove first so that we don’t end up with an incorrect scrollWidth + // Even when removing their width we risk having an incorrect scrollWidth + // so removing them entirely is the most robust solution + for (const virtualCol of virtualCols) { + virtualCol.remove() + } + + const colCountPerScreen = getColumnCountPerScreen(wnd) + const documentWidth = wnd.document.scrollingElement!.scrollWidth + const windowWidth = wnd.visualViewport!.width + + const totalColCount = Math.round( + (documentWidth / windowWidth) * colCountPerScreen + ) + const lonelyColCount = totalColCount % colCountPerScreen + + const needed = + colCountPerScreen === 1 || lonelyColCount === 0 + ? 0 + : colCountPerScreen - lonelyColCount + + if (needed > 0) { + for (let i = 0; i < needed; i++) { + const virtualCol = wnd.document.createElement("div") + virtualCol.setAttribute("id", `readium-virtual-page-${i}`) + virtualCol.dataset.readium = "true" + virtualCol.style.breakBefore = "column" + virtualCol.innerHTML = "​" // zero-width space + wnd.document.body.appendChild(virtualCol) } } + + return virtualColsCount != needed } function getColumnCountPerScreen(wnd: Window) { diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js index df2e9c5ab5..3b5a160497 100644 --- a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/reflowable-injectable-script.js @@ -1,2 +1,2 @@ -!function(){"use strict";const e=new class{constructor(e){this.gesturesBridge=e}onTap(e){const t={x:(e.clientX-visualViewport.offsetLeft)*visualViewport.scale,y:(e.clientY-visualViewport.offsetTop)*visualViewport.scale},n=JSON.stringify(t);this.gesturesBridge.onTap(n)}onLinkActivated(e,t){this.gesturesBridge.onLinkActivated(e,t)}}(window.gestures);new class{constructor(e,t){this.window=e,this.listener=t,document.addEventListener("click",(e=>{this.onClick(e)}),!1)}onClick(e){if(e.defaultPrevented)return;const t=this.window.getSelection();if(t&&"Range"==t.type)return;let n;n=e.target instanceof HTMLElement?this.nearestInteractiveElement(e.target):null,n?n instanceof HTMLAnchorElement&&this.listener.onLinkActivated(n.href,n.outerHTML):this.listener.onTap(e),e.stopPropagation(),e.preventDefault()}nearestInteractiveElement(e){return null==e?null:-1!=["a","audio","button","canvas","details","input","label","option","select","submit","textarea","video"].indexOf(e.nodeName.toLowerCase())||e.hasAttribute("contenteditable")&&"false"!=e.getAttribute("contenteditable").toLowerCase()?e:e.parentElement?this.nearestInteractiveElement(e.parentElement):null}}(window,e),Window.prototype.readiumcss=new class{constructor(e){this.document=e}setProperties(e){for(const[t,n]of e)this.setProperty(t,n)}setProperty(e,t){null===t||""===t?this.removeProperty(e):document.documentElement.style.setProperty(e,t,"important")}removeProperty(e){document.documentElement.style.removeProperty(e)}}(window.document),window.documentState.onScriptsLoaded(),window.addEventListener("load",(e=>{let t=!1;new ResizeObserver((()=>{requestAnimationFrame((()=>{if(!function(e){const t="readium-virtual-page";let n=e.document.getElementById(t);if(2!==function(e){return parseInt(e.getComputedStyle(e.document.documentElement).getPropertyValue("column-count"))}(e))return!!n&&(n.remove(),!0);{const o=e.document.scrollingElement.scrollWidth/e.innerWidth;return!!(Math.round(2*o)/2%1>.1)&&(n?n.remove():(n=e.document.createElement("div"),n.setAttribute("id",t),n.dataset.readium="true",n.style.breakBefore="column",n.innerHTML="​",e.document.body.appendChild(n)),!0)}}(window))if(t)window.documentState.onDocumentResized();else{const e=window.document.scrollingElement;if(null!=e&&0==e.scrollHeight&&0==e.scrollWidth)return;window.documentState.onDocumentLoadedAndSized(),t=!0}}))})).observe(document.body)}))}(); +!function(){"use strict";const e=new class{constructor(e){this.gesturesBridge=e}onTap(e){const t={x:(e.clientX-visualViewport.offsetLeft)*visualViewport.scale,y:(e.clientY-visualViewport.offsetTop)*visualViewport.scale},n=JSON.stringify(t);this.gesturesBridge.onTap(n)}onLinkActivated(e,t){this.gesturesBridge.onLinkActivated(e,t)}}(window.gestures);new class{constructor(e,t){this.window=e,this.listener=t,document.addEventListener("click",(e=>{this.onClick(e)}),!1)}onClick(e){if(e.defaultPrevented)return;const t=this.window.getSelection();if(t&&"Range"==t.type)return;let n;n=e.target instanceof HTMLElement?this.nearestInteractiveElement(e.target):null,n?n instanceof HTMLAnchorElement&&this.listener.onLinkActivated(n.href,n.outerHTML):this.listener.onTap(e),e.stopPropagation(),e.preventDefault()}nearestInteractiveElement(e){return null==e?null:-1!=["a","audio","button","canvas","details","input","label","option","select","submit","textarea","video"].indexOf(e.nodeName.toLowerCase())||e.hasAttribute("contenteditable")&&"false"!=e.getAttribute("contenteditable").toLowerCase()?e:e.parentElement?this.nearestInteractiveElement(e.parentElement):null}}(window,e),Window.prototype.readiumcss=new class{constructor(e){this.document=e}setProperties(e){for(const[t,n]of e)this.setProperty(t,n)}setProperty(e,t){null===t||""===t?this.removeProperty(e):document.documentElement.style.setProperty(e,t,"important")}removeProperty(e){document.documentElement.style.removeProperty(e)}}(window.document),window.documentState.onScriptsLoaded(),document.addEventListener("DOMContentLoaded",(()=>{const e=document.createElement("meta");e.setAttribute("name","viewport"),e.setAttribute("content","width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, shrink-to-fit=no"),document.head.appendChild(e)})),window.addEventListener("load",(e=>{let t=!1;new ResizeObserver((()=>{let e=!1;requestAnimationFrame((()=>{const n=window.document.scrollingElement,o=null==n||0==n.scrollHeight&&0==n.scrollWidth;if(t||!o){if(!e&&!o){const t=function(e){const t=e.document.querySelectorAll("div[id^='readium-virtual-page']"),n=t.length;for(const e of t)e.remove();const o=function(e){return parseInt(e.getComputedStyle(e.document.documentElement).getPropertyValue("column-count"))}(e),i=e.document.scrollingElement.scrollWidth,r=e.visualViewport.width,s=Math.round(i/r*o)%o,l=1===o||0===s?0:o-s;if(l>0)for(let t=0;t {\n let documentLoadedFired = false;\n const observer = new ResizeObserver(() => {\n requestAnimationFrame(() => {\n if (appendVirtualColumnIfNeeded(window)) {\n // Column has been added or removed, wait for next resize callback.\n return;\n }\n if (!documentLoadedFired) {\n const scrollingElement = window.document.scrollingElement;\n if (scrollingElement != null &&\n scrollingElement.scrollHeight == 0 &&\n scrollingElement.scrollWidth == 0) {\n // Document is not sized yet\n return;\n }\n window.documentState.onDocumentLoadedAndSized();\n documentLoadedFired = true;\n }\n else {\n window.documentState.onDocumentResized();\n }\n });\n });\n observer.observe(document.body);\n});\n","export class ReflowableListenerAdapter {\n constructor(gesturesBridge) {\n this.gesturesBridge = gesturesBridge;\n }\n onTap(event) {\n const tapEvent = {\n x: (event.clientX - visualViewport.offsetLeft) * visualViewport.scale,\n y: (event.clientY - visualViewport.offsetTop) * visualViewport.scale,\n };\n const stringEvent = JSON.stringify(tapEvent);\n this.gesturesBridge.onTap(stringEvent);\n }\n onLinkActivated(href, outerHtml) {\n this.gesturesBridge.onLinkActivated(href, outerHtml);\n }\n}\nexport class FixedListenerAdapter {\n constructor(window, gesturesApi, documentApi) {\n this.window = window;\n this.gesturesApi = gesturesApi;\n this.documentApi = documentApi;\n this.resizeObserverAdded = false;\n this.documentLoadedFired = false;\n }\n onTap(event) {\n this.gesturesApi.onTap(JSON.stringify(event));\n }\n onLinkActivated(href, outerHtml) {\n this.gesturesApi.onLinkActivated(href, outerHtml);\n }\n onLayout() {\n if (!this.resizeObserverAdded) {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const observer = new ResizeObserver(() => {\n requestAnimationFrame(() => {\n const scrollingElement = this.window.document.scrollingElement;\n if (!this.documentLoadedFired &&\n (scrollingElement == null ||\n scrollingElement.scrollHeight > 0 ||\n scrollingElement.scrollWidth > 0)) {\n this.documentApi.onDocumentLoadedAndSized();\n this.documentLoadedFired = true;\n }\n else {\n this.documentApi.onDocumentResized();\n }\n });\n });\n observer.observe(this.window.document.body);\n }\n this.resizeObserverAdded = true;\n }\n}\n","export class GesturesDetector {\n constructor(window, listener) {\n this.window = window;\n this.listener = listener;\n document.addEventListener(\"click\", (event) => {\n this.onClick(event);\n }, false);\n }\n onClick(event) {\n if (event.defaultPrevented) {\n return;\n }\n const selection = this.window.getSelection();\n if (selection && selection.type == \"Range\") {\n // There's an on-going selection, the tap will dismiss it so we don't forward it.\n // selection.type might be None (collapsed) or Caret with a collapsed range\n // when there is not true selection.\n return;\n }\n let nearestElement;\n if (event.target instanceof HTMLElement) {\n nearestElement = this.nearestInteractiveElement(event.target);\n }\n else {\n nearestElement = null;\n }\n if (nearestElement) {\n if (nearestElement instanceof HTMLAnchorElement) {\n this.listener.onLinkActivated(nearestElement.href, nearestElement.outerHTML);\n }\n }\n else {\n this.listener.onTap(event);\n }\n event.stopPropagation();\n event.preventDefault();\n }\n // See. https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling\n nearestInteractiveElement(element) {\n if (element == null) {\n return null;\n }\n const interactiveTags = [\n \"a\",\n \"audio\",\n \"button\",\n \"canvas\",\n \"details\",\n \"input\",\n \"label\",\n \"option\",\n \"select\",\n \"submit\",\n \"textarea\",\n \"video\",\n ];\n if (interactiveTags.indexOf(element.nodeName.toLowerCase()) != -1) {\n return element;\n }\n // Checks whether the element is editable by the user.\n if (element.hasAttribute(\"contenteditable\") &&\n element.getAttribute(\"contenteditable\").toLowerCase() != \"false\") {\n return element;\n }\n // Checks parents recursively because the touch might be for example on an inside a .\n if (element.parentElement) {\n return this.nearestInteractiveElement(element.parentElement);\n }\n return null;\n }\n}\n","export class CssBridge {\n constructor(document) {\n this.document = document;\n }\n setProperties(properties) {\n for (const [key, value] of properties) {\n this.setProperty(key, value);\n }\n }\n // For setting user setting.\n setProperty(key, value) {\n if (value === null || value === \"\") {\n this.removeProperty(key);\n }\n else {\n const root = document.documentElement;\n // The `!important` annotation is added with `setProperty()` because if it's part of the\n // `value`, it will be ignored by the Web View.\n root.style.setProperty(key, value, \"important\");\n }\n }\n // For removing user setting.\n removeProperty(key) {\n const root = document.documentElement;\n root.style.removeProperty(key);\n }\n}\n","/**\n * In paginated mode, the width of each resource must be a multiple of the viewport size\n * for proper snapping. This may not be automatically the case if the number of\n * columns in the resource is not a multiple of the number of columns fitting in the viewport.\n * To fix this, we insert a blank virtual column at the end of the resource.\n *\n * Returns if a virtual column has been added or removed.\n */\nexport function appendVirtualColumnIfNeeded(wnd) {\n // FIXME: what about scroll mode?\n const id = \"readium-virtual-page\";\n let virtualCol = wnd.document.getElementById(id);\n if (getColumnCountPerScreen(wnd) !== 2) {\n if (virtualCol) {\n virtualCol.remove();\n return true;\n }\n else {\n return false;\n }\n }\n else {\n const documentWidth = wnd.document.scrollingElement.scrollWidth;\n const colCount = documentWidth / wnd.innerWidth;\n const hasOddColCount = (Math.round(colCount * 2) / 2) % 1 > 0.1;\n if (hasOddColCount) {\n if (virtualCol) {\n virtualCol.remove();\n }\n else {\n virtualCol = wnd.document.createElement(\"div\");\n virtualCol.setAttribute(\"id\", id);\n virtualCol.dataset.readium = \"true\";\n virtualCol.style.breakBefore = \"column\";\n virtualCol.innerHTML = \"​\"; // zero-width space\n wnd.document.body.appendChild(virtualCol);\n }\n return true;\n }\n else {\n return false;\n }\n }\n}\nfunction getColumnCountPerScreen(wnd) {\n return parseInt(wnd\n .getComputedStyle(wnd.document.documentElement)\n .getPropertyValue(\"column-count\"));\n}\n"],"names":["bridgeListener","constructor","gesturesBridge","this","onTap","event","tapEvent","x","clientX","visualViewport","offsetLeft","scale","y","clientY","offsetTop","stringEvent","JSON","stringify","onLinkActivated","href","outerHtml","window","gestures","listener","document","addEventListener","onClick","defaultPrevented","selection","getSelection","type","nearestElement","target","HTMLElement","nearestInteractiveElement","HTMLAnchorElement","outerHTML","stopPropagation","preventDefault","element","indexOf","nodeName","toLowerCase","hasAttribute","getAttribute","parentElement","Window","prototype","readiumcss","setProperties","properties","key","value","setProperty","removeProperty","documentElement","style","documentState","onScriptsLoaded","documentLoadedFired","ResizeObserver","requestAnimationFrame","wnd","id","virtualCol","getElementById","parseInt","getComputedStyle","getPropertyValue","getColumnCountPerScreen","remove","colCount","scrollingElement","scrollWidth","innerWidth","Math","round","createElement","setAttribute","dataset","readium","breakBefore","innerHTML","body","appendChild","appendVirtualColumnIfNeeded","onDocumentResized","scrollHeight","onDocumentLoadedAndSized","observe"],"sourceRoot":""} \ No newline at end of file +{"version":3,"file":"reflowable-injectable-script.js","mappings":"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","sources":["webpack://readium-js/./src/index-reflowable-injectable.ts","webpack://readium-js/./src/bridge/all-listener-bridge.ts","webpack://readium-js/./src/common/gestures.ts","webpack://readium-js/./src/bridge/reflowable-css-bridge.ts","webpack://readium-js/./src/util/columns.ts"],"sourcesContent":["//\n// Copyright 2024 Readium Foundation. All rights reserved.\n// Use of this source code is governed by the BSD-style license\n// available in the top-level LICENSE file of the project.\n//\n/**\n * Script loaded by reflowable resources.\n */\nimport { ReflowableListenerAdapter, } from \"./bridge/all-listener-bridge\";\nimport { CssBridge } from \"./bridge/reflowable-css-bridge\";\nimport { GesturesDetector } from \"./common/gestures\";\nimport { appendVirtualColumnIfNeeded } from \"./util/columns\";\nconst bridgeListener = new ReflowableListenerAdapter(window.gestures);\nnew GesturesDetector(window, bridgeListener);\nWindow.prototype.readiumcss = new CssBridge(window.document);\nwindow.documentState.onScriptsLoaded();\ndocument.addEventListener(\"DOMContentLoaded\", () => {\n // Setups the `viewport` meta tag to disable overview.\n const meta = document.createElement(\"meta\");\n meta.setAttribute(\"name\", \"viewport\");\n meta.setAttribute(\"content\", \"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, shrink-to-fit=no\");\n document.head.appendChild(meta);\n});\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nwindow.addEventListener(\"load\", (event) => {\n let documentLoadedFired = false;\n const observer = new ResizeObserver(() => {\n let colCountFixed = false;\n requestAnimationFrame(() => {\n const scrollingElement = window.document.scrollingElement;\n const scrollingElementEmpty = scrollingElement == null ||\n (scrollingElement.scrollHeight == 0 &&\n scrollingElement.scrollWidth == 0);\n if (!documentLoadedFired && scrollingElementEmpty) {\n // Document is not sized yet\n return;\n }\n if (!colCountFixed && !scrollingElementEmpty) {\n const colChanged = appendVirtualColumnIfNeeded(window);\n colCountFixed = true;\n if (colChanged) {\n // Column number has changed, wait for next resize callback.\n return;\n }\n }\n colCountFixed = false;\n if (!documentLoadedFired) {\n window.documentState.onDocumentLoadedAndSized();\n documentLoadedFired = true;\n }\n else {\n window.documentState.onDocumentResized();\n }\n });\n });\n observer.observe(document.body);\n});\n","export class ReflowableListenerAdapter {\n constructor(gesturesBridge) {\n this.gesturesBridge = gesturesBridge;\n }\n onTap(event) {\n const tapEvent = {\n x: (event.clientX - visualViewport.offsetLeft) * visualViewport.scale,\n y: (event.clientY - visualViewport.offsetTop) * visualViewport.scale,\n };\n const stringEvent = JSON.stringify(tapEvent);\n this.gesturesBridge.onTap(stringEvent);\n }\n onLinkActivated(href, outerHtml) {\n this.gesturesBridge.onLinkActivated(href, outerHtml);\n }\n}\nexport class FixedListenerAdapter {\n constructor(window, gesturesApi, documentApi) {\n this.window = window;\n this.gesturesApi = gesturesApi;\n this.documentApi = documentApi;\n this.resizeObserverAdded = false;\n this.documentLoadedFired = false;\n }\n onTap(event) {\n this.gesturesApi.onTap(JSON.stringify(event));\n }\n onLinkActivated(href, outerHtml) {\n this.gesturesApi.onLinkActivated(href, outerHtml);\n }\n onLayout() {\n if (!this.resizeObserverAdded) {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const observer = new ResizeObserver(() => {\n requestAnimationFrame(() => {\n const scrollingElement = this.window.document.scrollingElement;\n if (!this.documentLoadedFired &&\n (scrollingElement == null ||\n scrollingElement.scrollHeight > 0 ||\n scrollingElement.scrollWidth > 0)) {\n this.documentApi.onDocumentLoadedAndSized();\n this.documentLoadedFired = true;\n }\n else {\n this.documentApi.onDocumentResized();\n }\n });\n });\n observer.observe(this.window.document.body);\n }\n this.resizeObserverAdded = true;\n }\n}\n","export class GesturesDetector {\n constructor(window, listener) {\n this.window = window;\n this.listener = listener;\n document.addEventListener(\"click\", (event) => {\n this.onClick(event);\n }, false);\n }\n onClick(event) {\n if (event.defaultPrevented) {\n return;\n }\n const selection = this.window.getSelection();\n if (selection && selection.type == \"Range\") {\n // There's an on-going selection, the tap will dismiss it so we don't forward it.\n // selection.type might be None (collapsed) or Caret with a collapsed range\n // when there is not true selection.\n return;\n }\n let nearestElement;\n if (event.target instanceof HTMLElement) {\n nearestElement = this.nearestInteractiveElement(event.target);\n }\n else {\n nearestElement = null;\n }\n if (nearestElement) {\n if (nearestElement instanceof HTMLAnchorElement) {\n this.listener.onLinkActivated(nearestElement.href, nearestElement.outerHTML);\n }\n }\n else {\n this.listener.onTap(event);\n }\n event.stopPropagation();\n event.preventDefault();\n }\n // See. https://github.com/JayPanoz/architecture/tree/touch-handling/misc/touch-handling\n nearestInteractiveElement(element) {\n if (element == null) {\n return null;\n }\n const interactiveTags = [\n \"a\",\n \"audio\",\n \"button\",\n \"canvas\",\n \"details\",\n \"input\",\n \"label\",\n \"option\",\n \"select\",\n \"submit\",\n \"textarea\",\n \"video\",\n ];\n if (interactiveTags.indexOf(element.nodeName.toLowerCase()) != -1) {\n return element;\n }\n // Checks whether the element is editable by the user.\n if (element.hasAttribute(\"contenteditable\") &&\n element.getAttribute(\"contenteditable\").toLowerCase() != \"false\") {\n return element;\n }\n // Checks parents recursively because the touch might be for example on an inside a .\n if (element.parentElement) {\n return this.nearestInteractiveElement(element.parentElement);\n }\n return null;\n }\n}\n","export class CssBridge {\n constructor(document) {\n this.document = document;\n }\n setProperties(properties) {\n for (const [key, value] of properties) {\n this.setProperty(key, value);\n }\n }\n // For setting user setting.\n setProperty(key, value) {\n if (value === null || value === \"\") {\n this.removeProperty(key);\n }\n else {\n const root = document.documentElement;\n // The `!important` annotation is added with `setProperty()` because if it's part of the\n // `value`, it will be ignored by the Web View.\n root.style.setProperty(key, value, \"important\");\n }\n }\n // For removing user setting.\n removeProperty(key) {\n const root = document.documentElement;\n root.style.removeProperty(key);\n }\n}\n","/**\n * In paginated mode, the width of each resource must be a multiple of the viewport size\n * for proper snapping. This may not be automatically the case if the number of\n * columns in the resource is not a multiple of the number of columns displayed in the viewport.\n * To fix this, we insert a blank virtual column at the end of the resource.\n *\n * Returns if the column number has changed.\n */\nexport function appendVirtualColumnIfNeeded(wnd) {\n const virtualCols = wnd.document.querySelectorAll(\"div[id^='readium-virtual-page']\");\n const virtualColsCount = virtualCols.length;\n // Remove first so that we don’t end up with an incorrect scrollWidth\n // Even when removing their width we risk having an incorrect scrollWidth\n // so removing them entirely is the most robust solution\n for (const virtualCol of virtualCols) {\n virtualCol.remove();\n }\n const colCountPerScreen = getColumnCountPerScreen(wnd);\n const documentWidth = wnd.document.scrollingElement.scrollWidth;\n const windowWidth = wnd.visualViewport.width;\n const totalColCount = Math.round((documentWidth / windowWidth) * colCountPerScreen);\n const lonelyColCount = totalColCount % colCountPerScreen;\n const needed = colCountPerScreen === 1 || lonelyColCount === 0\n ? 0\n : colCountPerScreen - lonelyColCount;\n if (needed > 0) {\n for (let i = 0; i < needed; i++) {\n const virtualCol = wnd.document.createElement(\"div\");\n virtualCol.setAttribute(\"id\", `readium-virtual-page-${i}`);\n virtualCol.dataset.readium = \"true\";\n virtualCol.style.breakBefore = \"column\";\n virtualCol.innerHTML = \"​\"; // zero-width space\n wnd.document.body.appendChild(virtualCol);\n }\n }\n return virtualColsCount != needed;\n}\nfunction getColumnCountPerScreen(wnd) {\n return parseInt(wnd\n .getComputedStyle(wnd.document.documentElement)\n .getPropertyValue(\"column-count\"));\n}\n"],"names":["bridgeListener","constructor","gesturesBridge","this","onTap","event","tapEvent","x","clientX","visualViewport","offsetLeft","scale","y","clientY","offsetTop","stringEvent","JSON","stringify","onLinkActivated","href","outerHtml","window","gestures","listener","document","addEventListener","onClick","defaultPrevented","selection","getSelection","type","nearestElement","target","HTMLElement","nearestInteractiveElement","HTMLAnchorElement","outerHTML","stopPropagation","preventDefault","element","indexOf","nodeName","toLowerCase","hasAttribute","getAttribute","parentElement","Window","prototype","readiumcss","setProperties","properties","key","value","setProperty","removeProperty","documentElement","style","documentState","onScriptsLoaded","meta","createElement","setAttribute","head","appendChild","documentLoadedFired","ResizeObserver","colCountFixed","requestAnimationFrame","scrollingElement","scrollingElementEmpty","scrollHeight","scrollWidth","colChanged","wnd","virtualCols","querySelectorAll","virtualColsCount","length","virtualCol","remove","colCountPerScreen","parseInt","getComputedStyle","getPropertyValue","getColumnCountPerScreen","documentWidth","windowWidth","width","lonelyColCount","Math","round","needed","i","dataset","readium","breakBefore","innerHTML","body","appendVirtualColumnIfNeeded","onDocumentResized","onDocumentLoadedAndSized","observe"],"sourceRoot":""} \ No newline at end of file diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesEditor.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesEditor.kt index 85165ee1ee..5bb37d5c41 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesEditor.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/preferences/ReflowableWebPreferencesEditor.kt @@ -19,6 +19,7 @@ import org.readium.r2.navigator.preferences.EnumPreference import org.readium.r2.navigator.preferences.EnumPreferenceDelegate import org.readium.r2.navigator.preferences.FontFamily import org.readium.r2.navigator.preferences.ImageFilter +import org.readium.r2.navigator.preferences.IntIncrement import org.readium.r2.navigator.preferences.Preference import org.readium.r2.navigator.preferences.PreferenceDelegate import org.readium.r2.navigator.preferences.RangePreference @@ -93,17 +94,19 @@ public class ReflowableWebPreferencesEditor internal constructor( ) /** - * Number of reflowable columns to display (one-page view or two-page spread). + * Number of reflowable columns to display . * * Only effective when [scroll] is off. */ - public val columnCount: EnumPreference = - EnumPreferenceDelegate( + public val columnCount: RangePreference = + RangePreferenceDelegate( getValue = { preferences.columnCount }, getEffectiveValue = { state.settings.columnCount }, getIsEffective = { true }, - updateValue = { value -> updateValues { it.copy(columnCount = value) } }, - supportedValues = listOf(1, 2) + supportedRange = 1..Int.MAX_VALUE, + progressionStrategy = IntIncrement(1), + valueFormatter = { it.format(5) }, + updateValue = { value -> updateValues { it.copy(columnCount = value) } } ) /** @@ -150,6 +153,20 @@ public class ReflowableWebPreferencesEditor internal constructor( progressionStrategy = DoubleIncrement(0.25) ) + /** + * Factor applied to horizontal margins. Default to 1. + */ + public val horizontalMargins: RangePreference = + RangePreferenceDelegate( + getValue = { preferences.horizontalMargins }, + getEffectiveValue = { state.settings.horizontalMargins }, + getIsEffective = { true }, + updateValue = { value -> updateValues { it.copy(horizontalMargins = value) } }, + supportedRange = 0.0..4.0, + progressionStrategy = DoubleIncrement(0.3), + valueFormatter = { it.format(5) } + ) + /** * Enable hyphenation for latin languages. * @@ -234,20 +251,6 @@ public class ReflowableWebPreferencesEditor internal constructor( valueFormatter = { it.format(5) } ) - /** - * Factor applied to horizontal margins. Default to 1. - */ - public val horizontalMargins: RangePreference = - RangePreferenceDelegate( - getValue = { preferences.horizontalMargins }, - getEffectiveValue = { state.settings.horizontalMargins }, - getIsEffective = { true }, - updateValue = { value -> updateValues { it.copy(horizontalMargins = value) } }, - supportedRange = 0.0..4.0, - progressionStrategy = DoubleIncrement(0.3), - valueFormatter = { it.format(5) } - ) - /** * Text indentation for paragraphs. * diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt index f9be3ad823..c72217edd2 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/reflowable/ReflowableResource.kt @@ -174,8 +174,8 @@ internal fun ReflowableResource( webview.settings.setSupportZoom(false) webview.settings.builtInZoomControls = false webview.settings.displayZoomControls = false - webview.settings.loadWithOverviewMode = false - webview.settings.useWideViewPort = false + webview.settings.loadWithOverviewMode = true + webview.settings.useWideViewPort = true webview.isVerticalScrollBarEnabled = false webview.isHorizontalScrollBarEnabled = false webview.setLayerType(View.LAYER_TYPE_HARDWARE, null) diff --git a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/ComposableWebView.kt b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/ComposableWebView.kt index 67185baeb6..8b3483bd8c 100644 --- a/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/ComposableWebView.kt +++ b/readium/navigators/web/src/main/java/org/readium/navigator/web/webview/ComposableWebView.kt @@ -45,7 +45,6 @@ import androidx.compose.ui.viewinterop.AndroidView * @param client Provides access to WebViewClient via subclassing * @param chromeClient Provides access to WebChromeClient via subclassing */ -@SuppressLint("UnusedBoxWithConstraintsScope") @Composable internal fun WebView( state: WebViewState, From 34fc3c3cf7aa9a930e4529c7f44ac5de41fdb8e7 Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Mon, 2 Jun 2025 09:21:51 +0200 Subject: [PATCH 56/88] Add table of contents to demo --- .../demo/src/main/AndroidManifest.xml | 1 - .../readium/navigator/demo/DemoViewModel.kt | 2 +- .../readium/navigator/demo/reader/Outline.kt | 166 ++++++++++++++++++ .../navigator/demo/reader/ReaderOpener.kt | 8 +- .../navigator/demo/reader/ReaderState.kt | 37 ++++ .../demo/reader/{ReaderUi.kt => Rendition.kt} | 86 +++++---- .../src/main/res/drawable/ic_outline_24.xml | 10 ++ .../main/res/drawable/ic_preferences_24.xml | 10 ++ .../res/mipmap-anydpi-v26/ic_launcher.xml | 11 +- .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 4537 bytes .../src/main/res/mipmap-hdpi/ic_launcher.webp | Bin 1404 -> 0 bytes .../mipmap-hdpi/ic_launcher_background.png | Bin 0 -> 13280 bytes .../mipmap-hdpi/ic_launcher_foreground.png | Bin 0 -> 10526 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2967 bytes .../src/main/res/mipmap-mdpi/ic_launcher.webp | Bin 982 -> 0 bytes .../mipmap-mdpi/ic_launcher_background.png | Bin 0 -> 6661 bytes .../mipmap-mdpi/ic_launcher_foreground.png | Bin 0 -> 5364 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 6602 bytes .../main/res/mipmap-xhdpi/ic_launcher.webp | Bin 1900 -> 0 bytes .../mipmap-xhdpi/ic_launcher_background.png | Bin 0 -> 23337 bytes .../mipmap-xhdpi/ic_launcher_foreground.png | Bin 0 -> 17998 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 11395 bytes .../main/res/mipmap-xxhdpi/ic_launcher.webp | Bin 2884 -> 0 bytes .../mipmap-xxhdpi/ic_launcher_background.png | Bin 0 -> 55455 bytes .../mipmap-xxhdpi/ic_launcher_foreground.png | Bin 0 -> 41512 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 18440 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.webp | Bin 3844 -> 0 bytes .../mipmap-xxxhdpi/ic_launcher_background.png | Bin 0 -> 100796 bytes .../mipmap-xxxhdpi/ic_launcher_foreground.png | Bin 0 -> 77568 bytes 29 files changed, 288 insertions(+), 43 deletions(-) create mode 100644 readium/navigators/demo/src/main/java/org/readium/navigator/demo/reader/Outline.kt create mode 100644 readium/navigators/demo/src/main/java/org/readium/navigator/demo/reader/ReaderState.kt rename readium/navigators/demo/src/main/java/org/readium/navigator/demo/reader/{ReaderUi.kt => Rendition.kt} (78%) create mode 100644 readium/navigators/demo/src/main/res/drawable/ic_outline_24.xml create mode 100644 readium/navigators/demo/src/main/res/drawable/ic_preferences_24.xml create mode 100644 readium/navigators/demo/src/main/res/mipmap-hdpi/ic_launcher.png delete mode 100644 readium/navigators/demo/src/main/res/mipmap-hdpi/ic_launcher.webp create mode 100644 readium/navigators/demo/src/main/res/mipmap-hdpi/ic_launcher_background.png create mode 100644 readium/navigators/demo/src/main/res/mipmap-hdpi/ic_launcher_foreground.png create mode 100644 readium/navigators/demo/src/main/res/mipmap-mdpi/ic_launcher.png delete mode 100644 readium/navigators/demo/src/main/res/mipmap-mdpi/ic_launcher.webp create mode 100644 readium/navigators/demo/src/main/res/mipmap-mdpi/ic_launcher_background.png create mode 100644 readium/navigators/demo/src/main/res/mipmap-mdpi/ic_launcher_foreground.png create mode 100644 readium/navigators/demo/src/main/res/mipmap-xhdpi/ic_launcher.png delete mode 100644 readium/navigators/demo/src/main/res/mipmap-xhdpi/ic_launcher.webp create mode 100644 readium/navigators/demo/src/main/res/mipmap-xhdpi/ic_launcher_background.png create mode 100644 readium/navigators/demo/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png create mode 100644 readium/navigators/demo/src/main/res/mipmap-xxhdpi/ic_launcher.png delete mode 100644 readium/navigators/demo/src/main/res/mipmap-xxhdpi/ic_launcher.webp create mode 100644 readium/navigators/demo/src/main/res/mipmap-xxhdpi/ic_launcher_background.png create mode 100644 readium/navigators/demo/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png create mode 100644 readium/navigators/demo/src/main/res/mipmap-xxxhdpi/ic_launcher.png delete mode 100644 readium/navigators/demo/src/main/res/mipmap-xxxhdpi/ic_launcher.webp create mode 100644 readium/navigators/demo/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png create mode 100644 readium/navigators/demo/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png diff --git a/readium/navigators/demo/src/main/AndroidManifest.xml b/readium/navigators/demo/src/main/AndroidManifest.xml index b6ae97f20d..9234dbecd4 100644 --- a/readium/navigators/demo/src/main/AndroidManifest.xml +++ b/readium/navigators/demo/src/main/AndroidManifest.xml @@ -5,7 +5,6 @@ android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" - android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@android:style/Theme.Material.Light.NoActionBar"> , + val readerState: ReaderState<*, *, *>, ) : State } diff --git a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/reader/Outline.kt b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/reader/Outline.kt new file mode 100644 index 0000000000..9856f73357 --- /dev/null +++ b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/reader/Outline.kt @@ -0,0 +1,166 @@ +/* + * Copyright 2024 Readium Foundation. All rights reserved. + * Use of this source code is governed by the BSD-style license + * available in the top-level LICENSE file of the project. + */ +@file:OptIn(ExperimentalReadiumApi::class) + +package org.readium.navigator.demo.reader + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.ListItem +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.compose.ui.zIndex +import org.readium.navigator.common.GoLocation +import org.readium.navigator.common.LocatorAdapter +import org.readium.r2.shared.ExperimentalReadiumApi +import org.readium.r2.shared.publication.Link +import org.readium.r2.shared.publication.Publication + +@Composable +fun Outline( + modifier: Modifier = Modifier, + publication: Publication, + locatorAdapter: LocatorAdapter<*, G>, + onBackActivated: () -> Unit, + onTocItemActivated: (G) -> Unit, +) { + Scaffold( + modifier = Modifier + .zIndex(1f) + .fillMaxSize(), + topBar = { TopBar(onBackActivated) }, + content = { padding -> + Box( + modifier = Modifier + .padding(padding) + .fillMaxSize() + ) { + Contents( + modifier = modifier, + publication = publication, + locatorAdapter = locatorAdapter, + onItemActivated = onTocItemActivated + ) + } + } + ) +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun TopBar( + onBackActivated: () -> Unit, +) { + TopAppBar( + title = { Text("Contents") }, + navigationIcon = { + IconButton( + onClick = onBackActivated + ) { + Icon( + Icons.AutoMirrored.Filled.ArrowBack, + contentDescription = "Back" + ) + } + } + ) +} + +@Composable +private fun Contents( + modifier: Modifier = Modifier, + publication: Publication, + locatorAdapter: LocatorAdapter<*, G>, + onItemActivated: (G) -> Unit, +) { + val items = publication.tableOfContents + .flatMap { it.toTocItems(publication, locatorAdapter) } + + val scrollState = rememberScrollState() + + Contents( + modifier = modifier.verticalScroll(scrollState), + items = items, + onClick = onItemActivated + ) +} + +private data class TocItem( + val title: String, + val locator: G, + val depth: Int, +) + +private fun Link.toTocItems( + publication: Publication, + locatorAdapter: LocatorAdapter<*, G>, + depth: Int = 0, +): List> { + val locator = publication.locatorFromLink(this@toTocItems) + ?: return emptyList() + + val goLocation = with(locatorAdapter) { locator.toGoLocation() } + + val title = locator.title ?: locator.href.filename ?: "" + + return buildList { + add(TocItem(title, goLocation, depth)) + for (child in children) { + addAll(child.toTocItems(publication, locatorAdapter, depth + 1)) + } + } +} + +@Composable +private fun Contents( + modifier: Modifier = Modifier, + items: List>, + onClick: (G) -> Unit, + depth: Int = 0, +) { + Column(modifier) { + for (item in items) { + TocItem( + item = item, + onClick = onClick, + depth = depth, + ) + } + } +} + +@Composable +private fun TocItem( + modifier: Modifier = Modifier, + item: TocItem, + onClick: (G) -> Unit, + depth: Int = 0, +) { + ListItem( + headlineContent = { + Text( + text = item.title, + ) + }, + modifier = modifier + .clickable { onClick(item.locator) } + .padding(start = 24.dp * depth) + ) +} diff --git a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/reader/ReaderOpener.kt b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/reader/ReaderOpener.kt index c727fcceac..318273ef19 100644 --- a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/reader/ReaderOpener.kt +++ b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/reader/ReaderOpener.kt @@ -19,7 +19,9 @@ import org.readium.navigator.web.FixedWebRenditionController import org.readium.navigator.web.FixedWebRenditionFactory import org.readium.navigator.web.ReflowableWebRenditionController import org.readium.navigator.web.ReflowableWebRenditionFactory +import org.readium.navigator.web.location.FixedWebGoLocation import org.readium.navigator.web.location.FixedWebLocation +import org.readium.navigator.web.location.ReflowableWebGoLocation import org.readium.navigator.web.location.ReflowableWebLocation import org.readium.navigator.web.preferences.FixedWebPreferences import org.readium.navigator.web.preferences.ReflowableWebPreferences @@ -54,7 +56,7 @@ class ReaderOpener( private val publicationOpener = PublicationOpener(publicationParser) - suspend fun open(url: AbsoluteUrl): Try, Error> { + suspend fun open(url: AbsoluteUrl): Try, Error> { val asset = assetRetriever.retrieve(url) .getOrElse { return Try.failure(it) } @@ -93,7 +95,7 @@ class ReaderOpener( url: AbsoluteUrl, publication: Publication, initialLocator: Locator?, - ): Try, Error> { + ): Try, Error> { val navigatorFactory = ReflowableWebRenditionFactory(application, publication) ?: return Try.failure(DebugError("Publication not supported")) @@ -143,7 +145,7 @@ class ReaderOpener( url: AbsoluteUrl, publication: Publication, initialLocator: Locator?, - ): Try, Error> { + ): Try, Error> { val navigatorFactory = FixedWebRenditionFactory(application, publication) ?: return Try.failure(DebugError("Publication not supported")) diff --git a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/reader/ReaderState.kt b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/reader/ReaderState.kt new file mode 100644 index 0000000000..fc8083979b --- /dev/null +++ b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/reader/ReaderState.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2024 Readium Foundation. All rights reserved. + * Use of this source code is governed by the BSD-style license + * available in the top-level LICENSE file of the project. + */ + +@file:OptIn(ExperimentalReadiumApi::class) + +package org.readium.navigator.demo.reader + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.cancel +import org.readium.navigator.common.GoLocation +import org.readium.navigator.common.Location +import org.readium.navigator.common.LocatorAdapter +import org.readium.navigator.common.NavigationController +import org.readium.navigator.common.PreferencesEditor +import org.readium.navigator.common.RenditionState +import org.readium.r2.shared.ExperimentalReadiumApi +import org.readium.r2.shared.publication.Publication +import org.readium.r2.shared.util.AbsoluteUrl + +data class ReaderState>( + val url: AbsoluteUrl, + val coroutineScope: CoroutineScope, + val publication: Publication, + val renditionState: RenditionState, + val preferencesEditor: PreferencesEditor<*, *>, + val locatorAdapter: LocatorAdapter, + val onControllerAvailable: (N) -> Unit, +) { + + fun close() { + coroutineScope.cancel() + publication.close() + } +} diff --git a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/reader/ReaderUi.kt b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/reader/Rendition.kt similarity index 78% rename from readium/navigators/demo/src/main/java/org/readium/navigator/demo/reader/ReaderUi.kt rename to readium/navigators/demo/src/main/java/org/readium/navigator/demo/reader/Rendition.kt index cc558cf64b..bf7ebd17b0 100644 --- a/readium/navigators/demo/src/main/java/org/readium/navigator/demo/reader/ReaderUi.kt +++ b/readium/navigators/demo/src/main/java/org/readium/navigator/demo/reader/Rendition.kt @@ -14,8 +14,6 @@ import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Settings import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton @@ -28,26 +26,25 @@ import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource import androidx.compose.ui.zIndex -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.cancel import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch +import org.readium.navigator.common.GoLocation import org.readium.navigator.common.InputListener import org.readium.navigator.common.Location -import org.readium.navigator.common.LocatorAdapter import org.readium.navigator.common.NavigationController import org.readium.navigator.common.OverflowController -import org.readium.navigator.common.PreferencesEditor -import org.readium.navigator.common.RenditionState import org.readium.navigator.common.TapContext import org.readium.navigator.common.TapEvent import org.readium.navigator.common.defaultHyperlinkListener import org.readium.navigator.common.defaultInputListener +import org.readium.navigator.demo.R import org.readium.navigator.demo.persistence.LocatorRepository import org.readium.navigator.demo.preferences.UserPreferences import org.readium.navigator.demo.util.launchWebBrowser @@ -56,39 +53,25 @@ import org.readium.navigator.web.FixedWebRenditionState import org.readium.navigator.web.ReflowableWebRendition import org.readium.navigator.web.ReflowableWebRenditionState import org.readium.r2.shared.ExperimentalReadiumApi -import org.readium.r2.shared.publication.Publication -import org.readium.r2.shared.util.AbsoluteUrl import org.readium.r2.shared.util.toUri -data class ReaderState>( - val url: AbsoluteUrl, - val coroutineScope: CoroutineScope, - val publication: Publication, - val renditionState: RenditionState, - val preferencesEditor: PreferencesEditor<*, *>, - val locatorAdapter: LocatorAdapter, - val onControllerAvailable: (N) -> Unit, -) { - - fun close() { - coroutineScope.cancel() - publication.close() - } -} - @OptIn(ExperimentalMaterial3Api::class) @Composable -fun > Reader( - readerState: ReaderState, +fun > Reader( + readerState: ReaderState, fullScreenState: MutableState, ) { + val coroutineScope = rememberCoroutineScope() + val showPreferences = remember { mutableStateOf(false) } val preferencesSheetState = rememberModalBottomSheetState() if (showPreferences.value) { ModalBottomSheet( sheetState = preferencesSheetState, - onDismissRequest = { showPreferences.value = false } + onDismissRequest = { + showPreferences.value = false + } ) { UserPreferences( editor = readerState.preferencesEditor, @@ -97,11 +80,37 @@ fun > Reader( } } + val showOutline = rememberSaveable { mutableStateOf(false) } + + if (showOutline.value) { + Outline( + modifier = Modifier.fillMaxSize(), + publication = readerState.publication, + locatorAdapter = readerState.locatorAdapter, + onBackActivated = { + showOutline.value = false + fullScreenState.value = true + }, + onTocItemActivated = { + val controllerNow = readerState.renditionState.controller + ?: return@Outline + + coroutineScope.launch { + controllerNow.goTo(it) + } + + fullScreenState.value = true + showOutline.value = false + } + ) + } + Box { TopBar( - modifier = Modifier.zIndex(1f), + modifier = Modifier.zIndex(10f), visible = !fullScreenState.value, - onPreferencesActivated = { showPreferences.value = !showPreferences.value } + onPreferencesActivated = { showPreferences.value = !showPreferences.value }, + onOutlineActivated = { showOutline.value = !showOutline.value } ) val navigationHistory: MutableState> = remember { mutableStateOf(emptyList()) } @@ -122,8 +131,6 @@ fun > Reader( }.launchIn(readerState.coroutineScope) } - val coroutineScope = rememberCoroutineScope() - BackHandler(enabled = navigationHistory.value.isNotEmpty()) { val previousItem = navigationHistory.value.last() navigationHistory.value -= previousItem @@ -193,6 +200,7 @@ private fun TopBar( modifier: Modifier, visible: Boolean, onPreferencesActivated: () -> Unit, + onOutlineActivated: () -> Unit, ) { AnimatedVisibility( modifier = modifier, @@ -201,14 +209,22 @@ private fun TopBar( exit = fadeOut() ) { TopAppBar( - title = {}, + title = { }, actions = { IconButton( onClick = onPreferencesActivated ) { Icon( - imageVector = Icons.Filled.Settings, - contentDescription = "Preferences" + painterResource(R.drawable.ic_preferences_24), + contentDescription = "Preferences", + ) + } + IconButton( + onClick = onOutlineActivated + ) { + Icon( + painterResource(R.drawable.ic_outline_24), + contentDescription = "Outline" ) } } diff --git a/readium/navigators/demo/src/main/res/drawable/ic_outline_24.xml b/readium/navigators/demo/src/main/res/drawable/ic_outline_24.xml new file mode 100644 index 0000000000..4350ba96af --- /dev/null +++ b/readium/navigators/demo/src/main/res/drawable/ic_outline_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/readium/navigators/demo/src/main/res/drawable/ic_preferences_24.xml b/readium/navigators/demo/src/main/res/drawable/ic_preferences_24.xml new file mode 100644 index 0000000000..4cfa4c7cb6 --- /dev/null +++ b/readium/navigators/demo/src/main/res/drawable/ic_preferences_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/readium/navigators/demo/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/readium/navigators/demo/src/main/res/mipmap-anydpi-v26/ic_launcher.xml index 6f3b755bf5..729f828c86 100644 --- a/readium/navigators/demo/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ b/readium/navigators/demo/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -1,6 +1,11 @@ + + - - - + + \ No newline at end of file diff --git a/readium/navigators/demo/src/main/res/mipmap-hdpi/ic_launcher.png b/readium/navigators/demo/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..14bfe31eccd25d6adc61f10a1873e6544f6ea061 GIT binary patch literal 4537 zcmV;q5k~HbP)vFJGMa!c8EzQanE9RW+s_9P9@_tj={z@2HSvH42acX zF_;~+1Kt<*eFw4cLK2%;Z15H@J^zG0oH_SC=}Av|0tsn8B;{B2tNRf5NxDCsd+vEx zHgCQ4=6G|wIo=#^j$iiy0B@%c4ZZtYf{e*4a?%0b`K^BN9*@oT2^2={ew9(1r8G_# zD;KqeilylyijkmSpLqj6v-Zrg$m}uLGVcVV6+IV)ZlO@FHx?^&#w>;2xZh(*mJ7>Q z4ezU#riK)YQ$SgmG&5yoehTCit(7^#G?!T&4|fkDPH12VlmvsQGr%vqVX zWu8H|0CL^@P~ni_{Y^=-ouA6($zjFfB*+)WO$-wZ^MpwbvN^&Omsx_A%M4+fi-DlC zLvNDm^(L8~X&DSAsm`7mE7KNcxo9oSQHZ315$z}r@g4gyZyY_C#7J8@KXgE`Gy!ts zxJhB004tMLoJQ0J(Zm-~GdicyB(smE^&)D+XrfVMDjwHEYF*1=+cCQ%=Qy;C@?Q7e|l zLB41aWWk9jqbK=k+Ozy*a4$cZryZo!H{Bv*-Hf1j^T#{O6iZ_$Xw*bnBFniXS0YO5 z#fUQSOh4B}Np*81H$ieu!)-Fw%?X<9C|7a>*-LUInz*9mE>AnY9OZo4$=nnr)sf^q z14-2lcQ!33Z=$_IxjYK;C0jwBi<0w+^0YK?Cdx@7w+KqCslDq3K_e#8DwpjgxgpBQ zw3B-~kfpS46p58hBJ_>Nd6FN%b>c6tp~SA}v?aC@7YB zB)KYzFF(0l8t6P;@fbk{4+TxNqM%``APaV)l*{f;yNL}8&0_5UB-Kmdf+8Bu6r6=~ z#pfaBPA23GG+Cv2aO)y9cuUYj6tptL6~rrQ%!P>BNYoTaXGS3EW(pjL{1mu9ZioHh+u-XkBvb%_S;ru|uYP?|8{{Xc!9Z?XAhFh4g0Q7Hh#GaAdYeq-CAvNc z$~ufvcEG^|ANcWS5uC^p!-=a5KV^#GNU8u1T-uHVfTX4vWHXcN=P2ir$i1D1g0v{; z(GUt6vi$jLl2Hs|E= zAZ!D#iQ#aH01iq%hpT3~!L1){m$XeJ`BI+y}?f1ysVR zd_Ope1Q+dwh#Ln{-epLrje-kh`{7i<$MkokPY_Bvl;i^;C4nHDop7-<(9>N5tDqXs z1gTaBLGg$P8U#m4LmNaBe`%n!la$%3hQrA|G%`*V`ccl5{uzGm%EhIAgw0VhoQBEG z$tcdB=~sZ$En5gjQ$K;L{grMNo3dG*mjz)K(^55a(;@r9|=EY331?J zGk%cVl1R2$cni&hx(Em^_M?4I6^Jos2_W`?#I0KwDrjcfLqR$ev_=FCn20D9E6IYb zC`OLVsKJ$HFXoLOplG^f!)THlhakM-C{7y@oG$UBoKt)T#kw}9D_)7d3;TS*_7BPx zLWuM`te+-bE;PL)sEHA@ih|Y{LAF?BSw$r^XTZTEU-&*@I~+;*3uN|{uRHBz3;hs& z<9i&a7|uxjDB(B00qI=dx}`z%y~AvO5=kfX_h6ZzVGB)%t(AGMDA^p@>eYHf&;SbR zX9V#`QrSe5Y_S`c=YN9}xdJ#0)e@o;*`RvbX^4JZ}1aZCdB--1EWa{akYtb z#UqlW3vCd2cMsd|tU>^n?jFNP8C<6-$LhP~H1-!W&y62KaLLD5Vzg2@xg+(sx*dS@ zp6e)Nj4zr@a_2dRL+H4RxX;ceJl+7oGSH!LuuRL zVnq<bJbBy{JpFs`NAY4 zsA)5TfDu$c1>ti01O+{{2(pS&u4y2)HVjUd?4W}SzbED;^1&{UH1EfA5r>54?=X70 zX#JEsQE2@g3O=Lsh4lVh&T1!VOo8tc{~3;D{28(aDxhSx6{4#4vab_*T?pqZ4nV~1 zUd94z|rD_pH(*7;vY4aeu)}MK-ikUJ$YZ7p^>xTlp z9O9ezL7FBQrklBE@8=YojG%EZ33}FJA}v>v2BgcCIMAOUx^5>#)rwJy81i)a zAYH14xaNPs$3zq|*x0(mY-u1hR)cJ*$*vmjhqT^6_L_)FAx6O$P&89VYplffLl9LX zVt;=L&m*fCY#+BLy3QZ2O~@Q7a`_?(G7>@eJrPvP6=cCil5(vLvL_^Px%pE_>iPz2 zCR}+QchmFedJ!eE3I}`ZGZfM1w9q7Ek0sOoG4;&g!fuLia4KdB8k^xtUogZp>|~$U z6_UG-U^&t6P-w~*$Gs%zc@HRm>E;Tu6Qz3Ei>sLeisoc&e##g=2eC~e3VEYpH-%U) zRohkLTv5fd73?)Jjbt?xz!i;zy%AQdXyEFo1mao(%>BeRt(d*ma(=nlA9G(BTWBh6 z3r#9$3yP0y4oT6`m1ocMT{_S`rnC;J@ zeHRoNZt-mWj@k$s^@5;Zx=~OUSCCUt8dj8IwE(YFx`dRtHX(#R@B_u8Hr|TdA}V(}1LARj^tw(VL^p_WO39sU z)M0t>uph613 zt5`@5{RNWxMF{4UHeX!2KgR)7SrfXAB>BU32*3XYTy7VbuMt7&;OAI)-g7Jq*7&!6 zNk#7X&5OOHVY8rNZwTt7f{3WH^(66#Qa$T{tJ)tSc@PV>L5zkzAzXa09d84^$5p73 z<|(!+UulNe`XIP)e;bV)<{C`4W0=@iJDipVyb;CwtqWI_;-R+$y+lE;I!r{AMG`CO z#m1saS4tptXeT0s6qJj(X{O$jMkQ*OCe77&{NBXA@ zi6Cz_&gqKhN<=yPdP?zd*rZq)LP57Y5maRrge}EJl-h-eQax*j9DN|94vQ!$IOrsd zq^O1+DCAENtlSD`%KrorHQPa=5kQK$A0d5wFUTKNJ6-Wy5#=nRSV65G3&QYz)ovBU zN^&O3PS*2oP&}!DjLE-3+Ng*nb%e+g(y2$<)Da;*Zh`c{LeH4J?uzH?w6lm(*+^16 z8Zs#!4tglah=N{O1a$y|tD?Bkq;4!P(Y|H$~x;GbtYtK{vf6s2%tv*~xmrjVSecE8cTl0G_oXZ8TS{dymK2F);5M zxFu?kgK~AiOM+gT1-&MMEOfwz5oMO7wuz`RH)^PjM5%1IS2iI^xrTyP`#lp>XuMxu z_PUKn5RWXk^OLI;d5_bLI`<-qJMAojQaWzj*?a^okq9D!T1}*-k}SM(5>e}l>T)bL zy(miUhA8qcR+OuKklN)*1TEe#E&E?vK^FKVxg)C6#X_^&#jTZ%5_zA)v{OFrHz`&% zAZb!oY+8_{z361w-&#Taw>FddRV#2MxghH0`l8h49HrjO)N?_UvuIMT(Q{LYu^mE6 zQZJCPhL)HA-rfJy`#a>1IlAk!>Q~Kxkz}HxT&A7NYYQD#URmfgsmw6vT_)8_9$s`i z@=K2$y(ZODD@uySqVR&gztCbh_v@!f*OFNh6?X*TBs4P4qbUO01i^~&2w;erp&@VtivDO2{ z3#}k&Q5wbn{@IsgjQi5}z5CW?j;;H){v9@35dR;qh9+OC{<-pUQ%++{eRh3Zr<8A5K~=Pf4Qcx zG2(7c<SZ2t+_frt^mUpZp)SU&h**9U(fWAylM zTm%FJ{C?{`|M#{8_`LtYu5JJLYi5g&&-+{b{of;F`v3TQAaDOhcyqit-W+d^U&Zl% X@*4glp!6WB00000NkvXXu0mjf|8#R& literal 0 HcmV?d00001 diff --git a/readium/navigators/demo/src/main/res/mipmap-hdpi/ic_launcher.webp b/readium/navigators/demo/src/main/res/mipmap-hdpi/ic_launcher.webp deleted file mode 100644 index c209e78ecd372343283f4157dcfd918ec5165bb3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1404 zcmV-?1%vuhNk&F=1pok7MM6+kP&il$0000G0000-002h-06|PpNX!5L00Dqw+t%{r zzW2vH!KF=w&cMnnN@{whkTw+#mAh0SV?YL=)3MimFYCWp#fpdtz~8$hD5VPuQgtcN zXl<@<#Cme5f5yr2h%@8TWh?)bSK`O z^Z@d={gn7J{iyxL_y_%J|L>ep{dUxUP8a{byupH&!UNR*OutO~0{*T4q5R6@ApLF! z5{w?Z150gC7#>(VHFJZ-^6O@PYp{t!jH(_Z*nzTK4 zkc{fLE4Q3|mA2`CWQ3{8;gxGizgM!zccbdQoOLZc8hThi-IhN90RFT|zlxh3Ty&VG z?Fe{#9RrRnxzsu|Lg2ddugg7k%>0JeD+{XZ7>Z~{=|M+sh1MF7~ zz>To~`~LVQe1nNoR-gEzkpe{Ak^7{{ZBk2i_<+`Bq<^GB!RYG+z)h;Y3+<{zlMUYd zrd*W4w&jZ0%kBuDZ1EW&KLpyR7r2=}fF2%0VwHM4pUs}ZI2egi#DRMYZPek*^H9YK zay4Iy3WXFG(F14xYsoDA|KXgGc5%2DhmQ1gFCkrgHBm!lXG8I5h*uf{rn48Z!_@ z4Bk6TJAB2CKYqPjiX&mWoW>OPFGd$wqroa($ne7EUK;#3VYkXaew%Kh^3OrMhtjYN?XEoY`tRPQsAkH-DSL^QqyN0>^ zmC>{#F14jz4GeW{pJoRpLFa_*GI{?T93^rX7SPQgT@LbLqpNA}<@2wH;q493)G=1Y z#-sCiRNX~qf3KgiFzB3I>4Z%AfS(3$`-aMIBU+6?gbgDb!)L~A)je+;fR0jWLL-Fu z4)P{c7{B4Hp91&%??2$v9iRSFnuckHUm}or9seH6 z>%NbT+5*@L5(I9j@06@(!{ZI?U0=pKn8uwIg&L{JV14+8s2hnvbRrU|hZCd}IJu7*;;ECgO%8_*W Kmw_-CKmY()leWbG diff --git a/readium/navigators/demo/src/main/res/mipmap-hdpi/ic_launcher_background.png b/readium/navigators/demo/src/main/res/mipmap-hdpi/ic_launcher_background.png new file mode 100644 index 0000000000000000000000000000000000000000..be6198d0459962843b83e35fddcf2d4f2987bce8 GIT binary patch literal 13280 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 O0u*IG$y7<12LBI%_gaGh literal 0 HcmV?d00001 diff --git a/readium/navigators/demo/src/main/res/mipmap-mdpi/ic_launcher.png b/readium/navigators/demo/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..c9760a62a8ea942920cb4838533077c411af2116 GIT binary patch literal 2967 zcmV;I3uyF-P)FLhynCg8_qW z!0c!Ryd{nuo3NUF6Jkd!k`Q7y#u)6hnYJs`e8 zy>rjG_nQ0e`|&F>%9vzS(tkZ)@3-G$nbUTEzOh8ZRan+Y0QpNpY> z7uEq!EQ1cr(3s6oJF!4LC}WivkQtKbm$7j&+f1h@w4eACD1lTg+2*!iYwTVB(vI{% zZSTEHBBEx*Bw=UtNeuUi>fwF~8)Lx5(4Y&e*$s=Rwpc`!MZQ`^m04y;Vo=5=s)_u5 z>s|GL4cQ%i|K3-0{x@=SS^D&;;@LH!=Bvll_KpSZXg4$?Jt7m~*n3va$j~wwac0An z5zQ(x;t)Yrhv{}uwp!^Pt5<;o=d_P&?47r?qg~L9GJ$SL$P)j55ua0w3k*pDou=Di zM^6Z=6Bub<(2aGHK)1+5STXP7D@glN(p=b9rVBhCQ5R|bE+taroqA&(&tra9= zTDd-?j)klqe+4Gmp`GZE1Z2EsqsucJ?jj_SP^rb+`<}+%4nB^}2?5xgsKC21Yw=d3 z61xkc=n3~MTj-9~O9DN92uvCmbdzn80Euu`6j?g0QX0n)4)*>eINCdZ>efsX)Y;zw>)rPbd+b^R~~e2^Sa|M7F8Z z9{~dw&`lXdew{SJCDP7iVoOsHQ+kxv3gZ$HCJrp89RpQyy1Q{l+7)Ge7- zhbp2FoG&0)B_Osel7jE@D0G$8fXFX4Aw*4C$W-8H^GUBOIv21FkU+<31#%wOUSR^Q zB+w!<5ssTgYNu zPLuvTlAATOPDoQKqvxdaet5yF6o_F->rH7%lg7|@MV#480e3A~(bdCj=Su>8?fwWf zFX*o_fo743=%*zK-IM__W&077AAp^w1Q#cj2+=C=aq1I@E{UUEtO2Uw8tgv%2Yx?D z6^J}@)sjNb?z@DYrvnjAV?wnXc#&sxRp3y02CWZmT!d}iwe~*b_$4sS1X`fG+9Wa& zNy2~}YcU1$Ed5eigw6_XC^_M$6xfov7Ln&ZrL#mmqDtT3pNHrJaJ)_9tPi!Fy3w!^ zDqABWFTBXVBUlrF%-&L(Zo9EL?%uWCd-i0z6-~@5Av+UHN1}fWi)Nh2Oza8!=qdAb!4&`2QP1+F;pWIX!hVa zlB}iR_TWIpQ~YxY!RQ1#_Q|nmg zE<{x-v9Cmd1e)*e9ZOm}3`jD3z{f-u(_+<@!l#yYyanl|tQ$Fl{s>&FC4mM>fJ8WpL>O6?G(^_~BC1M(=&HA%ovL?9I7HHVqi77x=}HCS z>pyj@<`Oy9lQ`V;8ow_=V;WzE%3ke${%{DikU+d20@q1kwoYUsP6-c@W~j%%L~O%4 zMAs>3N<2q(QY>{WXX|Z6wj~!abpoPmsT0+0qAhwO9Q!OTp&BW}k+u&JQ!fxor1zzG ztmynyINpU^bF&`;vo$18FA0zc$BTr1rU8drpTnUhn!6QB%7_k9+ih`5WDe%zV6Bpm zNie)g0(G8S6SnJ}Xhv%9XGk)>PE)4NW9!aOg%h3r2^7v&FBHy^!1Y>@iMS*diOe?P zSnr33Gbky@0D8jPDQFtwXuY(OBfcRF(e(;G=4kh3+Fv!h)rjXFOFde#XxHmF6*2)! z)9sL~)e2l^0(BI0t;j?Q=G-I}iR9Ri`s}Y%qQ^Jdg{#p%=n%+P{yAtsfI+6c{53Ea0PzC?6xBK%Z1+3u&n922OO1W1JA5b>4~^_8!t+B_-mo76`uVC` zg*TZ%mB>W6gg22n-x=}Mdi@pQ$J%KoP=7ltH&IwoAg(4mpm6^3LgCG76x<+zn@m7v zIT2rl-soGzDdAolo+A8INHR=dM{evBJ_Y1IaD<+U`K@lg@;`;&R8z2*?-t&y5}62R zUZz@Nj#1;{I-^!(>xX`pQRjlTC7v|6;M?{_Q8&{hvNMPbWrwCu^WB0Ow(Y3??!EoH z9+d==AMo)freyZ#n_nF3Eh^E^SEA^j^wdeD=pQu>Y9+prsgteR&=?x z`q5_s*z~!7SpheR2Z`S+UtIUf3m^Yw(}wq6a@Sguuk^I08bJ5SfPka{akFOud>%YeI-bv|bm>vKC N002ovPDHLkV1h4|r&s_0 literal 0 HcmV?d00001 diff --git a/readium/navigators/demo/src/main/res/mipmap-mdpi/ic_launcher.webp b/readium/navigators/demo/src/main/res/mipmap-mdpi/ic_launcher.webp deleted file mode 100644 index 4f0f1d64e58ba64d180ce43ee13bf9a17835fbca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 982 zcmV;{11bDcNk&G_0{{S5MM6+kP&il$0000G0000l001ul06|PpNU8t;00Dqo+t#w^ z^1csucXz7-Qrhzl9HuHB%l>&>1tG2^vb*E&k^T3$FG1eQZ51g$uv4V+kI`0<^1Z@N zk?Jjh$olyC%l>)Xq;7!>{iBj&BjJ`P&$fsCfpve_epJOBkTF?nu-B7D!hO=2ZR}

C%4 zc_9eOXvPbC4kzU8YowIA8cW~Uv|eB&yYwAObSwL2vY~UYI7NXPvf3b+c^?wcs~_t{ ze_m66-0)^{JdOMKPwjpQ@Sna!*?$wTZ~su*tNv7o!gXT!GRgivP}ec?5>l1!7<(rT zds|8x(qGc673zrvYIz;J23FG{9nHMnAuP}NpAED^laz3mAN1sy+NXK)!6v1FxQ;lh zOBLA>$~P3r4b*NcqR;y6pwyhZ3_PiDb|%n1gGjl3ZU}ujInlP{eks-#oA6>rh&g+!f`hv#_%JrgYPu z(U^&XLW^QX7F9Z*SRPpQl{B%x)_AMp^}_v~?j7 zapvHMKxSf*Mtyx8I}-<*UGn3)oHd(nn=)BZ`d$lDBwq_GL($_TPaS{UeevT(AJ`p0 z9%+hQb6z)U9qjbuXjg|dExCLjpS8$VKQ55VsIC%@{N5t{NsW)=hNGI`J=x97_kbz@ E0Of=7!ToDP!qdiM+BB4 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 diff --git a/readium/navigators/demo/src/main/res/mipmap-xhdpi/ic_launcher_background.png b/readium/navigators/demo/src/main/res/mipmap-xhdpi/ic_launcher_background.png new file mode 100644 index 0000000000000000000000000000000000000000..ba70604015d064c7018c1a48ce24c1f0448d7747 GIT binary patch literal 23337 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 literal 0 HcmV?d00001 diff --git a/readium/navigators/demo/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/readium/navigators/demo/src/main/res/mipmap-xxhdpi/ic_launcher.webp deleted file mode 100644 index 28d4b77f9f036a47549d47db79c16788749dca10..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2884 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Ν3yIn;k(fV^S5GEWA*~mP%H(s1a7ndKSwg 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 _6gHQ6F>>Xw3FCIN|>86X;m(e-p7n5uWN zo=Qze${Ypyi;kqxTT4Ypm22$hTXdX)X!>PPqe9IAVh;m|GGNRKhCO;kmn^_&tlF(7 z8sQG`<9{wGIW|x*V~I-f2%EFflB%?gyrOkiK!P<2yrNY-jLGdgHr)VgVl^EdD}!L~MzT2*E-Am)YO*pq=RYJlTlnkMgF3*e~m zcWKBg(XMb5P~S3@9s?xAX&VLmY_XozB2_l=l0MhyNE*9cLNvk=sp?c^+KV!_SP@sH z%N2u4^iSEQQ_HTTqdhO(NMD30@`~Le8-t`CMp0;;ScMhmsu<7!dhJi$iJSaJn8^7+4IaYb6WjS7ja$YvwIF zY@edYCY91;WShCGY5@s{(O`6>g0)#k0c-a1iX&xbP%;gl>zQ+mIfbfDj`Mp_+oL*) ztw@qACm8#q8KgLrjv3-D9tc&7dhAe-xLwC~j!{d0vDd6khdb7<9XeBX1`Sc+MLZIy zZGcrDLCG;Lw^+2}?@}fE7)z=1ic}+awM>Ixg7KBy&Y&vve@WC}w56(3(hQ}`8P#=) z3DYi?8@qEFz!>W;4hVZ1*($WEX**pNT2g>v> zl~Q+Kx+MfggF=f)Vr+n9hr9-3`uXUh-B6m#D_R~2w9u-rL6 zVv0EdFy;~zyB)$u+F_ibZLatvhwnI<+_g6E7u!--{)dm|2{*!ud#3 zfJfvS9i`!wOkGDI8j)%Gr6vxiOC#Y7n9?e>lpH?iG>b1eS=CvVUz9X@tArwS-TxB9 zX@Qk00f-0)yL>Rb6*I&9Ej1YC1z?!HRYzm;Wzb@)jtC3~)s<+MV2!TA!ho81p#&uQ zjhLaAG!EFXF!5r`9#!h^QnIMpUFLKcqasT+S(H}Z=uJ<#xNKz_Ri(>Wyj~QcbSaGv zqpYFZFqAHuvc|f;IyWIPmXn0mIrec9Aqi5&Tc^o8$;N=KN_##acKZwwE*}KDXi#LB zqfW7f&NYfh0rR#BFWNQ+hR%QnqkyhrHk$Q!@ftE`z!b_lVHJ8L8obF?9h)sXGN7xa zlNfW7G#IODX)(DTBgqUIK?&AVT8ll_lHCAHX&bs_AXw7}L*t2;dg{p*b?;(>X~$vJ zboBCzMt(0rUePTCfarr^R{)H}Z2}C*{9>L7qvh-|fhB4Iqh_nlpoQK=r7K`RGvUGm zq?9c-Xr@TF?2wgby{Q*ZB{ycvF11!?RgBT)LTMHd>71i$1tcYf7ge4y^*Eq`7Gp`J*sYct z%NYP=PF0~U@HVMAf!~XkBVfOH%0&<|)60v%kO-*-`9-~^ZuUN+LOqmq^2IciPT9Mt zWn<8nXl1}FcNd6Ix{#?&M=c(aHH0P&utvh)g|ALK8FGwNv$tTv#Yyyyt}qf~yp@67 zNtcoGd#R_JfGMVN2{i9n%t=7eKR%$Gd~pQfw384@%ff345c5Jn?26c7$P~ROtR^bb z0(PikknuhPibFb;X~X&G)Q#P}+M%?GZ7S8+-QfEeJ#NyapYxCQQqM;h?1sS2;LI(G758x-STR52$Z&(y0xp(DH^&N5OgV3oqlDG zF%c}ouz8@Lk{c6^1?maYk`3NA1thYv#xi4oWiC*wugMta8dVi&orZ6Rvo#?47Jn*t zK%=&ux}EVrjg=D`U)9ajbBa0*-VIKzJ4ZEq>oG^P+z1eFcS%_y3zB?j-A#wm33)|N z#U_U|gle%mY3G>kdCX!<*d|n3F2JilKbJ3)DM8on3Aj=wSBj5~3^)tp{b=pvx zoPbe<%sRf(tar3q(P+sL+;$nJ=<0%EDT}2+-M|PdeIH{^C`_A8NFpb32xNsLc#&Fl zi;fS7ce*8EvMwlgQz3Q!mbef#s&u!ZT6cyVSS{xLFfT#_SLiSjsx0%>uiD8N(V4Z3qjCMr8$OuU|8lkdC zIKolb7jSvTMBiwcYIn`DkF=<R_x{_#n`?@#xB)rZn2sSjAfl%V$zIs zExCuWBw&UaYz=Zc8jPaKH0AF?JO4Qec|-yb1BQ6JlV^tp`9+pJvTV_$MJG`-Vpzru zQ-b42iAM~Wx9Yf}qKiOQEJ=*k({0qmqkY|cqGrC4l@`0DlUEdg6 z_4JN_#WY?ojcnSC1xcefB@!VPrFF%CC<4ZiC3a>9#9Lj`enmZrF^wFfQPHJ0qrXdE zYO7TJcAY*YOLT>H25j-A-#mn_kAR1CO%zHOv-d9=RHDtMUDzh?pwU~>!{}-WNK|O1 z$WFl6RME*i>5{?gMFohZq?VmVwubJ43=~B|68_dx1EOFVf}kg8)A5KgKsKB<14BlC zamWl9^Sb?uL#A`ly(yc!)Aun_9xoI?7KEX6DtEw!Wh(+yj0Msofc?rGqn?MfWh(=jYIi+jC0b&a z>R6e45vz5pEK%JAS3pO`5=Y9$pk%X$F{MjjqMboTfGotUk!6ZGM$OxtA&SE4l&p~z zkYIZlE*ccLWk+tdC1&grvpFn$CdADzpV}X`|vx3O7KJ{$h4O z6tP8?Id&$r^Q?L?Bp6>myy2tLKz$i~<@~ zr&IJY=F+mqpxW$}5Fma7LF-P34`g?U{WR-V`cRsyNDmWQjKk*h(IiVG0WxpY$ep3+ zGL%$!=}iusHD{$=O)W;=@1;QH8Fd{2g*FCCA888)SXoB^tCGg8rL9u?jr^p!MsG@xHrepXOH%D_SXS)j6m@J_8jzkZX)DkyW276oMgA_T zMsHUz6RqrFB$abgSEX$?bf?TGCbj958VTXEd;~D34Tup_B=%DQW0z1g!ZQ?($V*%S zIX6Io?g24N!E*=5B$S4(t2kX!J1BpjfdGN@tjSNez;<^i^l+V@Ov(Qmj_Z95EoirUQsk zp(O~X?_|j@c4_x9dJ@wsj|rctndn<;5X=)rmOR(o-7W8993BDx=%I{bfEvm=u3`+( z6_{SRqCQ4NC0e^(M`&q~vN~N;fMeaZXhfDuwA>vqu1J@Sn!Dv=fqa9vTd_6iQcac` zlYw2?vQoG9oU~aOol9hhB7mfFiX9olX`)T%mPzkoH74BJ|}I_MUrFG zEWmggI*hVvv`+Y(mkCE0E9&%QoOm&udKu7F)zQx-dJ@JM3)1#$+opPTy-`5VmUu+H zG(u8iVi5_)AlJzGM^_kI0}}MAYG9;=X)E$#O9E4Le{z7V>rcKE>*hYvQUff~2rKSk zBmnWIK1-CcMhk5^x8;i6o|cG2H+BOgnIkJso7ZHF`~-|7gdWZ?1~`~jm^OMuw+~ThqDSu^vD6x*yp8JKa7?(clT+lb_>;Y zD2oGeF42>)MXvhX7=eiw8OYVsvcyu#>a$6MH!m~hR^;tEVg|{$0+y>Wn^cYbRWka$ zl(JT(4V(arX=bD8)*Q?bUn2qW8?-vIF~%&Tf495TiaNLT+jTs~@XBMDVt$xrjjEBr zyh4;VKa{q?+prQnWYPR8p(5?dLS~s&DxtyXHCV~9elvd;);?8IWbx8gq-&P!45~8G zh*F}mj-zd9P~l|8*nFa+Ax_JiVJQ^5GfRzCEw|{@6{_7S3NQ+g^h4&m9RUyq>rMcQ znSrsBnS8O8TkO;@xDv5OGN;%@v&CE8TFgG~KQ%GZS$ z3)D2dN)n}Y6M7kiA#|drw5E^rKSP*SF(0j9h&Sml+7u8)OwraTAXka*Os(3@%}5W^ zA+(ov9MH;)bV5&~Ru7{>RcF9dL_%JKVVk=}Zh)+9YHIyOw%~%>d2CF*5XBaoI*e62 zRt6$F1D6e-tGud?-fZ+p2-8;e8oFh`SRNrzEXqS@KZkf%z!0SX*})WEI?TZGwq#b? zMmVj_4#nnI9s!Q3iI>#oSHoF^X?s%G8Dy_YyP9?eZo(KKsi-5XL`z$8lp}ye%LZ5_ zv5$1!5-?^Crz--Gtk4WHVJ zCZ;H1jaEYG>>e*7MIBO{)-w{PwE>E~8Ps+9H1dkQDJ)X^q~m`&IYw6yN+%UqJk{u5 zL$5u@O9PCd!j4tp2tlzWwR(3YHoU5c3ojHnR&|^JMLmsGi{Mz3gws_$#cnOtZUg4X z0Hhg1q}XDIpiRdR5N|X4nbo@ef{Q1qM0?tkE?snU_iz@w)SgUMsYc4(gCpSclHeU} zs;J|#BY^_*D^F8%(bK9<7yfl7UaHJ~<}h09?LtnzB(>`3+NC-~|DtQf4X|eB@ls9` zM%Rob#`GDY5F|S+<`_E#eT*I1^NhE$>o9tP5x}GdZ&?8*pE-=Sp~Kjlv8h{SZJ-fK zH+X*+PvGy8WP&9Pt8F_2j_4?0*`kMZh0|da*%~;CK1P*DE#)JvQDm`de3j(yQZ}7@ z5w8dk+X%30W5BQNrwpSrtLZS!-M2c8s?p+!7r&vKHNi5=G4_aUQ-{*1cWWqk4<=a} z7=of^@x?XJT;xXp<+IVAPHwRt+$RdB8#b*B(lm7&XfS5TF*+KKfDTi9QI7#u1c1me zM(ehznrhufjoo@7bO4A5^lk(|cf*`5a;&i<8%SCKMNzv>XGX65F;hia zW9ntdQn5wLOS<386;QzjGKwHI0S?o3ta z)Hy~2tJEPKf!f{-z^Fe8=qknnU2fW?U&9HoAAZSuK(5>czaX6;*MAM1?!6371uIv$ z4sxYVa2hVB(gT5}kg=(|XhE^N%nQ?IG`!OGlCG$2Q)M&JvUVL;R&*KZmYqz#E;SV( z-pB@s-!NhHH(8ltN5*Lv2_TYyciS|C=G%2d>fFgDSZq#_5vLsq@8}Vqc+sDBQMT#~ z@MC~36`d#qSJBPr={AMt3=M!M&^S=jAuKx{qWaYi!!DY?SdUVy# z!4n&Pi|?Pe^GUEFzXiPX?h$a{tM|a^Vh04%zVz)nbxR?%XyT<-vIB&ba-`TDsdr15 zqK^NIlVFwVS{ny6WQ(PA)o2P3+wR6-*p>+t2_THNHs+%{EQZkO3NN0je{r~*vrDA_ z@RqCq!-8VgqKl?-_mHm7i>8XVk}dXYj{^#w0m(4B-V1WY8({Y*ZD7rbRbcva{{r0xCi`x{ylI%UcaADANxIe9QhdH zIp{tFqJLO020XU*KCtrmO0e(Cw_*6*Z4QbyG#IO*!b{oO3P%DR3LwiuWgS<`6;NS* zr3$AS1Ip4NN9px`i{+ zq#K}2hcTaK3~(esanNqNjw=C1H-&Hn&Lu)dc<|!8VDY|ZaM+7MFa*GGAuwCu1Kb}M z#_Lau;95*9c>9lw!u#3RxF>oIw2%JI{Yxf+dApthyZ?3uevx}KIs@7ek0?d6(bjT{ zl`;*4Ro?8%t>}*eN=0eQk^+oP!H7~ecR)X6MhuYz#9-UTu*G};gl*s4q;9i-C}ob6 zyqF;0n5l=+ayXr$RmUUDukzHE&oSl`3NRE{4%r$5G;Gt!+P|n&)?w{Z#cexBZ~PT3 zKRh1-(?syU^G5~X6@%X&Lf~6G28O+3AYhIK4=o=H9$pF8s&U{Ev{u8lCfLH;==j4c z$AO1djKzy|m-sB1}Z3ZDVH~sRBr8b@0 z7N=fPHF-0(1n@eLEe)QuCs6PqT0CpS+3(>6~8)1Hsllbij8 z?w|VH1o-&z;IVb%@$=E^px3(}0xJf`01!jwh#BMJiD3EBrQmqySIHIXnm|p5bO@~5 zbOkJBvM}K0qzT~&nRm2av4!@MR{FeDvdE4}6uV1i=2!ZF$O7Zt8xd1%i;6He%z*KZ zsKNWDy~4{K+l7}-X)ZCTT_?&n4vQ<(W+D;^{fomH46tMk-9swd)buSnE@ze62aaC< z7%Y5sX28@&M~n@zw?82kh!`MbdkDx7_#uFs_QE7E{l!UO=F5}8%xz8J>FrHm*3KsI z%qwU$$7^RZK0XWHKXcn;FatgwJr6w}y$*W4$JUR>Z1O?KAQ3o5tTD(rB4B)M%`d_B z4^R88JE6+X33Jl7JATrNv`(Ip6^;LLrHeA?Am5CSH0I z05VOn#jqkR2&3IbFWC3_8{o+ezlN-AR0M=5B))&?Js6-KT{{l5z$YQwLqLWA4S^p5 zyV<+p+S3f?>}>&a_qBj|Xzg$1*FOJ#^td^DTEMfrn=x>r*Fk_fed{Fr`Uo7+-+O4K zA6EOUG0ZWJ27g*K9;`UF9GvLAV$jfCqCKQ-hS60fzi42On%u6#sC6e)qLb#LU9Lr^ zVo_D6rl-T0%n+{!fOnk(#Wn#jwuJ>2Dx{_xyW4cC&{V4qGbf#;f01R1sl#c>C}5Cd z^bAd~JhmczE4d;qFSyuJ)zPd(OB=jJKqyz!ahalvTkir}-`oWrS~?k5jQ@zj;st(g z@Sy+*pMW9mv@H+>Uz!AF?PvneLJ*u20^nXB?B=6&Ua)9=@$1igX)<`~1wXug6tdBWR|UX`@|Fmw7x>lf+1nojhpv2V zHaAVljEMjfFROSagB?>5LJU8Ts8)Wu865UwPhj%!pRt@W<$W5^C}C1 z{=&c)?9V?KfF9n5_mPhw9~V9bvqyiS*GG)=nH@fBdvawO2E1|#bu zT}oegsZ_Xd+L0*g$od#vroiG#CS9U@qof+`+Gx`u7-I~G-(C+w(E%{8K zC<8?LI0}=WYv1gH;X0{!J8?qg*2bW}IW(JQ0V{D6jdaC1FqFXmJ0M2@n+Blrz#LN#VsJI9lml zjD=}qh3+z4aH-0fp(>o_Rdob%V-oLZHJ5g?Nk)Kz5aOouQ z%3s?8P%NacLR0%$z_C1neT)@mEU>~icx!~w;;M92J_cx@-tB4?UHttZhe!aT1Q_#N z=zLwAM`YV{?$SjUUPR)C86a}1IvJ;5C@{1fO5Zm1c8RT0^K5=m5Js!SBl0@xI>yy# z1ICyTP9M1V7IB5<5f0wci| zpWZPUJoVxvF!edVj}i4SB49^s_u-YTVAtQyq!XyEF+j+v>y+$(Vzo?zV=cJ=<0$tl zO#2S6tm7o)6~)4}Rcc0>tWdj|4Y26OZl583Ct!$5fRu;Jc~MUBE&xa1vH$McCKc4ooI^WX`C-?3PR)-zcPHtUkiing2VKdJ09#W zWNuUU=^U5cht@%#v7&y)Ij{OXjHnd|O~yR74o$p_!F`hm6rbJxC^%KPVL_m_L>pgG zOtEO8ski&l6_y9%)MDzy+0uL;3Wxb6}K z7^Y1}S!f|zbK0m;K)woXT!|iuiI+QBT6DS+Lg`MfD(z{?jd21J!wf(s=rHn(v0GVq z$*1jQ6fnhIe>sk;vlt9lLof`&WSC1)9$0>l4~82M z7)}5)ATvZPYiG zd?pP>(FkBS*x0r<0z<^2P>6|G6#^0jDDw`)Ve&$b`TgsyFf5;cuq9%Os2DW;r68xc z4uK*9#CyP#n|=jO^j?-Y0~YNv$69d&JYGtcoB-vr71V&N~OjmhFCIz+KLDe zYb+qLpm;4A9KRJ+q_1<8Xw`nyvq+8vQjC!V#}t)m8~H_{7Ndn}ms@6Y(w?OFf?IZm zB^7CjAy!_e5^X`8_Snr2z!Mu=!6N|}qR?l1hL4dwei8L}|8KC*N%}jB1g{qzI}$7c6fslWfkYxEf~oLY5mQ90_~BLK!M?99 z#9&AjT5RPPnGo8R&kLJVw5Z3(<`YdAqI_OjEEwS?2-FgQculc1!s)v@AvHZCotO12 zvaLFIMSY6~mFYV&wrI)YB~yD&7Y&ZLI(Y#JZ7^glQ~6OqPjm6pFX@@%v5pTRJ8Z^m z3H9tvdtm~Yxor}7c6Sq)yRR9CoC`u`NC2H^#bDGbJih2i2vjkPTYT*2VCjkbqP6Jg zz3_MoUW<;jN?%)i9<9Q23fUscDWZv*XZIlWoJm+50$uZCYY|f%0~Q{bjvWDcw?Nx$ zaikbynQ#ZpJ{#?bKryONmxXLmM@&Lim3BoMj8Z`S?pgvcUdzN9b=aavQ711{?>6^( z5d&gYkhCl{rXfh{B{X*P{w{(ZMoAHd?`Q1MYwnh^3bRN`Wy!AVPHf8`-3b1wZM`xy4RNllRDiqM1uzw=rAHn|Mjfz!2V-D}4=SZTmF_ zgeM>vJ_WXuM zA*gg}nP26qH^H&455U$B)_}zjNHNGA6P(A<_&g#eNt|2woDdY}9i;P#=!XFP4<3b} zIB)Nx*g91TiXnTn35b;TV$m`n+7F}2Rvl^-u&Qq6mWSC@fe{uTI@5rt#SmFwyk>zd zUQZN`5a$&|wy8JL0itl~C2MoHEgJ)|pR_qB^57`*lJ?TfNDKCN{$;-phMVG0`I%jl zF@u_aCwe)?)lwA@fMM}T2x>k023V{K76FV-y$kHW?84Xmtq+PC=S7`c$XG*A+z&x<_hc{=u2m;;%vWnd$JNBuhVmAwpwKOAu6@mUD!xF3V!i$?& zaH(*vfL>Juh>2ly5;$HKL~So~N7R%>5-2psSI z2!dLVz&qN&9Z;|icf1YOz5Zwfii?cS&1bF)j-b9uG?$Gm4v>G#MEt)%mFFinH-jTL zKjDij3^)oIo=S3nI;U-q1t3r|5Foe#>fOu66ir-~m zi+4>z>FY|t2q92%HU`Pf-A1iC-&pKjOgrr&Y}d&aLVJvQw`}|`Z!-Bp%tP<`M{Xc1MT(-vTA2|^Oq zE7B!9IYnYd+93sNE6J@p0JcC$zqH<>ID}RMqG;KwM&DI8cat;H`2>MlT9o#tvP~yd zRoaT04g-!^s?xW33j@wiTDxV3nU5x`&7;N zlW_<+|8T$#kJHRh7>1sJ`zOfbtzhY?`@qr8w-kyxGV`lmBc_O)08jS+9js~p6FiSr z>O9eTEhf&3yL~(^_8>NltIoS7;~$2nUYr1)fIk$ocmFqh{VU0UNPwb80HG%Z!;AoF z+agsYHI}t!k??nM34a$+2%XgAO@`3{AYLN?@hT6F-=+zpuj}U-?*w-^UP1`X0j9MU9Y#E& zZmUg4WMyC$PCEkIRFNPpwXbP<2rDD5fi3_KDL$)d}xxPAq%(%moSIJ2f=#MmHo9gc)G)L#rl&7vI?m@B07(~L#O*kuN_5N+zfS_etNH~ODRaDTo@2bLvN5=>HTA-= zL{4t(CKXB>6=3eLpqNH`@g~^Nz7qUt=_v50Wuw9U%kKfJa|^-g@@Lr`0YxIUDFBgD z*BKU!05Xix9k>qGy3^p7ej+ZU%-QF&Lp(nmfFS~mC8r?hoeHteh@owvyUWvS;!;qQ~rzIF-u67A5I`muc%*%-X zIGSEBj!>JC)@Ae=;tvEEes2PbhM}}pUQqy$cQuPKistS%MQaW#H`XSxNNv+C#IW`)%;}hDqR|Rri1gSKfmar5{*68n648`@s0XiZS4Y^9T^GW)!AXRHbj33)Fgy zQnwcf)Vh@~ArSr>n7wy0{PH(pRAFMAIw#CI`91i4Yin4vutw5;H?`ON7zn@`zR)*EGLq zqwo@j%2JP)5dcL^6D&t#>ct^gBRc0>Txm_aurtzn zZ9C-TOWQXhBP_G&mo`Z#-FE9bSe<(oJiKN!cx2re@aX!nc%l7=){OB1a)l3)2ppFl znE_7r|AkTP?#Qm#t(cSc5)H6;wwNn?48QO#V9tIBhKC4tc#>d#IeIM--1dQ_6)bn| z11AfAPGNf0BM+ws(^RAV+b8<}3eT-odG4ZXS$wJ${~u5b4*K6b3x6_{Ond z>ZWnHQTNFg{DmeN9)rgpUK<1B{mVyzSug(%9J%o(VS?3}y_Zqezj#~i>B8n1!|n0T z^N<}*qS&DyDhFUF07PyDV2FATSLXj40#S!pm{!|1wO7s_2hDmIPggF1wP*eS&$Cr{ z?#ratx}K=!Al?RikKnE61@-zqvHjp03*6xNNn=vdKeqF`xu!P zoqEPz#;QtHCristg$khwhA08U@0oD=yNu!Vw;HWF-({P62@5QFPC&v?JVFGLS@ai) zzQwlN*TBk?(;(=L!Ql7Q*70D*wuv}|LKR4~o&NF!@WhsJkTs6+L+TZyF(^L1u?6h- z^B&+1U6IU5rzpHo;d7_9*NZ3ccsbtj24p~!AUkY=A!2h7Dz{LqDiI7%`z7`Ex;Yn32}C}4=~ z-v`IPyUG_`SaAG4MMXN1IbKf(io(3&4WWfWo2n8mQ0|V{;a#?u(QH2Y@U=GZ_;cgH z)Xn4kdEf05Fk3*ZVJ-}(P>urroCgCqV&K*LQhuI-yRLjtE_!ZuVwwM{7^uz20N1DL8Gmk^??~v;+ z8k=EhRHhTc>0N){4nezFd@YXn8kYsvhOP@&n<0aK_Ei`*zcLXlKK3BURc;cq)N!ax zh0JW8u|b5@383f+n!EWTOwnI9m2_$)e(J^MtTdZntfg=8#(?-b7cyT-4xx=1W5Rs2 zg(`HO4WAR$bjTc|T$52aAAOevLk-p#gv*E>E<5%(cOrFAvkp?rN{EaS*%if#DJ*CGal=C zAD(Xub?)pniLMbd-xDqPe}lqi42bZ(e`fc;1$o3iAyahOmK>5fQVfy?!*uh}MMg}* z0zlRT0BMUUD$K7OL)MtDRYeSu1;d0;`nxp1sL{`;6pXl*ZZweSSX2c^B)~TKg_`Jhw@xd@)NiHgq1Y6hNhQ~vu=r=Mq9%437A!)+~dQmVdxA&5#<&iSu+8={NBqD5U%oa zV|P0203s(jCJw3H@+W~LR(L%=7%V41aJfqZWO#e&=`dVw#^LhZ1Czmu+#mfOL;*w0 zvpS4J87)&abBs>?26*nRC!%Z8UFaH@1V45-j|i_1z5h?|91k|0Tjlp7Vvy^TR-KcU z%QSN*0iyO;;E0Gvu(`#oirv|C7bQ7FF*vrX*y8tD!svvM+J@X%*s3E6p})PZY{`+@ z8hpdF=`e*C5mVfI@q}Md-V(4w7!KnC1pM+ZIvIc=k&9ZA^VuRQF3f{pAjBk}eq{oD z?l=spD1;7s7#~_a2CQ)xz%b!+iHJlxw&)p%Mc`Hc8h+`25wOGHdR&b~03y0x1Q-Yq z7ajX8{G#7b03xHwm`^W=_VUN8;d!@+uf>xeLq8Dcy+&a(`XNLW`KNbH04v;S zkmdCfdW`){PB9rI$=ssbVB2+gRUM_0j;Mdp=Cn&q5>DH;O|7M1i0T}oVL1JrX><2A z`M!}L?KSgIS}7o*)?Ji_(L#aRoA66|8M4ENz|_rSaUlh-o<;Og3E&|M}c{-{s|oEcq`dD)rxQgzuJbb!!P%* zF_7cdln@L&0vJTgMLz%t5SxRL(yzqMJun4c&zlNoz#hTYG?eZ&3#%a@zWVh(9}ttS zi@8QWEdT)#U*lxIfCk^s`3HXsj`e&d5UlMN0AimS6q(#2%^C|tNUiX4QL#ia*I2h~ zf@M=cqH5+JO@+)6(EXrhigIAQl7T52w(8hY>}CaOzfI0Bs%#Bd0SQuNXZIHe!Bo_1 z2-)HEm&b!y@Jle~z$Ey^XoBF;9D(6-ZwgqRpW<)BFHr!Bm@UG`&pm`ft%-Q_>&X|! z`XTh1fGw^X4W@1RIoSKM6z5YM=d~sMDT~DjO6)gN1 zZ;B6y@ER8cjM#5YnE-ZwdBniZfGM^NXJL$ja5`X!Ckub`Lt*ZE1n2oOyRFB$x!1-*>w$rlAsGG5Z|&_yu+!2d!(9E(F`)O&_PrTK>^<6IjG zm3=S_7Xu<83vpU7lf-QC2x1o~|1<%==G0AN!6T>&y?QhT#YfhS2hX410Kddn6n@e+ zbr*xe3uK5deJ~e-TXTF(;k5+77Xw6V03iP3P~{f=ID{c{2#7Cz^n5fLm`~7RRJsBV z+X$omb*lUYSbOHbqVr!7fZ+-b6kDV13UuuxOFZhQ1yFu?77UwretN{WQXNp6V5P}1 zhLvh}fF1#4bBmr)vBkDv1ly)F0%5d5r8{2_L*^eYN1%wo@P{jLq2&jCP;AefSG=a! zrkRsY0gQ!&<;xJ< znu2SJ0V7!6-wN6o9EBZn3fxiVu2PkYtx#3y6CxCTl7W#!1k)?qU5c{;jkZadrWX43=i{{{H z5hzD2w^*iGBgYVbyy`PU1`yM;#HY8Y@emXvHig1V|4W5{V+N{1 zL(qLR2%!;Md|>4$@a&HN1V?Yasg@XsTHm25E;dyES%uYCTJ4~UX$60PVuA@HNzahw{M2$r6D2srgl zvFD3MD6N`>=5mW5c-EJ zDGM(NBY{~}y1zAT)zPR*E3FJ}C`SQ#26-K9`*@oVhFiyhnLEbg+#dq4MJJm4urgp# z_zTmnu>z1pU&N&lbTEJfj4Ev8p0;&7u0lVu4zb12m@PiBxdrU{+d*G7M`>q}U1H3w z{28ol|AqcFwTEC4hs`*gJm|Bh*?XHH$hOg7cuO2Qi~V1En5wj-@M1Xaa-{PtJokUo zzeeUdLzW)`|D6550Eat1F!GS*fw5065WzNdGkuIMqoU)bY0nYm78^D_UW)dCQ4WZg z>3kxaS2P01tK!?=WohoVX_1=J6_5i)`JA*n_&IoH*DrDJATFfrnt@+2gSDG z>tMtA|Ml6e;9A)03a<%Y4`xrzIGupQ$^DaX9&y*_`~49?#s zRccGEIyQ?hL1Q=0A-=`|qQ8y7@iLWTY){N18idiQCC3c37=;dj*RvO4gg{7-2EO#s z7RV0AfN3v{!-W*Y0>V&vDFKEu@LS0-j8+~X1Gc!#^ZOY6Fbws#O$-{jgDUjefGxtc zcGPj~BvoYtg>8@LIy_hzdssAW*zI0c<=s7lP1DLS2Uurqyr* zj6>&cx&qArVqOyvbG6H0nl}H65-!CtG-(ua{$n*e(P_qS*37Tx@9*wCS`P zht2}w2qWgGS&6pQ;4NT^sxd&P@hJqPDSjbkd(dWca1vxblX0lL9DX5u1_eRxHMo5( z-iG^H3w;?8D58bIq!}ze*#zbvMeGWK;w$4ZAmb1kvqc1oKLby1`@i7e)z|!yKOL4x z<{CBD{>!`Ic{QuAr9EEwy4w-BxA=?~Uc&--4RhiD4E>NSI{rHd1lJkQ7lJL`;sG$p zM_Sn29V+W+7GJjgZ52H4=IEMq-n;NRmpIMv$FT_m|J(rhSGY()yW7YBOC45g6j>w% z7nd0c)NbfbVvp86UP$4HV(OknO+e(?VmlK`hk)3gwr4TZv`f~IT2ECc|E+;d>NnTG zmUq{JCtes0o_cv4cp8Ed0w?qZUvjz$vV&&Ko>sQQ^%}ia1&ci<+NU4iieC?b&~gv8 z@-$)aop;C&IcID`^V4I%qZ>v;wg}gnQDExEiD3IjJ0-0-vS}ARP(0C-56;gAfmM?8 zXBYavp#RU})4};4o(TVU6ChJ;1t$w1b8=((TfET~nPZgY8S@%_j5=ZTD_?Gnu9JN4 z{Oe}lw^sT(U3i_RAn+fXgx{yx`ylWi`yDu0x@he85{J)E1WKk3`1;VfU#Y`8pD>H5G=V$wf20pMkxJ#nlZqudhUQ}o4OUnms8~r z!OZQ=VA|HPV8-@w7?6+x%%T&MA^T~@>|jMZ@g;h_l~^so^1nRM@z;X&x@d*K7=j`S z$5FF4VjvJyjv$r=L2<`8@Z^hQUC64e_-w*F;?JD$Jhzb6uiRTO{LTLsdPxOBTR-gHK{N4!Oqm}IY6m^w9(kTsxoO^`cRQ zRup1%1SI%EOo7WUiW<9>p3-$fv0Lc-VzB^2X)qSk1ELHB>0?(Yrr6FFVl?uL?Ly&* zE0+2guci>9P0`0F0>^Kzf=zENhrn|Wm=0Ol)4L!$gkR|S$9#5(zU(X71GWHxVC5OO zJ=21}H2!L#*BRn*;bWA~@sF*50JI#k#id@%LJ&(uY!w0Z&E~+(0#t@ZkaY#K1h+GEOpZ^_keZ+fprd7Nzy3V5z5D)s-x$BE#8kPnI z;qzdhU@p2(J^8}uFS-FJx}0*ip}&h3b1Y;RjG#=gj2Pk-VTh~(#E==bM+}iTE(N}1 z0SPVUXsasyohc|@(*noieQ!Zl*bJU}X)Ktzb3A4?=+__RicpBOA_$W)Q#eDe7Rgq% zT8PCwH~7+F#^w2pYr!#;lbZ-;?H&(9`LST?W(bNKMn`OM#@3&Mys(-CVGMy)WK6som4A1wmKq5=?qyzDPwc&q}*D-m04BZ2b!D_m8&{d;||luC|$XQI@7 zRlk{AE6=Fm>+;PNu>OsC;K{9Hf>3!p{?*5Y6vzZneh-I-6cEH;lGS+8K(U$wyyWLl zUp@pd1RGg=($6a*phh9|6EC0;8iL|_#1?-B9(!&ac=7E`z!~^j6BNl&K)Ud9_~v2E z5ZUuuO`Sh;?g5*O!)BxgG!ci*i;w>XIE_m}6>pK>OB7BsdB!~BCGBa>M$38^cYXN+ zJojei+Wh_1;dQ>z%3bTq*P5drt1xVyeP9Aumb)KYp6Xf}gtw3PUj#3Id;+r8E;@`J zRE5my{Guxep((*ys%593r@vU&)L?8_oQEu*r5O{ z$-+y!j+&0qloeq1T7NI0~#h{WQo`KGOh00Wb!D zm@8cXYtQ|Xxt12@oLi`K4p|}_P9kQDWcLrF+d^x*7C!l*AkvOf>^#5Asp;_vA(b2dw3ssc*7{n^k=^EUtsswZxSs$f&vT$lKn~7QJ@MgUY02rGK{VZ0r3(Aif!R-3~ZNtko!>&9O+6mQ+;MC(faK= z{Nzjfcebny5~|SO>DU=u1BW~FcvgA(wy|K=u5n-v{7^4|%m%f;tjPPJG7fLwh}W94 z!InH0-EO5G8$X9WzDDqzHKNx%8;5Nq14Dp~!3KrU+sDEX`W_rYqxPIfATU0;Wir_P z*+KZlzh(xCXx+LFw*PfD{JYK6xroo5z8@DILiQAd&9fmOZhC7zJeM0GgVU6ILsoP}Od>V;;ObXhJ#(@_;cpidPkCy2bTFM=3}7tcVs+ml%s5PmQA6}yWpAcmlL zDPBKZj*tH!&NH$A*~S%Lt`L=JK3rDi7v=dzBAotCQE>TQr>Xm@ert{-q|V>D1Xi~_ zh1ucEo#Sw&5Ph&wsJsk^$^jsp_1Btn@xInNm*P3W^MuFW2y$2?3qw^-6hgl;4u;TU zz~h@@P(+h1&z)TXKkOHcnc{(~J0Lr1=FTDMdN50j!sbc%{N^5<0G6Ek9XyXKypOaZ zpC|`OqL1;GenU42hQ7B;C)obkDtO-Hb+#(64`2Tqe$I4xTN9BUK>5-MU{(Hc;0|`n z0gU&tlS zWL&^N=Z>x+451$-*y7S-Q^BdiU(~8O%sSE6hJnK9I)n583hz<6VNnn^&pnJrA6voc z+UJBYZD^m`sqGBNf#h&E#UgdubJ+bom$v(W7`#ubHQvMMI@^QmJQcPXO#q8e{s%Z! zzMN=yg;?bJa~r{9&%qzA=SD~Do?MTt{}}|#-+=9(dcdi7$$J^O%5=YRIIRLjFRV@v z@cBbe8!(Fs^Q&yd7X={7mbx0dEukWmhI1>tktyO>w>FS6TX zeQ&{YpA!GilirVW#C5(FTxSIQsFA-J?7wzat=tW_N4oz8X6^dF_MeOl%yUWN!S{`PTDmsMY-z_<7bQ)JM@ULOsv$er{CVszK@pWRBo{w2N zx=xfH*!lTkrE0f3&m}G2B(laj;VIoOHcj@JOw{^GvS92RY4JuEP;#$ zF)s9lUUM!4Ke&Cf)&G*biS~nSaN9rb-yZ{J@SHcped4+2yY3-S*z(u-_DqThcAf&6(-Bgn|r>w(Ns6#+>2XBBEKb{#~i_Z*O znCorzulIaw@ZS4BZYamP0{+jJ1`Is}{`KePLJ;W?7-0qMu;*{!nOE-v)3=YoK={n7 zs3uU$hHUYT zfGy&75Wm9v>^}d?g{~ES0TDn>-+m8R2 zoN8GBe^e2mEpz__0i;uCi;4;^&t2FA!R{W+22qLwMJMP-1HEU9PfxxiE9sUd~I`-cf9G-?ifqsqA2YHDz z34XYnFsMWy{I|l@N^E7Tg;}!av`C%@Z8|?*=9hpe$|}+-EygxM0me*K#}+X9`@6o{9fvBY%?5se(XTQB5DE<8S{DG% zI^v74?yVMXtyOMKp2Gtx`F!>{>)7Xnp=R_5{D&2!wZixl11qZzUI9d<)fUVDa&( z7%bMmu>$7>JxV}At-qM7eF3lG-r!ou|97kKy7BhSFg?H*wvZ^u?u(}d^V3~m{rRm!{W>Hqu}TG zmtf0Bd*L;7Br-)eaq5L13v@N7Up&U!MFo7)S?RiD6fmJ8%`?Q*z$nNuGCL|KKnR%Ox(g6!F0}f96z*T} zS;D#t@v-oB^qdgHWY2j^@*HBjPWZa~bJmj2c`IHaIIbl^Kg=G_HDjP!^+pqT{(}c0 z7<`4jr^D6u4Fig|Z-DK8n+ad9Il30=+633KE?`e6x49C6u^%>1!eR5=!{fo050+s8 ziFB5!okE8A%HNOS5k>@vk3RP^u;}Px;NZ;*f^eDTY1K3 zi-V0Ei0qXe2Er3$OV}m-f^i(pOTB0s3p_-?#bf5dAvu8;3u<_}3W~ zQqGcKh`@$l{+A)VzcqSXd@T7nYl-Kq6|N9)M6acKPK)+)(CeS*Kh1#Q%>WF86)?vA z*ItC-ag)~HiO&127My#G!e)0844Wt7|MznDKOs}Ol+FlCzz$DWzXs3l`40$&qoRdC zamJ3HgWX@A2JX-eaW#6FD7e5dd+R52;QQYkT?4sY$GvaNb)E^>-02t)m%EQcrh0<{ z#I5{(`^V8m|kj^lf&Dp7XZG zbEso2!D5e*&uO9W6P}m+IcqO8ft{bvhG2J%0>pd-h#f>2eG>wwiy30#c`?_;v8U6M zaIOrAW?)60RDjq?F-4@YxaGYUAPD{pJcinf$b~BETgHKPZ!E_lbza35;d=GTF38X( z$828n{ln>j0Qf^Dhr1Sz{05w=T#1Av4&M9#JpIZPFg;+0sE~)kVZ@+UK|sZ+8tU^G zgzGq0>4(v{li;-`oU=s#Q&inX(alnKBG~-VDhR;cdVpvs9ATo|?W!u&0|icp(KEI% zC`cIM|6>^9KLjlCAC>?y45NQEXNn{cvg3eBz^Lsdo!GZ{1#J6dGk9wIJ=CvrSV%#k zO2`ajP>R=j3as>&@pCRTgXcf|E!gz_ui))wICRrZZIw!{V|{-H)3-H&$8kO_$g6FRmtTPR|G<*tQ^Db` z_oUTm1c-;b+wlYnZZqOO2d(1U7vk$gpChsm^32{Qu=mOvQSNZf>r22>+eU+#=<{~~ zrD`T%=DgzdgwNjvdWFo?&lQJho__~N`u>_;m^N_~(7?VxbRRqUlAxfI$Q+q4ng>K` z*=C7?(Ll|f#Wp6V$m=m);eB3yu;lMT0OhIL`(V!gpMx2=kOJA^;qf?xLtoUDZ!`s= zQp|WlFeA6|3XjA6cUn_FXFd0vX7KV~9{_I-UI05jn}%<%r(T5q|j>ob(F>+dkbwm|&%I2=s1s zfK~aK;E5MU;X=c-m+!&tL{Dw=_tDgc4~(NQgPgJbUa1ng;KXtIKs>s(3J>Euo7dYs@-0L1;nBX z5HAXHix({dq8Tu%i!WFBQNSOPodMeutI@PL?Tav+n7-p4Fl*0P{Odg*7g8qS4>9^M z;}7FI!3XZ$V7=4A+$Q!#x5MYWD>_bW+1DhVv+0BTK>O{_Aqaf|_Fr8KHoSK)|C-Em zgy$%{mKLz(&;JebL!Sm@V|eT{@>&4e6z&|{x)=teva>%ePhA8vkO740blp6)$qp{f#KMokTL=O zKj_aN2Eg!rm45D8n9l%Y{O|t`94&mRAvtEt%7AU^?n}%qQh7x|0fy~cG!3Km0r4M~ z#EkJD7c(|>^Fp-kT9s$fVw<@yCwjc7{at84JXL!SJiD(Ihst3g1$}7Ihj;b4CY&Eb zzqT9Thit>UKhb)JSj2JkA@>>=u&qJ+-7DZk|532zqu=2Ve%8NbpJi3ymY zEesmLXT$d!fhB5e_QUB>cr86O4IJtDkO9R`$Xqw$d>pFyt_gvPe2?B~;oisfZt(k^A3e+5zx~ z43??iT>;O(zZm{HLv{#%ooAyDB>HvEPr_f)H9@f;2Ar0J6@Os;U*~(l#`mUZKPTMx zSr%fYEzvJMx^LY(P2hO%Udjp3YrF$q{`6t^nC67n79DSi{@#wiPlL?!VgQ8Xx|s-! zrz>aS>r4^+y;jLN`3wDTQ8dW?ks-;KpWD*+#$w-}9$2TlD+)9^ZoUjXwj=?EV$ld*wCAR68P2+;i~& zSa^Co4)Ir=4L%y#1!*UkP-rpRA%Hwb$WpVK9jKd-n z1_pq%{yk#*p7>YlivndG>!I`@D>Y_Td3F`mXipGE zdn(Pvm?2&=XNY7d{UZUAwu&yIF~A>n1S7<9WTbkx4ggY*`R*dv^zLl%%)T+0C7|5Z zV)&t47X13-P#OI)zt;*`9$fDS3+``tpE&j&v4Y2JfFH=MpFRM=;tOz~V>A4KHv6yh zzWh1V>%Z5EK@{cXaMSaf&6r`VeX9v<{rHdIwYwKNXTbKmS7GS77Xs6-;q#mMzY%OV zFn=GN+pCwCLeRSgU*|?pQ1Mq=v~EUWbQ{AI+wi&p8Rqo(@3Pkz{q2_Ez83#)2kgl& zI!wl(g@9rHiSgjYKQ9+p9CR|yfNUY~$+94&;>glI&YBAhm9-QmUn zzZYvUvim1tn78OuEB?YDR)Rj5IB&y%;RXh@HZc1e1jjeNKLxVS<9HnKRPD702sQ|w zFFH=OhfFzkC8#*7nz6GB1WbxmT+(v&N<=7B=^26pyL6i0bu=>m&AiKG!X@(WJ0d~C! z+5RLP0zVTq)=$K_JD<(@;I$$A|6Yhg*`;khV?)z2=(+y1#~92SXY9NO%s={Tu;=Te z@VxH#0TI7uz~bI*5&pQv*Ga#hDF28Rh~8+zOcOKLvjHo7Gt5o;KuZ0P$=*lq|J(xh zT;0#8=xBhVHZYpAMt2~coq;P2qYK>Bi%3Ai6Nk)SgZBS-FNBfW54JA~@c6lDA4F z_iud$_Fi29Uu%lbAjmJ!2d&Yu4e$G5eH#IW95CL!837~)!@J@T`ef0A|F@?2_0hGy zAOBCnFDm&z+z^Cz=>P7A%|2s7VeI1Ey^xXpJwd28b^}DRVXI$%>i=)=z5C-h&TQfL zbKJXDU<5$PTE}<2-snxfdp9^-r$%5>(r9ypB(vY-)Mc^9 zj2aZrnT`Ug1ZpMfI-hYZIvh}DIYrjmAYzD9e8^nS&k*S;7rLo?!o{4lxV&+*yrKts zywG#fR5(o)Vs?Jw$4bYTam8Q4=!+Krkb$-0ZTW5VB45gFA3jT27IdKv9p5*4Y`Wqf zZ1`h+nXreYVUCUbxNqCH5ItJGH#Nd42`q6StwL`<{Wx0n&NuM$HG{9Q{>VQfZ>WYr zZXg9kj|0VUrC=BX;}x1IMwj=UeG9ETa8tg0Vt^pv@|$uLJ`z?(6mXtD85n!KJlXp~ zs0>2{B1lf~)?HC?jIip6@i)hyMS*n!j0C8{ig#0-RMBZ%4-sf8_c7M@>jt`|j005CN#L0RLgmn%S>&3$8q<3+`@qF|c;QOMgPD`{H6Yppq z93zIDX z7~pysFpPk1K+Y7o9Ak;fGkTW?(BoadVu4rt1CI7d{yE(jhRso0fb{wihPV3dn^Eh~ zfEExR>)MC`Yf%JP`0+wQ)DPafN;0Ye#MQ~;t2P&{YaqVqo2s&huG!N~V9?&GA!O6NYH7-F&} zsAC9@UDUCjlQnj;4c^XXr1_A#+p1MZa0DFfO^->-&fW{Jp-r`a!{C5_!0+HM^gHAW z6&;r!NUkr7j>+xeZOL`^G35G&%J(q{)deAmz2{%2p0kC0JpDQcmZh&xUWfcZldzfm zAW81(w!Nf9qY3T){qH1R(f}Y1lMovJBRKsSTJ`SN(aM8g#b2D)!`rfOnFmI3@vM=_ zIbu-Ue(I_C@3{>8`z(Kl{=1Uv%hG)k5W44g7!avy^IhII(eBUMGA%{`4ELNpgdTkD zYv^90xbs?5RMCGsP7%a^>*e(OIKcnyyL@@osxGyRWo;McEbj3k6U`&;zFnI|wn_A@!hgdLVBkSyr{l4go{?fLZO z=x+(^MYm4^F!#N@Gz**e5tZm>wDaQw85mv`0rAO!)fmK@HFPVE#JG?B18*URJ(yBiec*h&3EJ5L5!9AzPG%(&tSWDZ~_^`DkhsaI^~p+4E>!+jsF7uNi-_mQkyPxxRur zzaqRX`yoA2{{aS=nnY%-2W{#8N&Fb`c~^4hS0t}-Ao@W@Ve`_s=&(4PmRNu27UU1p zKGHH!>=z0y0%%@Qt-+K*s+c2Ltrw1QUZv9j3KHR zSBM6Roy?Z0t@yTwb z{^Hi-4@7_qJQshC{vn6#>2=bc(G)fpld$>Ly^GKTFMkjDm+F~y>WBmcb@@eZl{hdg zaiHi)KrzZC_M^?!|6~Av1+y>yA52RM{11j!0*dJ4(OoUg>w|RD)&OZ ze}9giJ-t6x`94MY!JMLwrYuoYk^a0$bN3mub{%f*19FO{e$r%l=VT1g2pAoN(K;Q* zLIoFg!o?dmn{x3LKGG>`9PU8RonD7lANup?3;FIc?IJ(G&Gr9`*rC)ewHNLBv^4@- zgXheiJIW`LL~<8>GXMZsT1iAfR6kvXy=@;+<7q~F&b~!4MBP$@V@UwY!T9o^v=S|b z(*tPh(dGC@+hn#s>Tmc^2>eZ9F7P+WJ~8k=_{zVaeHXeokyY2}QP09rTNd3G0C*YVf*%hrrm z#a}w|6tyYc&OX7HXj0z4UY$ny=Fkc!h z30qz6XkCVOpFJ#5?-l`a-}wsK()F|Ov!h>UmGF0G&#w~RqyF~nbCW-I6>u5)F3GOz z-s|c^-$2j5|0?4F1208h@q!IwG@N|NrL1EwHMUPT3YY-m{;4i|hByf^#JVG<*bR&X z7SLiG15~>Wr(Cp*5(8Q3@_Xp9zT}71B3aF7OZN{sb_m<2mabIL#?F6|KG!PQYY?z_ zJF0lzM*wmE5_G3WD$NVfmd^V#FyujTBp*`*L2+1@U(D9N&)z_*-}{>NJ_+!X!bQju zNgi>395xf+|KMfO(*;uTjzO{YVmEr`IUQYu}bwBD4qj;%rfPE;d9IEzZ>}b zx3PX3{wHu;1BNtfq;rfXbA-{S%nC2(bxiTJebGfyaM`C|iu?3{ShHk~U0l(n?r1(5 zD!z0%6_4=7by|z^P&#CbBUSY5>9uIhk*}kb?-4e*j9WLNouBSBP}zyV@v;72h0n8+ zdmh#GFieWsQy4b?mP|@upxCz%tvT>x3|2iXODxJ5Rp2-bhH2(K&u+ne4`y%+W|E#PBT zDIa6$=~f%YXxyS>Ir-9vIq7qz23Q9KLjZgO768)`A_L=PUUD9{g zoB}@yoA1QHf7`xAXzjt9F~|)7nvBO3VRXb6cb`3gHr4(!0w&Y<^GC6o(dMpuF?gLw zy`0 zNztWr`5=1o=&fiq{xYsU)Ph;#O=#C=d#yAW_ndz@`p+IdNAx_| zQgnA5Hs4WdLc2ftod}3f7(HSJj(M3Py|$g&jDN5#!d{|tE$NY71Qbazg!K23YV*Be zzI1UIHs7=V+i1_Zc0EI6&SlNqdp~bSkN4k!8P$!#>t<^icWjYdr}v%*7T@sjJcFRgK*_q{cp%i_&I*I8}>*kX|{!aYEJD z-Q`F`qM(|Nwn9x+rN{L}7Z5;4Yxqm}7<#z<8|cx#A0dCFZsiC_@{;R1{v!HvAI4wu z!{TvO{N-PDm|E|(#O#R(3M>u7W}8CF3v}Xwh*MK7XFKkFn^SbOelP$SeTjR80wn z!5;)$k!9Is z>1v7C6A7DNC-byR!m#}W#sPC+yaH6H<74ZELuh@+ci4T# z`%vw3<)LVwq_{$wwC|3?=3Dn&kHhdMl)f%zxy7UCg^x;TedTX4s5BeBC)H=t*!#<$ zXKnjmq8%R}2HgQemdLS1+2vLcG^vK}LcpkCj8gjo({>$mtJHlVAihrl;uHjk4nye) zel-9X$GaSd(Duexo^)QC6{poX0&YEVU-+e7gTLHsj&KV)7oLwQjVt16b69jBRakEk zTK@V!VIb<_1SR^-08tr2=d4JF(qsMTk*Cm>@(a?d`wn&y{#o& zNm#g?sWy{*=_0h^&Hs(TtWT=gEj7cs1T)6g3w89=u?I2Rx+#2*AyZFR{P%BL#=O7P z$!C{J*`-a}a zU+}LoKMJFjhRsBAg;-RQusI4RU-+<90*KIM)9_gbi2X`H-1++#LO>Mu(I(kne4YXR zBwrd3;J*>=Id{a!&cHmB9zfeZ*oHyoTlSwv-qlv%K5fnDiKClCOH>&cii|P7e&GZN zhNg@W?qjqCNJV3JA*nHSD4hZ#$POt$Oo4H#p1LB#(IhZS*i^U(jBd)t+6BSQKf5ZweJ`Lg4=$F?7QF^cJ8Uzke;8j?vhq z+5qFuPhLWsyZ#k_CQaG_n0-@W7a6X z1JSuA^wjaEr0h_&S~-xULu&e{D!A}7(yfJZjHdy%c&eZypd1vv^CX8Dhs?6D+2?bL z1}7$;UDu-$$sFK06z(vAABnY#2EM=c;&Cq-t+AlGvxeUN|eWoF2CprQ!nx5 zOM__pN4wFw&TmHG#J|Um7K{Bf=XeZ#|K^k-ZauY~@t{_Lpb8LaV5EyJt#ml8DYTRX zrg)NV)j4kqjHh9M%r*8WPQ0Xm2!UY0U4{!SHL+zU_bjxHT6e)B4AZ95q z3#Gvdv?8y#>+CD&k)D6UpHY+fXN30xonLFQfBrG#^*7f4747-Fn*ziW*^vgoA)D~| z1eH@H1sCf21vZ>k^)M={(dY9rN6Y-8MsAD(#A*y|)fn`uAQ(#9bEF})gC0g&dvUVv zPJ3~Jvq^2hv`e;I344OUvHa2Z&Ymh3)B*nBWzPxrqX0U`+} zH&<>I^cd|yvEMwLHfYyrz4#tl-}yBr9RTg|Vg6iuOSI20U%Dh_iHp#k!2i=gq}UKmt}{-N&xP-78F|* z;3%}~SdRh%3OY{1=u^2EBL|38B@oK4r=fNTf_0`4lU1hmpcohnMnD1*E_xV?SED`N z5s>zfwy-gvLGqc?_u(&nQ_L#()eN2s^KeI^usO^lhG8=Xiv0`G^0)pTGs7Mh5cy>U zkp1S3-8x{r(u212{;PC9;`x{{bwtG#I$uiC19z6MM;qF2lUf+?rdL^B@hDe~HgDHy z9qK{Pop}O1T>YwKAF{pZmVE#8^^INsj`p7K(*WXe3Ji~H*g=7><)yAGz*SFo?b?!ZED@|Y;;%7LQ4;8W1wj8 z_M|RJ~^Sf#= zv|9Z@LB^gfZascS$a1p1#EiEy3l-N2t0fGZL*OU*QnJriaM=9Yg=o#YKfplMFH!8K zfblY5nHn=iPZ2)D*9Xz|-|s~m>fZ%Emv}FoY`DwZZu1!Geh+uvfS!AQuO18&K)gtW z(nC0)Bl~6E8b|{|s8wu_V_%iHO09gG-}*zJ~XS+3>?$$CHbs|juH{V`^TJ!XK&fnzIQjUG}nL$)o4 zV~pv1G+d1?6;;)-GQT27dtJ;P z*Bog|S>gk)M=X&T#qa#&HKqHX#~n+TxllSi9!*1Nj|!zr!euIizSxDHJboAT{*%up z*+cSK#(Sam%wJC*-^o5Uy8Q<9{0FU(3b-vGrd4SEctTs97IKUiPEbwUC)kSg1-6G# zt;xuXMw~1VJ{y=|QAdy=CgA8#(Z?E9Y{@_~0GTA0Yn&8kql5I=i1}zLY@T%4uG8(P zA`MKu#J!B5q}XT|dg{b4!ygm#qlrO6JeU1=NO5K5p%^G|IC&2VoA)n3>yG>%z2eR& z=l3#V1C*9(I%HjHN1JMY8HI=1eKs@uTodneIcA9uP%Lr#M}goFSkgHH(qPCJVwg}` z-{9Rk)Qh%#_#9ea|2p-a<)4{+!H*%|i7ov%qkR`h?vUs@9?u7gJU|Yax97-|bW(7< za8k%ILU~1a>V>sQbt5DpY1KJT10n%Ink7!t`9vBV&6r^TO}b3dAW7vCr)XyAKvAa= zl4Ij8*<+8isaqCSKmXwx{N-;#>uUIiQNurk6n&&!L@*5gkCrdOhEsw{-&bB%PKksk$ARi$6}#6z2V{vrGfA5K4~7U^df-4-wD z{+rSI+Skzbk6+HfFl32Ef$;=;w3>8*L+MtIEtW2t

F-FGZ{j)cHm40s+LCdJ2Lx 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 literal 0 HcmV?d00001 diff --git a/readium/navigators/demo/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/readium/navigators/demo/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..1c1d8b9913c25a3afe8b9ad69edb85be6054870d GIT binary patch literal 41512 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 literal 0 HcmV?d00001 diff --git a/readium/navigators/demo/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/readium/navigators/demo/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..121be937fea04fcc8a5b1d6e72fd684cb4734ef2 GIT binary patch literal 18440 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%0AsitN5^2(qy!m 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 z z4&Pbm@mQIS8515c!Nr1{2qKgC>psIK#dTANDfC^YQZ&qp|ID8ROAqBh)lYTa#2q85 zyowwfyW0#Um%b#Ews`#^JLB3P68dC-vI$^#(k`cF#Od3q8gX9bU!dZLZ(YI5FeO@& zd(N~d`NVXwWKqe~7*UpS;Y+qyl6xYlALxOSZ*$pLgh+o?V<6t!5XVUAJtbyDQ<+K4 zi1>M&QTi(E=suYMfKd?3Ke!S-1HXdzm%jk{hgL%Q4;}6x)~^zJs7tjtwmbHKXlq^0 z+Hu2I%`sK%82KGX2 zW3Dk|?G81^eEP{urq zE`bjD%$T4KaL1TS#jywYWk~p~MMje*y!q^{-S8t#XDY={zoCrsz2(mnlj7TX6A+M1 zfVXm=gE>3jg`HQABOvPXDe&N9$mnu&OEJ1uG(HD7fa1r72WP(DZ2tmgI-3*0$&s@N z5KqTu(QW7@VtY1}eRp1v(yRSpx(d=FsL9MMGH93JJNwG6Im+y}c9p||eF5PVPAc9=;iD+^b9;l8+xgkTR97M z^wuIE>T^~u4!C9YxbEFACbKe0rDzv<-0%lp91{~NK^yGsj;K(KqyoHde=o(3eK#Hf zteLeIi;0a%%xg>^Cl>c0x5qO3n3ObFP%BEJ5ARt%+U%*S9;8a8*yb*`_w66E{AA&~ zwJ>YfUkUsAxWo`{q!ZH(cBJDNEG%bV#7tfmyTBk6f}H)*zWsDxj*)}Z5tZ5z`u(p z5#h$C>!y$i6PvFL(;)^0!)K90-jvbuAOkPf7I|q0v&nJBu|`wvb85=-F>@6K0t8~w z0P`nh5;G_kLttk4Z^SYUlOhRzMojGeWtp)0%qpnrZ}e$WXp7^VxpV{Vk zD6!HlafEeKM`R4GjF1K|M5BovG=xlt;YHyG0*0yfzU$g=6W*LHxhF6r1sUVh8NxeSw| z;718#pHe0Zd`>5&IfzMd88s;yYz&ub$&JrIf4cgFOp39gc36J;ALtr_p0C%u?t|GT z^OzUsB;*);OVOl_?nlnP4-m+7bKuou0n@OvInlXsz-7dh4N6Ia9day2RdHi?dtk-+ z&&XKNXNJ4K28bQBKLh6H#55c<&4|RLx(8Q4$RLb*PQ@Eg`BR4-yfi?D%dq4fEQEg+ zPGF!lfwue!9FR>Qxix2$ehAxpY7m%Qb522}6?>?QX@))4BIB7@m}6pmE=5&QP2Yt! z4FJ32rF6^9#8Oi+5F4iqOw%42&6$zKG{6>9s1@T9Lo>~cQYC07=4DqgwsFNYeUxtT zlxwlwyIIjCo5$LkRq*dslbCRWu`e`H%q+_!{uu0ABJ9g#O5CLDIyr}&CvD%yhTMOb z_*z1wVV~W+c!2tqD)C!<1_9@(8xV+Llj4f!O_L&?%-+uX70lfBci7c?1c5@QKLA7D zUsv-LI&Z+`+I8bWS=cwoeE;yXH#f${qAZiC5!2E0`4VhtKcp_MIbdJz zxOxdbUHcovyeG1T?)#F7^xhX(Z0sGH>A3FZWIh)u+YJT~FG$sFrp{~>NtWFSV~ zmrmOFS}}7Ze!Lwt59Ri*xUDL*P-Jr`NhUVPi9QB<1qK#%l-S$%?YwpX-G`v( z{@Y(ftQQbE7Fp(4U@=EY?KW+3O}=6Fm4B!JK3Fk{ww05J85vs~K3MrYykGP@V&lgB zH-PLpv@Z+t4;RDEzIt!L&;z;z!QN_)g`G;cNT3xF_Ic0f5pgZ!!ZEHpsjCDXyYu}o z0H$g&o4?H6Kjvgs6d2n>FH0yo{~-4r)xJZDW7%gpnqzYg zS$;C(JI48hNhFJz6f@w9t%gZ)61>0sd3YDUl^0;M684Lw!^#s& z(FEw-q*#7)pKUyHRM)R)hKUseF1}7;MkH#)48%Cn(X~#2jZNEaHOWLU^AB7RoeynL zOc<=IF{bmAmEXDqxrcvk@2~L;v2hZgoosW7_ZeoyIlLJWGtzBouJ3AOmBguckUw-mFo3FsN1&jDV3x$R%Dwe!5) zq&T4Qk!kZPs_T)39fF}{2BrcrF}LCkM<(XYv}pLrIMrg3Ozal`)3PyZ8Iy$`x}fMW zy=gHfrKXBWDXL-)S?_HC_Q(q(YqLx7eV1-&_n*}R0a?ZEbMV!+*Wg3+r~YK!WWq?W zsR~aLbI=>_eDvl^VtEd5;BXkNAI|31#icnp9kzfe=dg4v+cu9qWIr~?cC56IJFod2 zJRvHMCF}-Ih6fOvG}u@qizxkglOmqj@S8aXGW`TK8-(_#AgVzxBK0>5}*_AHoG(OArnyai?7 z*ENNBMH< zXXE#%FFT>~r>?~ED-OsRKI|YC_EHi0j+Ncs1hD>_wkpw9F!T*?iGn?4y}$VjfVl$L z<0juMOzkH#z^hpeSc-iy7iJa{3TjG<#YaxeOAdbaU{ZXLY_@y1tRAhf`odDvbcop( zW+Rk+Wf2B|Ck_j|xQXWwKOu$ez#{DzK*i};#eNlV$$+Q(P5HbQ8w;9jj0il+m{4MK z8hs;2h7}fJ}*m~X!Ga@mmhOM!{ey|z4e+#>B)=CUa1hE~xmk|4UmE2DZUQ^ji z8vYIZTbPOChFLEDO{!F#OaSlQWz6XIpT0ETaveYHc>7zCPv1_=0qsdnX!kO>hRk= zHl^Y~Zv3{6C$-PFOo2HSzk{;A{Sdv^#j!DY*$o>Ta|nPfR$Q-f&FXQW*NDe_!G7lZ z!PkaUWMRJ@y0)+Pyb2XRT=G#dx<>#ouffl_mG+*7@*nCYQzHjxia==D54NdoBO3F7 zzQ39=GVYlrY@zq*>xxWsET(PCgsq)NwBS|M-wTDumXQ|`;@{msnb-7P>Ew4XAYx`m zUKC8Tayq%!pP&~ReB67>5r8c4d$-K@2{N+r0boyB?11$+aTXSP)FJ>{OcfYCrVogY*{VS60;5}n zbv~|4P$_EDQ?+U8ka-k(JoIW_Wb251;oN#3A!dR9*m#njhW^+y&|B&3%1km@7~o~H zha({gghCELC9kLI*hD@Hi2%#7I4m&0GH*-dkww58`~PN@;i}UaRztwPAod%m`r)i( zN<{1TL;x$hUWLy0g2VNM^x)1wmYNaSFXpqH0Tn2l4h2L>`M z^r6bd3Gm^nm!Rm}4k)|T?p@R|ppx6$%eL4P24C02h-rePC4ZP5tlR-i320^>MVWoM z1KK!YUo)wUuv)JyZxjd?*&$+pzzUS#!-XC>{_7^wPPqsHe00h_g zn#bDa=9LiR+1EV^UNHm2?oj}%x_uT3j{hd1F~CcFO^eud%#C4oK+RlVVSnBBDX^wy zg|CXycK=w9%{M0a!3Mh_|6mUMv*0<>J}G$xHZ{jcQB5oGnP+S2v{bl-``aP^_-l^+ z&Q*+0E_a{s{lRIeOn@OiK`LrleBetZcvao$hTQ%0iTT&?dlAzi8pBytnU;U|pw;kr z8%%Fzg>jBFQWg6n3}lFreZZ899~4hSz?g=B?`zm~L#0yeb7W*;7vYCfw)?PKRcLJ- z*$qb_N5n^dMKvSSn-|9k1LJ&PWSI(oSc`UB30z~|szJvbf~Rd2pdYzQ?%ji+H4MzJ z^!|PeEImGpnhw`d**tb)&oE^3_>X;n^WUI1;oPI>ZTKjCJI3qAHd(UIbGdEXKKa-q znq!6E4cU%e%zZcah`3J9t2mZSf{Jq)$K(nVX12frattsz7=RV$-ht@dI>xxH7UNmi zJqm1*fjU@u?k)N|N2T-f{pb5}#A=HV)9fAQgv!iY_#RfLM>{FOveH zx3wRF_m^jopkK^3{#l5#RHPF?sJz{xS1l?kKVtw}dioz|9D}xgn(e5xF5Dx^!i=%N zroNfw7P!nRdjqk&Ivap(?Klpfu6qH!q&*K)(M#GFL|scwhgckg85foKTmCsyK(m*I zTwtKXX5}xjS#c|6WS^q{%cmP?!~Y%3>gL7YgVMe$DJZ0QLlaBpZeG-7_z;C1vIJi* zz4t8q;3`5#Y(6qe!8ndgh)q`GSy(FAn2w>jq^EKQuvSH3P3PQ-v4mUlCdFMh55O0j zUPNz{lTEYAboR%_Z~F`O2dLl6cpE;7Ct-D?6Ak~JZ0<9E$L4xI)&MHq?~I^EzEuF4uqZ9W?HX4pTA5yuH+nNG4NaModSO z_A5~FV@;AQOkqw$`>XD>!rY3F31|^>*^&uXTRIWuRel0HdQT#7>d~aF5{qeKHn*-} zDJ;T%u%jXAg(W1cFBYB!wvW9;P+^PZ2g80W3}9bud4UBqTi_KQ=!M1m=E1*LO@xov zO(MW!_;+U^HaoAHdr9NjA7SK(h4XBTjs48>48q>F9s+U$FB=ga0C$ z+T_5_LD6mi#^+bG`No9OExZgri6WZXOdi(y_yn-W25>PpmNF1)(FaDWl!!j+lf{&( z#a0p6G^)jTq5$SmavvRSf`Y@-;KS7u;gj`~=^q=hFH<&OP2WoKA3663KiQ!5W7%Rm znr+{w`i|<@V~HHgCi-LY?W7S<#X7Ar){fac7+yjOz$P6V(!uVLOW_rq6>){5l@zx zhm+-yt5hJoz;qI6hxd^wc=(4b9A zWq{eP>qlVmq2E9bemOd#y64&Y=YhS*m}3!RracT`+tU$%O@iG0vspm%HK@AX1v%BT z82h3xY10jLEgHl5d%2f1;YBATz9>n}VrU_vFs1&|EXY6cHtf08;!wuLyI)M1K-fc> zmaxaqc!i>{v;{!>%kE(dl2%CX$0-Ao*w|RA%!w_EOdicRUj19oa});P{MHcvQ~E*BpSz=pa{Vc)HCSb5=Z1YG#H_`GBKW0i0FwmxPH-_K(J zwxz8A;`ch80Zi2fzD0ohXHN_?PgoDJ{xWkGVlKpVhTin|WUl9N>+*IU*TiE(=I8u(b8Wws zEo=*)BQRNc;Y~O&ie518o`ZFDpKE_RSMl58^?5iiI^Xhhe?dTW2?0{4-S_3t$mhc? zu=?_Q=yw91ljn?$ zi8VgiiggO=WGoI@elRi)EM{x^_TRv+8{a}ze>dbGUPxZjKHV^xepZ?WU!(8h7XUnt z3poJIJ7#|-683w^FLe%7D31JgLyP(%hqzdE}!%X#NR*EswQ)Zt3S(a~+?XZ{~MGu=MnA zAwF~&qN5!UA8CZrp4Cur@?|oaxSsd8^L5MDfG4zFS2rUt>SUl~fLNzDARB3iZEZ`? zcm}oom9IDNxVUaI4|IPpdzeiG3>n0HHoM~2u(R*51YC)k6eD*#AaDN+>KjGCHI*@R z{F3u!X&Q;S!sh-INjt z-&Cfh@|xY=s73Y*fT_eCD)VB(CdL+rU}$?*52yNL&LvzF1vFXWU|S6`m)c{hv{Z2g zkZtYSjozSft~aX4nzn=fvFC&{VLtj}FJf<{dD4VpZy^tW6w-XpW`>pz6ms z0^|-_kaM&RDu0N=%8P$R6G||F^M;h)$vYl^lG+a;Hr$B7vXg;Ur&@(50U5u(=X$vb zu3pY711_FuF@RwK1XUwu5>ps9`(oeaj-HrUP}4LicKc#vn_I&qnKNcxI9ml}F6l%< z{&gjdnX%bRjI>|0R09C&9F>)I5&Ot+Nr(nWn?T#!H&~ zLZdmawgq9?g-@aKcBj4mm~#EP2LST{Vgv3aTy(`U!?G_-RxR>o#r~VNz-XOsOt&2| zL>&FU0GM+d<3t|UJ7SAO7dH|WBCjoEn@7Lhw9IIv!b;>GI9kL#@ z=keb)m)XM7Xw;0yOib*&7+6Ysiz$GaAl3oV{*$n-?i22}r0e4Llixb2*vI;dmj$PO z4VAa5DR7N;GWNxmqg@gsvjds2torc?6rOt3vH$9QY>b&N49B6(-}$f$$h^H-gu#&WS26*`wkb5g zcMSru6%(m{jEFv-gDBYa)>`es&8Df`T_ml2p{Q^ts%@0sP)JdUqCu=6%SvKeH!) z4V$~8`VuZGAiL`XS{eZBPsTrX-E(DVS=1rtTI3m+T!+jnBO50G)|@zaJ(gm|9;YIk zM~iz+vPXK=V%)`VCNMO<+Or%8?EqMD2N1*iHnwge6_yQ$HZiM|Gews1$37OcfZ`-K zX`JM?75npr&w@~N;SH#|y%$zoe3NWD9V@K!+iZft*Muh=qY}Ug`Y!92=YGAP{OZnU}@F3~-`sEaqZPj14uRvG}_<5$n#c zx*jrV2WcjX{S-uIhck#z2Lo8{fp-u%wA+&kn{12&FC`=EhPB^rgb&vk*(xRzv*8Q^ zUX;0D-zYY{;pYUe<7=41L=;B4C7h)K3qRf~GJxzk#Lfaxbh;Q#f*l0JaAx|&2mb|M zBfyzw#2X$C*q=SK|Jkq#SPH_!w=bz&CpOhN=9tE-h?6|fTfk`6*na|OmJ?QCJ+xZCl zqmxbU5$Y?!lMiwH9|^#U^KU@)NG%00zG1)E{dU-MV0gbB@w z(g_=z$L2-<0O7mMimdoO5}0uS#sOK`_ZMN>=3fhnJ(B3Q(gH6kxS%gN_+FR{h_Eqg z!o#c$$6H|_Bn2WdBP*If{A4-RUqIO{oH4!|R-9dkp1(9=3dM><65M<&XtH0v@3e)? zWj@Ekh*=dqyZAZ`W{96@+^|@Ku*PZ%k|uZ^WlWFzO>xOTC){VJ#OJ*5)Nf&H?;$CH zunP?7;*A4}%w8@ujF*r75bMr3p29kpUHtjN2lGBN&QLiEhU5 ziaw}XJ_E2FJ*ye3W6X;;Au>>l-jiFG(np3{Y0o;;pDg`(oyM3kQat%CBxXbm9GN7W z1Qv75EDONSz5~uR$_$^_aJS$aiwt(c(&GyddzwhV=Q9>of!Q4a7{vH;4)dmEc3+Ot z`(m&$Dru)RwLaTysTFY$F*YxLR5B61-t#(aX^+F2ODik@+sowaM}royIE+s|2k7Rr zaftc{F;Feon?;^$42%m&HW~b^1URt>2VSS#8~=aEKgF&MJs+!T=RoD1E^YlWM<(V= z?BSD*>2fW4lHjXFAQ26Kh5PNLTy!}WBfkJxs=$mlF*c<%rYttrqVGNW5zWgM58n+N#@_*dZR?9cG zPg&cz?Yyzc44B@1Yme|d!f%{%`Yn1sYRaRGi@fn4pgy4a#21qeyRYw}m8B){igN4m z;W`B1`A~S~*Yu70RJOG|&DKv_`|?i(p}6M1AvW}_0A6O}S=eZo322syu}d&38emrO z!+vXwPfHW!X&%5r=6Co>n}Ru-s1GydQ%#u$1~423v9WoRr%KT#D`V_yXWt2!x-pXp zdzk5PH#Hp+c5axKId)`T&vC}am~Rfh6wR#2APgV-#xNLSf9t0kCll2o2DTZyUVw$w ze}!39m?3ct>?n5*+t~2?#PicwImXZr(dUHLU^Cdd73^++mvIjMehB9{Ej}Ch+&!WD zUV-h`jyV?4bZwp)+4ba8Qw=1@#$1|Qdn|HC_LbQ|Yb6WCWwYEf<}_{R{SQFCLL6f@R|CXtJ< z?A&YIc)PUI)-s=s1y(XHLSwPuAT}dX7ER1|d(vRl95JPPO$?~o1?FXnJ50Y=2l|s8hmyK~BajRVeKD>r|8xM>H+%;1k!BKO z7L`Cu04~F%sM}^rMN{B0R1YP!@1gSqg>$N!a!l~#$;N^(p1qmGjELpo7!Yy~{6pgh z)0q^zVPne<1TIvB@zpLCD`ko{vIuzP6Y!#bMB(}1Cw1vX1HUYhYr{g53JPYp;p?1T zNrgl6s&U*Q$G#NjDRdZ%LJm+2fG5YFpua;K_c=SJ@U;8$XEy#>W$R1M{sDGeKj{Eo zG84Pz&cYm-*>#1`LkDVo{xfmrkv&rlcd&HX+n{DhYrYWeYE7uZ}GTz5I0OMoGc7MNvG7iRc3eUJS z&36hE>*f-J9Qt#ws(lMhj5T87;QOtxq4g^=X*>SzY3sN6Yaz_;BsFu=H+%|Ugn6Ke zdqMm+=#Oz)%e+*879XjDZJoKW^z5%0I2-2p4d^-7_$@bKQacAaDYDT1Bj@ix}<_G(_JOEYwb)EsNs=po~n3@CKZMxn`|Da%<*?iChIP~{&6D*U^+5%V>(24H~1;6<{&m}YF3a~WfD zntkWAaelRF+E_QgcbXmR@T|+@&hINgFF0!&3Q3lG0!)L~JOG)@$ga5q*?=26yPlGa z_iE>-~ZxJ3|eL`N^f=B|aX~$t&6c4@hD9oOU5FSLClCV_N2kC>jyoW5xZbRO9>fA%e

J4s4uRGjSw*RMks!$m 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 literal 0 HcmV?d00001 diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/serif/NimbusRoman.woff b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/android-fonts-patch/serif/NimbusRoman.woff new file mode 100644 index 0000000000000000000000000000000000000000..f0a31dc6805d192f03470c7c1ceada826f0623f8 GIT binary patch literal 106680 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 literal 0 HcmV?d00001 diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-horizontal/ReadiumCSS-after.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-horizontal/ReadiumCSS-after.css new file mode 100644 index 0000000000..4871a2162a --- /dev/null +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-horizontal/ReadiumCSS-after.css @@ -0,0 +1,428 @@ +/* + * Readium CSS (v. 2.0.0-alpha.5) + * Developers: Jiminy Panoz + * Copyright (c) 2017. Readium Foundation. All rights reserved. + * Use of this source code is governed by a BSD-style license which is detailed in the + * LICENSE file present in the project repository where this source code is maintained. +*/ + +@namespace url("http://www.w3.org/1999/xhtml"); + +@namespace epub url("http://www.idpf.org/2007/ops"); + +@namespace m url("http://www.w3.org/1998/Math/MathML"); + +@namespace svg url("http://www.w3.org/2000/svg"); + +:root{ + --RS__colWidth:100vw; + --RS__colCount:1; + --RS__colGap:0; + --RS__defaultLineLength:40rem; + --RS__pageGutter:0; + --RS__viewportWidth:100%; +} + +@page{ + margin:0 !important; +} + +:root{ + position:relative; + + -webkit-column-width:var(--RS__colWidth); + -moz-column-width:var(--RS__colWidth); + column-width:var(--RS__colWidth); + -webkit-column-count:var(--RS__colCount); + -moz-column-count:var(--RS__colCount); + column-count:var(--RS__colCount); + + -webkit-column-gap:var(--RS__colGap); + -moz-column-gap:var(--RS__colGap); + column-gap:var(--RS__colGap); + -moz-column-fill:auto; + column-fill:auto; + width:var(--RS__viewportWidth); + height:100vh; + max-width:var(--RS__viewportWidth); + max-height:100vh; + min-width:var(--RS__viewportWidth); + min-height:100vh; + padding:0 !important; + margin:0 !important; + font-size:100% !important; + + -webkit-text-size-adjust:100%; + box-sizing:border-box; + -webkit-touch-callout:none; +} + +body{ + width:100%; + max-width:var(--RS__defaultLineLength) !important; + padding:0 var(--RS__pageGutter) !important; + margin:0 auto !important; + overflow:hidden; + box-sizing:border-box; +} + +@supports (overflow: clip){ + + :root{ + overflow:clip; + } + + body{ + overflow:clip; + overflow-clip-margin:content-box; + } +} + +:root[style*="readium-scroll-on"]{ + -webkit-columns:auto auto !important; + -moz-columns:auto auto !important; + columns:auto auto !important; + width:auto !important; + height:auto !important; + max-width:none !important; + max-height:none !important; + min-width:0 !important; + min-height:0 !important; +} + +:root[style*="readium-scroll-on"] body{ + overflow:auto; + --RS__defaultLineLength:40rem !important; +} + +@supports (overflow: clip){ + + :root[style*="readium-scroll-on"]{ + overflow:auto; + } + + :root[style*="readium-scroll-on"] body{ + overflow:clip; + } +} + +:root[style*="readium-night-on"]{ + --RS__backgroundColor:#000000; + --RS__textColor:#FEFEFE; + + --RS__linkColor:#63caff; + --RS__visitedColor:#0099E5; + --RS__selectionBackgroundColor:#b4d8fe; + --RS__selectionTextColor:inherit; +} + +:root[style*="readium-night-on"] *:not(a){ + color:inherit !important; + background-color:transparent !important; + border-color:currentcolor !important; +} + +:root[style*="readium-night-on"] svg text{ + fill:currentcolor !important; + stroke:none !important; +} + +:root[style*="readium-night-on"] a:link, +:root[style*="readium-night-on"] a:link *{ + color:var(--RS__linkColor) !important; +} + +:root[style*="readium-night-on"] a:visited, +:root[style*="readium-night-on"] a:visited *{ + color:var(--RS__visitedColor) !important; +} + +:root[style*="readium-night-on"] img[class*="gaiji"], +:root[style*="readium-night-on"] *[epub\:type~="titlepage"] img:only-child, +:root[style*="readium-night-on"] *[epub|type~="titlepage"] img:only-child{ + -webkit-filter:invert(100%); + filter:invert(100%); +} + +:root[style*="readium-night-on"][style*="readium-darken-on"] img{ + -webkit-filter:brightness(80%); + filter:brightness(80%); +} + +:root[style*="readium-night-on"][style*="readium-invert-on"] img{ + -webkit-filter:invert(100%); + filter:invert(100%); +} + +:root[style*="readium-night-on"][style*="readium-darken-on"][style*="readium-invert-on"] img{ + -webkit-filter:brightness(80%) invert(100%); + filter:brightness(80%) invert(100%); +} + +:root[style*="readium-sepia-on"]{ + --RS__backgroundColor:#faf4e8; + --RS__textColor:#121212; + + --RS__linkColor:#0000EE; + --RS__visitedColor:#551A8B; + --RS__selectionBackgroundColor:#b4d8fe; + --RS__selectionTextColor:inherit; + + --RS__defaultLineLength:40.01rem; +} + +:root[style*="readium-sepia-on"] *:not(a){ + color:inherit !important; + background-color:transparent !important; +} + +:root[style*="readium-sepia-on"] a:link, +:root[style*="readium-sepia-on"] a:link *{ + color:var(--RS__linkColor); +} + +:root[style*="readium-sepia-on"] a:visited, +:root[style*="readium-sepia-on"] a:visited *{ + color:var(--RS__visitedColor); +} + +:root[style*="readium-sepia-on"] svg, +:root[style*="readium-sepia-on"] img{ + background-color:transparent !important; + mix-blend-mode:multiply; +} + +@media screen and (-ms-high-contrast: active){ + + :root{ + color:windowText !important; + background-color:window !important; + } + + :root :not(#\#):not(#\#):not(#\#), + :root :not(#\#):not(#\#):not(#\#) :not(#\#):not(#\#):not(#\#) + :root :not(#\#):not(#\#):not(#\#) :not(#\#):not(#\#):not(#\#) :not(#\#):not(#\#):not(#\#){ + color:inherit !important; + background-color:inherit !important; + } + + .readiumCSS-mo-active-default{ + color:highlightText !important; + background-color:highlight !important; + } +} + +@media screen and (-ms-high-contrast: white-on-black){ + + :root[style*="readium-night-on"] img[class*="gaiji"], + :root[style*="readium-night-on"] *[epub\:type~="titlepage"] img:only-child, + :root[style*="readium-night-on"] *[epub|type~="titlepage"] img:only-child{ + -webkit-filter:none !important; + filter:none !important; + } + + :root[style*="readium-night-on"][style*="readium-invert-on"] img{ + -webkit-filter:none !important; + filter:none !important; + } + + :root[style*="readium-night-on"][style*="readium-darken-on"][style*="readium-invert-on"] img{ + -webkit-filter:brightness(80%); + filter:brightness(80%); + } +} + +@media screen and (inverted-colors){ + + :root[style*="readium-night-on"] img[class*="gaiji"], + :root[style*="readium-night-on"] *[epub\:type~="titlepage"] img:only-child, + :root[style*="readium-night-on"] *[epub|type~="titlepage"] img:only-child{ + -webkit-filter:none !important; + filter:none !important; + } + + :root[style*="readium-night-on"][style*="readium-invert-on"] img{ + -webkit-filter:none !important; + filter:none !important; + } + + :root[style*="readium-night-on"][style*="readium-darken-on"][style*="readium-invert-on"] img{ + -webkit-filter:brightness(80%); + filter:brightness(80%); + } +} + +@media screen and (monochrome){ +} + +@media screen and (prefers-reduced-motion){ +} + +:root[style*="--USER__colCount"]{ + -webkit-column-count:var(--USER__colCount); + -moz-column-count:var(--USER__colCount); + column-count:var(--USER__colCount); + + --RS__colWidth:auto; +} + +:root[style*="--USER__colCount: 0"], +:root[style*="--USER__colCount:0"]{ + -webkit-column-count:1; + -moz-column-count:1; + column-count:1; +} + +:root[style*="--USER__colCount: 0"], +:root[style*="--USER__colCount:0"], +:root[style*="--USER__colCount: 1"], +:root[style*="--USER__colCount:1"]{ + --RS__colWidth:100vw; +} + +:root[style*="--USER__lineLength"] body{ + max-width:var(--USER__lineLength) !important; + } + +:root[style*="--USER__backgroundColor"]{ + background-color:var(--USER__backgroundColor) !important; +} + +:root[style*="--USER__backgroundColor"] *{ + background-color:transparent !important; +} + +:root[style*="--USER__textColor"]{ + color:var(--USER__textColor) !important; +} + +:root[style*="--USER__textColor"] *:not(h1):not(h2):not(h3):not(h4):not(h5):not(h6):not(pre){ + color:inherit !important; +} + +:root[style*="readium-font-on"][style*="--USER__fontFamily"]{ + font-family:var(--USER__fontFamily) !important; +} + +:root[style*="readium-font-on"][style*="--USER__fontFamily"] *:not(code):not(var):not(kbd):not(samp){ + font-family:inherit !important; +} + +:root[style*="--USER__fontSize"]{ + zoom:var(--USER__fontSize) !important; +} + +@supports not (zoom: 1){ + + :root[style*="--USER__fontSize"]{ + font-size:var(--USER__fontSize) !important; + } +} + +:root[style*="readium-advanced-on"][style*="--USER__lineHeight"]{ + line-height:var(--USER__lineHeight) !important; +} + +:root[style*="readium-advanced-on"][style*="--USER__lineHeight"] body, +:root[style*="readium-advanced-on"][style*="--USER__lineHeight"] p, +:root[style*="readium-advanced-on"][style*="--USER__lineHeight"] li, +:root[style*="readium-advanced-on"][style*="--USER__lineHeight"] div{ + line-height:inherit; +} + +:root[style*="readium-advanced-on"][style*="--USER__paraSpacing"] p{ + margin-top:var(--USER__paraSpacing) !important; + margin-bottom:var(--USER__paraSpacing) !important; +} + +:root[style*="readium-font-on"][style*="--USER__fontWeight"] body{ + font-weight:var(--USER__fontWeight) !important; +} + +:root[style*="readium-font-on"][style*="--USER__fontWeight"] b, +:root[style*="readium-font-on"][style*="--USER__fontWeight"] strong{ + font-weight:bolder; +} + +:root[style*="readium-font-on"][style*="--USER__fontWidth"] body{ + font-stretch:var(--USER__fontWidth) !important; +} + +:root[style*="readium-font-on"][style*="--USER__fontOpticalSizing"] body{ + font-optical-sizing:var(--USER__fontOpticalSizing) !important; +} + +:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] h1, +:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] h2, +:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] h3, +:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] h4, +:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] h5, +:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] h6, +:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] p, +:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] li, +:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] div{ + letter-spacing:var(--USER__letterSpacing); + font-variant:none; +} + +:root[style*="readium-advanced-on"][style*="readium-noRuby-on"] body rt, +:root[style*="readium-advanced-on"][style*="readium-noRuby-on"] body rp{ + display:none; +} + +@supports not (zoom: 1){ + + :root[style*="readium-advanced-on"]{ + --USER__typeScale:1.2; + } + + :root[style*="readium-advanced-on"] p, + :root[style*="readium-advanced-on"] li, + :root[style*="readium-advanced-on"] div, + :root[style*="readium-advanced-on"] pre, + :root[style*="readium-advanced-on"] dd{ + font-size:1rem !important; + } + + :root[style*="readium-advanced-on"] h1{ + font-size:1.75rem !important; + font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important; + } + + :root[style*="readium-advanced-on"] h2{ + font-size:1.5rem !important; + font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important; + } + + :root[style*="readium-advanced-on"] h3{ + font-size:1.25rem !important; + font-size:calc(1rem * var(--USER__typeScale)) !important; + } + + :root[style*="readium-advanced-on"] h4, + :root[style*="readium-advanced-on"] h5, + :root[style*="readium-advanced-on"] h6{ + font-size:1rem !important; + } + + :root[style*="readium-advanced-on"] small{ + font-size:smaller !important; + } + + :root[style*="readium-advanced-on"] sub, + :root[style*="readium-advanced-on"] sup{ + font-size:67.5% !important; + } + + :root[style*="readium-advanced-on"][style*="--USER__typeScale"] h1{ + font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important; + } + + :root[style*="readium-advanced-on"][style*="--USER__typeScale"] h2{ + font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important; + } + + :root[style*="readium-advanced-on"][style*="--USER__typeScale"] h3{ + font-size:calc(1rem * var(--USER__typeScale)) !important; + } +} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-horizontal/ReadiumCSS-before.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-horizontal/ReadiumCSS-before.css new file mode 100644 index 0000000000..b4bfa36c26 --- /dev/null +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-horizontal/ReadiumCSS-before.css @@ -0,0 +1,397 @@ +/* + * Readium CSS (v. 2.0.0-alpha.5) + * Developers: Jiminy Panoz + * Copyright (c) 2017. Readium Foundation. All rights reserved. + * Use of this source code is governed by a BSD-style license which is detailed in the + * LICENSE file present in the project repository where this source code is maintained. +*/ + +@namespace url("http://www.w3.org/1999/xhtml"); + +@namespace epub url("http://www.idpf.org/2007/ops"); + +@namespace m url("http://www.w3.org/1998/Math/MathML"); + +@namespace svg url("http://www.w3.org/2000/svg"); + +@-ms-viewport{ + width:device-width; +} + +@viewport{ + width:device-width; + zoom:1; +} + +:root{ + --RS__oldStyleTf:"Iowan Old Style", sitka, "Sitka Text", palatino, "Book Antiqua", "URW Palladio L", p052, serif; + --RS__modernTf:athelas, constantia, charter, "Bitstream Charter", cambria, "Georgia Pro", georgia, serif; + --RS__sansTf:-ui-sans-serif, -apple-system, system-ui, blinkmacsystemfont, "Segoe UI Variable", "Segoe UI", inter, roboto, "Helvetica Neue", "Arial Nova", "Liberation Sans", arial, sans-serif; + --RS__humanistTf:seravek, calibri, "Gill Sans Nova", roboto, ubuntu, "DejaVu Sans", source-sans-pro, sans-serif; + --RS__monospaceTf:ui-monospace, "Andale Mono", "Cascadia Code", "Source Code Pro", menlo, consolas, "DejaVu Sans Mono", monospace; + --RS__baseFontFamily:var(--RS__oldStyleTf); + --RS__lineHeightCompensation:1; + --RS__baseLineHeight:calc((1em + (2ex - 1ch) - ((1rem - 16px) * 0.1667)) * var(--RS__lineHeightCompensation)); +} + +html{ + font-family:var(--RS__baseFontFamily); + line-height:1.6; + line-height:var(--RS__baseLineHeight); + text-rendering:optimizelegibility; +} + +h1, h2, h3{ + line-height:normal; +} + +:lang(ja), +:lang(zh), +:lang(ko){ + word-wrap:break-word; + -webkit-line-break:strict; + -epub-line-break:strict; + line-break:strict; +} + +math{ + font-family:"Latin Modern Math", "STIX Two Math", "XITS Math", "STIX Math", "Libertinus Math", "TeX Gyre Termes Math", "TeX Gyre Bonum Math", "TeX Gyre Schola", "DejaVu Math TeX Gyre", "TeX Gyre Pagella Math", "Asana Math", "Cambria Math", "Lucida Bright Math", "Minion Math", STIXGeneral, STIXSizeOneSym, Symbol, "Times New Roman", serif; +} + +:lang(am){ + --RS__baseFontFamily:kefa, nyala, roboto, noto, "Noto Sans Ethiopic", serif; + --RS__lineHeightCompensation:1.167; +} + +:lang(ar){ + --RS__baseFontFamily:"Geeza Pro", "Arabic Typesetting", roboto, noto, "Noto Naskh Arabic", "Times New Roman", serif; +} + +:lang(bn){ + --RS__baseFontFamily:"Kohinoor Bangla", "Bangla Sangam MN", vrinda, roboto, noto, "Noto Sans Bengali", sans-serif; + --RS__lineHeightCompensation:1.067; +} + +:lang(bo){ + --RS__baseFontFamily:kailasa, "Microsoft Himalaya", roboto, noto, "Noto Sans Tibetan", sans-serif; +} + +:lang(chr){ + --RS__baseFontFamily:"Plantagenet Cherokee", roboto, noto, "Noto Sans Cherokee"; + --RS__lineHeightCompensation:1.167; +} + +:lang(fa){ + --RS__baseFontFamily:"Geeza Pro", "Arabic Typesetting", roboto, noto, "Noto Naskh Arabic", "Times New Roman", serif; +} + +:lang(gu){ + --RS__baseFontFamily:"Gujarati Sangam MN", "Nirmala UI", shruti, roboto, noto, "Noto Sans Gujarati", sans-serif; + --RS__lineHeightCompensation:1.167; +} + +:lang(he){ + --RS__baseFontFamily:"New Peninim MT", "Arial Hebrew", gisha, "Times New Roman", roboto, noto, "Noto Sans Hebrew" sans-serif; + --RS__lineHeightCompensation:1.1; +} + +:lang(hi){ + --RS__baseFontFamily:"Kohinoor Devanagari", "Devanagari Sangam MN", kokila, "Nirmala UI", roboto, noto, "Noto Sans Devanagari", sans-serif; + + --RS__lineHeightCompensation:1.1; +} + +:lang(hy){ + --RS__baseFontFamily:mshtakan, sylfaen, roboto, noto, "Noto Serif Armenian", serif; +} + +:lang(iu){ + --RS__baseFontFamily:"Euphemia UCAS", euphemia, roboto, noto, "Noto Sans Canadian Aboriginal", sans-serif; +} + +:lang(ja){ + --RS__baseFontFamily:yugothic, "Hiragino Maru Gothic ProN", "Hiragino Sans", "Yu Gothic UI", "Meiryo UI", "MS Gothic", roboto, noto, "Noto Sans CJK JP", sans-serif; + --RS__lineHeightCompensation:1.167; + --RS__serif-ja:"Hiragino Mincho ProN", "Hiragino Mincho Pro", "YuMincho", "BIZ UDPMincho", "Yu Mincho", "MS P明朝", "MS PMincho", serif; + --RS__sans-serif-ja:"Hiragino Sans", "Hiragino Kaku Gothic ProN", "Hiragino Kaku Gothic Pro", "ヒラギノ角ゴ W3", "YuGothic", "Yu Gothic Medium", "BIZ UDPGothic", "Yu Gothic", "MS Pゴシック", "MS PGothic", sans-serif; + --RS__serif-ja-v:"Hiragino Mincho ProN", "Hiragino Mincho Pro", "YuMincho", "BIZ UDMincho", "Yu Mincho", "MS明朝", "MS Mincho", serif; + --RS__sans-serif-ja-v:"Hiragino Sans", "Hiragino Kaku Gothic ProN", "Hiragino Kaku Gothic Pro", "ヒラギノ角ゴ W3", "YuGothic", "Yu Gothic Medium", "BIZ UDGothic", "Yu Gothic", "MSゴシック", "MS Gothic", sans-serif; +} + +:lang(km){ + --RS__baseFontFamily:"Khmer Sangam MN", "Leelawadee UI", "Khmer UI", roboto, noto, "Noto Sans Khmer", sans-serif; + --RS__lineHeightCompensation:1.067; +} + +:lang(kn){ + --RS__baseFontFamily:"Kannada Sangam MN", "Nirmala UI", tunga, roboto, noto, "Noto Sans Kannada", sans-serif; + --RS__lineHeightCompensation:1.1; +} + +:lang(ko){ + --RS__baseFontFamily:"Nanum Gothic", "Apple SD Gothic Neo", "Malgun Gothic", roboto, noto, "Noto Sans CJK KR", sans-serif; + --RS__lineHeightCompensation:1.167; +} + +:lang(lo){ + --RS__baseFontFamily:"Lao Sangam MN", "Leelawadee UI", "Lao UI", roboto, noto, "Noto Sans Lao", sans-serif; +} + +:lang(ml){ + --RS__baseFontFamily:"Malayalam Sangam MN", "Nirmala UI", kartika, roboto, noto, "Noto Sans Malayalam", sans-serif; + --RS__lineHeightCompensation:1.067; +} + +:lang(or){ + --RS__baseFontFamily:"Oriya Sangam MN", "Nirmala UI", kalinga, roboto, noto, "Noto Sans Oriya", sans-serif; + --RS__lineHeightCompensation:1.167; +} + +:lang(pa){ + --RS__baseFontFamily:"Gurmukhi MN", "Nirmala UI", kartika, roboto, noto, "Noto Sans Gurmukhi", sans-serif; + --RS__lineHeightCompensation:1.1; +} + +:lang(si){ + --RS__baseFontFamily:"Sinhala Sangam MN", "Nirmala UI", "Iskoola Pota", roboto, noto, "Noto Sans Sinhala", sans-serif; + --RS__lineHeightCompensation:1.167; +} + +:lang(ta){ + --RS__baseFontFamily:"Tamil Sangam MN", "Nirmala UI", latha, roboto, noto, "Noto Sans Tamil", sans-serif; + --RS__lineHeightCompensation:1.067; +} + +:lang(te){ + --RS__baseFontFamily:"Kohinoor Telugu", "Telugu Sangam MN", "Nirmala UI", gautami, roboto, noto, "Noto Sans Telugu", sans-serif; +} + +:lang(th){ + --RS__baseFontFamily:"Thonburi", "Leelawadee UI", "Cordia New", roboto, noto, "Noto Sans Thai", sans-serif; + --RS__lineHeightCompensation:1.067; +} + +:lang(zh){ + --RS__baseFontFamily:"方体", "PingFang SC", "黑体", "Heiti SC", "Microsoft JhengHei UI", "Microsoft JhengHei", roboto, noto, "Noto Sans CJK SC", sans-serif; + --RS__lineHeightCompensation:1.167; +} + +:lang(zh-Hant), +:lang(zh-TW){ + --RS__baseFontFamily:"方體", "PingFang TC", "黑體", "Heiti TC", "Microsoft JhengHei UI", "Microsoft JhengHei", roboto, noto, "Noto Sans CJK TC", sans-serif; + --RS__lineHeightCompensation:1.167; +} + +:lang(zh-HK){ + --RS__baseFontFamily:"方體", "PingFang HK", "方體", "PingFang TC", "黑體", "Heiti TC", "Microsoft JhengHei UI", "Microsoft JhengHei", roboto, noto, "Noto Sans CJK TC", sans-serif; + --RS__lineHeightCompensation:1.167; +} + +:root{ + --RS__backgroundColor:#FFFFFF; + --RS__textColor:#121212; + --RS__selectionBackgroundColor:#b4d8fe; + --RS__selectionTextColor:inherit; +} + +:root{ + color:var(--RS__textColor) !important; + background-color:var(--RS__backgroundColor) !important; +} + +::-moz-selection{ + color:var(--RS__selectionTextColor); + background-color:var(--RS__selectionBackgroundColor); +} + +::selection{ + color:var(--RS__selectionTextColor); + background-color:var(--RS__selectionBackgroundColor); +} + +body{ + widows:2; + orphans:2; +} + +figcaption, th, td{ + widows:1; + orphans:1; +} + +h2, h3, h4, h5, h6, dt, +hr, caption{ + -webkit-column-break-after:avoid; + page-break-after:avoid; + break-after:avoid; +} + +h1, h2, h3, h4, h5, h6, dt, +figure, tr{ + -webkit-column-break-inside:avoid; + page-break-inside:avoid; + break-inside:avoid; +} + +body{ + -webkit-hyphenate-character:"\002D"; + -moz-hyphenate-character:"\002D"; + -ms-hyphenate-character:"\002D"; + hyphenate-character:"\002D"; + -webkit-hyphenate-limit-lines:3; + -ms-hyphenate-limit-lines:3; + hyphenate-limit-lines:3; +} + +h1, h2, h3, h4, h5, h6, dt, +figcaption, pre, caption, address, +center, code, var{ + -ms-hyphens:none; + -moz-hyphens:none; + -webkit-hyphens:none; + -epub-hyphens:none; + hyphens:none; +} + +body{ + font-variant-numeric:oldstyle-nums proportional-nums; +} + +:lang(ja) body, +:lang(zh) body, +:lang(ko) body{ + font-variant-numeric:lining-nums proportional-nums; +} + +h1, h2, h3, h4, h5, h6, dt{ + font-variant-numeric:lining-nums proportional-nums; +} + +table{ + font-variant-numeric:lining-nums tabular-nums; +} + +code, var{ + font-variant-ligatures:none; + font-variant-numeric:lining-nums tabular-nums slashed-zero; +} + +rt{ + font-variant-east-asian:ruby; +} + +:lang(ar){ + font-variant-ligatures:common-ligatures; +} + +:lang(ko){ + font-kerning:normal; +} + +hr{ + color:inherit; + border-color:currentcolor; +} + +table, th, td{ + border-color:currentcolor; +} + +figure, blockquote{ + margin:1em 5%; +} + +ul, ol{ + padding-left:5%; +} + +dd{ + margin-left:5%; +} + +pre{ + white-space:pre-wrap; + -ms-tab-size:2; + -moz-tab-size:2; + -webkit-tab-size:2; + tab-size:2; +} + +abbr[title], acronym[title]{ + text-decoration:dotted underline; +} + +nobr wbr{ + white-space:normal; +} + +ruby > rt, ruby > rp{ + -webkit-user-select:none; + -moz-user-select:none; + -ms-user-select:none; + user-select:none; +} + +*:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)), +*:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)), +*:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)), +:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)) cite, +:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)) dfn, +:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)) em, +:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)) i, +:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)) cite, +:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)) dfn, +:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)) em, +:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)) i, +:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)) cite, +:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)) dfn, +:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)) em, +:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)) i{ + font-style:normal; +} + +:lang(ja) a, +:lang(zh) a, +:lang(ko) a{ + text-decoration:none; +} + +:root{ + --RS__maxMediaWidth:100%; + --RS__maxMediaHeight:95vh; + --RS__boxSizingMedia:border-box; + --RS__boxSizingTable:border-box; +} + +a, a span, span a, h1, h2, h3, h4, h5, h6{ + word-wrap:break-word; +} + +div{ + max-width:var(--RS__maxMediaWidth); +} + +img, svg|svg, video{ + object-fit:contain; + + width:auto; + height:auto; + max-width:var(--RS__maxMediaWidth); + max-height:var(--RS__maxMediaHeight) !important; + box-sizing:var(--RS__boxSizingMedia); + -webkit-column-break-inside:avoid; + page-break-inside:avoid; + break-inside:avoid; +} + +audio{ + max-width:100%; + -webkit-column-break-inside:avoid; + page-break-inside:avoid; + break-inside:avoid; + } + +table{ + max-width:var(--RS__maxMediaWidth); + box-sizing:var(--RS__boxSizingTable); +} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-horizontal/ReadiumCSS-default.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-horizontal/ReadiumCSS-default.css new file mode 100644 index 0000000000..2e0bc2ca37 --- /dev/null +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-horizontal/ReadiumCSS-default.css @@ -0,0 +1,170 @@ +/* + * Readium CSS (v. 2.0.0-alpha.5) + * Developers: Jiminy Panoz + * Copyright (c) 2017. Readium Foundation. All rights reserved. + * Use of this source code is governed by a BSD-style license which is detailed in the + * LICENSE file present in the project repository where this source code is maintained. +*/ + +@namespace url("http://www.w3.org/1999/xhtml"); + +@namespace epub url("http://www.idpf.org/2007/ops"); + +@namespace m url("http://www.w3.org/1998/Math/MathML"); + +@namespace svg url("http://www.w3.org/2000/svg"); + +:root{ + + --RS__compFontFamily:var(--RS__baseFontFamily); + --RS__codeFontFamily:var(--RS__monospaceTf); + + --RS__typeScale:1.125; + --RS__baseFontSize:87.5%; + + --RS__flowSpacing:1.5rem; + --RS__paraSpacing:0; + --RS__paraIndent:1em; + + --RS__linkColor:#0000EE; + --RS__visitedColor:#551A8B; + + --RS__primaryColor:; + --RS__secondaryColor:; +} + +:root:lang(zh){ + --RS__paraIndent:2em; +} + +:root{ + quotes:"\201c" "\201d" "\2018" "\2019"; +} + +body{ + font-size:var(--RS__baseFontSize); + text-align:justify; + text-justify:inter-character; +} + +h1, h2, h3, h4, h5, h6{ + font-family:var(--RS__baseFontFamily); + text-align:left; + text-align:start; +} + +blockquote, figure, p, pre, +aside, footer, form, hr{ + margin-top:var(--RS__flowSpacing); + margin-bottom:var(--RS__flowSpacing); +} + +p{ + margin-top:var(--RS__paraSpacing); + margin-bottom:var(--RS__paraSpacing); + text-indent:var(--RS__paraIndent); +} + +pre{ + font-family:var(--RS__codeFontFamily); +} + +code, kbd, samp, tt{ + font-family:var(--RS__codeFontFamily); +} + +sub, sup{ + position:relative; + font-size:67.5%; + line-height:1; +} + +sub{ + bottom:-0.2ex; +} + +sup{ + bottom:0; +} + +em{ + -webkit-text-emphasis:dot; + -epub-text-emphasis:dot; + text-emphasis:dot; +} + +:link{ + color:var(--RS__linkColor); +} + +:visited{ + color:var(--RS__visitedColor); +} + +h1{ + margin-top:calc(var(--RS__flowSpacing) * 2); + margin-bottom:calc(var(--RS__flowSpacing) * 2); + font-size:calc(((1em * var(--RS__typeScale)) * var(--RS__typeScale)) * var(--RS__typeScale)); + text-align:center; +} + +h2{ + margin-top:calc(var(--RS__flowSpacing) * 2); + margin-bottom:var(--RS__flowSpacing); + font-size:calc((1em * var(--RS__typeScale)) * var(--RS__typeScale)); + text-align:center; +} + +h3{ + margin-top:var(--RS__flowSpacing); + margin-bottom:var(--RS__flowSpacing); + font-size:calc(1em * var(--RS__typeScale)); + text-align:center; +} + +h4{ + margin-top:var(--RS__flowSpacing); + margin-bottom:var(--RS__flowSpacing); + font-family:var(--RS__compFontFamily); + font-size:1em; +} + +h5{ + margin-top:var(--RS__flowSpacing); + margin-bottom:var(--RS__flowSpacing); + font-family:var(--RS__compFontFamily); + font-size:smaller; +} + +h6{ + margin-top:var(--RS__flowSpacing); + margin-bottom:0; + font-family:var(--RS__compFontFamily); + font-size:smaller; + font-weight:normal; +} + +dl, ol, ul{ + margin-top:var(--RS__flowSpacing); + margin-bottom:var(--RS__flowSpacing); +} + +table{ + margin:var(--RS__flowSpacing) 0; + border:1px solid currentcolor; + border-collapse:collapse; + empty-cells:show; +} + +thead, tbody, tfoot, table > tr{ + vertical-align:top; +} + +th{ + text-align:left; +} + +th, td{ + padding:4px; + border:1px solid currentcolor; +} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-vertical/ReadiumCSS-after.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-vertical/ReadiumCSS-after.css new file mode 100644 index 0000000000..638645fad1 --- /dev/null +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-vertical/ReadiumCSS-after.css @@ -0,0 +1,415 @@ +/* + * Readium CSS (v. 2.0.0-alpha.5) + * Developers: Jiminy Panoz + * Copyright (c) 2017. Readium Foundation. All rights reserved. + * Use of this source code is governed by a BSD-style license which is detailed in the + * LICENSE file present in the project repository where this source code is maintained. +*/ + +@namespace url("http://www.w3.org/1999/xhtml"); + +@namespace epub url("http://www.idpf.org/2007/ops"); + +@namespace m url("http://www.w3.org/1998/Math/MathML"); + +@namespace svg url("http://www.w3.org/2000/svg"); + +:root{ + --RS__colWidth:100vh; + --RS__colCount:1; + --RS__colGap:0; + --RS__defaultLineLength:40rem; + --RS__pageGutter:0; +} + +@page{ + margin:0 !important; +} + +:root{ + position:relative; + + -webkit-column-width:var(--RS__colWidth); + -moz-column-width:var(--RS__colWidth); + column-width:var(--RS__colWidth); + -webkit-column-count:var(--RS__colCount); + -moz-column-count:var(--RS__colCount); + column-count:var(--RS__colCount); + + -webkit-column-gap:var(--RS__colGap); + -moz-column-gap:var(--RS__colGap); + column-gap:var(--RS__colGap); + -moz-column-fill:auto; + column-fill:auto; + width:100%; + height:100vh; + max-width:100%; + max-height:100vh; + min-width:100%; + min-height:100vh; + padding:0 !important; + margin:0 !important; + font-size:100% !important; + + -webkit-text-size-adjust:100%; + box-sizing:border-box; + + hanging-punctuation:last allow-end; + -webkit-touch-callout:none; + -ms-writing-mode:tb-rl; + -webkit-writing-mode:vertical-rl; + writing-mode:vertical-rl; +} + +:root:lang(mn-Mong){ + -ms-writing-mode:tb; + -webkit-writing-mode:vertical-lr; + writing-mode:vertical-lr; +} + +body{ + width:100%; + max-height:var(--RS__defaultLineLength) !important; + padding:var(--RS__pageGutter) 0 !important; + margin:auto 0 !important; + overflow:hidden; + box-sizing:border-box; +} + +@supports (overflow: clip){ + + :root{ + overflow:clip; + } + + body{ + overflow:clip; + overflow-clip-margin:content-box; + } +} + +:root[style*="readium-scroll-on"], +:root[style*="readium-noVerticalPagination-on"]{ + -webkit-columns:auto auto !important; + -moz-columns:auto auto !important; + columns:auto auto !important; + width:auto !important; + max-width:none !important; + max-height:100vh !important; + min-width:0 !important; +} + +:root[style*="readium-scroll-on"] body, +:root[style*="readium-noVerticalPagination-on"] body{ + --RS__defaultLineLength:40.01rem !important; +} + +@supports (overflow: clip){ + + :root[style*="readium-scroll-on"]{ + overflow:auto; + } + + :root[style*="readium-scroll-on"] body{ + overflow:clip; + } +} + +:root[style*="readium-night-on"]{ + --RS__backgroundColor:#000000; + --RS__textColor:#FEFEFE; + + --RS__linkColor:#63caff; + --RS__visitedColor:#0099E5; + --RS__selectionBackgroundColor:#b4d8fe; + --RS__selectionTextColor:inherit; +} + +:root[style*="readium-night-on"] *:not(a){ + color:inherit !important; + background-color:transparent !important; + border-color:currentcolor !important; +} + +:root[style*="readium-night-on"] svg text{ + fill:currentcolor !important; + stroke:none !important; +} + +:root[style*="readium-night-on"] a:link, +:root[style*="readium-night-on"] a:link *{ + color:var(--RS__linkColor) !important; +} + +:root[style*="readium-night-on"] a:visited, +:root[style*="readium-night-on"] a:visited *{ + color:var(--RS__visitedColor) !important; +} + +:root[style*="readium-night-on"] img[class*="gaiji"], +:root[style*="readium-night-on"] *[epub\:type~="titlepage"] img:only-child, +:root[style*="readium-night-on"] *[epub|type~="titlepage"] img:only-child{ + -webkit-filter:invert(100%); + filter:invert(100%); +} + +:root[style*="readium-night-on"][style*="readium-darken-on"] img{ + -webkit-filter:brightness(80%); + filter:brightness(80%); +} + +:root[style*="readium-night-on"][style*="readium-invert-on"] img{ + -webkit-filter:invert(100%); + filter:invert(100%); +} + +:root[style*="readium-night-on"][style*="readium-darken-on"][style*="readium-invert-on"] img{ + -webkit-filter:brightness(80%) invert(100%); + filter:brightness(80%) invert(100%); +} + +:root[style*="readium-sepia-on"]{ + --RS__backgroundColor:#faf4e8; + --RS__textColor:#121212; + + --RS__linkColor:#0000EE; + --RS__visitedColor:#551A8B; + --RS__selectionBackgroundColor:#b4d8fe; + --RS__selectionTextColor:inherit; + + --RS__defaultLineLength:40.01rem; +} + +:root[style*="readium-sepia-on"] *:not(a){ + color:inherit !important; + background-color:transparent !important; +} + +:root[style*="readium-sepia-on"] a:link, +:root[style*="readium-sepia-on"] a:link *{ + color:var(--RS__linkColor); +} + +:root[style*="readium-sepia-on"] a:visited, +:root[style*="readium-sepia-on"] a:visited *{ + color:var(--RS__visitedColor); +} + +:root[style*="readium-sepia-on"] svg, +:root[style*="readium-sepia-on"] img{ + background-color:transparent !important; + mix-blend-mode:multiply; +} + +@media screen and (-ms-high-contrast: active){ + + :root{ + color:windowText !important; + background-color:window !important; + } + + :root :not(#\#):not(#\#):not(#\#), + :root :not(#\#):not(#\#):not(#\#) :not(#\#):not(#\#):not(#\#) + :root :not(#\#):not(#\#):not(#\#) :not(#\#):not(#\#):not(#\#) :not(#\#):not(#\#):not(#\#){ + color:inherit !important; + background-color:inherit !important; + } + + .readiumCSS-mo-active-default{ + color:highlightText !important; + background-color:highlight !important; + } +} + +@media screen and (-ms-high-contrast: white-on-black){ + + :root[style*="readium-night-on"] img[class*="gaiji"], + :root[style*="readium-night-on"] *[epub\:type~="titlepage"] img:only-child, + :root[style*="readium-night-on"] *[epub|type~="titlepage"] img:only-child{ + -webkit-filter:none !important; + filter:none !important; + } + + :root[style*="readium-night-on"][style*="readium-invert-on"] img{ + -webkit-filter:none !important; + filter:none !important; + } + + :root[style*="readium-night-on"][style*="readium-darken-on"][style*="readium-invert-on"] img{ + -webkit-filter:brightness(80%); + filter:brightness(80%); + } +} + +@media screen and (inverted-colors){ + + :root[style*="readium-night-on"] img[class*="gaiji"], + :root[style*="readium-night-on"] *[epub\:type~="titlepage"] img:only-child, + :root[style*="readium-night-on"] *[epub|type~="titlepage"] img:only-child{ + -webkit-filter:none !important; + filter:none !important; + } + + :root[style*="readium-night-on"][style*="readium-invert-on"] img{ + -webkit-filter:none !important; + filter:none !important; + } + + :root[style*="readium-night-on"][style*="readium-darken-on"][style*="readium-invert-on"] img{ + -webkit-filter:brightness(80%); + filter:brightness(80%); + } +} + +@media screen and (monochrome){ +} + +@media screen and (prefers-reduced-motion){ +} + +:root[style*="--USER__lineLength"] body{ + max-height:var(--USER__lineLength) !important; + } + +:root[style*="--USER__backgroundColor"]{ + background-color:var(--USER__backgroundColor) !important; +} + +:root[style*="--USER__backgroundColor"] *{ + background-color:transparent !important; +} + +:root[style*="--USER__textColor"]{ + color:var(--USER__textColor) !important; +} + +:root[style*="--USER__textColor"] *:not(h1):not(h2):not(h3):not(h4):not(h5):not(h6):not(pre){ + color:inherit !important; +} + +:root[style*="readium-font-on"][style*="--USER__fontFamily"]{ + font-family:var(--USER__fontFamily) !important; +} + +:root[style*="readium-font-on"][style*="--USER__fontFamily"] *:not(code):not(var):not(kbd):not(samp){ + font-family:inherit !important; +} + +:root[style*="--USER__fontSize"]{ + zoom:var(--USER__fontSize) !important; +} + +@supports not (zoom: 1){ + + :root[style*="--USER__fontSize"]{ + font-size:var(--USER__fontSize) !important; + } +} + +:root[style*="readium-advanced-on"][style*="--USER__lineHeight"]{ + line-height:var(--USER__lineHeight) !important; +} + +:root[style*="readium-advanced-on"][style*="--USER__lineHeight"] body, +:root[style*="readium-advanced-on"][style*="--USER__lineHeight"] p, +:root[style*="readium-advanced-on"][style*="--USER__lineHeight"] li, +:root[style*="readium-advanced-on"][style*="--USER__lineHeight"] div{ + line-height:inherit; +} + +:root[style*="readium-advanced-on"][style*="--USER__paraSpacing"] p{ + margin-right:var(--USER__paraSpacing) !important; + margin-left:var(--USER__paraSpacing) !important; +} + +:root[style*="readium-font-on"][style*="--USER__fontWeight"] body{ + font-weight:var(--USER__fontWeight) !important; +} + +:root[style*="readium-font-on"][style*="--USER__fontWeight"] b, +:root[style*="readium-font-on"][style*="--USER__fontWeight"] strong{ + font-weight:bolder; +} + +:root[style*="readium-font-on"][style*="--USER__fontWidth"] body{ + font-stretch:var(--USER__fontWidth) !important; +} + +:root[style*="readium-font-on"][style*="--USER__fontOpticalSizing"] body{ + font-optical-sizing:var(--USER__fontOpticalSizing) !important; +} + +:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] h1, +:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] h2, +:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] h3, +:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] h4, +:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] h5, +:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] h6, +:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] p, +:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] li, +:root[style*="readium-advanced-on"][style*="--USER__letterSpacing"] div{ + letter-spacing:var(--USER__letterSpacing); + font-variant:none; +} + +:root[style*="readium-advanced-on"][style*="readium-noRuby-on"] body rt, +:root[style*="readium-advanced-on"][style*="readium-noRuby-on"] body rp{ + display:none; +} + +@supports not (zoom: 1){ + + :root[style*="readium-advanced-on"]{ + --USER__typeScale:1.2; + } + + :root[style*="readium-advanced-on"] p, + :root[style*="readium-advanced-on"] li, + :root[style*="readium-advanced-on"] div, + :root[style*="readium-advanced-on"] pre, + :root[style*="readium-advanced-on"] dd{ + font-size:1rem !important; + } + + :root[style*="readium-advanced-on"] h1{ + font-size:1.75rem !important; + font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important; + } + + :root[style*="readium-advanced-on"] h2{ + font-size:1.5rem !important; + font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important; + } + + :root[style*="readium-advanced-on"] h3{ + font-size:1.25rem !important; + font-size:calc(1rem * var(--USER__typeScale)) !important; + } + + :root[style*="readium-advanced-on"] h4, + :root[style*="readium-advanced-on"] h5, + :root[style*="readium-advanced-on"] h6{ + font-size:1rem !important; + } + + :root[style*="readium-advanced-on"] small{ + font-size:smaller !important; + } + + :root[style*="readium-advanced-on"] sub, + :root[style*="readium-advanced-on"] sup{ + font-size:67.5% !important; + } + + :root[style*="readium-advanced-on"][style*="--USER__typeScale"] h1{ + font-size:calc(((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) * var(--USER__typeScale)) !important; + } + + :root[style*="readium-advanced-on"][style*="--USER__typeScale"] h2{ + font-size:calc((1rem * var(--USER__typeScale)) * var(--USER__typeScale)) !important; + } + + :root[style*="readium-advanced-on"][style*="--USER__typeScale"] h3{ + font-size:calc(1rem * var(--USER__typeScale)) !important; + } +} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-vertical/ReadiumCSS-before.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-vertical/ReadiumCSS-before.css new file mode 100644 index 0000000000..12633a47bb --- /dev/null +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-vertical/ReadiumCSS-before.css @@ -0,0 +1,397 @@ +/* + * Readium CSS (v. 2.0.0-alpha.5) + * Developers: Jiminy Panoz + * Copyright (c) 2017. Readium Foundation. All rights reserved. + * Use of this source code is governed by a BSD-style license which is detailed in the + * LICENSE file present in the project repository where this source code is maintained. +*/ + +@namespace url("http://www.w3.org/1999/xhtml"); + +@namespace epub url("http://www.idpf.org/2007/ops"); + +@namespace m url("http://www.w3.org/1998/Math/MathML"); + +@namespace svg url("http://www.w3.org/2000/svg"); + +@-ms-viewport{ + width:device-width; +} + +@viewport{ + width:device-width; + zoom:1; +} + +:root{ + --RS__oldStyleTf:"Iowan Old Style", sitka, "Sitka Text", palatino, "Book Antiqua", "URW Palladio L", p052, serif; + --RS__modernTf:athelas, constantia, charter, "Bitstream Charter", cambria, "Georgia Pro", georgia, serif; + --RS__sansTf:-ui-sans-serif, -apple-system, system-ui, blinkmacsystemfont, "Segoe UI Variable", "Segoe UI", inter, roboto, "Helvetica Neue", "Arial Nova", "Liberation Sans", arial, sans-serif; + --RS__humanistTf:seravek, calibri, "Gill Sans Nova", roboto, ubuntu, "DejaVu Sans", source-sans-pro, sans-serif; + --RS__monospaceTf:ui-monospace, "Andale Mono", "Cascadia Code", "Source Code Pro", menlo, consolas, "DejaVu Sans Mono", monospace; + --RS__baseFontFamily:var(--RS__oldStyleTf); + --RS__lineHeightCompensation:1; + --RS__baseLineHeight:calc((1em + (2ex - 1ch) - ((1rem - 16px) * 0.1667)) * var(--RS__lineHeightCompensation)); +} + +html{ + font-family:var(--RS__baseFontFamily); + line-height:1.6; + line-height:var(--RS__baseLineHeight); + text-rendering:optimizelegibility; +} + +h1, h2, h3{ + line-height:normal; +} + +:lang(ja), +:lang(zh), +:lang(ko){ + word-wrap:break-word; + -webkit-line-break:strict; + -epub-line-break:strict; + line-break:strict; +} + +math{ + font-family:"Latin Modern Math", "STIX Two Math", "XITS Math", "STIX Math", "Libertinus Math", "TeX Gyre Termes Math", "TeX Gyre Bonum Math", "TeX Gyre Schola", "DejaVu Math TeX Gyre", "TeX Gyre Pagella Math", "Asana Math", "Cambria Math", "Lucida Bright Math", "Minion Math", STIXGeneral, STIXSizeOneSym, Symbol, "Times New Roman", serif; +} + +:lang(am){ + --RS__baseFontFamily:kefa, nyala, roboto, noto, "Noto Sans Ethiopic", serif; + --RS__lineHeightCompensation:1.167; +} + +:lang(ar){ + --RS__baseFontFamily:"Geeza Pro", "Arabic Typesetting", roboto, noto, "Noto Naskh Arabic", "Times New Roman", serif; +} + +:lang(bn){ + --RS__baseFontFamily:"Kohinoor Bangla", "Bangla Sangam MN", vrinda, roboto, noto, "Noto Sans Bengali", sans-serif; + --RS__lineHeightCompensation:1.067; +} + +:lang(bo){ + --RS__baseFontFamily:kailasa, "Microsoft Himalaya", roboto, noto, "Noto Sans Tibetan", sans-serif; +} + +:lang(chr){ + --RS__baseFontFamily:"Plantagenet Cherokee", roboto, noto, "Noto Sans Cherokee"; + --RS__lineHeightCompensation:1.167; +} + +:lang(fa){ + --RS__baseFontFamily:"Geeza Pro", "Arabic Typesetting", roboto, noto, "Noto Naskh Arabic", "Times New Roman", serif; +} + +:lang(gu){ + --RS__baseFontFamily:"Gujarati Sangam MN", "Nirmala UI", shruti, roboto, noto, "Noto Sans Gujarati", sans-serif; + --RS__lineHeightCompensation:1.167; +} + +:lang(he){ + --RS__baseFontFamily:"New Peninim MT", "Arial Hebrew", gisha, "Times New Roman", roboto, noto, "Noto Sans Hebrew" sans-serif; + --RS__lineHeightCompensation:1.1; +} + +:lang(hi){ + --RS__baseFontFamily:"Kohinoor Devanagari", "Devanagari Sangam MN", kokila, "Nirmala UI", roboto, noto, "Noto Sans Devanagari", sans-serif; + + --RS__lineHeightCompensation:1.1; +} + +:lang(hy){ + --RS__baseFontFamily:mshtakan, sylfaen, roboto, noto, "Noto Serif Armenian", serif; +} + +:lang(iu){ + --RS__baseFontFamily:"Euphemia UCAS", euphemia, roboto, noto, "Noto Sans Canadian Aboriginal", sans-serif; +} + +:lang(ja){ + --RS__baseFontFamily:yugothic, "Hiragino Maru Gothic ProN", "Hiragino Sans", "Yu Gothic UI", "Meiryo UI", "MS Gothic", roboto, noto, "Noto Sans CJK JP", sans-serif; + --RS__lineHeightCompensation:1.167; + --RS__serif-ja:"Hiragino Mincho ProN", "Hiragino Mincho Pro", "YuMincho", "BIZ UDPMincho", "Yu Mincho", "MS P明朝", "MS PMincho", serif; + --RS__sans-serif-ja:"Hiragino Sans", "Hiragino Kaku Gothic ProN", "Hiragino Kaku Gothic Pro", "ヒラギノ角ゴ W3", "YuGothic", "Yu Gothic Medium", "BIZ UDPGothic", "Yu Gothic", "MS Pゴシック", "MS PGothic", sans-serif; + --RS__serif-ja-v:"Hiragino Mincho ProN", "Hiragino Mincho Pro", "YuMincho", "BIZ UDMincho", "Yu Mincho", "MS明朝", "MS Mincho", serif; + --RS__sans-serif-ja-v:"Hiragino Sans", "Hiragino Kaku Gothic ProN", "Hiragino Kaku Gothic Pro", "ヒラギノ角ゴ W3", "YuGothic", "Yu Gothic Medium", "BIZ UDGothic", "Yu Gothic", "MSゴシック", "MS Gothic", sans-serif; +} + +:lang(km){ + --RS__baseFontFamily:"Khmer Sangam MN", "Leelawadee UI", "Khmer UI", roboto, noto, "Noto Sans Khmer", sans-serif; + --RS__lineHeightCompensation:1.067; +} + +:lang(kn){ + --RS__baseFontFamily:"Kannada Sangam MN", "Nirmala UI", tunga, roboto, noto, "Noto Sans Kannada", sans-serif; + --RS__lineHeightCompensation:1.1; +} + +:lang(ko){ + --RS__baseFontFamily:"Nanum Gothic", "Apple SD Gothic Neo", "Malgun Gothic", roboto, noto, "Noto Sans CJK KR", sans-serif; + --RS__lineHeightCompensation:1.167; +} + +:lang(lo){ + --RS__baseFontFamily:"Lao Sangam MN", "Leelawadee UI", "Lao UI", roboto, noto, "Noto Sans Lao", sans-serif; +} + +:lang(ml){ + --RS__baseFontFamily:"Malayalam Sangam MN", "Nirmala UI", kartika, roboto, noto, "Noto Sans Malayalam", sans-serif; + --RS__lineHeightCompensation:1.067; +} + +:lang(or){ + --RS__baseFontFamily:"Oriya Sangam MN", "Nirmala UI", kalinga, roboto, noto, "Noto Sans Oriya", sans-serif; + --RS__lineHeightCompensation:1.167; +} + +:lang(pa){ + --RS__baseFontFamily:"Gurmukhi MN", "Nirmala UI", kartika, roboto, noto, "Noto Sans Gurmukhi", sans-serif; + --RS__lineHeightCompensation:1.1; +} + +:lang(si){ + --RS__baseFontFamily:"Sinhala Sangam MN", "Nirmala UI", "Iskoola Pota", roboto, noto, "Noto Sans Sinhala", sans-serif; + --RS__lineHeightCompensation:1.167; +} + +:lang(ta){ + --RS__baseFontFamily:"Tamil Sangam MN", "Nirmala UI", latha, roboto, noto, "Noto Sans Tamil", sans-serif; + --RS__lineHeightCompensation:1.067; +} + +:lang(te){ + --RS__baseFontFamily:"Kohinoor Telugu", "Telugu Sangam MN", "Nirmala UI", gautami, roboto, noto, "Noto Sans Telugu", sans-serif; +} + +:lang(th){ + --RS__baseFontFamily:"Thonburi", "Leelawadee UI", "Cordia New", roboto, noto, "Noto Sans Thai", sans-serif; + --RS__lineHeightCompensation:1.067; +} + +:lang(zh){ + --RS__baseFontFamily:"方体", "PingFang SC", "黑体", "Heiti SC", "Microsoft JhengHei UI", "Microsoft JhengHei", roboto, noto, "Noto Sans CJK SC", sans-serif; + --RS__lineHeightCompensation:1.167; +} + +:lang(zh-Hant), +:lang(zh-TW){ + --RS__baseFontFamily:"方體", "PingFang TC", "黑體", "Heiti TC", "Microsoft JhengHei UI", "Microsoft JhengHei", roboto, noto, "Noto Sans CJK TC", sans-serif; + --RS__lineHeightCompensation:1.167; +} + +:lang(zh-HK){ + --RS__baseFontFamily:"方體", "PingFang HK", "方體", "PingFang TC", "黑體", "Heiti TC", "Microsoft JhengHei UI", "Microsoft JhengHei", roboto, noto, "Noto Sans CJK TC", sans-serif; + --RS__lineHeightCompensation:1.167; +} + +:root{ + --RS__backgroundColor:#FFFFFF; + --RS__textColor:#121212; + --RS__selectionBackgroundColor:#b4d8fe; + --RS__selectionTextColor:inherit; +} + +:root{ + color:var(--RS__textColor) !important; + background-color:var(--RS__backgroundColor) !important; +} + +::-moz-selection{ + color:var(--RS__selectionTextColor); + background-color:var(--RS__selectionBackgroundColor); +} + +::selection{ + color:var(--RS__selectionTextColor); + background-color:var(--RS__selectionBackgroundColor); +} + +body{ + widows:2; + orphans:2; +} + +figcaption, th, td{ + widows:1; + orphans:1; +} + +h2, h3, h4, h5, h6, dt, +hr, caption{ + -webkit-column-break-after:avoid; + page-break-after:avoid; + break-after:avoid; +} + +h1, h2, h3, h4, h5, h6, dt, +figure, tr{ + -webkit-column-break-inside:avoid; + page-break-inside:avoid; + break-inside:avoid; +} + +body{ + -webkit-hyphenate-character:"\002D"; + -moz-hyphenate-character:"\002D"; + -ms-hyphenate-character:"\002D"; + hyphenate-character:"\002D"; + -webkit-hyphenate-limit-lines:3; + -ms-hyphenate-limit-lines:3; + hyphenate-limit-lines:3; +} + +h1, h2, h3, h4, h5, h6, dt, +figcaption, pre, caption, address, +center, code, var{ + -ms-hyphens:none; + -moz-hyphens:none; + -webkit-hyphens:none; + -epub-hyphens:none; + hyphens:none; +} + +body{ + font-variant-numeric:oldstyle-nums proportional-nums; +} + +:lang(ja) body, +:lang(zh) body, +:lang(ko) body{ + font-variant-numeric:lining-nums proportional-nums; +} + +h1, h2, h3, h4, h5, h6, dt{ + font-variant-numeric:lining-nums proportional-nums; +} + +table{ + font-variant-numeric:lining-nums tabular-nums; +} + +code, var{ + font-variant-ligatures:none; + font-variant-numeric:lining-nums tabular-nums slashed-zero; +} + +rt{ + font-variant-east-asian:ruby; +} + +:lang(ar){ + font-variant-ligatures:common-ligatures; +} + +:lang(ko){ + font-kerning:normal; +} + +hr{ + color:inherit; + border-color:currentcolor; +} + +table, th, td{ + border-color:currentcolor; +} + +figure, blockquote{ + margin:1em 5%; +} + +ul, ol{ + padding-left:5%; +} + +dd{ + margin-left:5%; +} + +pre{ + white-space:pre-wrap; + -ms-tab-size:2; + -moz-tab-size:2; + -webkit-tab-size:2; + tab-size:2; +} + +abbr[title], acronym[title]{ + text-decoration:dotted underline; +} + +nobr wbr{ + white-space:normal; +} + +ruby > rt, ruby > rp{ + -webkit-user-select:none; + -moz-user-select:none; + -ms-user-select:none; + user-select:none; +} + +*:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)), +*:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)), +*:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)), +:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)) cite, +:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)) dfn, +:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)) em, +:lang(ja):not(:lang(ja-Latn)):not(:lang(ja-Cyrl)) i, +:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)) cite, +:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)) dfn, +:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)) em, +:lang(zh):not(:lang(zh-Latn)):not(:lang(zh-Cyrl)) i, +:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)) cite, +:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)) dfn, +:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)) em, +:lang(ko):not(:lang(ko-Latn)):not(:lang(ko-Cyrl)) i{ + font-style:normal; +} + +:lang(ja) a, +:lang(zh) a, +:lang(ko) a{ + text-decoration:none; +} + +:root{ + --RS__maxMediaWidth:100%; + --RS__maxMediaHeight:100vw; + --RS__boxSizingMedia:border-box; + --RS__boxSizingTable:border-box; +} + +a, h1, h2, h3, h4, h5, h6{ + word-wrap:break-word; +} + +div{ + max-width:var(--RS__maxMediaHeight); +} + +img, svg|svg, video{ + object-fit:contain; + + width:auto; + height:auto; + max-width:var(--RS__maxMediaHeight); + max-height:var(--RS__maxMediaWidth) !important; + box-sizing:var(--RS__boxSizingMedia); + -webkit-column-break-inside:avoid; + page-break-inside:avoid; + break-inside:avoid; +} + +audio{ + max-width:100%; + -webkit-column-break-inside:avoid; + page-break-inside:avoid; + break-inside:avoid; +} + +table{ + max-height:var(--RS__maxMediaWidth); + box-sizing:var(--RS__boxSizingTable) +} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-vertical/ReadiumCSS-default.css b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-vertical/ReadiumCSS-default.css new file mode 100644 index 0000000000..d9513f9fed --- /dev/null +++ b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/cjk-vertical/ReadiumCSS-default.css @@ -0,0 +1,173 @@ +/* + * Readium CSS (v. 2.0.0-alpha.5) + * Developers: Jiminy Panoz + * Copyright (c) 2017. Readium Foundation. All rights reserved. + * Use of this source code is governed by a BSD-style license which is detailed in the + * LICENSE file present in the project repository where this source code is maintained. +*/ + +@namespace url("http://www.w3.org/1999/xhtml"); + +@namespace epub url("http://www.idpf.org/2007/ops"); + +@namespace m url("http://www.w3.org/1998/Math/MathML"); + +@namespace svg url("http://www.w3.org/2000/svg"); + +:root{ + + --RS__compFontFamily:var(--RS__baseFontFamily); + --RS__codeFontFamily:var(--RS__monospaceTf); + + --RS__typeScale:1.125; + --RS__baseFontSize:87.5%; + + --RS__flowSpacing:1.5rem; + --RS__paraSpacing:0; + --RS__paraIndent:1em; + + --RS__linkColor:#0000EE; + --RS__visitedColor:#551A8B; + + --RS__primaryColor:; + --RS__secondaryColor:; +} + +:root:lang(zh){ + --RS__paraIndent:2em; +} + +:lang("mn-Mong"){ + --RS__baseFontSize:100%; +} + +body{ + font-size:var(--RS__baseFontSize); + text-align:justify; + text-justify:inter-character; +} + +h1, h2, h3, h4, h5, h6{ + font-family:var(--RS__baseFontFamily); + text-align:left; + text-align:start; +} + +blockquote, figure, p, pre, +aside, footer, form, hr{ + margin-right:var(--RS__flowSpacing); + margin-left:var(--RS__flowSpacing); +} + +p{ + margin-right:var(--RS__paraSpacing); + margin-left:var(--RS__paraSpacing); + text-indent:var(--RS__paraIndent); +} + +pre{ + font-family:var(--RS__codeFontFamily); +} + +code, kbd, samp, tt{ + font-family:var(--RS__codeFontFamily); +} + +sub, sup{ + position:relative; + font-size:67.5%; + line-height:1; +} + +sub{ + left:-0.2ex; +} + +sup{ + right:0; +} + +em{ + -webkit-text-emphasis:sesame; + -epub-text-emphasis:sesame; + text-emphasis:sesame; +} + +:link{ + color:var(--RS__linkColor); +} + +:visited{ + color:var(--RS__visitedColor); +} + +h1{ + margin-right:calc(var(--RS__flowSpacing) * 2); + margin-left:calc(var(--RS__flowSpacing) * 2); + font-size:calc(((1em * var(--RS__typeScale)) * var(--RS__typeScale)) * var(--RS__typeScale)); + text-indent:2rem; +} + +h2{ + margin-right:calc(var(--RS__flowSpacing) * 2); + margin-left:var(--RS__flowSpacing); + font-size:calc((1em * var(--RS__typeScale)) * var(--RS__typeScale)); + text-indent:3rem; +} + +h3{ + margin-right:var(--RS__flowSpacing); + margin-left:var(--RS__flowSpacing); + font-size:calc(1em * var(--RS__typeScale)); + text-indent:4rem; +} + +h4{ + margin-right:var(--RS__flowSpacing); + margin-left:var(--RS__flowSpacing); + font-family:var(--RS__compFontFamily); + font-size:1em; + text-indent:4rem; +} + +h5{ + margin-right:var(--RS__flowSpacing); + margin-left:var(--RS__flowSpacing); + font-family:var(--RS__compFontFamily); + font-size:smaller; + text-indent:4rem; +} + +h6{ + margin-right:var(--RS__flowSpacing); + margin-left:0; + font-family:var(--RS__compFontFamily); + font-size:smaller; + font-weight:normal; + text-indent:4rem; +} + +dl, ol, ul{ + margin-right:var(--RS__flowSpacing); + margin-left:var(--RS__flowSpacing); +} + +table{ + margin:0 var(--RS__flowSpacing); + border:1px solid currentcolor; + border-collapse:collapse; + empty-cells:show; +} + +thead, tbody, tfoot, table > tr{ + vertical-align:top; +} + +th{ + text-align:left; +} + +th, td{ + padding:4px; + border:1px solid currentcolor; +} \ No newline at end of file diff --git a/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/fonts/AccessibleDfA-Bold.woff2 b/readium/navigators/web/src/main/assets/readium/navigators/web/generated/readium-css/fonts/AccessibleDfA-Bold.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..781eecd96cbc04f03a25c257a42acad096c0c785 GIT binary patch literal 66864 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