buninu-browser 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSES/jsmdcui.txt +22 -0
- package/README.md +40 -4
- package/frontends/wayland/LICENSE-land +21 -0
- package/frontends/wayland/README.md +152 -0
- package/frontends/wayland/casty/LICENSE +21 -0
- package/frontends/wayland/casty/bookmarks.js +32 -0
- package/frontends/wayland/casty/click.js +96 -0
- package/frontends/wayland/casty/commands.js +61 -0
- package/frontends/wayland/casty/config.js +45 -0
- package/frontends/wayland/casty/download-directory.js +28 -0
- package/frontends/wayland/casty/download.js +49 -0
- package/frontends/wayland/casty/hints.js +334 -0
- package/frontends/wayland/casty/keys.js +56 -0
- package/frontends/wayland/casty/page-commands.js +80 -0
- package/frontends/wayland/casty/prompt-width.js +148 -0
- package/frontends/wayland/casty/urlbar.js +606 -0
- package/frontends/wayland/client.js +88 -0
- package/frontends/wayland/clipboard.js +80 -0
- package/frontends/wayland/index.js +130 -0
- package/frontends/wayland/input.js +75 -0
- package/frontends/wayland/protocol.js +55 -0
- package/frontends/wayland/protocols/wayland.xml +3248 -0
- package/frontends/wayland/protocols/xdg-shell.xml +1415 -0
- package/frontends/wayland/transport.js +120 -0
- package/frontends/wayland/urlbar.js +162 -0
- package/index.js +28 -1
- package/lib/audio/shared-connection.js +31 -0
- package/lib/cdp-server.js +15 -2
- package/lib/clipboard-command.js +10 -0
- package/lib/clipboard-powershell.js +22 -0
- package/lib/clipboard.js +37 -2
- package/lib/document-types.js +11 -0
- package/lib/headless-shell.js +54 -12
- package/lib/layout/text-layout.js +17 -9
- package/lib/paint/display-list.js +6 -1
- package/lib/qml/README.md +1427 -0
- package/lib/qml/builtins.js +771 -0
- package/lib/qml/canvas-dom.js +115 -0
- package/lib/qml/canvas.js +76 -0
- package/lib/qml/document.js +1199 -0
- package/lib/qml/fonts.js +69 -0
- package/lib/qml/format.js +9 -0
- package/lib/qml/host.js +352 -0
- package/lib/qml/images.js +199 -0
- package/lib/qml/launcher.js +132 -0
- package/lib/qml/loader.js +521 -0
- package/lib/qml/media-renderer.js +49 -0
- package/lib/qml/media.js +86 -0
- package/lib/qml/models.js +622 -0
- package/lib/qml/parser.js +381 -0
- package/lib/qml/qs +5 -0
- package/lib/qml/qscasty +3 -0
- package/lib/qml/qsheadless +3 -0
- package/lib/qml/qswayland +3 -0
- package/lib/qml/reactive.js +182 -0
- package/lib/qml/runtime.js +3603 -0
- package/lib/qml/shader/fragment.js +83 -0
- package/lib/qml/shader/qsb.js +27 -0
- package/lib/qml/shader/renderer.js +39 -0
- package/lib/qml/shader/runtime.js +61 -0
- package/lib/qml/shapes.js +251 -0
- package/lib/qml/shortcuts.js +65 -0
- package/lib/qml/text.js +109 -0
- package/lib/qml/textures.js +126 -0
- package/lib/qml/wayland-clipboard.js +32 -0
- package/lib/qml/window-constraints.js +16 -0
- package/lib/qml/worker-thread.js +70 -0
- package/lib/render-tree/index.js +16 -1
- package/lib/renderer/bindings.js +16 -1
- package/lib/renderer/canvas-2d.js +29 -0
- package/lib/renderer/document-selection.js +19 -0
- package/lib/renderer/host.js +45 -17
- package/lib/renderer/main.js +21 -6
- package/lib/renderer/page-realm.js +20 -10
- package/lib/renderer/page-renderer.js +497 -42
- package/lib/renderer/pointer-move.js +5 -3
- package/lib/renderer/render-interval.js +9 -0
- package/lib/renderer/text-input-paint.js +54 -0
- package/lib/renderer/text-input.js +57 -0
- package/lib/style/computed-style.js +10 -4
- package/package.json +1 -1
- package/test/audio-connection-lifetime.test.js +46 -0
- package/test/canvas-paint.test.js +8 -0
- package/test/clipboard.test.js +19 -0
- package/test/computed-style.test.js +12 -0
- package/test/document-selection.test.js +27 -0
- package/test/double-click.test.js +85 -0
- package/test/fixtures/canvas-damage.js +40 -0
- package/test/fixtures/fake-renderer.js +1 -0
- package/test/fixtures/flea-helpers/Dockerfile +36 -0
- package/test/fixtures/flea-helpers/bat.mjs +43 -0
- package/test/fixtures/flea-helpers/bin/bat +3 -0
- package/test/fixtures/flea-helpers/bin/bwrap +10 -0
- package/test/fixtures/flea-helpers/bin/bwrap-real-filter +9 -0
- package/test/fixtures/flea-helpers/bin/glow +3 -0
- package/test/fixtures/flea-helpers/bin/qs +3 -0
- package/test/fixtures/flea-helpers/bin/unsupported +3 -0
- package/test/fixtures/flea-helpers/check-highlighting.mjs +47 -0
- package/test/fixtures/flea-helpers/check-media.mjs +29 -0
- package/test/fixtures/flea-helpers/check-preview.mjs +27 -0
- package/test/fixtures/flea-helpers/check.mjs +36 -0
- package/test/fixtures/flea-helpers/highlight-cases.json +227 -0
- package/test/fixtures/flea-helpers/source-mime.xml +28 -0
- package/test/fixtures/flea-helpers/syntax-compat.mjs +23 -0
- package/test/fixtures/flea-thumbnail-stub/flea-placeholder.thumbnailer +4 -0
- package/test/fixtures/flea-thumbnail-stub/flea-thumbnail-stub +3 -0
- package/test/fixtures/omastorm-helpers/Dockerfile +35 -0
- package/test/fixtures/omastorm-helpers/check.mjs +56 -0
- package/test/fixtures/omastorm-helpers/launch.mjs +24 -0
- package/test/fixtures/omastorm-helpers/prepare.mjs +17 -0
- package/test/fixtures/omastorm-helpers/runtime.mjs +32 -0
- package/test/fixtures/pointer-paint-batching.js +23 -0
- package/test/fixtures/qml/flea/EscapeHint.qml +11 -0
- package/test/fixtures/qml/flea/LICENSE +21 -0
- package/test/fixtures/qml/flea/README.md +25 -0
- package/test/fixtures/qml/flea/Theme.qml +8 -0
- package/test/fixtures/qml/flea/demo.qml +24 -0
- package/test/fixtures/qml/flea/qmldir +3 -0
- package/test/fixtures/qml/flea-theme/LICENSE-Flea +21 -0
- package/test/fixtures/qml/flea-theme/LICENSE-Omarchy +20 -0
- package/test/fixtures/qml/flea-theme/README.md +70 -0
- package/test/fixtures/qml/flea-theme/button.qml +17 -0
- package/test/fixtures/qml/flea-theme/demo.qml +27 -0
- package/test/fixtures/qml/flea-theme/field.qml +21 -0
- package/test/fixtures/qml/flea-theme/imports/qs/Commons/BorderGeometry.js +373 -0
- package/test/fixtures/qml/flea-theme/imports/qs/Commons/Color.qml +258 -0
- package/test/fixtures/qml/flea-theme/imports/qs/Commons/I18n.qml +118 -0
- package/test/fixtures/qml/flea-theme/imports/qs/Commons/Numbers.js +19 -0
- package/test/fixtures/qml/flea-theme/imports/qs/Commons/Plural.js +91 -0
- package/test/fixtures/qml/flea-theme/imports/qs/Commons/Style.qml +561 -0
- package/test/fixtures/qml/flea-theme/imports/qs/Commons/Util.qml +188 -0
- package/test/fixtures/qml/flea-theme/imports/qs/Commons/qmldir +13 -0
- package/test/fixtures/qml/flea-theme/segment.qml +17 -0
- package/test/fixtures/qml/flea-theme/settings.qml +58 -0
- package/test/fixtures/qml/flea-theme/text-metrics.qml +10 -0
- package/test/fixtures/qml/flea-theme/ui/DialogButton.qml +150 -0
- package/test/fixtures/qml/flea-theme/ui/DialogField.qml +147 -0
- package/test/fixtures/qml/flea-theme/ui/EscapeHint.qml +11 -0
- package/test/fixtures/qml/flea-theme/ui/Glass.qml +114 -0
- package/test/fixtures/qml/flea-theme/ui/Glyph.qml +54 -0
- package/test/fixtures/qml/flea-theme/ui/GlyphSolid.qml +22 -0
- package/test/fixtures/qml/flea-theme/ui/Reveal.qml +54 -0
- package/test/fixtures/qml/flea-theme/ui/SettingsRuler.qml +85 -0
- package/test/fixtures/qml/flea-theme/ui/SettingsSegment.qml +85 -0
- package/test/fixtures/qml/flea-theme/ui/StableModel.qml +89 -0
- package/test/fixtures/qml/flea-theme/ui/Theme.qml +460 -0
- package/test/fixtures/qml/flea-theme/ui/ThemeColors.qml +43 -0
- package/test/fixtures/qml/flea-theme/ui/ViewState.qml +565 -0
- package/test/fixtures/qml/flea-theme/ui/js/Anchor.js +379 -0
- package/test/fixtures/qml/flea-theme/ui/js/AnchorHold.js +162 -0
- package/test/fixtures/qml/flea-theme/ui/js/Archive.js +157 -0
- package/test/fixtures/qml/flea-theme/ui/js/BackReturn.js +110 -0
- package/test/fixtures/qml/flea-theme/ui/js/Buttons.js +54 -0
- package/test/fixtures/qml/flea-theme/ui/js/ColumnMenu.js +111 -0
- package/test/fixtures/qml/flea-theme/ui/js/Columns.js +298 -0
- package/test/fixtures/qml/flea-theme/ui/js/Contrast.js +157 -0
- package/test/fixtures/qml/flea-theme/ui/js/Density.js +44 -0
- package/test/fixtures/qml/flea-theme/ui/js/DirSizes.js +129 -0
- package/test/fixtures/qml/flea-theme/ui/js/ExtThumbs.js +115 -0
- package/test/fixtures/qml/flea-theme/ui/js/Filter.js +284 -0
- package/test/fixtures/qml/flea-theme/ui/js/FolderSorts.js +108 -0
- package/test/fixtures/qml/flea-theme/ui/js/Format.js +305 -0
- package/test/fixtures/qml/flea-theme/ui/js/Icons.js +206 -0
- package/test/fixtures/qml/flea-theme/ui/js/Input.js +39 -0
- package/test/fixtures/qml/flea-theme/ui/js/KeyName.js +64 -0
- package/test/fixtures/qml/flea-theme/ui/js/Keymap.js +370 -0
- package/test/fixtures/qml/flea-theme/ui/js/Kinds.js +145 -0
- package/test/fixtures/qml/flea-theme/ui/js/Lists.js +11 -0
- package/test/fixtures/qml/flea-theme/ui/js/MakeDefault.js +186 -0
- package/test/fixtures/qml/flea-theme/ui/js/Match.js +27 -0
- package/test/fixtures/qml/flea-theme/ui/js/Material.js +109 -0
- package/test/fixtures/qml/flea-theme/ui/js/Menu.js +513 -0
- package/test/fixtures/qml/flea-theme/ui/js/Motion.js +16 -0
- package/test/fixtures/qml/flea-theme/ui/js/Mounts.js +320 -0
- package/test/fixtures/qml/flea-theme/ui/js/MouseNav.js +13 -0
- package/test/fixtures/qml/flea-theme/ui/js/Nav.js +328 -0
- package/test/fixtures/qml/flea-theme/ui/js/Palette.js +33 -0
- package/test/fixtures/qml/flea-theme/ui/js/Places.js +236 -0
- package/test/fixtures/qml/flea-theme/ui/js/Protocols.js +296 -0
- package/test/fixtures/qml/flea-theme/ui/js/RecentMode.js +154 -0
- package/test/fixtures/qml/flea-theme/ui/js/Search.js +396 -0
- package/test/fixtures/qml/flea-theme/ui/js/Settings.js +476 -0
- package/test/fixtures/qml/flea-theme/ui/js/SettingsAbout.js +99 -0
- package/test/fixtures/qml/flea-theme/ui/js/SettingsShelf.js +52 -0
- package/test/fixtures/qml/flea-theme/ui/js/Sort.js +127 -0
- package/test/fixtures/qml/flea-theme/ui/js/StateWords.js +42 -0
- package/test/fixtures/qml/flea-theme/ui/js/Swap.js +166 -0
- package/test/fixtures/qml/flea-theme/ui/js/TextSize.js +107 -0
- package/test/fixtures/qml/flea-theme/ui/js/Thumbs.js +158 -0
- package/test/fixtures/qml/flea-theme/ui/js/UiState.js +438 -0
- package/test/fixtures/qml/flea-theme/ui/js/Update.js +132 -0
- package/test/fixtures/qml/flea-theme/ui/js/UserDirs.js +56 -0
- package/test/fixtures/qml/flea-theme/ui/qmldir +227 -0
- package/test/fixtures/qml/hello.qml +26 -0
- package/test/fixtures/qml/imports/Demo/Toolkit/VersionLabel.qml +2 -0
- package/test/fixtures/qml/imports/Demo/Toolkit/VersionLabelNew.qml +2 -0
- package/test/fixtures/qml/imports/Demo/Toolkit/qmldir +3 -0
- package/test/fixtures/qml/imports/components/Badge.qml +15 -0
- package/test/fixtures/qml/imports/logic/base.js +2 -0
- package/test/fixtures/qml/imports/logic/counter.js +4 -0
- package/test/fixtures/qml/imports/logic/math.js +3 -0
- package/test/fixtures/qml/imports/logic/shared.js +3 -0
- package/test/fixtures/qml/imports/main.qml +21 -0
- package/test/fixtures/qml/imports/theme/Theme.qml +8 -0
- package/test/fixtures/qml/imports/theme/qmldir +2 -0
- package/test/fixtures/qml/multiply.qml +61 -0
- package/test/fixtures/qml-canvas-dom.js +90 -0
- package/test/fixtures/qml-fonts/main.qml +10 -0
- package/test/fixtures/qml-locale/check.mjs +6 -0
- package/test/fixtures/qml-locale/main.qml +8 -0
- package/test/fixtures/qml-media-audio.js +39 -0
- package/test/fixtures/qml-shader/grab.qml +14 -0
- package/test/fixtures/qml-shader/gradient.frag +5 -0
- package/test/fixtures/qml-shader/main.qml +14 -0
- package/test/fixtures/qml-shader/texture-grab.qml +25 -0
- package/test/fixtures/qml-shader/texture-size.frag +5 -0
- package/test/fixtures/qml-shader-check.mjs +24 -0
- package/test/fixtures/title-no-paint.js +20 -0
- package/test/helpers/flea-sandbox.js +48 -0
- package/test/helpers/quickshell-fixture.js +125 -0
- package/test/html-clipboard-wayland.test.js +47 -0
- package/test/index.test.js +13 -0
- package/test/manual-casty-without-qml.js +87 -0
- package/test/manual-double-click.html +21 -0
- package/test/manual-flea-application.js +49 -0
- package/test/manual-flea-binary.js +62 -0
- package/test/manual-flea-qml.js +9 -0
- package/test/manual-flea-settings.js +40 -0
- package/test/manual-flea-theme.js +40 -0
- package/test/manual-mouse-buttons.html +18 -0
- package/test/manual-omastorm-engine.mjs +19 -0
- package/test/manual-omastorm-shaders.mjs +28 -0
- package/test/manual-omastorm-software.mjs +25 -0
- package/test/manual-pointer-scroll.html +43 -0
- package/test/manual-qml-removal.js +46 -0
- package/test/manual-without-qml.js +45 -0
- package/test/pointer-drag.test.js +104 -0
- package/test/qml-canvas-dom.test.js +37 -0
- package/test/qml-canvas.test.js +21 -0
- package/test/qml-clipboard-bridge.test.js +25 -0
- package/test/qml-clipboard-wayland.test.js +40 -0
- package/test/qml-connections-timing.test.js +95 -0
- package/test/qml-controls-window.test.js +182 -0
- package/test/qml-dynamic.test.js +401 -0
- package/test/qml-flea-app.test.js +146 -0
- package/test/qml-flea-backend.test.js +78 -0
- package/test/qml-flea-columns-backend.test.js +38 -0
- package/test/qml-flea-compile.test.js +78 -0
- package/test/qml-flea-launcher.test.js +88 -0
- package/test/qml-flea-markdown-backend.test.js +31 -0
- package/test/qml-flea-media.test.js +28 -0
- package/test/qml-flea-navigation-backend.test.js +35 -0
- package/test/qml-flea-navigation-timing.test.js +147 -0
- package/test/qml-flea-preview-backend.test.js +53 -0
- package/test/qml-flea-previews.test.js +163 -0
- package/test/qml-flea-rows.test.js +101 -0
- package/test/qml-flea-textures.test.js +59 -0
- package/test/qml-flea-view-switch.test.js +33 -0
- package/test/qml-flea-wayland.test.js +68 -0
- package/test/qml-flea.test.js +34 -0
- package/test/qml-fonts.test.js +31 -0
- package/test/qml-grid-multiline.test.js +48 -0
- package/test/qml-host.test.js +238 -0
- package/test/qml-imports.test.js +102 -0
- package/test/qml-inherited-handlers.test.js +51 -0
- package/test/qml-input-selection.test.js +66 -0
- package/test/qml-interactions.test.js +309 -0
- package/test/qml-language.test.js +167 -0
- package/test/qml-launcher.test.js +54 -0
- package/test/qml-layout-text.test.js +205 -0
- package/test/qml-locale.test.js +45 -0
- package/test/qml-media.test.js +63 -0
- package/test/qml-nonvisual-visible.test.js +19 -0
- package/test/qml-persisted-delegates.test.js +45 -0
- package/test/qml-quickshell-controls.test.js +65 -0
- package/test/qml-quickshell-settings.test.js +62 -0
- package/test/qml-repeater.test.js +72 -0
- package/test/qml-shader-runtime.test.js +6 -0
- package/test/qml-shortcuts.test.js +39 -0
- package/test/qml-socket.test.js +60 -0
- package/test/qml-software-shader.test.js +55 -0
- package/test/qml-style-updates.test.js +124 -0
- package/test/qml-textures.test.js +66 -0
- package/test/qml-views.test.js +332 -0
- package/test/qml-window-update.test.js +36 -0
- package/test/qml-worker.test.js +69 -0
- package/test/qml.test.js +83 -0
- package/test/render-interval.test.js +33 -0
- package/test/renderer-host.test.js +11 -0
- package/test/text-input-pointer.test.js +31 -0
- package/test/text-input-scroll.test.js +29 -0
- package/test/text-input.test.js +47 -0
- package/test/title-no-paint.test.js +6 -0
- package/test/wayland-frontend.test.js +83 -0
- package/test/wayland-scroll.test.js +40 -0
- package/test/wayland-urlbar.test.js +61 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
.pragma library
|
|
2
|
+
|
|
3
|
+
.import "Archive.js" as Archive
|
|
4
|
+
.import "Format.js" as Format
|
|
5
|
+
|
|
6
|
+
// How a row is classified: which of the twelve preview states it is, and the extension families that
|
|
7
|
+
// decide the three the backend's icon cannot. Split out of Facts.js, which owns the fact tables.
|
|
8
|
+
|
|
9
|
+
var IMAGE = "image"
|
|
10
|
+
var VIDEO = "video"
|
|
11
|
+
var AUDIO = "audio"
|
|
12
|
+
var PDF = "pdf"
|
|
13
|
+
var TEXT = "text"
|
|
14
|
+
var CODE = "code"
|
|
15
|
+
var ARCHIVE = "archive"
|
|
16
|
+
var SYMLINK = "symlink"
|
|
17
|
+
var MULTI = "multi"
|
|
18
|
+
var LOADING = "loading"
|
|
19
|
+
var ERROR = "error"
|
|
20
|
+
var UNSUPPORTED = "unsupported"
|
|
21
|
+
var FONT = "font"
|
|
22
|
+
|
|
23
|
+
// src/backend/rows.rs's own UNKNOWN_KIND: the Kind a row gets when nothing could describe its type.
|
|
24
|
+
var UNKNOWN_KIND = "Data"
|
|
25
|
+
|
|
26
|
+
var CODE_EXTENSIONS = [
|
|
27
|
+
".rs", ".py", ".js", ".ts", ".jsx", ".tsx", ".c", ".h", ".cpp", ".hpp", ".cc", ".go", ".rb",
|
|
28
|
+
".java", ".kt", ".swift", ".lua", ".pl", ".php", ".sh", ".bash", ".zsh", ".fish", ".vim",
|
|
29
|
+
".qml", ".css", ".scss", ".html", ".xml", ".json", ".toml", ".yaml", ".yml", ".ini", ".conf",
|
|
30
|
+
".sql", ".mjs", ".cjs"
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
function isCode(name) {
|
|
34
|
+
var lower = String(name).toLowerCase()
|
|
35
|
+
for (var i = 0; i < CODE_EXTENSIONS.length; i++) {
|
|
36
|
+
var e = CODE_EXTENSIONS[i]
|
|
37
|
+
if (lower.length > e.length && lower.indexOf(e, lower.length - e.length) !== -1) {
|
|
38
|
+
return true
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return false
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
var MARKDOWN_EXTENSIONS = [".md", ".markdown", ".mkd"]
|
|
45
|
+
|
|
46
|
+
function isMarkdown(name) {
|
|
47
|
+
var lower = String(name).toLowerCase()
|
|
48
|
+
for (var i = 0; i < MARKDOWN_EXTENSIONS.length; i++) {
|
|
49
|
+
var e = MARKDOWN_EXTENSIONS[i]
|
|
50
|
+
if (lower.length > e.length && lower.indexOf(e, lower.length - e.length) !== -1) {
|
|
51
|
+
return true
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return false
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function isHtml(name) { return /\.(html|htm)$/i.test(String(name)) }
|
|
58
|
+
|
|
59
|
+
// TrueType, OpenType and collections (font/ttf, font/otf, font/collection); the backend checks the MIME type again.
|
|
60
|
+
var FONT_EXTENSIONS = [".ttf", ".otf", ".ttc"]
|
|
61
|
+
|
|
62
|
+
function isFont(name) {
|
|
63
|
+
var lower = String(name).toLowerCase()
|
|
64
|
+
return FONT_EXTENSIONS.some(function (e) { return lower.length > e.length && lower.indexOf(e, lower.length - e.length) !== -1 })
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Quick Look's font sample: one sentence at three sizes, in board pixels before the text-size ratio and the pixel ratio.
|
|
68
|
+
var SAMPLE_TEXT = "The quick brown fox jumps over the lazy dog"
|
|
69
|
+
var SAMPLE_SIZES = [22, 15, 12]
|
|
70
|
+
|
|
71
|
+
// One count for every font pane, so an answer meant for an earlier pane never carries a later pane's id.
|
|
72
|
+
var lookSeq = 0
|
|
73
|
+
function nextLookId() { lookSeq += 1; return lookSeq }
|
|
74
|
+
|
|
75
|
+
// "Inter · Bold · 312.0 kB · 2,548 glyphs"; a table the font lacks drops its part, and the size is always known.
|
|
76
|
+
// pluralWord is Ops.pluralWord, handed in because Ops reaches Sort.js and RecentMode.js, which import this file.
|
|
77
|
+
function fontLine(family, style, bytes, glyphs, pluralWord) {
|
|
78
|
+
var parts = [family, style, Format.size(bytes)].filter(function (p) { return p })
|
|
79
|
+
if (glyphs > 0)
|
|
80
|
+
parts.push(pluralWord(glyphs, "%1 glyph", "%1 glyphs").replace("%1", Format.count(glyphs)))
|
|
81
|
+
return parts.join(" \u00b7 ")
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// The eleven camera RAW types the backend copies a preview out of, told apart by extension like a PDF; Sample input: "IMG_0412.CR3" is true.
|
|
85
|
+
function isRaw(name) {
|
|
86
|
+
return /\.(cr[23]|nef|nrw|arw|sr2|dng|raf|orf|rw2|pef)$/i.test(String(name))
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function isPdf(name) {
|
|
90
|
+
var lower = String(name).toLowerCase()
|
|
91
|
+
return lower.length > 4 && lower.indexOf(".pdf", lower.length - 4) !== -1
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// The MIME icon table files 3D models under image-x-generic, so they route as images, but no Qt image plugin decodes one.
|
|
95
|
+
function isModel(name) {
|
|
96
|
+
return /\.(stl|3mf|obj|mtl|gltf|glb)$/i.test(String(name))
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// The icon name is the classification the backend already made, so the column never re-derives one.
|
|
100
|
+
// Its first segment is the freedesktop family, and the family is what classifies: this box's
|
|
101
|
+
// generic-icons table maps text/* to five different text- names, and a list of the names seen so
|
|
102
|
+
// far is exactly how the Quick Look refused every image for as long as it kept one.
|
|
103
|
+
function kindState(icon) {
|
|
104
|
+
var name = String(icon)
|
|
105
|
+
switch (name) {
|
|
106
|
+
case "text-x-script":
|
|
107
|
+
case "text-html":
|
|
108
|
+
case "application-xml": return CODE
|
|
109
|
+
case "package-x-generic": return ARCHIVE
|
|
110
|
+
}
|
|
111
|
+
if (name.indexOf("image-") === 0) return IMAGE
|
|
112
|
+
if (name.indexOf("video-") === 0) return VIDEO
|
|
113
|
+
if (name.indexOf("audio-") === 0) return AUDIO
|
|
114
|
+
if (name.indexOf("text-") === 0) return TEXT
|
|
115
|
+
// A .doc or .odt shares the office icon with a PDF, and a PDF was already told apart by its
|
|
116
|
+
// extension. What is left is binary, so it is Unsupported rather than a newline count over a blob.
|
|
117
|
+
return UNSUPPORTED
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// A directory is not a preview subject: the column shows what is inside it instead.
|
|
121
|
+
function isPreviewable(row) {
|
|
122
|
+
return row !== null && row !== undefined && row.d !== true
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// A name the icon cannot route, told apart by its own extension: a PDF shares x-office-document, and widened archives draw other marks.
|
|
126
|
+
function stateByExtension(name) {
|
|
127
|
+
if (isPdf(name)) return PDF
|
|
128
|
+
if (Archive.isArchive(name)) return ARCHIVE
|
|
129
|
+
if (/\.(csv|tsv)$/i.test(String(name))) return TEXT
|
|
130
|
+
return ""
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Quick Look's kind from the icon, the name and a served thumbnail, Facts.state's row-free tests; code and markdown read as text.
|
|
134
|
+
function quickLookKind(icon, name, thumbnailed) {
|
|
135
|
+
if (isPdf(name)) return PDF
|
|
136
|
+
if (isFont(name)) return FONT
|
|
137
|
+
if (isMarkdown(name)) return TEXT
|
|
138
|
+
if (/\.(csv|tsv)$/i.test(String(name))) return TEXT
|
|
139
|
+
// The client's own extension rule, because the backend's icon cannot name the widened formats.
|
|
140
|
+
if (Archive.isArchive(name)) return ARCHIVE
|
|
141
|
+
var byIcon = kindState(icon)
|
|
142
|
+
// A model no thumbnailer serves has nothing to draw, so it takes the generic file pane.
|
|
143
|
+
if (byIcon === IMAGE && isModel(name) && !thumbnailed) return UNSUPPORTED
|
|
144
|
+
return byIcon === CODE ? TEXT : byIcon
|
|
145
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
.pragma library
|
|
2
|
+
|
|
3
|
+
// The largest length an ECMAScript array can hold, 2^32 - 1.
|
|
4
|
+
var MAX_LENGTH = 4294967295
|
|
5
|
+
|
|
6
|
+
// QVariant sequences crossing a QML var signal expose list methods without being JavaScript Arrays.
|
|
7
|
+
function isList(value) {
|
|
8
|
+
return Array.isArray(value) || (value !== null && typeof value === "object"
|
|
9
|
+
&& Number.isInteger(value.length) && value.length >= 0 && value.length <= MAX_LENGTH
|
|
10
|
+
&& typeof value.every === "function")
|
|
11
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
.pragma library
|
|
2
|
+
|
|
3
|
+
// Settings > About's Make Flea the default: which state the row is in, the note under it and what a press runs; ui/DefaultClaim.qml runs the processes.
|
|
4
|
+
|
|
5
|
+
.import "Format.js" as Format
|
|
6
|
+
|
|
7
|
+
// Whole sentences with "%1" for the program that never started, its name and not its command line.
|
|
8
|
+
var WORDS = {
|
|
9
|
+
unstarted: "%1 could not start"
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// The row's id, which ui/SettingsPanel.qml routes to the run instead of writing it into ui.json.
|
|
13
|
+
var ROW_ID = "makeDefault"
|
|
14
|
+
// The entry flea --default points the desktop at; the box is ticked exactly when xdg-mime answers it.
|
|
15
|
+
var DESKTOP_ID = "com.thisisgm.flea.desktop"
|
|
16
|
+
// src/main.rs claim_both() says this and still exits 0 when a build has no flea.portal to route file dialogs to.
|
|
17
|
+
var SKIPPED = "no file chooser service is installed, so Flea could not become the file chooser"
|
|
18
|
+
// src/defaults.rs EXIT_UNINSTALLED: the status claim() exits with when the running binary has no desktop entry to point at.
|
|
19
|
+
var UNINSTALLED_STATUS = 3
|
|
20
|
+
// The portal reads its routing once, at startup; try-restart leaves a portal that is not running alone.
|
|
21
|
+
var RESTART = ["systemctl", "--user", "try-restart", "xdg-desktop-portal.service"]
|
|
22
|
+
// flea's own stderr lines start with its name, which the note drops.
|
|
23
|
+
var OWN_PREFIX = "flea: "
|
|
24
|
+
|
|
25
|
+
// Nothing run in this process yet; an entry is assumed until the probe or a refusal says otherwise.
|
|
26
|
+
function idle() {
|
|
27
|
+
return { running: false, claiming: false, reading: false, readFrom: 0, restarting: false, outcome: "", error: "", packaged: true }
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// A run in flight, or a build with no entry, takes no press.
|
|
31
|
+
function inert(claim) {
|
|
32
|
+
return claim.running || claim.packaged === false
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// flea's arguments for a press, or null while the row is inert.
|
|
36
|
+
function press(handler, claim) {
|
|
37
|
+
if (inert(claim))
|
|
38
|
+
return null
|
|
39
|
+
return handler === DESKTOP_ID ? ["--default", "off"] : ["--default"]
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// A new run drops the last one's outcome; which way it goes picks the working note.
|
|
43
|
+
function started(claim, args) {
|
|
44
|
+
return { running: true, claiming: args.length === 1, reading: false, readFrom: 0, restarting: false, outcome: "", error: "",
|
|
45
|
+
packaged: claim.packaged }
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Still running until a handler read numbered nextRead or later lands and a switch that went through has restarted the portal.
|
|
49
|
+
// Sample stderr: "flea: no file chooser service is installed, so Flea could not become the file chooser\n"
|
|
50
|
+
function finished(claim, code, stderr, nextRead) {
|
|
51
|
+
var text = stderr || ""
|
|
52
|
+
var next = Object.assign({}, claim, { reading: true, readFrom: nextRead, restarting: code === 0 })
|
|
53
|
+
if (code === 0) {
|
|
54
|
+
next.outcome = text.indexOf(SKIPPED) >= 0 ? "partly" : ""
|
|
55
|
+
return next
|
|
56
|
+
}
|
|
57
|
+
if (code === UNINSTALLED_STATUS) {
|
|
58
|
+
next.packaged = false
|
|
59
|
+
return next
|
|
60
|
+
}
|
|
61
|
+
next.outcome = "failed"
|
|
62
|
+
next.error = errorLine(text, code, claim.claiming)
|
|
63
|
+
return next
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// xdg-mime's stderr reaches flea's own, so flea's line is the one that starts with its name.
|
|
67
|
+
// Sample stderr: "xdg-mime: no method available\nflea: xdg-mime default exited 3\n"
|
|
68
|
+
function errorLine(stderr, code, claiming) {
|
|
69
|
+
var lines = stderr.split("\n").map(function (line) { return line.trim() })
|
|
70
|
+
var own = lines.filter(function (line) { return line.indexOf(OWN_PREFIX) === 0 })[0]
|
|
71
|
+
if (own !== undefined)
|
|
72
|
+
return own.substring(OWN_PREFIX.length)
|
|
73
|
+
var first = lines.filter(function (line) { return line.length > 0 })[0]
|
|
74
|
+
return first !== undefined ? first : (claiming ? "flea --default" : "flea --default off") + " exited " + code
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// The handler read numbered read has landed; only one begun after the run exited ends it, and only once the portal restart has answered too.
|
|
78
|
+
function settled(claim, read) {
|
|
79
|
+
if (!claim.reading || read < claim.readFrom)
|
|
80
|
+
return claim
|
|
81
|
+
return Object.assign({}, claim, { reading: false, running: claim.restarting })
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// A Process's exit and its collector's text land in either order (AGENTS.md "The state file"), so an answer is read once it holds both.
|
|
85
|
+
// Sample: landed(landed({}, { code: 0 }), { text: "com.thisisgm.flea.desktop\n" }) is { code: 0, text: "com.thisisgm.flea.desktop\n" }
|
|
86
|
+
function landed(answer, half) {
|
|
87
|
+
return Object.assign({}, answer, half)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// An empty text is an answer too: a run that says nothing has still finished saying it.
|
|
91
|
+
function whole(answer) {
|
|
92
|
+
return answer.code !== undefined && answer.text !== undefined
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// The whole answer a program that never started is given: no real exit status is negative.
|
|
96
|
+
var NEVER_RAN = { code: -1, text: "" }
|
|
97
|
+
|
|
98
|
+
// ui/ViewState.qml's writer rule, measured on Quickshell 0.3.1: a program that cannot start raises no exited, only running going false, and a real exit lands its status before that false.
|
|
99
|
+
function neverRan(answer, running) {
|
|
100
|
+
return !running && answer.code === undefined
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// The handler an answer states; any other status, a read that never ran among them, states none, which About shows as Not reported.
|
|
104
|
+
function handlerOf(answer) {
|
|
105
|
+
return answer.code === 0 ? answer.text.trim() : ""
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// A run whose program never started wrote nothing, so it is over at once, failed, naming what could not start.
|
|
109
|
+
// Sample command: ["/usr/bin/flea", "--default"]
|
|
110
|
+
function unstarted(claim, command) {
|
|
111
|
+
return Object.assign({}, claim, { running: false, reading: false, restarting: false, outcome: "failed",
|
|
112
|
+
error: Format.fill(WORDS.unstarted, String(command[0]).split("/").pop()) })
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// A portal that would not restart keeps the switch as it went; partly keeps its own note, whose dialogs never follow.
|
|
116
|
+
function restarted(claim, ok) {
|
|
117
|
+
var outcome = !ok && claim.outcome === "" ? "portal" : claim.outcome
|
|
118
|
+
return Object.assign({}, claim, { restarting: false, running: claim.reading, outcome: outcome })
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// restarted() clears restarting on a real exit before running goes false, so a stop that finds it still set is a systemctl that never ran.
|
|
122
|
+
function restartStopped(claim, running) {
|
|
123
|
+
return !running && claim.restarting ? restarted(claim, false) : claim
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function probed(claim, found) {
|
|
127
|
+
return Object.assign({}, claim, { packaged: found })
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// One of off, on, working, partly, portal, failed, unpackaged.
|
|
131
|
+
function state(handler, claim) {
|
|
132
|
+
if (claim.packaged === false)
|
|
133
|
+
return "unpackaged"
|
|
134
|
+
if (claim.running)
|
|
135
|
+
return "working"
|
|
136
|
+
if (claim.outcome === "failed")
|
|
137
|
+
return "failed"
|
|
138
|
+
if (handler === DESKTOP_ID && claim.outcome === "partly")
|
|
139
|
+
return "partly"
|
|
140
|
+
if (claim.outcome === "portal")
|
|
141
|
+
return "portal"
|
|
142
|
+
return handler === DESKTOP_ID ? "on" : "off"
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// [words, role] for the one line under the row, or null when off says nothing.
|
|
146
|
+
function note(handler, claim) {
|
|
147
|
+
var now = state(handler, claim)
|
|
148
|
+
if (now === "on")
|
|
149
|
+
return ["Folders, Show in folder and file dialogs open Flea.", "foreground"]
|
|
150
|
+
if (now === "working")
|
|
151
|
+
return [claim.claiming ? "Making Flea the default" : "Handing folders back", "muted"]
|
|
152
|
+
if (now === "partly")
|
|
153
|
+
return ["File dialogs need the flea package's portal files.", "foreground"]
|
|
154
|
+
if (now === "portal")
|
|
155
|
+
return ["File dialogs follow after xdg-desktop-portal restarts.", "foreground"]
|
|
156
|
+
if (now === "failed")
|
|
157
|
+
return [claim.error, "error"]
|
|
158
|
+
if (now === "unpackaged")
|
|
159
|
+
return ["Install a Flea package to make it the default.", "foreground"]
|
|
160
|
+
return null
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// The check row and its note for About's This box group; the note elides on one line rather than wrapping.
|
|
164
|
+
function rows(handler, claim) {
|
|
165
|
+
var live = claim || idle()
|
|
166
|
+
var out = [{ kind: "check", id: ROW_ID, label: "Make Flea the default", on: handler === DESKTOP_ID, inert: inert(live) }]
|
|
167
|
+
var line = note(handler, live)
|
|
168
|
+
if (line !== null)
|
|
169
|
+
out.push({ kind: "hint", label: line[0], role: line[1], elide: "right" })
|
|
170
|
+
return out
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// src/userfile.rs data_file()'s ladder: the data home, then every data dir, an empty variable read as unset.
|
|
174
|
+
// Sample env: { HOME: "/home/gm", XDG_DATA_HOME: "", XDG_DATA_DIRS: "/usr/local/share:/usr/share" }
|
|
175
|
+
function entryPaths(env) {
|
|
176
|
+
var home = env.XDG_DATA_HOME || (env.HOME ? env.HOME + "/.local/share" : "")
|
|
177
|
+
var dirs = (env.XDG_DATA_DIRS || "/usr/local/share:/usr/share").split(":")
|
|
178
|
+
return [home].concat(dirs)
|
|
179
|
+
.filter(function (dir) { return dir.length > 0 })
|
|
180
|
+
.map(function (dir) { return dir + "/applications/" + DESKTOP_ID })
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// data_file()'s regular-file test; each path is an argument, so no path reaches the shell as code.
|
|
184
|
+
function probeCommand(paths) {
|
|
185
|
+
return ["sh", "-c", "for f; do [ -f \"$f\" ] && exit 0; done; exit 1", "sh"].concat(paths)
|
|
186
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
.pragma library
|
|
2
|
+
|
|
3
|
+
// A search row's name is its path relative to the search root, so the display splits it here and
|
|
4
|
+
// the wire never carries a second shape; see docs/protocol.md "search".
|
|
5
|
+
function base(path) {
|
|
6
|
+
var i = String(path).lastIndexOf("/")
|
|
7
|
+
return i < 0 ? String(path) : String(path).substring(i + 1)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// The location column: the parent path relative to the scope, empty for a match in the root itself.
|
|
11
|
+
function location(path) {
|
|
12
|
+
var i = String(path).lastIndexOf("/")
|
|
13
|
+
return i < 0 ? "" : String(path).substring(0, i)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Where to paint the accent run inside a name, mirroring the backend's own case-insensitive match.
|
|
17
|
+
// corner: a character whose lowercase form is a different length (Turkish dotted capital I) can
|
|
18
|
+
// shift the run by one; the name still renders whole, and the backend alone decides what matched.
|
|
19
|
+
function run(hay, needle) {
|
|
20
|
+
var h = String(hay)
|
|
21
|
+
var n = String(needle)
|
|
22
|
+
if (n.length === 0) {
|
|
23
|
+
return { start: -1, length: 0 }
|
|
24
|
+
}
|
|
25
|
+
var at = h.toLowerCase().indexOf(n.toLowerCase())
|
|
26
|
+
return at < 0 ? { start: -1, length: 0 } : { start: at, length: n.length }
|
|
27
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
.pragma library
|
|
2
|
+
.import "Contrast.js" as Contrast
|
|
3
|
+
|
|
4
|
+
// Omarchy Glassy dims its blurred backdrop to 0.75; channels and alpha use whole 8-bit steps.
|
|
5
|
+
var STEPS = 255
|
|
6
|
+
var MIN_ALPHA = Math.ceil(0.75 * STEPS)
|
|
7
|
+
var INK_STEP = 1.25
|
|
8
|
+
// Twenty bisections resolve lightness more finely than one 8-bit colour channel.
|
|
9
|
+
var LIGHTNESS_SEARCH_STEPS = 20
|
|
10
|
+
// Half an 8-bit channel step repairs rounding without skipping the first passing colour.
|
|
11
|
+
var ROUNDING_REPAIR_STEPS = 512
|
|
12
|
+
|
|
13
|
+
function ground(plane, a, backdrop) {
|
|
14
|
+
return Contrast.hexOf(Contrast.over(String(plane), a / STEPS, backdrop))
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function worst(ink, c, a, planes) {
|
|
18
|
+
var least = Infinity
|
|
19
|
+
var grounds = planes || [c.background, c.surface]
|
|
20
|
+
var brightness = c.blurBrightness === undefined ? 0.75 : c.blurBrightness
|
|
21
|
+
var white = Contrast.hexOf([brightness, brightness, brightness])
|
|
22
|
+
var backdrops = [white, "#000000"]
|
|
23
|
+
for (var p = 0; p < grounds.length; p++)
|
|
24
|
+
for (var b = 0; b < backdrops.length; b++)
|
|
25
|
+
least = Math.min(least, Contrast.ratio(String(ink), ground(grounds[p], a, backdrops[b])))
|
|
26
|
+
return least
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function direction(c) {
|
|
30
|
+
var fg = Contrast.parse(String(c.foreground)), bg = Contrast.parse(String(c.background))
|
|
31
|
+
return Contrast.luminance(fg[0], fg[1], fg[2]) > Contrast.luminance(bg[0], bg[1], bg[2]) ? [1, 1, 1] : [0, 0, 0]
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// The R3 lightness walk, including its rounding repair, applied to the live palette rather than a theme-name table.
|
|
35
|
+
function inkHolds(ink, c, a, need, quiet) {
|
|
36
|
+
if (worst(ink, c, a) < need) return false
|
|
37
|
+
if (quiet === undefined) return true
|
|
38
|
+
var x = Contrast.parse(String(ink)), q = Contrast.parse(String(quiet))
|
|
39
|
+
var lx = Contrast.luminance(x[0], x[1], x[2]), lq = Contrast.luminance(q[0], q[1], q[2])
|
|
40
|
+
return direction(c)[0] === 1 ? lx >= lq : lx <= lq
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function liftInk(ink, c, a, need, quiet) {
|
|
44
|
+
if (inkHolds(ink, c, a, need, quiet)) return String(ink)
|
|
45
|
+
var from = Contrast.parse(String(ink)), to = direction(c), lo = 0, hi = 1
|
|
46
|
+
for (var i = 0; i < LIGHTNESS_SEARCH_STEPS; i++) {
|
|
47
|
+
var mid = (lo + hi) / 2
|
|
48
|
+
if (inkHolds(Contrast.hexOf(Contrast.mix(from, to, mid)), c, a, need, quiet)) hi = mid
|
|
49
|
+
else lo = mid
|
|
50
|
+
}
|
|
51
|
+
for (var t = hi; t <= 1; t += 1 / ROUNDING_REPAIR_STEPS) {
|
|
52
|
+
var hex = Contrast.hexOf(Contrast.mix(from, to, t))
|
|
53
|
+
if (inkHolds(hex, c, a, need, quiet)) return hex
|
|
54
|
+
}
|
|
55
|
+
return Contrast.hexOf(to)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function quieter(ink, primary, c) {
|
|
59
|
+
var x = Contrast.parse(String(ink)), fg = Contrast.parse(String(primary))
|
|
60
|
+
var lx = Contrast.luminance(x[0], x[1], x[2]), lf = Contrast.luminance(fg[0], fg[1], fg[2])
|
|
61
|
+
return (direction(c)[0] === 1 ? lx < lf : lx > lf) && Contrast.ratio(String(ink), String(primary)) >= INK_STEP
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function primaryHolds(primary, c, a, need, muted, metadata) {
|
|
65
|
+
return worst(primary, c, a) >= need && quieter(muted, primary, c) && quieter(metadata, primary, c)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// A mode may lift primary ink too, so legible secondary ink never becomes the primary rung.
|
|
69
|
+
function primaryInk(c, a, need, muted, metadata) {
|
|
70
|
+
if (primaryHolds(c.foreground, c, a, need, muted, metadata)) return String(c.foreground)
|
|
71
|
+
var from = Contrast.parse(String(c.foreground)), to = direction(c), lo = 0, hi = 1
|
|
72
|
+
for (var i = 0; i < LIGHTNESS_SEARCH_STEPS; i++) {
|
|
73
|
+
var mid = (lo + hi) / 2
|
|
74
|
+
if (primaryHolds(Contrast.hexOf(Contrast.mix(from, to, mid)), c, a, need, muted, metadata)) hi = mid
|
|
75
|
+
else lo = mid
|
|
76
|
+
}
|
|
77
|
+
for (var t = hi; t <= 1; t += 1 / ROUNDING_REPAIR_STEPS) {
|
|
78
|
+
var hex = Contrast.hexOf(Contrast.mix(from, to, t))
|
|
79
|
+
if (primaryHolds(hex, c, a, need, muted, metadata)) return hex
|
|
80
|
+
}
|
|
81
|
+
return Contrast.hexOf(to)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function inks(c, a, need) {
|
|
85
|
+
var muted = liftInk(c.muted, c, a, need), metadata = liftInk(c.metadata, c, a, need)
|
|
86
|
+
var meta = Contrast.parse(metadata), fg = Contrast.parse(String(c.foreground))
|
|
87
|
+
var lm = Contrast.luminance(meta[0], meta[1], meta[2]), lf = Contrast.luminance(fg[0], fg[1], fg[2])
|
|
88
|
+
// Darkening a light palette's foreground put metadata beyond primary, or on it in White; reuse its muted rung.
|
|
89
|
+
if (direction(c)[0] === 1 ? lm >= lf : lm <= lf) metadata = muted
|
|
90
|
+
var primary = primaryInk(c, a, need, muted, metadata)
|
|
91
|
+
return {foreground: primary, muted: muted, metadata: metadata}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// One alpha for every main plane in A, raised only if its ink cannot hold the two text rungs.
|
|
95
|
+
function floor(c, need) {
|
|
96
|
+
for (var a = MIN_ALPHA; a < STEPS; a++) {
|
|
97
|
+
var ink = inks(c, a, need)
|
|
98
|
+
if (primaryHolds(ink.foreground, c, a, need, ink.muted, ink.metadata)
|
|
99
|
+
&& worst(ink.muted, c, a) >= need && worst(ink.metadata, c, a) >= need) return a
|
|
100
|
+
}
|
|
101
|
+
return STEPS
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// B keeps the unlifted listing text legible on its own background plane, never thinner than A.
|
|
105
|
+
function listFloor(c, need) {
|
|
106
|
+
var a = STEPS
|
|
107
|
+
while (a > 0 && Math.min(worst(c.muted, c, a - 1, [c.background]), worst(c.metadata, c, a - 1, [c.background])) >= need) a--
|
|
108
|
+
return a
|
|
109
|
+
}
|