Repository navigation
Move the files and platform code into libfiles and libdesktop, and fetch every dependency - #253
Merged
Merged
Conversation
Search: a media type written in the display language could not be read back, so it was lost at restart in every non-English catalog; with:/without: discarded the term's modifiers, inverting -with: and intersecting an or; with:orientation tested the wrong enumerator; and with: offered eleven scopes the matcher cannot answer. Multi-word completion needed every word and stopped after the first. Rendering: the Locate map and the Photo edit picture had no route to shed a texture on device loss; a refused video shared-texture build was silent, had no fallback and repeated per frame; the compare preview decoded at source resolution per pointer move; the video decoder had no size ceiling; and the two backends decoded the drop-shadow art through different decoders. Model: every cached checksum was destroyed on the first folder validation of every launch, because a cache-loaded node has no filesystem stamp to compare. Plus Burn absent rather than dimmed, repeat mode validated on read, and the dead files, orphan declarations and build-description drift the sweep found. Five tests added, each verified discriminating. lint 13/13, 840/840, po clean.
Foundry stamps the version into the executable name, so each release needs its own entry; -v is the documented flag for showing an image in a Viewer, since a bare path is read as a .nk script. Requested in discussion #210.
A submission the Store never accepted has to be rebuilt at the same version, which the unconditional bump made impossible. Also points store signing at the current self-signed cert.
The documentation set is what git tracks, so the per-release v-*.md notes go to GitHub releases, which own release history, and each remaining document is trimmed to the one subject it owns. The LGPL requires the licence to travel with the binary, so LICENSE and COPYING.GPLv3 are staged into exe\ for the zip rather than left at the repository root. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Continues the Movie document and its view, reworks the YUV and colour paths across the D3D11 and software backends, and carries the decode, WebP and encode fixes that went with them. Also restores the items scroll menu's back-to-top entry to the front of the menu, which is where both the design comment and the test say it belongs. The build no longer declares libfacedetection or ncnn, and no longer embeds a face model resource: face search is not in this release. See docs/faces.md. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Face search needs more time than the release stream can wait for, so the feature moves to the face-search branch: no detector, no embedding model, no background pass, no search term and no user interface. What stays is the part that is settled, tested and expensive to re-derive - alignment onto the reference template, the normalized vector and cosine similarity, anchored grouping, the sample face that identifies a group, the face token, upright geometry, and the stored blob form. It is headless and nothing in this release calls it. The item_faces table stays with it so the release that turns detection on needs no migration over a large database. There is also a licence reason not to ship the model now: the MobileFaceNet weights' own redistribution grant is unresolved, so the embedded pair cannot be released until that grant exists or the model is replaced. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The strings these entries translate left app_text.h with the feature, so an entry for one now names nothing. Twenty entries go from each of the thirteen catalogues; nothing else in them changes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
A 1.27.2.1305 crash report faulted in metadata_tree_control::copy_text with a null `this`, reached from a click on a metadata section's copy button. One call both captured the tree by value, for the copy callback, and moved it into the section it was being added to. Function arguments are indeterminately sequenced and MSVC evaluates them right to left, so the move emptied the pointer before the capture copied it. Building the title control in its own statement sequences the capture first. Nothing looked wrong until the button was pressed: the section owns the tree either way, so the listing measured, laid out and drew correctly, and only the callback held nothing. The new test therefore runs the callback rather than just building the elements - against the old code it reproduces the reported access violation exactly. Reaching it needed verbose metadata switched on and a file carrying container metadata blocks, which is why it survived to a release. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
One call that both captures a variable by copy, for a lambda, and std::move-s that same variable into another argument reads it in unspecified order. MSVC evaluates arguments right to left, so the move empties the variable and the lambda keeps an emptied value. The fault then surfaces wherever the callback is finally invoked, which is why review misses it and why it is worth linting. The rule brackets each lambda's enclosing call expressions and looks for a move of a name the lambda captured by copy. Three shapes are deliberately not reported, because each is correct: moving the captured copy inside the lambda's own body, an init-capture such as [f = std::move(f)], and a nested lambda whose name is bound by an enclosing capture rather than by the function. Verified both ways - it reports nothing on the current tree, and reverting the view_items.cpp fix makes it report that line and only that line. Also removes the unit test added with that fix. copy_clip_element writes to the clipboard through OpenClipboard(app_wnd()), and a headless run has no window, so invoking the element is not something a test can do - it failed or crashed regardless of whether the code under test was correct. docs/testing.md calls for extracting the decision in that situation, and until the text generation is separable from the clipboard write the lint rule is the honest guard. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fifteen files that carried a UTF-8 BOM lost it when they were rewritten during the extraction. The repository is mixed - 131 of 200 source files carry one at the pre-extraction base - so the rule is not that every file has a mark but that no file silently changes whether it has one. Losing it rewrites line 1 of each file and puts unrelated churn in the release diff. No text changes. src/test_search.cpp also lost its mark and has it back in the working tree, but it is left out of this commit because it carries unrelated work in progress. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…shape Two independent defects, both making a video draw at the wrong shape. #252: av_format_decoder::extract_metadata ended with an unconditional sr.orientation = calc_orientation(). calc_orientation reads _rotation, which is only established by init_streams, so for any scan that decodes no frame it held its default and erased the container rotation that populate_video_properties had just read from the display matrix. Indexing and the rescan that follows a rating, label or tag write therefore recorded a rotated video as upright, and a portrait tile flipped to landscape after the first label. The orientation is now published only once a video context exists. #78: the media view fitted its destination to the texture's own extent. For video that is the coded frame, which need not have square pixels, so a file storing 528x560 and declaring 4:3 was letterboxed inside an already correctly shaped box and drawn squeezed. The thumbnail escaped this because extract_thumbnail bakes the aspect into the bitmap, which is why tiles looked right while playback did not. The destination now takes the container's declared display dimensions for video, which is what the zoom and region paths already used. Tests: the rotation survives a metadata write, the player agrees with the scan on both aspect and rotation, and the draw shape is derived from the reporter's real dimensions. rotated90.mp4 is gizmo.mp4 with a 90 degree display matrix, in excluded1 so indexed item counts are unchanged. Also extends the #219 Korean NFC/NFD coverage to the qualified tag: form that clicking a tag actually produces. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
A reliability audit of the tree at 63b0ebc confirmed defects across the index, search, the write paths, metadata, the platform layer, Movie and the views. This fixes the ones that can be fixed and proven headlessly, each with a regression test that fails against the old code wherever one can be written. - Index and database: descendants of a deleted folder stayed searchable; CRC and picture hashes published against content that had since changed, and kept across in-place edits; a folder rebuild could publish over newer scan state; failed commits left a transaction open; failed scans persisted as scanned. - Search: a nested group after OR matched everything; recursive wildcards skipped subfolders; a negated f-number pair broke De Morgan; byte counts past 2 GB wrapped; dimensions, TB sizes, west longitudes and quoted operators did not read back as written; a cancelled pass reported itself complete. - Files and metadata: saves truncated before a fallible write; files over the blob ceiling were read as prefixes and re-encoded over the original; progressive JPEG coefficients, lossless rotates and RAW now observe the decode budget; ICC tag copies are bounded; Exif GPS on the equator and meridian, partial XMP GPS, IPTC extended lengths and UTF-16 in either byte order. - Operations: Rename, Import, Sync and Convert are held to the identity of what was reviewed, sidecars roll back with their group, Sync refuses a delete on an unreadable checksum, and a failed import folder keeps its bookkeeping. - Platform: enumeration failures no longer pass for complete listings, Linux delete no longer follows directory symlinks and fail-if-exists is atomic, UTF-8 to ANSI conversion, clipboard DIBs, installer downloads and the crash handler's locks. - Movie and views: render cancellation, an output naming a clip, unbounded project durations, capture currency, Escape on a pressed control, dialog lifetime, favourites, per-item Delete, focus leaving the address box, and translations that a language switch could rewrite under a worker. Reviewing that work found and fixed: - The Linux build: _When_ had no portable definition, and Linux temp_file created a missing folder, so a save into one succeeded there alone. - The ICC cap refused the tone curves the common sRGB profile shares; shared regions are now charged once. A RAW and JPEG sharing an XMP refused the JPEG on import; the sidecar now travels once. - A lossless rotate refused for its budget fell back to a lossy re-encode that holds more memory; it now fails. The picture-hash cap sat above the read cap. - A refresh superseding Delete's listing dropped the item to land on, and a navigation superseded that way its path-change work; the refresh now inherits both. A folder racing its parent's placeholder published as empty. - Capture held the display and item on the media read thread and dropped Copy when the display moved on; only a newer capture now overtakes one. Escape on the scrubber rewound playback to the start. - Stale hashes returned from the database next launch; they are now cleared there too. find_attributed still ranked raw degrees. utf8_to_a truncated CJK names under the UTF-8 locale. The comma-sign rule negated nothing after an ordinary term. Plural forms and file-group spellings still raced a language switch; both are published whole, and the synchronized-type registry names them. Two files gained a byte-order mark they never had. From the branch's earlier commits: a safe start no longer clears the YUV fault latch that no option can set again; shutdown saves state before asking whether it may end, and does not ask on a critical shutdown; and the capture-and-move lint rule now sees past digit separators and copying init-captures, with self-test cases proving both. Tests: 944 pass in Release and 938 in Debug; lint, the lint self-test and the translation checks pass, and every changed file passes a GCC syntax check with the Linux build's flags. Progressive.jpg is a 256x256 progressive 4:2:0 fixture in excluded1, so indexed item counts are unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The reliability audit left 70 items open. The audio and video playback items that need a supervised session on real hardware stay open, as do the ones already shown not to be defects, the face-search foundations that do not ship, and Edit's synchronous decode, which needs its loading moved off the UI thread and checked by hand. Of the rest, these were real and small enough to fix and prove: - Animation: the hover colour fade and the media overlay fades bypassed the animation gate and stepped per frame. They now take ui::animations_enabled and ui::animation_step_factor, as every animate_alpha fade does. - Zoom and controls: Toggle Fit turned a Fit width or Fill into the fixed scale it last computed; it now restores the mode itself. Rating hit-testing could answer a sixth star at the right edge. Cut was enabled on any selection while its own invocation demanded Copy's eligibility. - Movie: a '%' in a clip path was written raw and decoded on reload, so "50% off.jpg" was dropped and "a%20b.jpg" came back as another file. It is now escaped, and a '%' that begins no escape reads as itself. - Import: the explanation for rows refused since review was added after the copy had already completed the run, and only the first completion is shown. - Metadata: the orientation-only Exif block linked an empty IFD1 whose next-IFD offset was two bytes short. Saving through WIC with a dotless "jpg" wrote PNG bytes. - Windows: Open With reported success when the invoker could not be created; refused clipboard text leaked; the date control's focus loss was never forwarded (WM_KILLFOCUS compared against a notification code); toolbar image lists leaked whenever their host window went first. - Crash and support reports attach their archive only when it closed. - Index: a presence recalculation could overwrite a duplicates bit published while it ran, dropping the item from a duplicates search. - Linux move crosses filesystems by copying, as the Windows move does. - Hardening: an audio buffer realloc failure no longer leaks or keeps a stale size, and file_read_stream and prop_variant_t cannot be copied into a double free. Tests: 942 pass in Debug, and each new or extended test fails with its fix removed; lint passes, and every changed portable file passes a GCC syntax check with the Linux build's flags. The Release executable could not be relinked while the application was running, so the six Release-only tests were not rerun for this commit. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
A design review for future productivity found interface methods that both render backends and both platforms still implemented although nothing called them, copies of the same scaffolding, and routing comments that named the wrong file. Every change preserves behaviour. - Remove draw_context primitives nothing draws (draw_rect_gradient, draw_shadow, draw_edge_shadows) from the D3D11 and software backends, with the inverse-shadow art only they used. - Remove uncalled interface methods (edit::limit_text_len, trackbar::buddy, web_window/web_events, platform_app::get_font_base_size, the platform::file created/modified accessors, play_state_changed) and declarations that had no definition. - Remove unused and write-only members, locals and duplicate helpers found by search, GCC -Wunused and MSVC C4505/C4189. - Default the comparisons of eight value types with C++20 operator<=>. - list_view owns the task views' status line and builds a run's status in one place (make_run_status) instead of four inline copies; each view's conclusion policy is unchanged. - Eleven selection commands share can_process_selection_or_explain. - The colour palette and key names are portable code, defined once instead of a Windows copy and a Linux copy (the Linux key names were a stub). - Correct the Purpose comments of app.cpp, app_search.cpp, app_toolbar.cpp, app_workers.cpp and view_list.h. - Re-glob embedded resources at build time, so deleting one cannot leave an existing build tree depending on a missing file. New tests pin the status a finished rename reports and how keyboard accelerators are spelled. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Two Maps API keys were decrypted from secrets.h during static initialisation, and nothing has read them since 1.27.0. That decryption was the only production use of AES, so crypto::encrypt/decrypt, the aes256 module and their test go with it. A local secrets.h is now simply unused. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
A finished run now states what it did, then why any rows did nothing, and a run that reports neither leaves the review's status. Import and Sync already did; Rename dropped the counts whenever there was a reason and went blank with neither, and Tags kept "Processing" with neither. The rule lives once, in list_view::conclude_run, with a test of each case. Opening the Movie view recorded no feature-use bit because view_bit had no case for it; it now records bit 57, and a test requires a distinct bit for every view. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
GCC 13 reported 160 distinct warnings across the portable sources and MSVC two in the Windows build, which hid any new one. All are fixed without changing behaviour: explicit parentheses where precedence was relied on, matching signedness in comparisons (key names now take char32_t, and file_group::max_count is an int), default cases in switches over open enums, constexpr dropped from functions that call non-constexpr rounding, member initialisers in declaration order, a value-initialised fill instead of memset over csv_entry, a fixed 64-byte line instead of the tuning-dependent interference size, and unused locals removed or marked. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
loc:, near:, place:, city:, state:, country: and countries: were spelled out separately in address-box completion, the tokenizer's coordinate rule, part coalescing, term parsing and term formatting. They now all read df::location_scopes, which also records each spelling's level and whether it takes a centre; the first entry for a level is the spelling a formatted query writes. A table-driven test completes, parses and formats every entry. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Supporting a still format meant touching signature detection, the scan dispatch, the in-memory decode in image_to_surface, the file load and the encoded-format mapping, plus its extension-table entry - six lists that had to agree. files_formats.cpp now holds one still_format per format: its extensions, description and traits, its signature, its header scanner, its whole-file loader, its in-memory decoder and whether loads keep it encoded. detect_format, scan_photo, image_to_surface, files::load, load_image_file and is_image_format all dispatch through it, and the extension table takes each still type from it with still_file_type. Each decoder keeps the error handling its branch had. A test requires every entry to be detectable, scannable and registered under its extensions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
model_index.cpp held scanning, querying, duplicate prediction, presence, the summary and auto-complete in 5,600 lines. Duplicate prediction and presence (with the constants and helpers only they use) move to model_index_duplicates.cpp, and the summary, histograms, location matrix and the auto-complete answers built from them move to model_index_summary.cpp. The two helpers all three share - find_file and needs_scan_impl - are in model_index_internal.h. dup_key and its hash and equality functors were unused and are removed. Code is moved, not changed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
model.h carried view_state and, beside it, the 900-line display_state_t that pulls in the audio and video headers, so every file that only needed view_state compiled the player. display_state_t is now in model_display.h; model.h keeps view_state, texture_state and the display state it holds by value, and needs only the small av_host interface, split out of av_player.h. The five view_state members that read the display moved out of line into model.cpp. Nine translation units no longer compile av_player.h; ui_controls.h, app.h and the media views include model_display.h because they draw the display. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
app_commands.cpp mixed the command handlers and their registration with 1,900 lines of dialogs that are features of their own: advanced search, the update offer, the keyboard reference (with the key names it spells), About and Support, settings, collection settings and maintenance, sidebar customisation and email. Those move unchanged to app_dialogs.cpp, with app_dialogs.h declaring the entry points the commands open. make_file_encode_params moves to app_util.h, and can_process_selection_or_explain is declared in app_dialogs.h, because both sides use them. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The window framework shared its file with the code wWinMain runs around the window: the console for the command-line tools, the fatal-error message, the minidump and its unhandled-exception filter, restart and recovery registration, and the graphics crash guard. Those move unchanged to platform_win_process.cpp, with platform_win_process.h declaring what wWinMain calls. The restart command line is now passed to setup_restart rather than held in a file-level global. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The edit box, buttons, slider, date and time picker and the owner-drawn toolbar move to platform_win_controls.cpp. The window plumbing both files use - geometry and GDI helpers, owner_context, the window and control base classes, win32_menu - moves to platform_win_ui_internal.h. The controls reach their host through a small native_control_host interface (show_menu and hover_command_bounds) rather than the concrete control_host_impl. control_host_impl keeps id allocation, the child map, the default button and radio grouping, and builds each control with a create_native_* factory. Behaviour is unchanged. Also removes the unused window_from_location, the unused ABM_GETAUTOHIDEBAREX define and an unused local in the date picker's paint handler. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fills the Movie fade-length label, the six reasons a movie render can fail, and the import note for a created date that could not be set, in all 13 catalogues. Each reuses the terms its catalogue already uses for the neighbouring strings: the fade label names the same fade in and fade out the panel's two checkboxes do, and the import note follows the existing "items were processed" plural forms, including the extra Czech, Polish, Russian and Ukrainian forms. check_translations.py --strict now reports every language complete with no placeholder, accelerator or quality issue. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CI has not run on any 1.27.3 commit, and three of the configurations it gates had never been through these changes. Running them found: - Release x86, which the desktop package ships as diffractor32.exe, did not compile: a test compared a size_t literal with a uint64_t file size, one type on x64 but two on x86, so assert_equal was ambiguous. The movie audio mixer also warned there, adding int64 offsets to iterators whose difference type is 32 bits; the clamps above keep every offset inside both buffers, so the casts that now say so are lossless. - Linux failed two tests that asserted Windows path identity: a movie output differing from a clip only in case names a different file on Linux, and a planned path prints with forward slashes there. Each now asserts the platform's own identity. - GCC's Release build caught a face test reading coefficients through a pointer into a temporary destroyed at the end of its statement; the transform is now held in a local. Release x64 and x86, the Store build and Debug x64 pass 953/953/953/947, and Linux Release passes 926/926. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
str::to_string(double, digits) formatted through _fcvt_s into a 128-byte buffer. A value whose fixed form does not fit - about 1e120 and up - is an invalid parameter to the CRT, which ends the process through fail-fast, so no crash report records it. Inspecting a RAW file whose maker notes state such a value, the Hasselblad gain for one, was enough. The buffer now holds the fixed form of any double; every value that formatted before formats identically. Test: Should format a double of any magnitude. With the old buffer the run terminates with 0xC0000409 instead of reporting a result. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The released binary is LGPL-3.0-or-later, which must accompany every copy together with the GPL-3.0 it incorporates. Only the portable zip carried them: the installer's licence page states LGPL-3.0 but installed neither text, and the Store package carried nothing. dd.ps1 now stages both through one Copy-LicenceTexts step - into exe\ before the installer is compiled, and into the Store package root - and the installer installs and uninstalls them beside the executables. docs/third-party.md records that every release package carries them. Verified by compiling installer/diff.nsi: LICENSE.txt and COPYING.GPLv3.txt are packed beside diffractor-tools.json. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Update libpng, Expat, libheif, libde265, XZ, Hunspell and utf8cpp; refresh Adobe DNG, skcms and RapidJSON snapshots. Update NASM and 7-Zip Extra with upstream notices, and preserve the existing integration configuration. Pin the validated FFmpeg upstream merge at 33eee91fb834bc7ea226bbe4f163fa05604bf152 and update its MSVC source inventory. Restore library, build-tool and asset tables plus current CMake-based upgrade guidance in docs/third-party.md. Validated x64 Debug (947 tests), x64 Release and Win32 Release (953 tests each), the complete dd.ps1 test gateway, Linux dependency/FFmpeg builds, and unchanged FFmpeg platform configuration parity. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Movie: entering rebuilds the timeline when the photo and video selection differs from the one it was built from, and Close, Items and Escape offer Save project, Discard or Cancel for unsaved work, including an edited empty timeline, which can now be saved. The model tracks the clean undo depth, ignores no-op trims, settings and replacements, and makes a multi-file Add or drop one undo step. The timeline gains a scrollbar, smooth wheel and touchpad scrolling and edge auto-scroll while dragging; trim handles move relative to the press; preview audio is read in prefetched windows into a larger WASAPI buffer and starts with the picture at the media volume. Source review: fixes 163 of the 164 findings, each with a regression test shown to fail before its fix, across text and metadata parsing, codecs and writers, the index and its publication protocol, search grammar, tag actions, places, file operations, Import, Convert, Sync, playback, Movie, controls, tooltips, the Windows shell and clipboard, and the Linux port. The P1 fixes keep apostrophes when splitting metadata, keep decoded ICC text alive, restore replaced Import sidecars when a later write fails, enforce Convert's collision decision at publication, and confirm before a requested recycle becomes a permanent delete. MOD-002 (folder availability off the UI navigation path) is deferred pending a decision on parsing ambiguous paths without a file system probe. Also: Rotate saves the displayed quarter-turn for EXIF orientations 6 and 8; Scroll to top comes last in the items scroll menu, directly below the settings; two order and clock dependent tests are made deterministic; build 1.27.3.1310. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
FFmpeg is configured for speed rather than size, decodes software AV1 through libdav1d, and drops DXVA2, libavdevice and every muxer; the fork's configuration and the MSVC and Linux builds follow. Hardware decode is chosen per stream from the driver's own decoder profiles, falls back to software when the driver still refuses a stream, and shares one D3D11 device across videos. Decoders read only the streams they decode, can be interrupted while blocked in the demuxer, drain at the end of a stream, and size their threads by cores and memory. Each picture is prepared on the decode thread as the NV12, P010 or BGRA the renderer uploads, with P010 only for a device that samples it, so presenting a frame is an upload. PQ and HLG video is tone mapped to SDR through one cube per clip that the GPU samples and the CPU applies with the same trilinear arithmetic, with SSE2 on x86. PQ rolls highlights off with the BT.2390 EETF into 203-nit SDR white. HLG is rendered by FFmpeg's HLG EOTF for a display whose peak is SDR white, close to how Windows' own player shows it, which keeps phone HLG from blowing out. Also: HEIC's HEVC decodes with FFmpeg through libheif - faster, and bit-exact where libde265's 32-bit build is not; the Streams row shows codec profile, bit depth and HDR transfer; Movie's Next and Previous count from the clip under the playhead while it plays; and a scrub seek near one still decoding retargets it, with one correction seek when the settled frame overshoots, so a stopped trim handle shows its own frame. Each fix has a regression test shown to fail without it; the new test clips are LFS files in exe/test/excluded1. Validated with the x64 and Win32 Release suites (1177 tests each), the dd.ps1 test gateway, the Linux build and suite (1144 tests), and FFmpeg Windows/Linux component parity. FFmpeg fork: eea8d39 on upgrade/upstream-20261004. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fall back to the CPU backend as a whole, and sooner: on Windows 7, which has no flip-model presentation; on the Microsoft Basic Render Driver, which is WARP posing as a GPU in virtual machines and remote sessions; and when a hardware window cannot build its Direct3D context, which used to leave fades, the YUV gates and hardware frames set for a GPU no window was drawing with. Swap chains come from the factory that owns the device's adapter. NV12 and P010 count as supported only where the device can sample them, and hardware frames respect those gates and the driver-fault latch; a render device that refuses a shared format is remembered rather than asked again every frame. The CPU backend has the decode thread download hardware frames instead of doing it on the UI thread every frame. A texture whose view failed draws nothing rather than the previous texture. Glyph atlas rows fit their tallest glyph, and a full atlas starts again rather than leaving new text undrawn. Integrated GPUs count shared memory, so Intel laptops no longer show photos over 16 MP downscaled at 100%. The hardware decode device is made on the adapter the renderer draws with, found by its LUID, so docking or a new primary display can no longer put decoder and renderer on different GPUs and send every frame through system memory. A window that cannot be seen - its top-level window minimised, or its present answered DXGI_STATUS_OCCLUDED behind the secure desktop - skips drawing and presenting, and a poll repaints it whole once it is visible. The app's tick is unchanged, so playback keeps time with its audio. Validated with the dd.ps1 test gateway (1181 tests, x64 Release), the Win32 Release build, the Linux build and its video tests, and normal, -no-gpu and minimise/restore runs on an RTX 3060. New tests cover WARP detection, the sampling requirement, the integrated-GPU texture budget and the decode device's adapter, each shown to fail without its fix. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…dings Direct3D: a released plain texture is kept with its views in a per-device pool of an eighth of the texture budget and handed to the next texture of the same size and format, never while a scene a redraw can replay still draws it. Counted as textures_reused. Edit: a preview decoded short of its request is drawn instead of leaving Edit on Loading, and a file whose header loads but whose pixels do not decode is reported as a load failure. Concurrency review fixes: - Duplicate prediction compares against the anchor hash it checked. A rescan clearing that hash mid-walk crashed the comparison. - The startup cache merge no longer adopts CRC or picture hashes scanned before a file last changed, and clears those rows, so an edited file is not reported as identical to an old copy. - A saved playback position is published into the index, so a later rescan no longer writes the position loaded at startup back over it. - Import and Sync analysis workers own their cancellation source, starting a new run cancels the run it replaces, and Refresh leaves a running Import or Sync alone while still restarting an Analyze. - Rename, Convert, Metadata and Date runs do not start once their view closes while media handles are released; Import takes its cancellation baseline before releasing them. - command_status hands its dialog and controls back to the UI thread for their final release. - Index maintenance: Escape cancels the read-only check, and defragment or reset waits on a completion event rather than on the dialog window. - Nested UI waits drain input after every wake and run requested idle work even when the frame timer wins the wait. - Every collection walk can bring the index scan workers up, and walks wait for the database cache before validating folders. - A late Locate place search no longer overrides an explicit map choice. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The release carried a headless face foundation and the scaffolding the face pipeline was built on, none of which anything in it called. All of it moves to the face-search branch, so the release ships no face code, schema or documentation: - model_faces, test_faces and docs/faces.md, and their rows in AGENTS.md and docs/testing.md; - the reserved item_faces table, and the drop of the face_assignments and face_groups tables that only pre-release face builds created; - the faces presence bit, which nothing in the release set; - decode_intent::analysis and the scale rule behind it, which nothing in the release requested, and area_downscale_luma with its test, which only the face foundation read; and - the face libraries section of docs/third-party.md, and the face mentions in docs/design.md and docs/implementation.md. The schema script still runs on every open, so a database written by either branch opens in the other: the release ignores an item_faces table it finds, and face-search creates it when it is missing. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The last of the sixteen files the face-search extraction stripped of their UTF-8 mark. e9415f9 restored the other fifteen and left this one out because it carried unrelated work in progress at the time. No text changes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…oPlay Snap layouts: on Windows 11 the toolbar reports its maximize button to Windows as the window's maximize caption button, so snap layouts open over it. Not while maximized, where the flyout would cover the taller restore button. The DWM shadow pixel moves to the bottom edge, because a top margin made DWM treat the frame as having its own title bar. Share replaces Email. Tools > Share (F10) offers the selected files to another app through the Windows share sheet. Share keeps its own options, which start with everything off so originals are sent; resized, converted or zipped copies are staged in %TEMP%\diffractor-share until the next share. Email remains where the system has no share sheet. The preparation Share and Email have in common no longer enlarges photos already inside the size limit, keeps two files of one name apart in the zip, and no longer sends after a late cancel. Long-running work shows on the taskbar button, and the button flashes when work finishes while another app is in front. Store build: an AutoPlay handler for camera cards and USB sticks, a "diffractor" command, and a restart after a Store update. A trailing "**" on the command line opens a folder with its subfolders, which is how AutoPlay opens a card. Import offers every removable drive holding media; empty card-reader slots and fixed drives no longer use up its five places. Sync treats modified times within two seconds as equal, so files on FAT32 and exFAT drives are not copied again on every run. The new strings are translated in all 13 catalogs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Exit no longer ends in heap corruption. Closing a task panel freed the panel's window object while it was still handling its own destroy, so quitting after Import, Edit or Rename crashed and Windows restarted the app. The window now stays alive until its destroy handler finishes, the selection thumbnail strip holds its frame weakly, and a host releases its child controls from a local rather than from the map being destroyed. Movie mixer: - Exif-rotated photos and portrait phone videos are turned upright where their frames are made, so the strip, preview, output size and rendered file agree. Render decodes on the output's longer side, so a rotated source is no longer decoded small and stretched back up. - The frame cache counted a re-stored frame twice, sat over budget and decoded the same photo in a loop, holding a core at full load. - A probe result landing during Save or Open is no longer taken for an edit, and a save overtaken by an Undo leaves the timeline unsaved. - The controls panel is laid out again when a control appears or a text grows, so the photo checkbox no longer stays drawn over the trim control. - Save no longer waits behind a running render, and a project file nested deeply enough to overflow the stack is refused instead of ending the process. Edit: saving a pixel edit of an Exif-rotated photo resets the orientation, in XMP and in the Exif a PNG or WebP copies, so the upright result is not turned a second time. An empty XMP packet is reported as such rather than "not understood". Search and settings: a folder-scoped query with a term is kept as typed, recent folders that no longer exist are offered as text, and network locations are not probed while building suggestions. INI values are written quoted so lists of quoted paths round-trip, and entries older builds damaged that way are dropped on load. Rename, Tags and batch tools keep a completed run's results through the file notifications their own writes raise; Refresh still re-plans. The focused view gets first refusal of keys, -no-indexing skips collection discovery, and a video's cover art no longer stands in for its codec. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Movie > Import reads a Windows Live Movie Maker project as Movie Maker wrote it. Clips follow the project's main track rather than the order they were added in, an untrimmed clip (an out point of zero) runs to the end of its source instead of being dropped, and a media path relative to the project resolves beside it. Everything left out - titles, music, effects, transitions other than crossfades, and a clip's speed, rotation, volume or mute - is counted, and the command line names each. Import then finds each source missing from its stored path among the collection's members, by name. A namesake whose length disagrees with the length the project recorded is another file and is never used; then the only file of that name wins, then the one in folders named like the stored ones, then the one where the project's other sources from that folder went. An unresolved clip keeps its stored path and length, so a saved project keeps it for Relink. The view says how many clips were relinked. The app answers from the index on the import worker; the command line walks the collection's folders. New command line options run without a window: - -movie-check:<project or folder> reports what import would make of a .wlmp, or what render would find in an .otio, and writes nothing. - -movie-import:<project or folder> writes a native .otio for each .wlmp, beside it or into -movie-out. - -movie-render:<project or folder> renders .otio projects to .mp4. - -movie-media adds a folder to search, -movie-overwrite replaces existing output, and -movie-skip-missing renders without the clips whose source cannot be used. The probe, the import and the render are the Movie view's own, so the command line and the app make the same movie. A clip whose sound outlasts its picture, common in camera files, failed the render with "A clip could not be decoded" once the frame walk ran off the last picture. The decoder now answers with the last frame, as a seek to the same time already did. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
A review of the Movie mixer before release confirmed 28 defects. All are fixed, each with a test that fails without it. Startup no longer spends half a second on the UI thread asking Media Foundation whether the machine can encode a movie: the startup worker asks once, and Render appears when it answers. Project files: - Projects from OpenTimelineIO 0.15 and later (Clip.2, named media references) open with their clips instead of empty. - Transitions follow OpenTimelineIO's model: a clip's range stops at the cut and the crossfade draws on the media past it, so other tools show the movie at its own length. Projects are marked version 2; older ones are read as they were written. - Times are written exactly, so an untrimmed clip no longer reopens as trimmed, and older rounded projects snap back to their source length. - A clip path that is not valid UTF-8 no longer ends the application on Save; one that cannot be resolved drops only that clip. - Clips saved before they were measured, and OTIO's null ranges, are kept for the probe instead of dropped. Timecoded media, disabled clips and clip effects are read or reported. - Out-of-range times are bounded and always written as valid JSON, and a crafted Movie Maker project can no longer stall the import. - An opened or saved empty project is returned to on entering Movie. Editing and preview: - One slider drag, or one typed length, is one undo step, and a drag back to where it began is no edit. Typed lengths are held to the document's bounds; lengths the panel shows rounded keep their exact value. - Escape cancels a strip drag, a trim handle or the scrubber instead of leaving Movie mid-drag. A trim applies only to the clip pressed on, pressing a handle stops playback, and handles on one pixel can still be told apart. - Trim end frames are exact at the clip's own frame rate, the paused preview no longer keeps a stale frame after playing, and the playhead bar marks the incoming clip during a crossfade. - Two photos in a crossfade no longer decode in a loop on large displays. Audio-level scans are cancellable and off the load queue, so they no longer delay Save, probes or preview sound. A clip that fails to open stops the clip player, and a superseded open is closed. - Files dragged in from another application show where they will be inserted. Rendering keeps Media Foundation's throttling on, so memory stays bounded when encoding is slower than composing; measured, render time is unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Preserve shared Import sidecars across renamed destinations and unfinished moves. Recover canceled Rename media and companions as one group, including late collision rollback. Compensate resampled PCM timing, skip existing Movie outputs before reading sources, and refuse unapproved late output replacements. Restrict Movie Open and Save to OTIO while retaining Movie Maker Import. Add regression coverage and update the owning documentation. Validate Release x64, Release x86 and Store with 1210 tests each, Debug x64 with 1204 tests, repository lint and all translation catalogs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Correct platform file, clipboard, settings, window placement, and time-zone API usage. Cache date-specific offsets, preserve audio decode resilience, and fix codec, archive, metadata, and allocation contracts. Add regression coverage and update owning documentation; align desktop release versions with the signed 1313 builds. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…tch every dependency Pre-flight: User-visible behavior. Scope: All scopes - the file layer, the platform layer and the build. Contents: how every file is scanned, decoded and encoded, and its metadata read, listed and written; the foundation, OS services and desktop UI; how the dependencies are acquired. Target: Visible items, and every build: Windows x64, x86 and Store, and Linux. Effect: Files read, show and save as before, but for the faults the moves' records found and fixed, and JPX and WBMP metadata, now kept in a sidecar - each listed below. UI-thread work stays disjoint from decoding and I/O, and the paint layer is untouched. master takes v1.27.3's commits as that branch has them, then this one. The repository's URLs point at github.com/ZacWalk. Files. libfiles, pinned at 2ec5a07, does what Diffractor's files code and Adobe's XMP Toolkit did, and Diffractor's copies are deleted. XMP is read and written with its data model - the toolkit and Expat are gone - and through it Diffractor scans stills, HEIF, JPEG XL and raw files; writes the metadata of every format it embeds it in, patching an edit that fits in place and staging one that moves the file in one pass; decodes PSD, JPEG, PNG, WebP, HEIF, AVIF, JPEG XL and raw files; lists Commodore 64 media; and encodes JPEG, PNG and WebP and turns JPEGs losslessly. EXIF is read, written and listed only through libfiles - libexif is gone - and IPTC is read through it. Each move was held to a record of the old code's outcomes over the fixtures; where the old code was wrong, the move fixed it: - every photo is turned by one EXIF orientation rule; - a fresh EXIF block is written as libexif wrote one, and a lossless turn patches the block in place, keeping its maker note; - Windows' XP title and tags read as written, not "?"; - IPTC text that is not UTF-8 reads as Windows-1252, not Latin-1; - a block that repeats a tag is turned upright in every copy; - an ISO speed of several values reads as its first; - of IPTC resources a file repeats, the first that holds anything is read and edited. Platform. The foundation (df::, str::), the OS services (platform::) and the desktop UI (ui::) are libdesktop's system and render modules, pinned at 184bdd0, and Diffractor's copies are deleted; its own side of FFmpeg's hardware decoding, its resource script and its Linux entry point stay here. Dates read alike on Windows and Linux, a date out of range is no date on Linux either, and an audio endpoint is laid out by its channel count, not its speaker mask, which could overrun the endpoint's ring. Dependencies. Nothing is vendored: third-party/, Include/ and .gitmodules are gone. bzip2, liblzma, SQLite, minizip-ng, libarchive, Hunspell and libopenmpt are fetched at their releases and the FFmpeg fork at its commit, each by SHA-256; the codecs come with libfiles and RapidJSON with libdesktop; NASM and 7-Zip are fetched by SHA-256; and libebml, libmatroska and utf8cpp, which nothing used, are dropped. docs/third-party.md lists each pin. 1,296 tests pass on Windows x64, x86 and Store and 1,240 on Linux; lint is clean. One commit for the week's work. The commits it was made from, each with its Pre-flight and its record, are kept on the local branch backup/pre-squash-2026-10-25: - 4d7da86e Point repository and submodule URLs at ZacWalk - aca57748 Fetch libfiles and hold it to the XMP Toolkit's results - 4f0bd6fa Read and write XMP with libfiles' data model - 185d1a81 Prove libfiles scans stills as Diffractor does - 62b54131 Scan stills through libfiles and delete Diffractor's scanners - 01a92b28 Write PNG, GIF and WebP metadata with libfiles - 2bf69cde Write JPEG, TIFF and PSD metadata with libfiles - e79e4f5f Write MP4 and QuickTime metadata with libfiles - 464655c6 Write ASF metadata with libfiles - fa0c0b52 Write RIFF, MPEG audio and FLV metadata with libfiles - c7fb2057 Read and write every packet with libfiles, leaving XMPFiles unused - abad82a1 Build the XMP Toolkit without XMPFiles - 3cdee319 Keep JPX and WBMP metadata in a sidecar - ce21f5db Build the DNG SDK's XMP backend over libfiles - 287cfe03 Remove the XMP Toolkit and Expat - 1286cedf Say what the Linux build depends on now - 675a8d78 Pin libfiles abb4637 - 6f812156 Move crc32c and fnv1a_i into the foundation - f0c4de86 Let the foundation own the words it formats with - 0e0d4a27 Format sizes in the foundation - 525d7f84 Read JSON files in the JSON wrapper - 33201942 Let the platform layer own its messages - 03ddb0c9 Move the environment facts into the platform layer - 4dec4d24 Keep the Windows services free of the UI layer - 5210764d State what the system layer requires of the application - 2a93080b Read shell properties into neutral values - cedb18f6 Record burn-to-disc use where the app asks for it - b3119248 Offer clipboard pictures through a platform interface - ae45f20e Keep the Linux services free of the application - 91177c68 Give the system layer its own resources, window and recovery hooks - 4a3b0c52 Keep the application's assets out of the platform layer - 02060380 Derive the system layer's names from the application's - 87c6b90f Count the index's words in the application, not the foundation - bff90213 Keep the application's diagnostics and version out of the foundation - 1079207c Wait on events in the services, with the UI thread's wait as a hook - 7b28c5ae Declare the desktop UI's platform services apart from the system's - 04963d4a Keep the UI thread's identity in the services - 644ca6d0 Build on libdesktop's system module instead of a copy of it - 9375b562 Pin libfiles at 24fd467 - 680e7186 Prove libfiles scans HEIF and JPEG XL as libheif and libjxl do - 53833d84 Scan HEIF and JPEG XL through libfiles and delete their scanners - 047a9a79 Pin libdesktop at daf406c - 3af14d2c Stage a metadata edit that moves the file in one pass - 3db3d891 Pin libfiles at 666bd8a - de8b2f6e Patch a metadata edit that fits, in every format libfiles writes - 8e23a44c Decode PSDs with libfiles beside load_psd, and hold them alike - 863b5a8c Decode PSDs with libfiles - 0f9a493d Take libjpeg-turbo from libfiles instead of vendoring it - d0a1c250 Decode JPEGs with libfiles beside jpeg_decoder_x, and hold them alike - 92252e75 Decode JPEGs with libfiles - fe241b7e Hold the decode records on x86 too - 8599cffa Read EXIF with libfiles beside metadata_exif::parse, and hold them alike - 02bcdb48 Take libdesktop 314075b: a date out of range is no date on Linux too - 2631ed0b Read EXIF with libfiles alone: metadata_exif::parse is read_exif's - 57a4e015 Turn every photo by libfiles' one EXIF orientation rule - 9db9b5e2 Write a fresh EXIF block through libfiles, as libexif wrote it - 560a7837 Turn a picture's EXIF in place, keeping its maker note - 8b5aabe8 List EXIF through libfiles; libexif leaves Diffractor - 54da96d5 Take libfiles 5031eb4: the TIFF editor reads with the shared reader - 73a83bc7 Read the XP title and tags Windows writes, not "?" - 56fb13b8 Record the Commodore listing before it moves to libfiles - 8179c82d List Commodore 64 media with libfiles - 1f20b18e Take zlib from libfiles: one zlib-ng, fetched rather than vendored - eee6e719 Take libpng from libfiles, fetched rather than vendored - 9493a2d3 Record the PNG loader's outcomes before it moves to libfiles - 15732a25 Decode PNGs with libfiles - 13472b57 Take libwebp from libfiles, fetched rather than vendored - 337caba1 Record the WebP loader's outcomes before it moves to libfiles - 300dc3c8 Decode still WebPs with libfiles - 7e169ffb Delete scan_webp, which only its tests called - 2d5acef9 Take libheif, libde265 and dav1d from libfiles; build only FFmpeg's plugin - b42b2ded Record the HEIF loader's outcomes before it moves to libfiles - 0632c6a8 Decode HEIF and AVIF with libfiles - c5350b77 Take libjxl, Highway, Brotli and skcms from libfiles - 5ed8bb39 Record the JPEG XL loader's outcomes before it moves to libfiles - 2db4d06d Decode JPEG XL with libfiles - d2e2b604 Optimise libjxl and Highway like every other library - 3ee98632 Take LibRaw and the DNG SDK from libfiles, with the SDK's XMP backend - f22b491d Record the raw loader's outcomes before it moves to libfiles - d313650d Load raw files through libfiles - e1008973 Record the raw scan's outcomes before it moves to libfiles - aa1287e5 Scan raw files through libfiles - c8e1cc90 Take RapidJSON from libdesktop's pin, not a copy vendored here - a6e4b04f Fetch bzip2 at its release rather than vendoring it - 6b529bbb Fetch liblzma at its XZ release rather than vendoring it - 0eab40e4 Fetch SQLite's amalgamation at its release rather than vendoring it - c2f8aec8 Fetch minizip-ng at its release rather than vendoring it - 47111c06 Fetch libarchive at its release rather than vendoring it - a1b5170e Fetch Hunspell at its release rather than vendoring it - 3c05e571 Drop libebml, libmatroska and utf8cpp, which nothing in Diffractor uses - 399b05f2 Fetch libopenmpt at its release rather than vendoring it - 21590409 Fetch the FFmpeg fork at its pinned commit rather than as a submodule - ccd448da Retire Include/ and third-party/, and diffractor_dependency's in-tree path - 090b979b Fetch NASM and 7-Zip by SHA-256 rather than keeping them in tools/ - c1d68324 Cut three of the desktop UI's ties to the application - 5f46fb42 Let the application read its command line and run its headless modes - ee024c5f Drop three application names ui.h declared and never used - 9f638f8a Decode the chrome's embedded images through a hook the application sets - bb6a7c5a Record what the encoders write before they move to libfiles - 8a2a7c17 Turn an EXIF whose thumbnail has an orientation in the encoder record - fddbc4e8 Encode JPEG, PNG and WebP, and turn JPEGs, with libfiles - 09c0e476 Hold every build to the fallback from a source JPEG libjpeg fails on - c3f2777e Name still formats with libfiles' detection, not a second copy of it - dd2cf492 Keep the app's settings out of the platform: crash guard and YUV latch - 63b692db Keep app_commands.h and files.h out of the platform sources - f2042394 Apply photo edits in the app, not in ui::surface - 6c403a02 Move FFmpeg's D3D11VA decode hooks out of the renderer - c3be3ffb Hand the renderers video frames and a scaler through ui:: interfaces - cf38b8c2 Lay out an audio endpoint by its channel count, not its speaker mask - 5fcebfcb Play sound through a platform::audio_output that names no decoder type - 06288d91 Show a bubble's content and draw the chrome's glyphs without the app's types - 020e4b03 Count what painting costs in the render layer, and link the app's assets alike everywhere - d5c9c91d Keep the UI layer's own sources apart from the app's: ui.cpp and the Linux stand-ins - a3f0a5c7 Give the desktop UI its own resource script and IDs, which the app's script includes - 1915ce1c Name no application in the desktop UI, and draw the app's mark in the app - 541d0997 Build the desktop UI from libdesktop-render, and delete Diffractor's copy - e141ab74 Define command_group's values and the highlight colours in the app - 9d0d366a Read IPTC through libfiles, and delete Diffractor's IPTC parser - 7a22331a Read IPTC text that is not UTF-8 as Windows-1252, through libfiles 969c49e - 6151032e Turn a block that repeats a tag upright in every copy, through libfiles 403b34e - f5de2388 Read an ISO speed of several values as its first, through libfiles 04e30fb - a4d62e1a Read the first IPTC resource that holds anything, through libfiles bc4b7df - a9b8a8d2 Read dates alike on Windows and Linux, through libdesktop 1e5289e - ad0d46ac Repin libdesktop and libfiles to their aggregated commits on GitHub Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pre-flight: Internal. Component: src/test_files.cpp, scan_parity::add_folder, which collects the files the record tests digest. Invariant: a record digests the same outcomes in the same order wherever it runs. Effect: each folder's files and subfolders are sorted as NTFS lists ASCII names - letters folded to upper case, then by byte - rather than taken in the order the file system returns them. NTFS returned them in that order already, so the records, taken on Windows, are unchanged; an ext4 checkout lists a folder in hash order, and on Ubuntu CI the JPEG, EXIF read and listing, Commodore, PNG, HEIF and JPEG XL records digested their outcomes in another order and failed. Observable behavior: unchanged; only a test helper changes. The local Linux build had linked its test folders to the Windows checkout, which lists them in NTFS's order, so it passed where CI failed: with the test files copied to ext4, whose order differs, every record passes. 1,296 tests pass on Windows x64, x86 and Store and 1,290 in Debug x64, and 1,240 on Linux with the test files on ext4; lint is clean. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pre-flight: User-visible behavior. Scope: All scopes - HEIF and AVIF decoding, under every view and scan. Contents: the pixels of a HEIF or AVIF grid image whose tiles decode in different formats, and the time a grid takes to decode. Target: Visible items. Effect: libheif made a grid's canvas from whichever tile a thread finished first and pasted the others into its format, so a damaged grid whose tiles decode in different formats showed one way on one run and another on the next. libfiles 044fd2a decodes the tiles in grid order until one has made the canvas, then the rest in parallel as before: such a grid now always decodes as its first decodable tile makes it. A grid whose tiles agree decodes to the same pixels as before, at most one tile's decoding later - libheif decodes four tiles at a time, so a 48-tile photo takes 13 rounds where it took 12. UI-thread work stays disjoint from decoding and I/O, and the paint layer is untouched. "Should decode HEIFs as load_heif did" holds 2,347 outcomes to da7bc3f5; on CI, Windows Debug x64 and the Store build gave c632c82b. It now holds unconfined and on 4, 2 and 1 cores. 1,296 tests pass on Windows x64, x86 and Store and 1,290 in Debug x64, and 1,240 on Linux with the test files on ext4; lint is clean. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pre-flight: Internal. Component: docs/testing.md. Invariant: the guide names what a test must not depend on. Effect: the rule against depending on ordering now names a folder's listing order - NTFS lists names sorted and ext4 does not - and says why a WSL build from /mnt/c cannot show the dependency, which is how the record tests' reached CI. Observable behavior: unchanged; documentation only. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pre-flight: Internal. Component: src/test_files.cpp, "Should decode HEIFs as load_heif did", and the rule in docs/testing.md. Invariant: the record holds the same 2,347 outcomes on every machine. Effect: dav1d decodes a damaged stream differently with different kernels - here its C kernels give the sweep d9b43129 where its SSE4.1 and AVX2 kernels, with gathers or without, give the record's da7bc3f5. On CI the Windows x64 jobs gave c632c82b on some runners and da7bc3f5 on others, from run to run - six of nine, in Debug, Release and the Store build alike - while x86 and Linux, whose builds never pick dav1d's AVX2 or AVX-512 kernels, never failed. This machine cannot run AVX-512, so that its kernels gave c632c82b is inferred, not seen. The sweep now holds dav1d to its SSE4.1 kernels while it runs, through the mask dav1d exports for its own tools, and restores the mask after. Holding it to its C kernels instead fails the record with d9b43129, so the pin is in force. FFmpeg's HEVC decode gives da7bc3f5 with its C kernels too, so it needs no pin. Observable behavior: unchanged; only a test and the testing guide change. 1,296 tests pass on Windows x64, x86 and Store and 1,290 in Debug x64, and 1,240 on Linux with the test files on ext4; lint is clean. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pre-flight: User-visible behavior. Scope: All scopes - HEIF and AVIF decoding, under every view and scan. Contents: the pixels of a HEIF or AVIF grid image whose tiles decode in different formats, and the time a grid takes to decode. Target: Visible items. Effect: This undoes 25ff009. A grid decodes as libheif releases it again, all its tiles in parallel from the first: a grid whose tiles agree decodes to the same pixels, up to one tile's decoding sooner, and a damaged grid whose tiles decode in different formats takes the format of whichever tile finishes first, as before 25ff009. That commit was made for the HEIF record's c632c82b on CI, which came from dav1d's kernels instead (4d32149): the record failed with it as without it. UI-thread work stays disjoint from decoding and I/O, and the paint layer is untouched. With libheif's grid as released and dav1d's kernels pinned, the record holds da7bc3f5 unconfined and on 4, 2 and 1 cores. 1,296 tests pass on Windows x64, x86 and Store, and 1,240 on Linux with the test files on ext4; lint is clean. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pre-flight: User-visible behavior.
Scope: All scopes - the file layer, the platform layer and the build.
Contents: how every file is scanned, decoded and encoded, and its metadata
read, listed and written; the foundation, OS services and desktop UI; how
the dependencies are acquired.
Target: Visible items, and every build: Windows x64, x86 and Store, and
Linux.
Effect: Files read, show and save as before, but for the faults the moves'
records found and fixed, and JPX and WBMP metadata, now kept in a sidecar -
each listed below. UI-thread work stays disjoint from decoding and I/O, and
the paint layer is untouched.
master accepts only squash merges, so this lands as one commit: the week's work, and v1.27.3's 43 commits beneath it, which the v1.27.3 branch keeps. The
repository's URLs point at github.com/ZacWalk.
Files. libfiles, pinned at 2ec5a07, does what Diffractor's files code and
Adobe's XMP Toolkit did, and Diffractor's copies are deleted. XMP is read and
written with its data model - the toolkit and Expat are gone - and through
it Diffractor scans stills, HEIF, JPEG XL and raw files; writes the metadata
of every format it embeds it in, patching an edit that fits in place and
staging one that moves the file in one pass; decodes PSD, JPEG, PNG, WebP,
HEIF, AVIF, JPEG XL and raw files; lists Commodore 64 media; and encodes
JPEG, PNG and WebP and turns JPEGs losslessly. EXIF is read, written and
listed only through libfiles - libexif is gone - and IPTC is read through
it. Each move was held to a record of the old code's outcomes over the
fixtures; where the old code was wrong, the move fixed it:
patches the block in place, keeping its maker note;
and edited.
Platform. The foundation (df::, str::), the OS services (platform::) and the
desktop UI (ui::) are libdesktop's system and render modules, pinned at
184bdd0, and Diffractor's copies are deleted; its own side of FFmpeg's
hardware decoding, its resource script and its Linux entry point stay here.
Dates read alike on Windows and Linux, a date out of range is no date on
Linux either, and an audio endpoint is laid out by its channel count, not its
speaker mask, which could overrun the endpoint's ring.
Dependencies. Nothing is vendored: third-party/, Include/ and .gitmodules are
gone. bzip2, liblzma, SQLite, minizip-ng, libarchive, Hunspell and libopenmpt
are fetched at their releases and the FFmpeg fork at its commit, each by
SHA-256; the codecs come with libfiles and RapidJSON with libdesktop; NASM
and 7-Zip are fetched by SHA-256; and libebml, libmatroska and utf8cpp, which
nothing used, are dropped. docs/third-party.md lists each pin.
1,296 tests pass on Windows x64, x86 and Store and 1,240 on Linux; lint is
clean.
One commit for the week's work. The commits it was made from, each with its
Pre-flight and its record, are kept on the local branch
backup/pre-squash-2026-10-25:
Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com