From aa7d577032467763f7551e4c3556b92d17c5f5dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A3o=20Gottwald?= Date: Mon, 16 Sep 2024 19:53:42 +0000 Subject: [PATCH 001/115] Bug 1918676 - Disable tab opening / closing animations and tab size locking in vertical mode, properly set --tab-min-width rather than overriding min-width in vertical mode, and restrict some styles to horizontal mode. r=sidebar-reviewers,desktop-theme-reviewers,tabbrowser-reviewers,emilio,kcochrane,sclements,dwalker Differential Revision: https://phabricator.services.mozilla.com/D222202 --- browser/components/sidebar/browser-sidebar.js | 14 +----- .../tabbrowser/content/tabbrowser.js | 15 ++++--- browser/components/tabbrowser/content/tabs.js | 34 +++++++++++--- browser/themes/shared/tabbrowser/tabs.css | 45 ++++++++++--------- 4 files changed, 65 insertions(+), 43 deletions(-) diff --git a/browser/components/sidebar/browser-sidebar.js b/browser/components/sidebar/browser-sidebar.js index 372bc9eb79baf..ea2579705c7c2 100644 --- a/browser/components/sidebar/browser-sidebar.js +++ b/browser/components/sidebar/browser-sidebar.js @@ -1519,7 +1519,8 @@ var SidebarController = { toggleTabstrip() { let toVerticalTabs = CustomizableUI.verticalTabsEnabled; - let arrowScrollbox = gBrowser.tabContainer.arrowScrollbox; + let tabStrip = gBrowser.tabContainer; + let arrowScrollbox = tabStrip.arrowScrollbox; let currentScrollOrientation = arrowScrollbox.getAttribute("orient"); if ( @@ -1530,7 +1531,6 @@ var SidebarController = { return; } - let tabStrip = gBrowser.tabContainer; if (toVerticalTabs) { this.toggleExpanded(this._sidebarMain.expanded); arrowScrollbox.setAttribute("orient", "vertical"); @@ -1544,16 +1544,6 @@ var SidebarController = { let verticalToolbar = document.getElementById( CustomizableUI.AREA_VERTICAL_TABSTRIP ); - let indicatorTabs = gBrowser.visibleTabs.filter(tab => { - return ( - tab.hasAttribute("soundplaying") || - tab.hasAttribute("muted") || - tab.hasAttribute("activemedia-blocked") - ); - }); - for (const indicatorTab of indicatorTabs) { - tabStrip.updateTabIndicatorAttr(indicatorTab); - } verticalToolbar.toggleAttribute("visible", toVerticalTabs); }, }; diff --git a/browser/components/tabbrowser/content/tabbrowser.js b/browser/components/tabbrowser/content/tabbrowser.js index 1f91d92efbe3d..18ab3445472cd 100644 --- a/browser/components/tabbrowser/content/tabbrowser.js +++ b/browser/components/tabbrowser/content/tabbrowser.js @@ -2751,7 +2751,8 @@ let animate = !skipAnimation && !pinned && - this.tabContainer.getAttribute("overflow") != "true" && + !this.tabContainer.verticalMode && + !this.tabContainer.overflowing && !gReduceMotion; let uriInfo = this._determineURIToLoad(uriString, createLazyBrowser); @@ -4160,11 +4161,12 @@ } let lockTabSizing = - !aTab.pinned && - !aTab.hidden && - aTab._fullyOpen && - triggeringEvent?.inputSource == MouseEvent.MOZ_SOURCE_MOUSE && - triggeringEvent?.target.closest(".tabbrowser-tab"); + !this.tabContainer.verticalMode || + (!aTab.pinned && + !aTab.hidden && + aTab._fullyOpen && + triggeringEvent?.inputSource == MouseEvent.MOZ_SOURCE_MOUSE && + triggeringEvent?.target.closest(".tabbrowser-tab")); if (lockTabSizing) { this.tabContainer._lockTabSizing(aTab, tabWidth); } else { @@ -4177,6 +4179,7 @@ isLastTab || aTab.pinned || aTab.hidden || + this.tabContainer.verticalMode || this._removingTabs.size > 3 /* don't want lots of concurrent animations */ || !aTab.hasAttribute( diff --git a/browser/components/tabbrowser/content/tabs.js b/browser/components/tabbrowser/content/tabs.js index a00e4abd30784..6f8f017a07d14 100644 --- a/browser/components/tabbrowser/content/tabs.js +++ b/browser/components/tabbrowser/content/tabs.js @@ -115,14 +115,13 @@ "_tabMinWidthPref", "browser.tabs.tabMinWidth", null, - (pref, prevValue, newValue) => (this._tabMinWidth = newValue), + (pref, prevValue, newValue) => this.#updateTabMinWidth(newValue), newValue => { const LIMIT = 50; return Math.max(newValue, LIMIT); } ); - - this._tabMinWidth = this._tabMinWidthPref; + this.#updateTabMinWidth(this._tabMinWidthPref); CustomizableUI.addListener(this); this._updateNewTabVisibility(); @@ -158,6 +157,19 @@ } this._positionPinnedTabs(); + this.#updateTabMinWidth(); + + let indicatorTabs = gBrowser.visibleTabs.filter(tab => { + return ( + tab.hasAttribute("soundplaying") || + tab.hasAttribute("muted") || + tab.hasAttribute("activemedia-blocked") + ); + }); + for (const indicatorTab of indicatorTabs) { + this.updateTabIndicatorAttr(indicatorTab); + } + super.attributeChangedCallback(name, oldValue, newValue); } @@ -1326,8 +1338,16 @@ return node.before(tab); } - set _tabMinWidth(val) { - this.style.setProperty("--tab-min-width", val + "px"); + #updateTabMinWidth(val) { + const minWidthVariable = "--tab-min-width"; + if (this.verticalMode) { + this.style.removeProperty(minWidthVariable); + } else { + this.style.setProperty( + minWidthVariable, + (val ?? this._tabMinWidthPref) + "px" + ); + } } get _isCustomizing() { @@ -1474,6 +1494,10 @@ * Try to keep the active tab's close button under the mouse cursor */ _lockTabSizing(aTab, aTabWidth) { + if (this.verticalMode) { + return; + } + let tabs = this._getVisibleTabs(); if (!tabs.length) { return; diff --git a/browser/themes/shared/tabbrowser/tabs.css b/browser/themes/shared/tabbrowser/tabs.css index 2cde31d8cf2f3..e845b2db3c8cc 100644 --- a/browser/themes/shared/tabbrowser/tabs.css +++ b/browser/themes/shared/tabbrowser/tabs.css @@ -50,24 +50,32 @@ } #tabbrowser-tabs { - --tab-min-width: 76px; - --tab-overflow-pinned-tabs-width: 0px; - padding-inline: var(--tab-overflow-pinned-tabs-width) 0; /* Use a bigger flex value than the searchbar to prevent it from * taking all the toolbar space. */ flex: 1000 1000; - &[orient="horizontal"][positionpinnedtabs] > #tabbrowser-arrowscrollbox::part(scrollbox) { - /* Add padding to match the shadow's blur radius so the - shadow doesn't get clipped when either the first or - last tab is selected */ - padding-inline: var(--tab-shadow-max-size); - } + &[orient="horizontal"] { + --tab-overflow-pinned-tabs-width: 0px; + padding-inline: var(--tab-overflow-pinned-tabs-width) 0; + + --tab-min-width: 76px; + :root[uidensity="touch"] & { + /* Touch mode needs additional space for the close button. */ + --tab-min-width: 86px; + } + + &[positionpinnedtabs] > #tabbrowser-arrowscrollbox::part(scrollbox) { + /* Add padding to match the shadow's blur radius so the + shadow doesn't get clipped when either the first or + last tab is selected */ + padding-inline: var(--tab-shadow-max-size); + } - /* Make it easier to drag tabs by expanding the drag area downwards. */ - &[movingtab] { - padding-bottom: 15px; - margin-bottom: -15px; + /* Make it easier to drag tabs by expanding the drag area downwards. */ + &[movingtab] { + padding-bottom: 15px; + margin-bottom: -15px; + } } } @@ -120,11 +128,6 @@ min-width: var(--tab-min-width); transition: min-width 100ms ease-out, max-width 100ms ease-out; - - :root[uidensity=touch] & { - /* Touch mode needs additional space for the close button. */ - min-width: calc(var(--tab-min-width) + 10px); - } } &:not([pinned], [fadein]) { @@ -872,6 +875,7 @@ tab-group { flex-direction: column; align-content: flex-start; grid-gap: var(--space-small); + padding: 0; /* override tabbox.css on macOS */ &[overflow] { border-bottom: var(--tabstrip-inner-border); @@ -892,8 +896,9 @@ tab-group { } &:not([expanded]) { + --tab-min-width: inherit; + .tabbrowser-tab { - min-width: inherit; width: var(--collapsed-tab-width); flex: none; } @@ -904,10 +909,10 @@ tab-group { } &[expanded] { + --tab-min-width: calc(100% - var(--space-medium)); --tab-icon-end-margin: 7.5px; .tabbrowser-tab { - min-width: calc(100% - var(--space-medium)); flex: none; max-width: none; padding: 0; From 06c438b27cc7a374e15ca403af117fe865c369cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A3o=20Gottwald?= Date: Mon, 16 Sep 2024 19:53:43 +0000 Subject: [PATCH 002/115] Bug 1918638 - [Vertical tabs] Stop clipping the tab-background shadow. r=sidebar-reviewers,tabbrowser-reviewers,sclements,kcochrane,dwalker Differential Revision: https://phabricator.services.mozilla.com/D222209 --- browser/themes/shared/tabbrowser/tabs.css | 39 ++++++++++++----------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/browser/themes/shared/tabbrowser/tabs.css b/browser/themes/shared/tabbrowser/tabs.css index e845b2db3c8cc..b447bcf90f964 100644 --- a/browser/themes/shared/tabbrowser/tabs.css +++ b/browser/themes/shared/tabbrowser/tabs.css @@ -11,9 +11,10 @@ &[uidensity=touch] { --tab-min-height: 41px; } - --collapsed-tab-width: 40px; - --inline-tab-padding: var(--space-medium); + --tab-collapsed-width: 40px; + --tab-inline-padding: var(--space-medium); --tab-border-radius: 4px; + --tab-overflow-clip-margin: 2px; --tab-shadow-max-size: 6px; --tab-block-margin: 4px; --tab-icon-end-margin: 5.5px; @@ -111,16 +112,15 @@ border-radius: 0; border-width: 0; margin: 0; - padding: 0 2px; + padding: 0 var(--tab-overflow-clip-margin); align-items: stretch; /* Needed so that overflowing content overflows towards the end rather than getting centered. That prevents tab opening animation from looking off at the start, see bug 1759221. */ justify-content: flex-start; overflow: clip; - /* Needed to avoid clipping the tab-background shadow, which has a 4px blur - * (we only have 2px padding in the inline direction) */ - overflow-clip-margin: 2px; + /* Needed to avoid clipping the tab-background shadow, which has a 4px blur. */ + overflow-clip-margin: var(--tab-overflow-clip-margin); &:not([pinned]) { flex: 100 100; @@ -161,7 +161,7 @@ } .tab-content { - padding: 0 var(--inline-tab-padding); + padding: 0 var(--tab-inline-padding); &:not([pinned]) { min-width: 0; @@ -518,7 +518,7 @@ .tab-close-button { -moz-context-properties: fill, fill-opacity; - margin-inline-end: calc(var(--inline-tab-padding) / -2); + margin-inline-end: calc(var(--tab-inline-padding) / -2); width: 24px; height: 24px; padding: 6px; @@ -808,7 +808,8 @@ tab-group { font: message-box; /* match .tabbrowser-tab on macOS */ min-height: var(--tab-min-height); border-radius: var(--border-radius-medium); - padding: 0 var(--inline-tab-padding); + padding: 0 var(--tab-inline-padding); + margin-inline: var(--tab-overflow-clip-margin); #tabbrowser-tabs[orient="horizontal"] > &, #tabbrowser-tabs[orient="vertical"]:not([expanded]) > & > .toolbarbutton-text { @@ -829,7 +830,7 @@ tab-group { #vertical-tabs { overflow: hidden; display: none; - padding-inline: var(--space-medium); + padding-inline: calc(var(--space-medium) - var(--tab-overflow-clip-margin)); padding-block-start: var(--space-medium); &[visible] { @@ -839,7 +840,7 @@ tab-group { #vertical-pinned-tabs-container { display: grid; - grid-template-columns: repeat(auto-fit, minmax(var(--collapsed-tab-width), auto)); + grid-template-columns: repeat(auto-fit, minmax(var(--tab-collapsed-width), auto)); overflow-y: auto; overflow-x: hidden; scrollbar-width: thin; @@ -870,7 +871,9 @@ tab-group { } #tabbrowser-tabs[orient="vertical"] { - overflow: hidden; + --tab-min-width: unset; + + min-height: 0; display: flex; flex-direction: column; align-content: flex-start; @@ -881,6 +884,10 @@ tab-group { border-bottom: var(--tabstrip-inner-border); } + .tabbrowser-tab { + flex: none; + } + .tab-close-button { display: none; } @@ -896,11 +903,8 @@ tab-group { } &:not([expanded]) { - --tab-min-width: inherit; - .tabbrowser-tab { - width: var(--collapsed-tab-width); - flex: none; + width: var(--tab-collapsed-width); } .tab-label-container { @@ -909,13 +913,10 @@ tab-group { } &[expanded] { - --tab-min-width: calc(100% - var(--space-medium)); --tab-icon-end-margin: 7.5px; .tabbrowser-tab { - flex: none; max-width: none; - padding: 0; &:is(:hover, [selected]):not([pinned]) .tab-close-button { display: flex; From 271f3b10540beae5367bc53d3fb4a492b0f499d2 Mon Sep 17 00:00:00 2001 From: David Parks Date: Mon, 16 Sep 2024 20:07:09 +0000 Subject: [PATCH 003/115] Bug 1915309: Add Windows Geolocation UI to artifact builds r=firefox-build-system-reviewers,nalexander Differential Revision: https://phabricator.services.mozilla.com/D222339 --- dom/geolocation/moz.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dom/geolocation/moz.build b/dom/geolocation/moz.build index ef3cef6d049d4..4f9bf41b67341 100644 --- a/dom/geolocation/moz.build +++ b/dom/geolocation/moz.build @@ -38,7 +38,7 @@ UNIFIED_SOURCES += [ # Permission UI so it uses the platform-agnostic version. if ( CONFIG["OS_TARGET"] == "WINNT" - and CONFIG["CC_TYPE"] == "clang-cl" + and (CONFIG["CC_TYPE"] == "clang-cl" or CONFIG["MOZ_ARTIFACT_BUILDS"]) and CONFIG["MOZ_BUILD_APP"] == "browser" ): UNIFIED_SOURCES += [ From 0899941f1087b5f0e6b579a33eeb9eadade78310 Mon Sep 17 00:00:00 2001 From: Sanchaai Mathiyarasan Date: Mon, 16 Sep 2024 20:29:29 +0000 Subject: [PATCH 004/115] Bug 1907086 - Implement the max height of the menu. r=android-reviewers,petru When expanded, the height of the menu should match the Figma specifications as mentioned here: https://www.figma.com/design/RFz9fYtotQCQuinwcZujZt/Menu-Redesign?node-id=15937-406408&t=q4Tbc8EJllfh5xF0-4 Differential Revision: https://phabricator.services.mozilla.com/D217864 --- .../org/mozilla/fenix/components/menu/MenuDialogFragment.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/menu/MenuDialogFragment.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/menu/MenuDialogFragment.kt index 905ba3887021d..75426648cb748 100644 --- a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/menu/MenuDialogFragment.kt +++ b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/menu/MenuDialogFragment.kt @@ -81,7 +81,7 @@ import org.mozilla.fenix.utils.exitSubmenu // three states instead of the expected two states required by design. private const val PEEK_HEIGHT = 460 private const val EXPANDED_MIN_RATIO = 0.0001f -private const val TOP_EXPANDED_OFFSET = 80 +private const val EXPANDED_OFFSET = 80 private const val HIDING_FRICTION = 0.9f /** @@ -111,7 +111,7 @@ class MenuDialogFragment : BottomSheetDialogFragment() { isFitToContents = true peekHeight = PEEK_HEIGHT.dpToPx(resources.displayMetrics) halfExpandedRatio = EXPANDED_MIN_RATIO - expandedOffset = TOP_EXPANDED_OFFSET + maxHeight = resources.displayMetrics.heightPixels - EXPANDED_OFFSET.dpToPx(resources.displayMetrics) state = BottomSheetBehavior.STATE_COLLAPSED hideFriction = HIDING_FRICTION } From 2ce4eb86d1072089057914d3ebc2c83ef862d2f8 Mon Sep 17 00:00:00 2001 From: Andreas Pehrson Date: Mon, 16 Sep 2024 20:34:21 +0000 Subject: [PATCH 005/115] Bug 1918746 - Don't stop video capturers before reconfiguring them. r=grulja,webrtc-reviewers,jib Already today we reconfigure capturers without stopping them in cases where they are shared between multiple gUM/gDM requests: We find the device capability (for cameras) that satisfies all the requested capabilities (downscaling, frame dropping allowed) and call StartCapture again with that. Thus, there is no concern about camera backends not supporting this call sequence. Desktop capture backends have a simpler API (only Start, for Stop they have to be destroyed) and are not actually re-started. Resolution is always captured in full and frame rate is controlled by the timer that triggers CaptureFrame(). This patch makes content processes not request capture to be stopped when updating their requested capability. This means the path described above will be exercised more. This also brings with it some invariants that no longer hold, but are handled explicitly instead: capabilities for a captureId may now be updated on the fly, without prior removal. Differential Revision: https://phabricator.services.mozilla.com/D222242 --- dom/media/systemservices/CamerasParent.cpp | 70 +++++++++++-------- .../video_engine/desktop_capture_impl.cc | 32 ++++++--- .../video_engine/desktop_capture_impl.h | 1 + .../webrtc/MediaEngineRemoteVideoSource.cpp | 17 +---- 4 files changed, 69 insertions(+), 51 deletions(-) diff --git a/dom/media/systemservices/CamerasParent.cpp b/dom/media/systemservices/CamerasParent.cpp index d6fe5986da17e..044c2963cf952 100644 --- a/dom/media/systemservices/CamerasParent.cpp +++ b/dom/media/systemservices/CamerasParent.cpp @@ -902,7 +902,6 @@ ipc::IPCResult CamerasParent::RecvStartCapture( mVideoCaptureThread, __func__, [this, self = RefPtr(this), aCapEngine, aCaptureId, aIpcCaps] { LOG_FUNCTION(); - CallbackHelper** cbh; int error = -1; if (!EnsureInitialized(aCapEngine)) { @@ -910,9 +909,6 @@ ipc::IPCResult CamerasParent::RecvStartCapture( "CamerasParent::RecvStartCapture"); } - cbh = mCallbacks.AppendElement(new CallbackHelper( - static_cast(aCapEngine), aCaptureId, this)); - mEngines->ElementAt(aCapEngine) ->WithEntry(aCaptureId, [&](VideoEngine::CaptureEntry& cap) { webrtc::VideoCaptureCapability capability; @@ -923,19 +919,21 @@ ipc::IPCResult CamerasParent::RecvStartCapture( static_cast(aIpcCaps.videoType()); capability.interlaced = aIpcCaps.interlaced(); -#ifndef FUZZING_SNAPSHOT - MOZ_DIAGNOSTIC_ASSERT(sDeviceUniqueIDs.find(aCaptureId) == - sDeviceUniqueIDs.end()); -#endif - sDeviceUniqueIDs.emplace(aCaptureId, - cap.VideoCapture()->CurrentDeviceName()); - -#ifndef FUZZING_SNAPSHOT - MOZ_DIAGNOSTIC_ASSERT( - sAllRequestedCapabilities.find(aCaptureId) == - sAllRequestedCapabilities.end()); -#endif - sAllRequestedCapabilities.emplace(aCaptureId, capability); + if (sDeviceUniqueIDs.find(aCaptureId) == sDeviceUniqueIDs.end()) { + sDeviceUniqueIDs.emplace( + aCaptureId, cap.VideoCapture()->CurrentDeviceName()); + sAllRequestedCapabilities.emplace(aCaptureId, capability); + } else { + // Starting capture for an id that already exists. Update its + // requested capability. + MOZ_DIAGNOSTIC_ASSERT( + strcmp(sDeviceUniqueIDs[aCaptureId], + cap.VideoCapture()->CurrentDeviceName()) == 0); + MOZ_DIAGNOSTIC_ASSERT( + sAllRequestedCapabilities.find(aCaptureId) != + sAllRequestedCapabilities.end()); + sAllRequestedCapabilities[aCaptureId] = capability; + } if (aCapEngine == CameraEngine) { for (const auto& it : sDeviceUniqueIDs) { @@ -999,20 +997,36 @@ ipc::IPCResult CamerasParent::RecvStartCapture( } } - cap.VideoCapture()->SetTrackingId( - (*cbh)->mTrackingId.mUniqueInProcId); + bool cbhExists = false; + CallbackHelper** cbh = nullptr; + for (auto* cb : mCallbacks) { + if (cb->mCapEngine == aCapEngine && + cb->mStreamId == (uint32_t)aCaptureId) { + cbhExists = true; + break; + } + } + if (!cbhExists) { + cbh = mCallbacks.AppendElement(new CallbackHelper( + static_cast(aCapEngine), aCaptureId, this)); + cap.VideoCapture()->SetTrackingId( + (*cbh)->mTrackingId.mUniqueInProcId); + } + error = cap.VideoCapture()->StartCapture(capability); if (!error) { - cap.VideoCapture()->RegisterCaptureDataCallback( - static_cast*>( - *cbh)); - if (auto* event = cap.CaptureEndedEvent(); - event && !(*cbh)->mConnectedToCaptureEnded) { - (*cbh)->mCaptureEndedListener = - event->Connect(mVideoCaptureThread, (*cbh), - &CallbackHelper::OnCaptureEnded); - (*cbh)->mConnectedToCaptureEnded = true; + if (cbh) { + cap.VideoCapture()->RegisterCaptureDataCallback( + static_cast*>( + *cbh)); + if (auto* event = cap.CaptureEndedEvent(); + event && !(*cbh)->mConnectedToCaptureEnded) { + (*cbh)->mCaptureEndedListener = + event->Connect(mVideoCaptureThread, (*cbh), + &CallbackHelper::OnCaptureEnded); + (*cbh)->mConnectedToCaptureEnded = true; + } } } else { sDeviceUniqueIDs.erase(aCaptureId); diff --git a/dom/media/systemservices/video_engine/desktop_capture_impl.cc b/dom/media/systemservices/video_engine/desktop_capture_impl.cc index 8fc2de94e4a9a..c43a1b3b24510 100644 --- a/dom/media/systemservices/video_engine/desktop_capture_impl.cc +++ b/dom/media/systemservices/video_engine/desktop_capture_impl.cc @@ -315,15 +315,22 @@ int32_t DesktopCaptureImpl::StartCapture( const VideoCaptureCapability& aCapability) { RTC_DCHECK_RUN_ON(&mControlThreadChecker); + const int maxFps = std::max(aCapability.maxFPS, 1); if (mRequestedCapability) { - // Already initialized - MOZ_ASSERT(*mRequestedCapability == aCapability); - + MOZ_DIAGNOSTIC_ASSERT(mCaptureThread); + if (std::max(mRequestedCapability->maxFPS, 1) == maxFps) { + // No change in effective requested capability (only knob is fps). + return 0; + } + mRequestedCapability = mozilla::Some(aCapability); + MOZ_ALWAYS_SUCCEEDS(mCaptureThread->Dispatch( + NS_NewRunnableFunction("DesktopCaptureImpl::UpdateOnThread", + [this, self = RefPtr(this), maxFps]() mutable { + UpdateOnThread(maxFps); + }))); return 0; } - MOZ_ASSERT(!mCaptureThread); - DesktopCapturer::SourceId sourceId = std::stoi(mDeviceUniqueId); std::unique_ptr capturer = CreateDesktopCapturerAndThread( mDeviceType, sourceId, getter_AddRefs(mCaptureThread)); @@ -339,9 +346,7 @@ int32_t DesktopCaptureImpl::StartCapture( MOZ_ALWAYS_SUCCEEDS(mCaptureThread->Dispatch(NS_NewRunnableFunction( "DesktopCaptureImpl::InitOnThread", [this, self = RefPtr(this), capturer = std::move(capturer), - maxFps = std::max(aCapability.maxFPS, 1)]() mutable { - InitOnThread(std::move(capturer), maxFps); - }))); + maxFps]() mutable { InitOnThread(std::move(capturer), maxFps); }))); return 0; } @@ -523,6 +528,17 @@ void DesktopCaptureImpl::InitOnThread( CaptureFrameOnThread(); } +void DesktopCaptureImpl::UpdateOnThread(int aFramerate) { + RTC_DCHECK_RUN_ON(&mCaptureThreadChecker); + MOZ_DIAGNOSTIC_ASSERT(mCapturer); + MOZ_DIAGNOSTIC_ASSERT(mCaptureTimer); + + mRequestedCaptureInterval = mozilla::Some( + TimeDuration::FromSeconds(1. / static_cast(aFramerate))); + + CaptureFrameOnThread(); +} + void DesktopCaptureImpl::ShutdownOnThread() { RTC_DCHECK_RUN_ON(&mCaptureThreadChecker); if (mCaptureTimer) { diff --git a/dom/media/systemservices/video_engine/desktop_capture_impl.h b/dom/media/systemservices/video_engine/desktop_capture_impl.h index 0f98c4b3c9561..a76b7de569db1 100644 --- a/dom/media/systemservices/video_engine/desktop_capture_impl.h +++ b/dom/media/systemservices/video_engine/desktop_capture_impl.h @@ -96,6 +96,7 @@ class DesktopCaptureImpl : public DesktopCapturer::Callback, // Maximum CPU usage in %. static constexpr uint32_t kMaxDesktopCaptureCpuUsage = 50; void InitOnThread(std::unique_ptr aCapturer, int aFramerate); + void UpdateOnThread(int aFramerate); void ShutdownOnThread(); // DesktopCapturer::Callback interface. void OnCaptureResult(DesktopCapturer::Result aResult, diff --git a/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp b/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp index 594f890b80a35..72e09fd24d3aa 100644 --- a/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp +++ b/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp @@ -216,7 +216,7 @@ nsresult MediaEngineRemoteVideoSource::Start() { LOG("%s", __PRETTY_FUNCTION__); AssertIsOnOwningThread(); - MOZ_ASSERT(mState == kAllocated || mState == kStopped); + MOZ_ASSERT(mState == kAllocated || mState == kStarted || mState == kStopped); MOZ_ASSERT(mTrack); { @@ -317,26 +317,13 @@ nsresult MediaEngineRemoteVideoSource::Reconfigure( return NS_OK; } - bool started = mState == kStarted; - if (started) { - nsresult rv = Stop(); - if (NS_WARN_IF(NS_FAILED(rv))) { - nsAutoCString name; - GetErrorName(rv, name); - LOG("Video source %p for video device %d Reconfigure() failed " - "unexpectedly in Stop(). rv=%s", - this, mCaptureId, name.Data()); - return NS_ERROR_UNEXPECTED; - } - } - { MutexAutoLock lock(mMutex); // Start() applies mCapability on the device. mCapability = newCapability; } - if (started) { + if (mState == kStarted) { nsresult rv = Start(); if (NS_WARN_IF(NS_FAILED(rv))) { nsAutoCString name; From 677047ffe18a0909188ae403b70f5820534af165 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Mon, 16 Sep 2024 20:53:26 +0000 Subject: [PATCH 006/115] Bug 1917017 - Add a null-check in FirePageHideEventForFrameLoaderSwap. r=smaug Not sure what guarantees this in presence of random script running? Differential Revision: https://phabricator.services.mozilla.com/D222335 --- dom/base/nsContentUtils.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index d1b89b13258c9..ad128a0ac398b 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -8914,9 +8914,9 @@ void nsContentUtils::FirePageHideEventForFrameLoaderSwap( MOZ_DIAGNOSTIC_ASSERT(aItem); MOZ_DIAGNOSTIC_ASSERT(aChromeEventHandler); - RefPtr doc = aItem->GetDocument(); - NS_ASSERTION(doc, "What happened here?"); - doc->OnPageHide(true, aChromeEventHandler, aOnlySystemGroup); + if (RefPtr doc = aItem->GetDocument()) { + doc->OnPageHide(true, aChromeEventHandler, aOnlySystemGroup); + } int32_t childCount = 0; aItem->GetInProcessChildCount(&childCount); From 16d3f6f70f57d9313741fd166e226aab6e43e236 Mon Sep 17 00:00:00 2001 From: John Schanck Date: Mon, 16 Sep 2024 20:53:32 +0000 Subject: [PATCH 007/115] Bug 1919097 - set security.tls.enable_kyber to true by default on desktop. r=keeler Differential Revision: https://phabricator.services.mozilla.com/D222330 --- modules/libpref/init/StaticPrefList.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml index 2b07a0bb74d42..8230e627efaeb 100644 --- a/modules/libpref/init/StaticPrefList.yaml +++ b/modules/libpref/init/StaticPrefList.yaml @@ -15587,7 +15587,7 @@ - name: security.tls.enable_kyber type: RelaxedAtomicBool - value: false + value: @IS_NOT_ANDROID@ mirror: always rust: true From 49cabef3ab30b489b33f560a79194d3989151d98 Mon Sep 17 00:00:00 2001 From: Roger Yang Date: Mon, 16 Sep 2024 21:06:39 +0000 Subject: [PATCH 008/115] Bug 1917640 - Update toolbar default position to top r=android-reviewers,skhan,harrisono Differential Revision: https://phabricator.services.mozilla.com/D222020 --- mobile/android/fenix/app/.experimenter.yaml | 8 -------- mobile/android/fenix/app/nimbus.fml.yaml | 7 ------- .../fenix/helpers/FeatureSettingsHelper.kt | 5 +++++ .../helpers/FeatureSettingsHelperDelegate.kt | 4 ++++ .../fenix/helpers/HomeActivityTestRule.kt | 11 +++++++++++ .../java/org/mozilla/fenix/ui/CollectionTest.kt | 3 +++ .../org/mozilla/fenix/ui/ContextMenusTest.kt | 3 +++ .../java/org/mozilla/fenix/ui/HistoryTest.kt | 3 +++ .../java/org/mozilla/fenix/ui/SearchTest.kt | 3 +++ .../java/org/mozilla/fenix/utils/Settings.kt | 17 ++--------------- .../org/mozilla/fenix/utils/SettingsTest.kt | 9 --------- 11 files changed, 34 insertions(+), 39 deletions(-) diff --git a/mobile/android/fenix/app/.experimenter.yaml b/mobile/android/fenix/app/.experimenter.yaml index b8cdf14cfecb7..d78513f57c11f 100644 --- a/mobile/android/fenix/app/.experimenter.yaml +++ b/mobile/android/fenix/app/.experimenter.yaml @@ -224,14 +224,6 @@ splash-screen: maximum_duration_ms: type: int description: The maximum amount of time in milliseconds the splashscreen will be visible while waiting for initialization calls to complete. -toolbar: - description: The searchbar/awesomebar that user uses to search. - hasExposure: true - exposureDescription: "" - variables: - toolbar-position-top: - type: boolean - description: "If true, toolbar appears at top of the screen." unified-search: description: A feature allowing user to easily search for specified results directly in the search bar. hasExposure: true diff --git a/mobile/android/fenix/app/nimbus.fml.yaml b/mobile/android/fenix/app/nimbus.fml.yaml index 44ea89b03edf4..34c3182b0d5b7 100644 --- a/mobile/android/fenix/app/nimbus.fml.yaml +++ b/mobile/android/fenix/app/nimbus.fml.yaml @@ -35,13 +35,6 @@ import: } features: - toolbar: - description: The searchbar/awesomebar that user uses to search. - variables: - toolbar-position-top: - description: If true, toolbar appears at top of the screen. - type: Boolean - default: false homescreen: description: The homescreen that the user goes to when they press home or new tab. variables: diff --git a/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/helpers/FeatureSettingsHelper.kt b/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/helpers/FeatureSettingsHelper.kt index 34bb7a0d44a42..706bb0dd8b225 100644 --- a/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/helpers/FeatureSettingsHelper.kt +++ b/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/helpers/FeatureSettingsHelper.kt @@ -104,6 +104,11 @@ interface FeatureSettingsHelper { */ var isSetAsDefaultBrowserPromptEnabled: Boolean + /** + * Enable or disable bottom toolbar position. + */ + var shouldUseBottomToolbar: Boolean + fun applyFlagUpdates() fun resetAllFeatureFlags() diff --git a/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/helpers/FeatureSettingsHelperDelegate.kt b/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/helpers/FeatureSettingsHelperDelegate.kt index df63b34081d7c..8b515ee2bc1b4 100644 --- a/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/helpers/FeatureSettingsHelperDelegate.kt +++ b/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/helpers/FeatureSettingsHelperDelegate.kt @@ -47,6 +47,7 @@ class FeatureSettingsHelperDelegate() : FeatureSettingsHelper { isNavigationToolbarEnabled = settings.navigationToolbarEnabled, isMicrosurveyEnabled = settings.microsurveyFeatureEnabled, isSetAsDefaultBrowserPromptEnabled = settings.setAsDefaultBrowserPromptForExistingUsersEnabled, + shouldUseBottomToolbar = settings.shouldUseBottomToolbar, ) /** @@ -80,6 +81,7 @@ class FeatureSettingsHelperDelegate() : FeatureSettingsHelper { override var isNavigationToolbarEnabled: Boolean by updatedFeatureFlags::isNavigationToolbarEnabled override var isMicrosurveyEnabled: Boolean by updatedFeatureFlags::isMicrosurveyEnabled override var isSetAsDefaultBrowserPromptEnabled: Boolean by updatedFeatureFlags::isSetAsDefaultBrowserPromptEnabled + override var shouldUseBottomToolbar: Boolean by updatedFeatureFlags::shouldUseBottomToolbar override fun applyFlagUpdates() { Log.i(TAG, "applyFlagUpdates: Trying to apply the updated feature flags: $updatedFeatureFlags") @@ -112,6 +114,7 @@ class FeatureSettingsHelperDelegate() : FeatureSettingsHelper { settings.navigationToolbarEnabled = featureFlags.isNavigationToolbarEnabled settings.microsurveyFeatureEnabled = featureFlags.isMicrosurveyEnabled settings.setAsDefaultBrowserPromptForExistingUsersEnabled = featureFlags.isSetAsDefaultBrowserPromptEnabled + settings.shouldUseBottomToolbar = featureFlags.shouldUseBottomToolbar setETPPolicy(featureFlags.etpPolicy) setPermissions(PhoneFeature.LOCATION, featureFlags.isLocationPermissionEnabled) } @@ -136,6 +139,7 @@ private data class FeatureFlags( var isNavigationToolbarEnabled: Boolean, var isMicrosurveyEnabled: Boolean, var isSetAsDefaultBrowserPromptEnabled: Boolean, + var shouldUseBottomToolbar: Boolean, ) internal fun getETPPolicy(settings: Settings): ETPPolicy { diff --git a/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/helpers/HomeActivityTestRule.kt b/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/helpers/HomeActivityTestRule.kt index e6e391cd4836b..c23afba008f60 100644 --- a/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/helpers/HomeActivityTestRule.kt +++ b/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/helpers/HomeActivityTestRule.kt @@ -64,6 +64,7 @@ class HomeActivityTestRule( isNavigationToolbarEnabled: Boolean = false, isMicrosurveyEnabled: Boolean = settings.microsurveyFeatureEnabled, isSetAsDefaultBrowserPromptEnabled: Boolean = settings.setAsDefaultBrowserPromptForExistingUsersEnabled, + shouldUseBottomToolbar: Boolean = settings.shouldUseBottomToolbar, ) : this(initialTouchMode, launchActivity, skipOnboarding) { this.isHomeOnboardingDialogEnabled = isHomeOnboardingDialogEnabled this.isPocketEnabled = isPocketEnabled @@ -82,6 +83,7 @@ class HomeActivityTestRule( this.isNavigationToolbarEnabled = isNavigationToolbarEnabled this.isMicrosurveyEnabled = isMicrosurveyEnabled this.isSetAsDefaultBrowserPromptEnabled = isSetAsDefaultBrowserPromptEnabled + this.shouldUseBottomToolbar = shouldUseBottomToolbar } /** @@ -144,6 +146,9 @@ class HomeActivityTestRule( composeTopSitesEnabled = composeTopSitesEnabled, isMicrosurveyEnabled = false, isSetAsDefaultBrowserPromptEnabled = false, + // workaround for toolbar at top position by default + // remove with https://bugzilla.mozilla.org/show_bug.cgi?id=1917640 + shouldUseBottomToolbar = true, ) } } @@ -187,6 +192,7 @@ class HomeActivityIntentTestRule internal constructor( isNavigationToolbarEnabled: Boolean = false, isMicrosurveyEnabled: Boolean = settings.microsurveyFeatureEnabled, isSetAsDefaultBrowserPromptEnabled: Boolean = settings.setAsDefaultBrowserPromptForExistingUsersEnabled, + shouldUseBottomToolbar: Boolean = settings.shouldUseBottomToolbar, ) : this(initialTouchMode, launchActivity, skipOnboarding) { this.isHomeOnboardingDialogEnabled = isHomeOnboardingDialogEnabled this.isPocketEnabled = isPocketEnabled @@ -205,6 +211,7 @@ class HomeActivityIntentTestRule internal constructor( this.isNavigationToolbarEnabled = isNavigationToolbarEnabled this.isMicrosurveyEnabled = isMicrosurveyEnabled this.isSetAsDefaultBrowserPromptEnabled = isSetAsDefaultBrowserPromptEnabled + this.shouldUseBottomToolbar = shouldUseBottomToolbar } private val longTapUserPreference = getLongPressTimeout() @@ -278,6 +285,7 @@ class HomeActivityIntentTestRule internal constructor( isNavigationToolbarEnabled = settings.navigationToolbarEnabled isMicrosurveyEnabled = settings.microsurveyFeatureEnabled isSetAsDefaultBrowserPromptEnabled = settings.setAsDefaultBrowserPromptForExistingUsersEnabled + shouldUseBottomToolbar = settings.shouldUseBottomToolbar } companion object { @@ -308,6 +316,9 @@ class HomeActivityIntentTestRule internal constructor( composeTopSitesEnabled = composeTopSitesEnabled, isMicrosurveyEnabled = false, isSetAsDefaultBrowserPromptEnabled = false, + // workaround for toolbar at top position by default + // remove with https://bugzilla.mozilla.org/show_bug.cgi?id=1917640 + shouldUseBottomToolbar = true, ) } } diff --git a/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/ui/CollectionTest.kt b/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/ui/CollectionTest.kt index 5818b2a7b2abd..4b9b940e7261f 100644 --- a/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/ui/CollectionTest.kt +++ b/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/ui/CollectionTest.kt @@ -42,6 +42,9 @@ class CollectionTest : TestSetup() { isPocketEnabled = false, isWallpaperOnboardingEnabled = false, isTCPCFREnabled = false, + // workaround for toolbar at top position by default + // remove with https://bugzilla.mozilla.org/show_bug.cgi?id=1917640 + shouldUseBottomToolbar = true, ), ) { it.activity } diff --git a/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/ui/ContextMenusTest.kt b/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/ui/ContextMenusTest.kt index 38ed4b464f388..3fae6460adfb6 100644 --- a/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/ui/ContextMenusTest.kt +++ b/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/ui/ContextMenusTest.kt @@ -47,6 +47,9 @@ class ContextMenusTest : TestSetup() { AndroidComposeTestRule( HomeActivityIntentTestRule( isJumpBackInCFREnabled = false, + // workaround for toolbar at top position by default + // remove with https://bugzilla.mozilla.org/show_bug.cgi?id=1917640 + shouldUseBottomToolbar = true, ), ) { it.activity } diff --git a/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/ui/HistoryTest.kt b/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/ui/HistoryTest.kt index 436763ccd7cee..c8cb6c445f62b 100644 --- a/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/ui/HistoryTest.kt +++ b/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/ui/HistoryTest.kt @@ -36,6 +36,9 @@ class HistoryTest : TestSetup() { AndroidComposeTestRule( HomeActivityIntentTestRule( isJumpBackInCFREnabled = false, + // workaround for toolbar at top position by default + // remove with https://bugzilla.mozilla.org/show_bug.cgi?id=1917640 + shouldUseBottomToolbar = true, ), ) { it.activity } diff --git a/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/ui/SearchTest.kt b/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/ui/SearchTest.kt index 7f33fb2903e07..7b1b155c05348 100644 --- a/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/ui/SearchTest.kt +++ b/mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/ui/SearchTest.kt @@ -74,6 +74,9 @@ class SearchTest : TestSetup() { isTCPCFREnabled = false, isWallpaperOnboardingEnabled = false, isLocationPermissionEnabled = SitePermissionsRules.Action.BLOCKED, + // workaround for toolbar at top position by default + // remove with https://bugzilla.mozilla.org/show_bug.cgi?id=1917640 + shouldUseBottomToolbar = true, ), ) { it.activity } diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/utils/Settings.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/utils/Settings.kt index 4816c3c908f2f..c14f571d94103 100644 --- a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/utils/Settings.kt +++ b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/utils/Settings.kt @@ -949,10 +949,9 @@ class Settings(private val appContext: Context) : PreferencesHolder { default = true, ) - var shouldUseBottomToolbar by lazyFeatureFlagPreference( + var shouldUseBottomToolbar by booleanPreference( appContext.getPreferenceKey(R.string.pref_key_toolbar_bottom), - featureFlag = true, - default = { shouldDefaultToBottomToolbar() }, + default = false, ) val toolbarPosition: ToolbarPosition @@ -996,18 +995,6 @@ class Settings(private val appContext: Context) : PreferencesHolder { return touchExplorationIsEnabled || switchServiceIsEnabled } - val toolbarPositionTop: Boolean - get() = FxNimbus.features.toolbar.value().toolbarPositionTop - - /** - * Checks if we should default to bottom toolbar. - */ - fun shouldDefaultToBottomToolbar(): Boolean { - // Default accessibility users to top toolbar - return (!touchExplorationIsEnabled && !switchServiceIsEnabled) && - !toolbarPositionTop - } - fun getDeleteDataOnQuit(type: DeleteBrowsingDataOnQuitType): Boolean = preferences.getBoolean(type.getPreferenceKey(appContext), false) diff --git a/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/utils/SettingsTest.kt b/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/utils/SettingsTest.kt index ff857fcdff9ae..e983189817a27 100644 --- a/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/utils/SettingsTest.kt +++ b/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/utils/SettingsTest.kt @@ -863,15 +863,6 @@ class SettingsTest { assertTrue(actual) } - @Test - fun `GIVEN toolbarPositionTop is false, touchExplorationIsEnabled is true THEN shouldDefaultToBottomToolbar returns false`() { - val settings = spyk(settings) - every { settings.toolbarPositionTop } returns true - every { settings.touchExplorationIsEnabled } returns true - - assertEquals(false, settings.shouldDefaultToBottomToolbar()) - } - @Test fun `GIVEN Https-only mode is disabled THEN the engine mode is HttpsOnlyMode#DISABLED`() { settings.shouldUseHttpsOnly = false From feb335de17df3226a79f3c690931cd34615dc5c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Mon, 16 Sep 2024 21:09:31 +0000 Subject: [PATCH 009/115] Bug 1634785 - Move SharedLibrary IPC ParamTraits outside of shared library header file r=mstange,profiler-reviewers We will remove the libxul implementation soon and use the one in mozglue. We can't keep these structs inside the mozglue, so we have to move them to somewhere else in libxul. This file made the most sense since it's the one who implements their methods. Differential Revision: https://phabricator.services.mozilla.com/D220880 --- .../core/ProfileAdditionalInformation.cpp | 16 ++++++++++++++++ tools/profiler/public/shared-libraries.h | 18 ------------------ 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/tools/profiler/core/ProfileAdditionalInformation.cpp b/tools/profiler/core/ProfileAdditionalInformation.cpp index 5c9a0d52e446c..c4be4f56504b4 100644 --- a/tools/profiler/core/ProfileAdditionalInformation.cpp +++ b/tools/profiler/core/ProfileAdditionalInformation.cpp @@ -40,6 +40,22 @@ void mozilla::ProfileGenerationAdditionalInformation::ToJSValue( namespace IPC { +template <> +struct ParamTraits { + typedef SharedLibrary paramType; + + static void Write(MessageWriter* aWriter, const paramType& aParam); + static bool Read(MessageReader* aReader, paramType* aResult); +}; + +template <> +struct ParamTraits { + typedef SharedLibraryInfo paramType; + + static void Write(MessageWriter* aWriter, const paramType& aParam); + static bool Read(MessageReader* aReader, paramType* aResult); +}; + void IPC::ParamTraits::Write(MessageWriter* aWriter, const paramType& aParam) { WriteParam(aWriter, aParam.mStart); diff --git a/tools/profiler/public/shared-libraries.h b/tools/profiler/public/shared-libraries.h index 9b36d0fc3f98b..606571882342e 100644 --- a/tools/profiler/public/shared-libraries.h +++ b/tools/profiler/public/shared-libraries.h @@ -199,22 +199,4 @@ class SharedLibraryInfo { friend struct IPC::ParamTraits; }; -namespace IPC { -template <> -struct ParamTraits { - typedef SharedLibrary paramType; - - static void Write(MessageWriter* aWriter, const paramType& aParam); - static bool Read(MessageReader* aReader, paramType* aResult); -}; - -template <> -struct ParamTraits { - typedef SharedLibraryInfo paramType; - - static void Write(MessageWriter* aWriter, const paramType& aParam); - static bool Read(MessageReader* aReader, paramType* aResult); -}; -} // namespace IPC - #endif From a1b72f21a40aea240fb748d5dd8dbf1f802c0d9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Mon, 16 Sep 2024 21:09:32 +0000 Subject: [PATCH 010/115] Bug 1634785 - Add missing shared libraries methods to the baseprofiler implementation r=mstange,profiler-reviewers These methods were already inside the shared libraries that was in tools/profiler. Adding these methods here to make the implementations closer and make the deduplication easier in the following commits. Differential Revision: https://phabricator.services.mozilla.com/D220882 --- .../public/BaseProfilerSharedLibraries.h | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/mozglue/baseprofiler/public/BaseProfilerSharedLibraries.h b/mozglue/baseprofiler/public/BaseProfilerSharedLibraries.h index ba9eb67b62885..a6612b50ee234 100644 --- a/mozglue/baseprofiler/public/BaseProfilerSharedLibraries.h +++ b/mozglue/baseprofiler/public/BaseProfilerSharedLibraries.h @@ -14,6 +14,7 @@ #include #include #include +#include class SharedLibrary { public: @@ -86,6 +87,12 @@ class SharedLibrary { const std::string& GetDebugPath() const { return mDebugPath; } const std::string& GetVersion() const { return mVersion; } const std::string& GetArch() const { return mArch; } + size_t SizeOf() const { + return sizeof *this + mBreakpadId.length() + mCodeId.length() + + mModuleName.length() * 2 + mModulePath.length() * 2 + + mDebugName.length() * 2 + mDebugPath.length() * 2 + + mVersion.length() + mArch.size(); + } private: SharedLibrary() : mStart{0}, mEnd{0}, mOffset{0} {} @@ -142,6 +149,11 @@ class SharedLibraryInfo { void AddSharedLibrary(SharedLibrary entry) { mEntries.push_back(entry); } + void AddAllSharedLibraries(const SharedLibraryInfo& sharedLibraryInfo) { + mEntries.insert(mEntries.end(), sharedLibraryInfo.mEntries.begin(), + sharedLibraryInfo.mEntries.end()); + } + const SharedLibrary& GetEntry(size_t i) const { return mEntries[i]; } SharedLibrary& GetMutableEntry(size_t i) { return mEntries[i]; } @@ -163,8 +175,40 @@ class SharedLibraryInfo { std::sort(mEntries.begin(), mEntries.end(), CompareAddresses); } + // Remove duplicate entries from the vector. + // + // We purposefully don't use the operator== implementation of SharedLibrary + // because it compares all the fields including mStart, mEnd and mOffset which + // are not the same across different processes. + void DeduplicateEntries() { + static auto cmpSort = [](const SharedLibrary& a, const SharedLibrary& b) { + return std::tie(a.GetModuleName(), a.GetBreakpadId()) < + std::tie(b.GetModuleName(), b.GetBreakpadId()); + }; + static auto cmpEqual = [](const SharedLibrary& a, const SharedLibrary& b) { + return std::tie(a.GetModuleName(), a.GetBreakpadId()) == + std::tie(b.GetModuleName(), b.GetBreakpadId()); + }; + // std::unique requires the vector to be sorted first. It can only remove + // consecutive duplicate elements. + std::sort(mEntries.begin(), mEntries.end(), cmpSort); + // Remove the duplicates since it's sorted now. + mEntries.erase(std::unique(mEntries.begin(), mEntries.end(), cmpEqual), + mEntries.end()); + } + void Clear() { mEntries.clear(); } + size_t SizeOf() const { + size_t size = 0; + + for (const auto& item : mEntries) { + size += item.SizeOf(); + } + + return size; + } + private: #ifdef XP_WIN void AddSharedLibraryFromModuleInfo(const wchar_t* aModulePath, From c33b76893a8ca77c14ebd88f404bf3e4fc98ed22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Mon, 16 Sep 2024 21:09:32 +0000 Subject: [PATCH 011/115] Bug 1634785 - Make the base profiler shared libraries file closer to gecko profiler one r=mstange,profiler-reviewers Again removing some unused/unneeded things so it's going to be easier to deduplicate the files. Differential Revision: https://phabricator.services.mozilla.com/D220883 --- .../public/BaseProfilerSharedLibraries.h | 33 ------------------- 1 file changed, 33 deletions(-) diff --git a/mozglue/baseprofiler/public/BaseProfilerSharedLibraries.h b/mozglue/baseprofiler/public/BaseProfilerSharedLibraries.h index a6612b50ee234..ac9ec4aa889da 100644 --- a/mozglue/baseprofiler/public/BaseProfilerSharedLibraries.h +++ b/mozglue/baseprofiler/public/BaseProfilerSharedLibraries.h @@ -35,37 +35,6 @@ class SharedLibrary { mVersion(aVersion), mArch(aArch) {} - SharedLibrary(const SharedLibrary& aEntry) - : mStart(aEntry.mStart), - mEnd(aEntry.mEnd), - mOffset(aEntry.mOffset), - mBreakpadId(aEntry.mBreakpadId), - mCodeId(aEntry.mCodeId), - mModuleName(aEntry.mModuleName), - mModulePath(aEntry.mModulePath), - mDebugName(aEntry.mDebugName), - mDebugPath(aEntry.mDebugPath), - mVersion(aEntry.mVersion), - mArch(aEntry.mArch) {} - - SharedLibrary& operator=(const SharedLibrary& aEntry) { - // Gracefully handle self assignment - if (this == &aEntry) return *this; - - mStart = aEntry.mStart; - mEnd = aEntry.mEnd; - mOffset = aEntry.mOffset; - mBreakpadId = aEntry.mBreakpadId; - mCodeId = aEntry.mCodeId; - mModuleName = aEntry.mModuleName; - mModulePath = aEntry.mModulePath; - mDebugName = aEntry.mDebugName; - mDebugPath = aEntry.mDebugPath; - mVersion = aEntry.mVersion; - mArch = aEntry.mArch; - return *this; - } - bool operator==(const SharedLibrary& other) const { return (mStart == other.mStart) && (mEnd == other.mEnd) && (mOffset == other.mOffset) && (mModuleName == other.mModuleName) && @@ -145,8 +114,6 @@ class SharedLibraryInfo { static void Initialize() {} #endif - SharedLibraryInfo() {} - void AddSharedLibrary(SharedLibrary entry) { mEntries.push_back(entry); } void AddAllSharedLibraries(const SharedLibraryInfo& sharedLibraryInfo) { From f67f994dc2b5a5891da197af93d347fe48529983 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Mon, 16 Sep 2024 21:09:32 +0000 Subject: [PATCH 012/115] Bug 1634785 - Fix how shared library names are found on linux and macOS r=mstange,profiler-reviewers While testing the de-duplication on Linux and macOS, I noticed that the symbolication was completely broken due to having incorrect library names in libs array. They were always like: "/dist/bin/libxul.so" instead of "libxul.so". The library names are found from their paths, and apparently we were using an incorrect path separator for Linux and macOS, "\" instead of "/". Differential Revision: https://phabricator.services.mozilla.com/D220885 --- mozglue/baseprofiler/core/shared-libraries-linux.cc | 2 +- mozglue/baseprofiler/core/shared-libraries-macos.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mozglue/baseprofiler/core/shared-libraries-linux.cc b/mozglue/baseprofiler/core/shared-libraries-linux.cc index 9a4bfc19e064f..41efc0bc118f8 100644 --- a/mozglue/baseprofiler/core/shared-libraries-linux.cc +++ b/mozglue/baseprofiler/core/shared-libraries-linux.cc @@ -696,7 +696,7 @@ static SharedLibrary SharedLibraryAtPath(const char* path, unsigned long offset = 0) { std::string pathStr = path; - size_t pos = pathStr.rfind('\\'); + size_t pos = pathStr.rfind('/'); std::string nameStr = (pos != std::string::npos) ? pathStr.substr(pos + 1) : pathStr; diff --git a/mozglue/baseprofiler/core/shared-libraries-macos.cc b/mozglue/baseprofiler/core/shared-libraries-macos.cc index f9955810011bf..396290e38afe6 100644 --- a/mozglue/baseprofiler/core/shared-libraries-macos.cc +++ b/mozglue/baseprofiler/core/shared-libraries-macos.cc @@ -161,7 +161,7 @@ static void addSharedLibrary(const platform_mach_header* header, std::string pathStr = path; - size_t pos = pathStr.rfind('\\'); + size_t pos = pathStr.rfind('/'); std::string nameStr = (pos != std::string::npos) ? pathStr.substr(pos + 1) : pathStr; From 9d03b260f0b6bc05317d044767854926b1a02c3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Mon, 16 Sep 2024 21:09:33 +0000 Subject: [PATCH 013/115] Bug 1634785 - Do not expose AddSharedLibraryFromModuleInfo that's only used internally r=mstange,profiler-reviewers This method was used only internally, and having this method declaration causes issues. That's this method was already like this in tools/profiler version of this but it wasn't implemented here. Differential Revision: https://phabricator.services.mozilla.com/D220886 --- mozglue/baseprofiler/core/shared-libraries-win32.cc | 13 +++++++------ .../public/BaseProfilerSharedLibraries.h | 5 ----- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/mozglue/baseprofiler/core/shared-libraries-win32.cc b/mozglue/baseprofiler/core/shared-libraries-win32.cc index fc92914101f29..b6faf49cd746b 100644 --- a/mozglue/baseprofiler/core/shared-libraries-win32.cc +++ b/mozglue/baseprofiler/core/shared-libraries-win32.cc @@ -73,8 +73,9 @@ static bool IsModuleUnsafeToLoad(const std::string& aModuleName) { return false; } -void SharedLibraryInfo::AddSharedLibraryFromModuleInfo( - const wchar_t* aModulePath, mozilla::Maybe aModule) { +void AddSharedLibraryFromModuleInfo(SharedLibraryInfo& sharedLibraryInfo, + const wchar_t* aModulePath, + mozilla::Maybe aModule) { mozilla::UniquePtr utf8ModulePath( mozilla::glue::WideToUTF8(aModulePath)); if (!utf8ModulePath) { @@ -172,7 +173,7 @@ void SharedLibraryInfo::AddSharedLibraryFromModuleInfo( 0, // DLLs are always mapped at offset 0 on Windows breakpadId, codeId, moduleNameStr, modulePathStr, pdbNameStr, pdbPathStr, versionStr, ""); - AddSharedLibrary(shlib); + sharedLibraryInfo.AddSharedLibrary(shlib); } SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf() { @@ -180,8 +181,8 @@ SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf() { auto addSharedLibraryFromModuleInfo = [&sharedLibraryInfo](const wchar_t* aModulePath, HMODULE aModule) { - sharedLibraryInfo.AddSharedLibraryFromModuleInfo( - aModulePath, mozilla::Some(aModule)); + AddSharedLibraryFromModuleInfo(sharedLibraryInfo, aModulePath, + mozilla::Some(aModule)); }; mozilla::EnumerateProcessModules(addSharedLibraryFromModuleInfo); @@ -190,7 +191,7 @@ SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf() { SharedLibraryInfo SharedLibraryInfo::GetInfoFromPath(const wchar_t* aPath) { SharedLibraryInfo sharedLibraryInfo; - sharedLibraryInfo.AddSharedLibraryFromModuleInfo(aPath, mozilla::Nothing()); + AddSharedLibraryFromModuleInfo(sharedLibraryInfo, aPath, mozilla::Nothing()); return sharedLibraryInfo; } diff --git a/mozglue/baseprofiler/public/BaseProfilerSharedLibraries.h b/mozglue/baseprofiler/public/BaseProfilerSharedLibraries.h index ac9ec4aa889da..7732718833ffb 100644 --- a/mozglue/baseprofiler/public/BaseProfilerSharedLibraries.h +++ b/mozglue/baseprofiler/public/BaseProfilerSharedLibraries.h @@ -177,11 +177,6 @@ class SharedLibraryInfo { } private: -#ifdef XP_WIN - void AddSharedLibraryFromModuleInfo(const wchar_t* aModulePath, - mozilla::Maybe aModule); -#endif - std::vector mEntries; }; From e22fc5c7bc7d59d019a6a8272e70338a962ca593 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Mon, 16 Sep 2024 21:09:33 +0000 Subject: [PATCH 014/115] Bug 1634785 - Return early for ntdll.dll if EAF+ is enabled on mozglue SharedLibrary as well r=mstange,profiler-reviewers,bobowen We already had this early return on the shared-libraries code that was on the tools/profiler directory. Adding this check here as well to keep the both files in sync. It will help us deduplicating the shared libraries code later. Differential Revision: https://phabricator.services.mozilla.com/D220908 --- .../core/shared-libraries-win32.cc | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/mozglue/baseprofiler/core/shared-libraries-win32.cc b/mozglue/baseprofiler/core/shared-libraries-win32.cc index b6faf49cd746b..3a3225242d5fa 100644 --- a/mozglue/baseprofiler/core/shared-libraries-win32.cc +++ b/mozglue/baseprofiler/core/shared-libraries-win32.cc @@ -10,6 +10,7 @@ #include "mozilla/glue/WindowsUnicode.h" #include "mozilla/NativeNt.h" #include "mozilla/WindowsEnumProcessModules.h" +#include "mozilla/WindowsProcessMitigations.h" #include #include @@ -54,11 +55,11 @@ static void AppendHex(T aValue, std::string& aOut, bool aWithPadding, } } -static bool IsModuleUnsafeToLoad(const std::string& aModuleName) { - auto LowerCaseEqualsLiteral = [](char aModuleChar, char aDetouredChar) { - return std::tolower(aModuleChar) == aDetouredChar; - }; +bool LowerCaseEqualsLiteral(char aModuleChar, char aDetouredChar) { + return std::tolower(aModuleChar) == aDetouredChar; +} +static bool IsModuleUnsafeToLoad(const std::string& aModuleName) { // Hackaround for Bug 1723868. There is no safe way to prevent the module // Microsoft's VP9 Video Decoder from being unloaded because mfplat.dll may // have posted more than one task to unload the module in the work queue @@ -93,6 +94,15 @@ void AddSharedLibraryFromModuleInfo(SharedLibraryInfo& sharedLibraryInfo, return; } + // If EAF+ is enabled, parsing ntdll's PE header causes a crash. + constexpr std::string_view ntdll_dll = "ntdll.dll"; + if (mozilla::IsEafPlusEnabled() && + std::equal(moduleNameStr.cbegin(), moduleNameStr.cend(), + ntdll_dll.cbegin(), ntdll_dll.cend(), + LowerCaseEqualsLiteral)) { + return; + } + // Load the module again - to make sure that its handle will remain valid as // we attempt to read the PDB information from it - or for the first time if // we only have a path. We want to load the DLL without running the newly From c90e007aa496ae59e123c4b3467343891abde819 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Mon, 16 Sep 2024 21:09:34 +0000 Subject: [PATCH 015/115] Bug 1634785 - Deduplicate shared libraries code r=mstange,profiler-reviewers This patch finally removes the shared libraries code that was inside tools/profiler and uses the one in base profiler everywhere. Differential Revision: https://phabricator.services.mozilla.com/D220887 --- .../public/BaseProfilerSharedLibraries.h | 17 +- .../backgroundhangmonitor/HangDetails.cpp | 5 +- .../components/telemetry/core/Telemetry.cpp | 29 +- .../telemetry/other/ProcessedStack.cpp | 5 +- .../telemetry/other/ProcessedStack.h | 2 +- .../other/UntrustedModulesDataSerializer.cpp | 8 +- tools/profiler/core/EHABIStackWalk.cpp | 4 +- tools/profiler/core/platform.cpp | 12 +- tools/profiler/core/platform.h | 2 +- tools/profiler/core/shared-libraries-linux.cc | 280 ------------------ tools/profiler/core/shared-libraries-macos.cc | 211 ------------- tools/profiler/core/shared-libraries-win32.cc | 145 --------- tools/profiler/gecko/nsProfiler.cpp | 2 +- tools/profiler/lul/platform-linux-lul.cpp | 6 +- tools/profiler/moz.build | 9 - .../public/ProfileAdditionalInformation.h | 2 +- tools/profiler/public/shared-libraries.h | 202 ------------- 17 files changed, 55 insertions(+), 886 deletions(-) delete mode 100644 tools/profiler/core/shared-libraries-linux.cc delete mode 100644 tools/profiler/core/shared-libraries-macos.cc delete mode 100644 tools/profiler/core/shared-libraries-win32.cc delete mode 100644 tools/profiler/public/shared-libraries.h diff --git a/mozglue/baseprofiler/public/BaseProfilerSharedLibraries.h b/mozglue/baseprofiler/public/BaseProfilerSharedLibraries.h index 7732718833ffb..43eacdb8849ec 100644 --- a/mozglue/baseprofiler/public/BaseProfilerSharedLibraries.h +++ b/mozglue/baseprofiler/public/BaseProfilerSharedLibraries.h @@ -16,6 +16,11 @@ #include #include +namespace IPC { +template +struct ParamTraits; +} // namespace IPC + class SharedLibrary { public: SharedLibrary(uintptr_t aStart, uintptr_t aEnd, uintptr_t aOffset, @@ -63,9 +68,9 @@ class SharedLibrary { mVersion.length() + mArch.size(); } - private: SharedLibrary() : mStart{0}, mEnd{0}, mOffset{0} {} + private: uintptr_t mStart; uintptr_t mEnd; uintptr_t mOffset; @@ -87,6 +92,8 @@ class SharedLibrary { std::string mDebugPath; std::string mVersion; std::string mArch; + + friend struct IPC::ParamTraits; }; static bool CompareAddresses(const SharedLibrary& first, @@ -97,12 +104,12 @@ static bool CompareAddresses(const SharedLibrary& first, class SharedLibraryInfo { public: #ifdef MOZ_GECKO_PROFILER - static SharedLibraryInfo GetInfoForSelf(); + MFBT_API static SharedLibraryInfo GetInfoForSelf(); # ifdef XP_WIN - static SharedLibraryInfo GetInfoFromPath(const wchar_t* aPath); + MFBT_API static SharedLibraryInfo GetInfoFromPath(const wchar_t* aPath); # endif - static void Initialize(); + MFBT_API static void Initialize(); #else static SharedLibraryInfo GetInfoForSelf() { return SharedLibraryInfo(); } # ifdef XP_WIN @@ -178,6 +185,8 @@ class SharedLibraryInfo { private: std::vector mEntries; + + friend struct IPC::ParamTraits; }; #endif // BASE_PROFILER_SHARED_LIBRARIES_H_ diff --git a/toolkit/components/backgroundhangmonitor/HangDetails.cpp b/toolkit/components/backgroundhangmonitor/HangDetails.cpp index de6ee056f6f30..362decdc7fd95 100644 --- a/toolkit/components/backgroundhangmonitor/HangDetails.cpp +++ b/toolkit/components/backgroundhangmonitor/HangDetails.cpp @@ -20,7 +20,7 @@ #include "mozilla/GfxMessageUtils.h" // For ParamTraits #include "mozilla/ResultExtensions.h" #include "mozilla/Try.h" -#include "shared-libraries.h" +#include "BaseProfilerSharedLibraries.h" static const char MAGIC[] = "permahangsavev1"; @@ -399,7 +399,8 @@ void ReadModuleInformation(HangStack& stack) { } if (moduleReferenced) { - HangModule module(info.GetDebugName(), info.GetBreakpadId()); + HangModule module(NS_ConvertUTF8toUTF16(info.GetDebugName().c_str()), + nsCString(info.GetBreakpadId().c_str())); stack.modules().AppendElement(module); } } diff --git a/toolkit/components/telemetry/core/Telemetry.cpp b/toolkit/components/telemetry/core/Telemetry.cpp index 5f99375dac491..6324a03e934eb 100644 --- a/toolkit/components/telemetry/core/Telemetry.cpp +++ b/toolkit/components/telemetry/core/Telemetry.cpp @@ -723,7 +723,9 @@ class GetLoadedModulesResultRunnable final : public Runnable { // Module name. JS::Rooted moduleName( - cx, JS_NewUCStringCopyZ(cx, info.GetModuleName().get())); + cx, + JS_NewUCStringCopyZ( + cx, NS_ConvertUTF8toUTF16(info.GetModuleName().c_str()).get())); if (!moduleName || !JS_DefineProperty(cx, moduleObj, "name", moduleName, JSPROP_ENUMERATE)) { mPromise->MaybeReject(NS_ERROR_FAILURE); @@ -733,9 +735,11 @@ class GetLoadedModulesResultRunnable final : public Runnable { // Module debug name. JS::Rooted moduleDebugName(cx); - if (!info.GetDebugName().IsEmpty()) { + if (!info.GetDebugName().empty()) { JS::Rooted str_moduleDebugName( - cx, JS_NewUCStringCopyZ(cx, info.GetDebugName().get())); + cx, + JS_NewUCStringCopyZ( + cx, NS_ConvertUTF8toUTF16(info.GetDebugName().c_str()).get())); if (!str_moduleDebugName) { mPromise->MaybeReject(NS_ERROR_FAILURE); return NS_OK; @@ -754,9 +758,9 @@ class GetLoadedModulesResultRunnable final : public Runnable { // Module Breakpad identifier. JS::Rooted id(cx); - if (!info.GetBreakpadId().IsEmpty()) { + if (!info.GetBreakpadId().empty()) { JS::Rooted str_id( - cx, JS_NewStringCopyZ(cx, info.GetBreakpadId().get())); + cx, JS_NewStringCopyZ(cx, info.GetBreakpadId().c_str())); if (!str_id) { mPromise->MaybeReject(NS_ERROR_FAILURE); return NS_OK; @@ -774,9 +778,9 @@ class GetLoadedModulesResultRunnable final : public Runnable { // Module version. JS::Rooted version(cx); - if (!info.GetVersion().IsEmpty()) { + if (!info.GetVersion().empty()) { JS::Rooted v( - cx, JS_NewStringCopyZ(cx, info.GetVersion().BeginReading())); + cx, JS_NewStringCopyZ(cx, info.GetVersion().c_str())); if (!v) { mPromise->MaybeReject(NS_ERROR_FAILURE); return NS_OK; @@ -794,7 +798,8 @@ class GetLoadedModulesResultRunnable final : public Runnable { # if defined(XP_WIN) // Cert Subject. - if (auto subject = mCertSubjects.Lookup(info.GetModulePath())) { + if (auto subject = mCertSubjects.Lookup( + NS_ConvertUTF8toUTF16(info.GetModulePath().c_str()))) { JS::Rooted jsOrg(cx, ToJSString(cx, *subject)); if (!jsOrg) { mPromise->MaybeReject(NS_ERROR_FAILURE); @@ -834,10 +839,12 @@ class GetLoadedModulesResultRunnable final : public Runnable { for (unsigned int i = 0, n = mRawModules.GetSize(); i != n; i++) { const SharedLibrary& info = mRawModules.GetEntry(i); - auto orgName = dllSvc->GetBinaryOrgName(info.GetModulePath().get()); + auto orgName = dllSvc->GetBinaryOrgName( + NS_ConvertUTF8toUTF16(info.GetModulePath().c_str()).get()); if (orgName) { - mCertSubjects.InsertOrUpdate(info.GetModulePath(), - nsDependentString(orgName.get())); + mCertSubjects.InsertOrUpdate( + NS_ConvertUTF8toUTF16(info.GetModulePath().c_str()), + nsDependentString(orgName.get())); } } } diff --git a/toolkit/components/telemetry/other/ProcessedStack.cpp b/toolkit/components/telemetry/other/ProcessedStack.cpp index ce62826a05f87..7f11cab0c92a3 100644 --- a/toolkit/components/telemetry/other/ProcessedStack.cpp +++ b/toolkit/components/telemetry/other/ProcessedStack.cpp @@ -141,8 +141,9 @@ static ProcessedStack GetStackAndModulesInternal( #ifdef MOZ_GECKO_PROFILER for (unsigned i = 0, n = rawModules.GetSize(); i != n; ++i) { const SharedLibrary& info = rawModules.GetEntry(i); - mozilla::Telemetry::ProcessedStack::Module module = {info.GetDebugName(), - info.GetBreakpadId()}; + mozilla::Telemetry::ProcessedStack::Module module = { + NS_ConvertUTF8toUTF16(info.GetDebugName().c_str()), + nsCString(info.GetBreakpadId().c_str())}; Ret.AddModule(module); } #endif diff --git a/toolkit/components/telemetry/other/ProcessedStack.h b/toolkit/components/telemetry/other/ProcessedStack.h index 375cab37a722d..beb6ef7a67378 100644 --- a/toolkit/components/telemetry/other/ProcessedStack.h +++ b/toolkit/components/telemetry/other/ProcessedStack.h @@ -13,7 +13,7 @@ #include "mozilla/ipc/MessageChannel.h" #include "mozilla/Vector.h" #include "nsStringFwd.h" -#include "shared-libraries.h" +#include "BaseProfilerSharedLibraries.h" namespace mozilla { namespace Telemetry { diff --git a/toolkit/components/telemetry/other/UntrustedModulesDataSerializer.cpp b/toolkit/components/telemetry/other/UntrustedModulesDataSerializer.cpp index f352485e2b47f..49645b1db972f 100644 --- a/toolkit/components/telemetry/other/UntrustedModulesDataSerializer.cpp +++ b/toolkit/components/telemetry/other/UntrustedModulesDataSerializer.cpp @@ -14,7 +14,7 @@ #include "nsITelemetry.h" #include "nsUnicharUtils.h" #include "nsXULAppAPI.h" -#include "shared-libraries.h" +#include "BaseProfilerSharedLibraries.h" namespace mozilla { namespace Telemetry { @@ -173,9 +173,9 @@ static bool SerializeModule(JSContext* aCx, if (aModule->mResolvedDosName->GetPath(path) == NS_OK) { SharedLibraryInfo info = SharedLibraryInfo::GetInfoFromPath(path.Data()); if (info.GetSize() > 0) { - nsCString breakpadId = info.GetEntry(0).GetBreakpadId(); - if (!AddLengthLimitedStringProp(aCx, obj, "debugID", - NS_ConvertASCIItoUTF16(breakpadId))) { + nsString breakpadId = + NS_ConvertUTF8toUTF16(info.GetEntry(0).GetBreakpadId()); + if (!AddLengthLimitedStringProp(aCx, obj, "debugID", breakpadId)) { return false; } } diff --git a/tools/profiler/core/EHABIStackWalk.cpp b/tools/profiler/core/EHABIStackWalk.cpp index e3099b89ecf28..6578ba349fb5b 100644 --- a/tools/profiler/core/EHABIStackWalk.cpp +++ b/tools/profiler/core/EHABIStackWalk.cpp @@ -24,7 +24,7 @@ #include "EHABIStackWalk.h" -#include "shared-libraries.h" +#include "BaseProfilerSharedLibraries.h" #include "platform.h" #include "mozilla/Atomics.h" @@ -560,7 +560,7 @@ void EHAddrSpace::Update() { // the start address will not point at the file header. But this is worked // around by magic number checks in the EHTable constructor. EHTable tab(reinterpret_cast(lib.GetStart()), - lib.GetEnd() - lib.GetStart(), lib.GetNativeDebugPath()); + lib.GetEnd() - lib.GetStart(), lib.DebugPath()); if (tab.isValid()) tables.push_back(tab); } space = new EHAddrSpace(tables); diff --git a/tools/profiler/core/platform.cpp b/tools/profiler/core/platform.cpp index 33d8091232611..d252bb0f66505 100644 --- a/tools/profiler/core/platform.cpp +++ b/tools/profiler/core/platform.cpp @@ -53,7 +53,7 @@ #include "nsDebug.h" #include "nsISupports.h" #include "nsXPCOM.h" -#include "shared-libraries.h" +#include "BaseProfilerSharedLibraries.h" #include "VTuneProfiler.h" #include "ETWTools.h" @@ -3053,12 +3053,10 @@ static void AddSharedLibraryInfoToStream(JSONWriter& aWriter, aWriter.IntProperty("start", SafeJSInteger(aLib.GetStart())); aWriter.IntProperty("end", SafeJSInteger(aLib.GetEnd())); aWriter.IntProperty("offset", SafeJSInteger(aLib.GetOffset())); - aWriter.StringProperty("name", NS_ConvertUTF16toUTF8(aLib.GetModuleName())); - aWriter.StringProperty("path", NS_ConvertUTF16toUTF8(aLib.GetModulePath())); - aWriter.StringProperty("debugName", - NS_ConvertUTF16toUTF8(aLib.GetDebugName())); - aWriter.StringProperty("debugPath", - NS_ConvertUTF16toUTF8(aLib.GetDebugPath())); + aWriter.StringProperty("name", aLib.GetModuleName()); + aWriter.StringProperty("path", aLib.GetModulePath()); + aWriter.StringProperty("debugName", aLib.GetDebugName()); + aWriter.StringProperty("debugPath", aLib.GetDebugPath()); aWriter.StringProperty("breakpadId", aLib.GetBreakpadId()); aWriter.StringProperty("codeId", aLib.GetCodeId()); aWriter.StringProperty("arch", aLib.GetArch()); diff --git a/tools/profiler/core/platform.h b/tools/profiler/core/platform.h index 59d2c7ff428ef..d1ed958540708 100644 --- a/tools/profiler/core/platform.h +++ b/tools/profiler/core/platform.h @@ -44,7 +44,7 @@ #include "mozilla/UniquePtr.h" #include "mozilla/Vector.h" #include "nsString.h" -#include "shared-libraries.h" +#include "BaseProfilerSharedLibraries.h" #include #include diff --git a/tools/profiler/core/shared-libraries-linux.cc b/tools/profiler/core/shared-libraries-linux.cc deleted file mode 100644 index ec969e98e2eb7..0000000000000 --- a/tools/profiler/core/shared-libraries-linux.cc +++ /dev/null @@ -1,280 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "shared-libraries.h" - -#define PATH_MAX_TOSTRING(x) #x -#define PATH_MAX_STRING(x) PATH_MAX_TOSTRING(x) -#include -#include -#include -#include -#include -#include -#include "platform.h" -#include "shared-libraries.h" -#include "GeckoProfiler.h" -#include "mozilla/Sprintf.h" -#include "mozilla/Unused.h" -#include "nsDebug.h" -#include "nsNativeCharsetUtils.h" -#include - -#include "common/linux/file_id.h" -#include -#include -#if defined(GP_OS_linux) || defined(GP_OS_android) -# include -#endif -#include - -#if defined(GP_OS_linux) || defined(GP_OS_android) || defined(GP_OS_freebsd) -# include // dl_phdr_info -#else -# error "Unexpected configuration" -#endif - -#if defined(GP_OS_android) -extern "C" MOZ_EXPORT __attribute__((weak)) int dl_iterate_phdr( - int (*callback)(struct dl_phdr_info* info, size_t size, void* data), - void* data); -#endif - -struct LoadedLibraryInfo { - LoadedLibraryInfo(const char* aName, unsigned long aBaseAddress, - unsigned long aFirstMappingStart, - unsigned long aLastMappingEnd) - : mName(aName), - mBaseAddress(aBaseAddress), - mFirstMappingStart(aFirstMappingStart), - mLastMappingEnd(aLastMappingEnd) {} - - nsCString mName; - unsigned long mBaseAddress; - unsigned long mFirstMappingStart; - unsigned long mLastMappingEnd; -}; - -static nsCString IDtoUUIDString( - const google_breakpad::wasteful_vector& aIdentifier) { - using namespace google_breakpad; - - nsCString uuid; - const std::string str = FileID::ConvertIdentifierToUUIDString(aIdentifier); - uuid.Append(str.c_str(), str.size()); - // This is '0', not '\0', since it represents the breakpad id age. - uuid.Append('0'); - return uuid; -} - -// Return raw Build ID in hex. -static nsCString IDtoString( - const google_breakpad::wasteful_vector& aIdentifier) { - using namespace google_breakpad; - - nsCString uuid; - const std::string str = FileID::ConvertIdentifierToString(aIdentifier); - uuid.Append(str.c_str(), str.size()); - return uuid; -} - -// Get the breakpad Id for the binary file pointed by bin_name -static nsCString getBreakpadId(const char* bin_name) { - using namespace google_breakpad; - - PageAllocator allocator; - auto_wasteful_vector identifier(&allocator); - - FileID file_id(bin_name); - if (file_id.ElfFileIdentifier(identifier)) { - return IDtoUUIDString(identifier); - } - - return ""_ns; -} - -// Get the code Id for the binary file pointed by bin_name -static nsCString getCodeId(const char* bin_name) { - using namespace google_breakpad; - - PageAllocator allocator; - auto_wasteful_vector identifier(&allocator); - - FileID file_id(bin_name); - if (file_id.ElfFileIdentifier(identifier)) { - return IDtoString(identifier); - } - - return ""_ns; -} - -static SharedLibrary SharedLibraryAtPath(const char* path, - unsigned long libStart, - unsigned long libEnd, - unsigned long offset = 0) { - nsAutoString pathStr; - mozilla::Unused << NS_WARN_IF( - NS_FAILED(NS_CopyNativeToUnicode(nsDependentCString(path), pathStr))); - - nsAutoString nameStr = pathStr; - int32_t pos = nameStr.RFindChar('/'); - if (pos != kNotFound) { - nameStr.Cut(0, pos + 1); - } - - return SharedLibrary(libStart, libEnd, offset, getBreakpadId(path), - getCodeId(path), nameStr, pathStr, nameStr, pathStr, - ""_ns, ""); -} - -static int dl_iterate_callback(struct dl_phdr_info* dl_info, size_t size, - void* data) { - auto libInfoList = reinterpret_cast*>(data); - - if (dl_info->dlpi_phnum <= 0) return 0; - - unsigned long baseAddress = dl_info->dlpi_addr; - unsigned long firstMappingStart = -1; - unsigned long lastMappingEnd = 0; - - for (size_t i = 0; i < dl_info->dlpi_phnum; i++) { - if (dl_info->dlpi_phdr[i].p_type != PT_LOAD) { - continue; - } - unsigned long start = dl_info->dlpi_addr + dl_info->dlpi_phdr[i].p_vaddr; - unsigned long end = start + dl_info->dlpi_phdr[i].p_memsz; - if (start < firstMappingStart) { - firstMappingStart = start; - } - if (end > lastMappingEnd) { - lastMappingEnd = end; - } - } - - libInfoList->AppendElement(LoadedLibraryInfo( - dl_info->dlpi_name, baseAddress, firstMappingStart, lastMappingEnd)); - - return 0; -} - -SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf() { - SharedLibraryInfo info; - -#if defined(GP_OS_linux) - // We need to find the name of the executable (exeName, exeNameLen) and the - // address of its executable section (exeExeAddr) in the running image. - char exeName[PATH_MAX]; - memset(exeName, 0, sizeof(exeName)); - - ssize_t exeNameLen = readlink("/proc/self/exe", exeName, sizeof(exeName) - 1); - if (exeNameLen == -1) { - // readlink failed for whatever reason. Note this, but keep going. - exeName[0] = '\0'; - exeNameLen = 0; - LOG("SharedLibraryInfo::GetInfoForSelf(): readlink failed"); - } else { - // Assert no buffer overflow. - MOZ_RELEASE_ASSERT(exeNameLen >= 0 && - exeNameLen < static_cast(sizeof(exeName))); - } - - unsigned long exeExeAddr = 0; -#endif - -#if defined(GP_OS_android) - // If dl_iterate_phdr doesn't exist, we give up immediately. - if (!dl_iterate_phdr) { - // On ARM Android, dl_iterate_phdr is provided by the custom linker. - // So if libxul was loaded by the system linker (e.g. as part of - // xpcshell when running tests), it won't be available and we should - // not call it. - return info; - } -#endif - -#if defined(GP_OS_linux) || defined(GP_OS_android) - // Read info from /proc/self/maps. We ignore most of it. - pid_t pid = profiler_current_process_id().ToNumber(); - char path[PATH_MAX]; - char modulePath[PATH_MAX + 1]; - SprintfLiteral(path, "/proc/%d/maps", pid); - std::ifstream maps(path); - std::string line; - while (std::getline(maps, line)) { - int ret; - unsigned long start; - unsigned long end; - char perm[6 + 1] = ""; - unsigned long offset; - modulePath[0] = 0; - ret = sscanf(line.c_str(), - "%lx-%lx %6s %lx %*s %*x %" PATH_MAX_STRING(PATH_MAX) "s\n", - &start, &end, perm, &offset, modulePath); - if (!strchr(perm, 'x')) { - // Ignore non executable entries - continue; - } - if (ret != 5 && ret != 4) { - LOG("SharedLibraryInfo::GetInfoForSelf(): " - "reading /proc/self/maps failed"); - continue; - } - -# if defined(GP_OS_linux) - // Try to establish the main executable's load address. - if (exeNameLen > 0 && strcmp(modulePath, exeName) == 0) { - exeExeAddr = start; - } -# elif defined(GP_OS_android) - // Use /proc/pid/maps to get the dalvik-jit section since it has no - // associated phdrs. - if (0 == strcmp(modulePath, "/dev/ashmem/dalvik-jit-code-cache")) { - info.AddSharedLibrary( - SharedLibraryAtPath(modulePath, start, end, offset)); - if (info.GetSize() > 10000) { - LOG("SharedLibraryInfo::GetInfoForSelf(): " - "implausibly large number of mappings acquired"); - break; - } - } -# endif - } -#endif - - nsTArray libInfoList; - - // We collect the bulk of the library info using dl_iterate_phdr. - dl_iterate_phdr(dl_iterate_callback, &libInfoList); - - for (const auto& libInfo : libInfoList) { - info.AddSharedLibrary( - SharedLibraryAtPath(libInfo.mName.get(), libInfo.mFirstMappingStart, - libInfo.mLastMappingEnd, - libInfo.mFirstMappingStart - libInfo.mBaseAddress)); - } - -#if defined(GP_OS_linux) - // Make another pass over the information we just harvested from - // dl_iterate_phdr. If we see a nameless object mapped at what we earlier - // established to be the main executable's load address, attach the - // executable's name to that entry. - for (size_t i = 0; i < info.GetSize(); i++) { - SharedLibrary& lib = info.GetMutableEntry(i); - if (lib.GetStart() <= exeExeAddr && exeExeAddr <= lib.GetEnd() && - lib.GetNativeDebugPath().empty()) { - lib = SharedLibraryAtPath(exeName, lib.GetStart(), lib.GetEnd(), - lib.GetOffset()); - - // We only expect to see one such entry. - break; - } - } -#endif - - return info; -} - -void SharedLibraryInfo::Initialize() { /* do nothing */ } diff --git a/tools/profiler/core/shared-libraries-macos.cc b/tools/profiler/core/shared-libraries-macos.cc deleted file mode 100644 index 415fda3633797..0000000000000 --- a/tools/profiler/core/shared-libraries-macos.cc +++ /dev/null @@ -1,211 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "shared-libraries.h" - -#include "ClearOnShutdown.h" -#include "mozilla/StaticMutex.h" -#include "mozilla/Unused.h" -#include "nsNativeCharsetUtils.h" -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Architecture specific abstraction. -#if defined(GP_ARCH_x86) -typedef mach_header platform_mach_header; -typedef segment_command mach_segment_command_type; -# define MACHO_MAGIC_NUMBER MH_MAGIC -# define CMD_SEGMENT LC_SEGMENT -# define seg_size uint32_t -#else -typedef mach_header_64 platform_mach_header; -typedef segment_command_64 mach_segment_command_type; -# define MACHO_MAGIC_NUMBER MH_MAGIC_64 -# define CMD_SEGMENT LC_SEGMENT_64 -# define seg_size uint64_t -#endif - -struct NativeSharedLibrary { - const platform_mach_header* header; - std::string path; -}; -static std::vector* sSharedLibrariesList = nullptr; -static mozilla::StaticMutex sSharedLibrariesMutex MOZ_UNANNOTATED; - -static void SharedLibraryAddImage(const struct mach_header* mh, - intptr_t vmaddr_slide) { - // NOTE: Presumably for backwards-compatibility reasons, this function accepts - // a mach_header even on 64-bit where it ought to be a mach_header_64. We cast - // it to the right type here. - auto header = reinterpret_cast(mh); - - Dl_info info; - if (!dladdr(header, &info)) { - return; - } - - mozilla::StaticMutexAutoLock lock(sSharedLibrariesMutex); - if (!sSharedLibrariesList) { - return; - } - - NativeSharedLibrary lib = {header, info.dli_fname}; - sSharedLibrariesList->push_back(lib); -} - -static void SharedLibraryRemoveImage(const struct mach_header* mh, - intptr_t vmaddr_slide) { - // NOTE: Presumably for backwards-compatibility reasons, this function accepts - // a mach_header even on 64-bit where it ought to be a mach_header_64. We cast - // it to the right type here. - auto header = reinterpret_cast(mh); - - mozilla::StaticMutexAutoLock lock(sSharedLibrariesMutex); - if (!sSharedLibrariesList) { - return; - } - - uint32_t count = sSharedLibrariesList->size(); - for (uint32_t i = 0; i < count; ++i) { - if ((*sSharedLibrariesList)[i].header == header) { - sSharedLibrariesList->erase(sSharedLibrariesList->begin() + i); - return; - } - } -} - -void SharedLibraryInfo::Initialize() { - // NOTE: We intentionally leak this memory here. We're allocating dynamically - // in order to avoid static initializers. - sSharedLibrariesList = new std::vector(); - - _dyld_register_func_for_add_image(SharedLibraryAddImage); - _dyld_register_func_for_remove_image(SharedLibraryRemoveImage); -} - -static void addSharedLibrary(const platform_mach_header* header, - const char* path, SharedLibraryInfo& info) { - const struct load_command* cmd = - reinterpret_cast(header + 1); - - seg_size size = 0; - unsigned long long start = reinterpret_cast(header); - // Find the cmd segment in the macho image. It will contain the offset we care - // about. - const uint8_t* uuid_bytes = nullptr; - for (unsigned int i = 0; - cmd && (i < header->ncmds) && (uuid_bytes == nullptr || size == 0); - ++i) { - if (cmd->cmd == CMD_SEGMENT) { - const mach_segment_command_type* seg = - reinterpret_cast(cmd); - - if (!strcmp(seg->segname, "__TEXT")) { - size = seg->vmsize; - } - } else if (cmd->cmd == LC_UUID) { - const uuid_command* ucmd = reinterpret_cast(cmd); - uuid_bytes = ucmd->uuid; - } - - cmd = reinterpret_cast( - reinterpret_cast(cmd) + cmd->cmdsize); - } - - nsAutoCString uuid; - nsAutoCString breakpadId; - if (uuid_bytes != nullptr) { - uuid.AppendPrintf( - "%02X" - "%02X" - "%02X" - "%02X" - "%02X" - "%02X" - "%02X" - "%02X" - "%02X" - "%02X" - "%02X" - "%02X" - "%02X" - "%02X" - "%02X" - "%02X", - uuid_bytes[0], uuid_bytes[1], uuid_bytes[2], uuid_bytes[3], - uuid_bytes[4], uuid_bytes[5], uuid_bytes[6], uuid_bytes[7], - uuid_bytes[8], uuid_bytes[9], uuid_bytes[10], uuid_bytes[11], - uuid_bytes[12], uuid_bytes[13], uuid_bytes[14], uuid_bytes[15]); - - // Breakpad id is the same as the uuid but with the additional trailing 0 - // for the breakpad id age. - breakpadId.AppendPrintf( - "%s" - "0" /* breakpad id age */, - uuid.get()); - } - - nsAutoString pathStr; - mozilla::Unused << NS_WARN_IF( - NS_FAILED(NS_CopyNativeToUnicode(nsDependentCString(path), pathStr))); - - nsAutoString nameStr = pathStr; - int32_t pos = nameStr.RFindChar('/'); - if (pos != kNotFound) { - nameStr.Cut(0, pos + 1); - } - - const NXArchInfo* archInfo = - NXGetArchInfoFromCpuType(header->cputype, header->cpusubtype); - - info.AddSharedLibrary(SharedLibrary(start, start + size, 0, breakpadId, uuid, - nameStr, pathStr, nameStr, pathStr, ""_ns, - archInfo ? archInfo->name : "")); -} - -// Translate the statically stored sSharedLibrariesList information into a -// SharedLibraryInfo object. -SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf() { - mozilla::StaticMutexAutoLock lock(sSharedLibrariesMutex); - SharedLibraryInfo sharedLibraryInfo; - - for (auto& info : *sSharedLibrariesList) { - addSharedLibrary(info.header, info.path.c_str(), sharedLibraryInfo); - } - - // Add the entry for dyld itself. - // We only support macOS 10.12+, which corresponds to dyld version 15+. - // dyld version 15 added the dyldPath property. - task_dyld_info_data_t task_dyld_info; - mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT; - if (task_info(mach_task_self(), TASK_DYLD_INFO, (task_info_t)&task_dyld_info, - &count) != KERN_SUCCESS) { - return sharedLibraryInfo; - } - - struct dyld_all_image_infos* aii = - (struct dyld_all_image_infos*)task_dyld_info.all_image_info_addr; - if (aii->version >= 15) { - const platform_mach_header* header = - reinterpret_cast( - aii->dyldImageLoadAddress); - addSharedLibrary(header, aii->dyldPath, sharedLibraryInfo); - } - - return sharedLibraryInfo; -} diff --git a/tools/profiler/core/shared-libraries-win32.cc b/tools/profiler/core/shared-libraries-win32.cc deleted file mode 100644 index 44423952620d9..0000000000000 --- a/tools/profiler/core/shared-libraries-win32.cc +++ /dev/null @@ -1,145 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include - -#include "shared-libraries.h" -#include "nsWindowsHelpers.h" -#include "mozilla/NativeNt.h" -#include "mozilla/WindowsEnumProcessModules.h" -#include "mozilla/WindowsProcessMitigations.h" -#include "nsPrintfCString.h" - -static bool IsModuleUnsafeToLoad(const nsAString& aModuleName) { - // Hackaround for Bug 1723868. There is no safe way to prevent the module - // Microsoft's VP9 Video Decoder from being unloaded because mfplat.dll may - // have posted more than one task to unload the module in the work queue - // without calling LoadLibrary. - if (aModuleName.LowerCaseEqualsLiteral("msvp9dec_store.dll")) { - return true; - } - - return false; -} - -void AddSharedLibraryFromModuleInfo(SharedLibraryInfo& sharedLibraryInfo, - const wchar_t* aModulePath, - mozilla::Maybe aModule) { - nsDependentSubstring moduleNameStr( - mozilla::nt::GetLeafName(nsDependentString(aModulePath))); - - // If the module is unsafe to call LoadLibraryEx for, we skip. - if (IsModuleUnsafeToLoad(moduleNameStr)) { - return; - } - - // If EAF+ is enabled, parsing ntdll's PE header causes a crash. - if (mozilla::IsEafPlusEnabled() && - moduleNameStr.LowerCaseEqualsLiteral("ntdll.dll")) { - return; - } - - // Load the module again - to make sure that its handle will remain valid as - // we attempt to read the PDB information from it - or for the first time if - // we only have a path. We want to load the DLL without running the newly - // loaded module's DllMain function, but not as a data file because we want - // to be able to do RVA computations easily. Hence, we use the flag - // LOAD_LIBRARY_AS_IMAGE_RESOURCE which ensures that the sections (not PE - // headers) will be relocated by the loader. Otherwise GetPdbInfo() and/or - // GetVersionInfo() can cause a crash. If the original handle |aModule| is - // valid, LoadLibraryEx just increments its refcount. - nsModuleHandle handleLock( - ::LoadLibraryExW(aModulePath, NULL, LOAD_LIBRARY_AS_IMAGE_RESOURCE)); - if (!handleLock) { - return; - } - - mozilla::nt::PEHeaders headers(handleLock.get()); - if (!headers) { - return; - } - - mozilla::Maybe> bounds = headers.GetBounds(); - if (!bounds) { - return; - } - - // Put the original |aModule| into SharedLibrary, but we get debug info - // from |handleLock| as |aModule| might be inaccessible. - const uintptr_t modStart = - aModule.isSome() ? reinterpret_cast(*aModule) - : reinterpret_cast(handleLock.get()); - const uintptr_t modEnd = modStart + bounds->length(); - - nsAutoCString breakpadId; - nsAutoString pdbPathStr; - if (const auto* debugInfo = headers.GetPdbInfo()) { - MOZ_ASSERT(breakpadId.IsEmpty()); - const GUID& pdbSig = debugInfo->pdbSignature; - breakpadId.AppendPrintf( - "%08lX" // m0 - "%04X%04X" // m1,m2 - "%02X%02X%02X%02X%02X%02X%02X%02X" // m3 - "%X", // pdbAge - pdbSig.Data1, pdbSig.Data2, pdbSig.Data3, pdbSig.Data4[0], - pdbSig.Data4[1], pdbSig.Data4[2], pdbSig.Data4[3], pdbSig.Data4[4], - pdbSig.Data4[5], pdbSig.Data4[6], pdbSig.Data4[7], debugInfo->pdbAge); - - // The PDB file name could be different from module filename, - // so report both - // e.g. The PDB for C:\Windows\SysWOW64\ntdll.dll is wntdll.pdb - pdbPathStr = NS_ConvertUTF8toUTF16(debugInfo->pdbFileName); - } - - nsAutoCString codeId; - DWORD timestamp; - DWORD imageSize; - if (headers.GetTimeStamp(timestamp) && headers.GetImageSize(imageSize)) { - codeId.AppendPrintf( - "%08lX" // Uppercase 8 digits of hex timestamp with leading zeroes. - "%lx", // Lowercase hex image size - timestamp, imageSize); - } - - nsAutoCString versionStr; - uint64_t version; - if (headers.GetVersionInfo(version)) { - versionStr.AppendPrintf("%u.%u.%u.%u", - static_cast((version >> 48) & 0xFFFFu), - static_cast((version >> 32) & 0xFFFFu), - static_cast((version >> 16) & 0xFFFFu), - static_cast(version & 0xFFFFu)); - } - - const nsString& pdbNameStr = - PromiseFlatString(mozilla::nt::GetLeafName(pdbPathStr)); - SharedLibrary shlib(modStart, modEnd, - 0, // DLLs are always mapped at offset 0 on Windows - breakpadId, codeId, PromiseFlatString(moduleNameStr), - nsDependentString(aModulePath), pdbNameStr, pdbPathStr, - versionStr, ""); - sharedLibraryInfo.AddSharedLibrary(shlib); -} - -SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf() { - SharedLibraryInfo sharedLibraryInfo; - - auto addSharedLibraryFromModuleInfo = - [&sharedLibraryInfo](const wchar_t* aModulePath, HMODULE aModule) { - AddSharedLibraryFromModuleInfo(sharedLibraryInfo, aModulePath, - mozilla::Some(aModule)); - }; - - mozilla::EnumerateProcessModules(addSharedLibraryFromModuleInfo); - return sharedLibraryInfo; -} - -SharedLibraryInfo SharedLibraryInfo::GetInfoFromPath(const wchar_t* aPath) { - SharedLibraryInfo sharedLibraryInfo; - AddSharedLibraryFromModuleInfo(sharedLibraryInfo, aPath, mozilla::Nothing()); - return sharedLibraryInfo; -} - -void SharedLibraryInfo::Initialize() { /* do nothing */ } diff --git a/tools/profiler/gecko/nsProfiler.cpp b/tools/profiler/gecko/nsProfiler.cpp index ed559f40d9188..88d893b4bf870 100644 --- a/tools/profiler/gecko/nsProfiler.cpp +++ b/tools/profiler/gecko/nsProfiler.cpp @@ -37,7 +37,7 @@ #include "nsString.h" #include "nsThreadUtils.h" #include "platform.h" -#include "shared-libraries.h" +#include "BaseProfilerSharedLibraries.h" #include "zlib.h" #ifndef ANDROID diff --git a/tools/profiler/lul/platform-linux-lul.cpp b/tools/profiler/lul/platform-linux-lul.cpp index 4027905c60262..c72de2bb4267b 100644 --- a/tools/profiler/lul/platform-linux-lul.cpp +++ b/tools/profiler/lul/platform-linux-lul.cpp @@ -13,7 +13,7 @@ #include "platform.h" #include "PlatformMacros.h" #include "LulMain.h" -#include "shared-libraries.h" +#include "BaseProfilerSharedLibraries.h" #include "AutoObjectMapper.h" // Contains miscellaneous helpers that are used to connect the Gecko Profiler @@ -31,7 +31,7 @@ void read_procmaps(lul::LUL* aLUL) { for (size_t i = 0; i < info.GetSize(); i++) { const SharedLibrary& lib = info.GetEntry(i); - std::string nativePath = lib.GetNativeDebugPath(); + std::string nativePath = lib.GetDebugPath(); // We can use the standard POSIX-based mapper. AutoObjectMapperPOSIX mapper(aLUL->mLog); @@ -44,7 +44,7 @@ void read_procmaps(lul::LUL* aLUL) { if (ok && image && size > 0) { aLUL->NotifyAfterMap(lib.GetStart(), lib.GetEnd() - lib.GetStart(), nativePath.c_str(), image); - } else if (!ok && lib.GetDebugName().IsEmpty()) { + } else if (!ok && lib.GetDebugName().empty()) { // The object has no name and (as a consequence) the mapper failed to map // it. This happens on Linux, where GetInfoForSelf() produces such a // mapping for the VDSO. This is a problem on x86-{linux,android} because diff --git a/tools/profiler/moz.build b/tools/profiler/moz.build index 0f444ecb806d9..70c4c66efdef9 100644 --- a/tools/profiler/moz.build +++ b/tools/profiler/moz.build @@ -66,10 +66,6 @@ if CONFIG["MOZ_GECKO_PROFILER"]: "lul/LulMain.cpp", "lul/platform-linux-lul.cpp", ] - # These files cannot be built in unified mode because of name clashes with mozglue headers on Android. - SOURCES += [ - "core/shared-libraries-linux.cc", - ] if not CONFIG["MOZ_CRASHREPORTER"]: SOURCES += [ "/toolkit/crashreporter/google-breakpad/src/common/linux/elfutils.cc", @@ -94,9 +90,6 @@ if CONFIG["MOZ_GECKO_PROFILER"]: "core/EHABIStackWalk.cpp", ] elif CONFIG["OS_TARGET"] == "Darwin": - UNIFIED_SOURCES += [ - "core/shared-libraries-macos.cc", - ] if CONFIG["TARGET_CPU"] == "aarch64": UNIFIED_SOURCES += [ "core/PowerCounters-mac-arm64.cpp", @@ -115,7 +108,6 @@ if CONFIG["MOZ_GECKO_PROFILER"]: } SOURCES += [ "core/ProfilerCPUFreq-win.cpp", - "core/shared-libraries-win32.cc", ] LOCAL_INCLUDES += [ @@ -180,7 +172,6 @@ EXPORTS += [ "public/ProfilerParent.h", "public/ProfilerRustBindings.h", "public/ProfilerStackWalk.h", - "public/shared-libraries.h", ] EXPORTS.mozilla += [ diff --git a/tools/profiler/public/ProfileAdditionalInformation.h b/tools/profiler/public/ProfileAdditionalInformation.h index 7c9e3db2f6a8c..2da41f4380245 100644 --- a/tools/profiler/public/ProfileAdditionalInformation.h +++ b/tools/profiler/public/ProfileAdditionalInformation.h @@ -14,7 +14,7 @@ #ifndef ProfileAdditionalInformation_h #define ProfileAdditionalInformation_h -#include "shared-libraries.h" +#include "BaseProfilerSharedLibraries.h" #include "js/Value.h" #include "nsString.h" diff --git a/tools/profiler/public/shared-libraries.h b/tools/profiler/public/shared-libraries.h deleted file mode 100644 index 606571882342e..0000000000000 --- a/tools/profiler/public/shared-libraries.h +++ /dev/null @@ -1,202 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef SHARED_LIBRARIES_H_ -#define SHARED_LIBRARIES_H_ - -#include "nsNativeCharsetUtils.h" -#include "nsString.h" -#include - -#include -#include -#include -#include -#include - -namespace IPC { -class MessageReader; -class MessageWriter; -template -struct ParamTraits; -} // namespace IPC - -class SharedLibrary { - public: - SharedLibrary(uintptr_t aStart, uintptr_t aEnd, uintptr_t aOffset, - const nsCString& aBreakpadId, const nsCString& aCodeId, - const nsString& aModuleName, const nsString& aModulePath, - const nsString& aDebugName, const nsString& aDebugPath, - const nsCString& aVersion, const char* aArch) - : mStart(aStart), - mEnd(aEnd), - mOffset(aOffset), - mBreakpadId(aBreakpadId), - mCodeId(aCodeId), - mModuleName(aModuleName), - mModulePath(aModulePath), - mDebugName(aDebugName), - mDebugPath(aDebugPath), - mVersion(aVersion), - mArch(aArch) {} - - bool operator==(const SharedLibrary& other) const { - return (mStart == other.mStart) && (mEnd == other.mEnd) && - (mOffset == other.mOffset) && (mModuleName == other.mModuleName) && - (mModulePath == other.mModulePath) && - (mDebugName == other.mDebugName) && - (mDebugPath == other.mDebugPath) && - (mBreakpadId == other.mBreakpadId) && (mCodeId == other.mCodeId) && - (mVersion == other.mVersion) && (mArch == other.mArch); - } - - uintptr_t GetStart() const { return mStart; } - uintptr_t GetEnd() const { return mEnd; } - uintptr_t GetOffset() const { return mOffset; } - const nsCString& GetBreakpadId() const { return mBreakpadId; } - const nsCString& GetCodeId() const { return mCodeId; } - const nsString& GetModuleName() const { return mModuleName; } - const nsString& GetModulePath() const { return mModulePath; } - const std::string GetNativeDebugPath() const { - nsAutoCString debugPathStr; - - NS_CopyUnicodeToNative(mDebugPath, debugPathStr); - - return debugPathStr.get(); - } - const nsString& GetDebugName() const { return mDebugName; } - const nsString& GetDebugPath() const { return mDebugPath; } - const nsCString& GetVersion() const { return mVersion; } - const std::string& GetArch() const { return mArch; } - size_t SizeOf() const { - return sizeof *this + mBreakpadId.Length() + mCodeId.Length() + - mModuleName.Length() * 2 + mModulePath.Length() * 2 + - mDebugName.Length() * 2 + mDebugPath.Length() * 2 + - mVersion.Length() + mArch.size(); - } - - SharedLibrary() : mStart{0}, mEnd{0}, mOffset{0} {} - - private: - uintptr_t mStart; - uintptr_t mEnd; - uintptr_t mOffset; - nsCString mBreakpadId; - // A string carrying an identifier for a binary. - // - // All platforms have different formats: - // - Windows: The code ID for a Windows PE file. - // It's the PE timestamp and PE image size. - // - macOS: The code ID for a macOS / iOS binary (mach-O). - // It's the mach-O UUID without dashes and without the trailing 0 for the - // breakpad ID. - // - Linux/Android: The code ID for a Linux ELF file. - // It's the complete build ID, as hex string. - nsCString mCodeId; - nsString mModuleName; - nsString mModulePath; - nsString mDebugName; - nsString mDebugPath; - nsCString mVersion; - std::string mArch; - - friend struct IPC::ParamTraits; -}; - -static bool CompareAddresses(const SharedLibrary& first, - const SharedLibrary& second) { - return first.GetStart() < second.GetStart(); -} - -class SharedLibraryInfo { - public: -#ifdef MOZ_GECKO_PROFILER - static SharedLibraryInfo GetInfoForSelf(); -# ifdef XP_WIN - static SharedLibraryInfo GetInfoFromPath(const wchar_t* aPath); -# endif - - static void Initialize(); -#else - static SharedLibraryInfo GetInfoForSelf() { return SharedLibraryInfo(); } -# ifdef XP_WIN - static SharedLibraryInfo GetInfoFromPath(const wchar_t* aPath) { - return SharedLibraryInfo(); - } -# endif - - static void Initialize() {} -#endif - - void AddSharedLibrary(SharedLibrary entry) { mEntries.push_back(entry); } - - void AddAllSharedLibraries(const SharedLibraryInfo& sharedLibraryInfo) { - mEntries.insert(mEntries.end(), sharedLibraryInfo.mEntries.begin(), - sharedLibraryInfo.mEntries.end()); - } - - const SharedLibrary& GetEntry(size_t i) const { return mEntries[i]; } - - SharedLibrary& GetMutableEntry(size_t i) { return mEntries[i]; } - - // Removes items in the range [first, last) - // i.e. element at the "last" index is not removed - void RemoveEntries(size_t first, size_t last) { - mEntries.erase(mEntries.begin() + first, mEntries.begin() + last); - } - - bool Contains(const SharedLibrary& searchItem) const { - return (mEntries.end() != - std::find(mEntries.begin(), mEntries.end(), searchItem)); - } - - size_t GetSize() const { return mEntries.size(); } - - void SortByAddress() { - std::sort(mEntries.begin(), mEntries.end(), CompareAddresses); - } - - // Remove duplicate entries from the vector. - // - // We purposefully don't use the operator== implementation of SharedLibrary - // because it compares all the fields including mStart, mEnd and mOffset which - // are not the same across different processes. - void DeduplicateEntries() { - static auto cmpSort = [](const SharedLibrary& a, const SharedLibrary& b) { - return std::tie(a.GetModuleName(), a.GetBreakpadId()) < - std::tie(b.GetModuleName(), b.GetBreakpadId()); - }; - static auto cmpEqual = [](const SharedLibrary& a, const SharedLibrary& b) { - return std::tie(a.GetModuleName(), a.GetBreakpadId()) == - std::tie(b.GetModuleName(), b.GetBreakpadId()); - }; - // std::unique requires the vector to be sorted first. It can only remove - // consecutive duplicate elements. - std::sort(mEntries.begin(), mEntries.end(), cmpSort); - // Remove the duplicates since it's sorted now. - mEntries.erase(std::unique(mEntries.begin(), mEntries.end(), cmpEqual), - mEntries.end()); - } - - void Clear() { mEntries.clear(); } - - size_t SizeOf() const { - size_t size = 0; - - for (const auto& item : mEntries) { - size += item.SizeOf(); - } - - return size; - } - - private: - std::vector mEntries; - - friend struct IPC::ParamTraits; -}; - -#endif From 6b1d8370ec872ec7c2c96d1e87e54897b5cde5c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Mon, 16 Sep 2024 21:09:34 +0000 Subject: [PATCH 016/115] Bug 1634785 - Rename BaseProfilerSharedLibraries.h to SharedLibraries.h r=mstange,profiler-reviewers Now that we only have one implementation of this code, we don't have to differentiate it with "BaseProfiler". Differential Revision: https://phabricator.services.mozilla.com/D220888 --- mozglue/baseprofiler/core/EHABIStackWalk.cpp | 2 +- mozglue/baseprofiler/core/platform.cpp | 2 +- mozglue/baseprofiler/core/shared-libraries-linux.cc | 2 +- mozglue/baseprofiler/core/shared-libraries-macos.cc | 2 +- mozglue/baseprofiler/core/shared-libraries-win32.cc | 2 +- mozglue/baseprofiler/lul/platform-linux-lul.cpp | 2 +- mozglue/baseprofiler/moz.build | 2 +- .../{BaseProfilerSharedLibraries.h => SharedLibraries.h} | 6 +++--- toolkit/components/backgroundhangmonitor/HangDetails.cpp | 2 +- toolkit/components/telemetry/other/ProcessedStack.h | 2 +- .../telemetry/other/UntrustedModulesDataSerializer.cpp | 2 +- tools/profiler/core/EHABIStackWalk.cpp | 2 +- tools/profiler/core/platform.cpp | 2 +- tools/profiler/core/platform.h | 2 +- tools/profiler/gecko/nsProfiler.cpp | 2 +- tools/profiler/lul/platform-linux-lul.cpp | 2 +- tools/profiler/public/ProfileAdditionalInformation.h | 2 +- 17 files changed, 19 insertions(+), 19 deletions(-) rename mozglue/baseprofiler/public/{BaseProfilerSharedLibraries.h => SharedLibraries.h} (98%) diff --git a/mozglue/baseprofiler/core/EHABIStackWalk.cpp b/mozglue/baseprofiler/core/EHABIStackWalk.cpp index 0c2c855c9bd84..e44fbf144d143 100644 --- a/mozglue/baseprofiler/core/EHABIStackWalk.cpp +++ b/mozglue/baseprofiler/core/EHABIStackWalk.cpp @@ -26,7 +26,7 @@ #include "EHABIStackWalk.h" -#include "BaseProfilerSharedLibraries.h" +#include "SharedLibraries.h" #include "platform.h" #include "mozilla/Atomics.h" diff --git a/mozglue/baseprofiler/core/platform.cpp b/mozglue/baseprofiler/core/platform.cpp index 6080ba88c61f4..9b980472d732b 100644 --- a/mozglue/baseprofiler/core/platform.cpp +++ b/mozglue/baseprofiler/core/platform.cpp @@ -70,7 +70,7 @@ #include "ProfilerBacktrace.h" #include "ProfileBuffer.h" #include "RegisteredThread.h" -#include "BaseProfilerSharedLibraries.h" +#include "SharedLibraries.h" #include "ThreadInfo.h" #include "VTuneProfiler.h" diff --git a/mozglue/baseprofiler/core/shared-libraries-linux.cc b/mozglue/baseprofiler/core/shared-libraries-linux.cc index 41efc0bc118f8..fa5ef88a3f443 100644 --- a/mozglue/baseprofiler/core/shared-libraries-linux.cc +++ b/mozglue/baseprofiler/core/shared-libraries-linux.cc @@ -4,7 +4,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "BaseProfilerSharedLibraries.h" +#include "SharedLibraries.h" #define PATH_MAX_TOSTRING(x) #x #define PATH_MAX_STRING(x) PATH_MAX_TOSTRING(x) diff --git a/mozglue/baseprofiler/core/shared-libraries-macos.cc b/mozglue/baseprofiler/core/shared-libraries-macos.cc index 396290e38afe6..384d95238583b 100644 --- a/mozglue/baseprofiler/core/shared-libraries-macos.cc +++ b/mozglue/baseprofiler/core/shared-libraries-macos.cc @@ -3,7 +3,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "BaseProfilerSharedLibraries.h" +#include "SharedLibraries.h" #include "platform.h" diff --git a/mozglue/baseprofiler/core/shared-libraries-win32.cc b/mozglue/baseprofiler/core/shared-libraries-win32.cc index 3a3225242d5fa..7c1b9d1d5e012 100644 --- a/mozglue/baseprofiler/core/shared-libraries-win32.cc +++ b/mozglue/baseprofiler/core/shared-libraries-win32.cc @@ -5,7 +5,7 @@ #include -#include "BaseProfilerSharedLibraries.h" +#include "SharedLibraries.h" #include "mozilla/glue/WindowsUnicode.h" #include "mozilla/NativeNt.h" diff --git a/mozglue/baseprofiler/lul/platform-linux-lul.cpp b/mozglue/baseprofiler/lul/platform-linux-lul.cpp index a9ee65858dd5d..b247b7161970a 100644 --- a/mozglue/baseprofiler/lul/platform-linux-lul.cpp +++ b/mozglue/baseprofiler/lul/platform-linux-lul.cpp @@ -11,7 +11,7 @@ #include "AutoObjectMapper.h" #include "BaseProfiler.h" -#include "BaseProfilerSharedLibraries.h" +#include "SharedLibraries.h" #include "platform.h" #include "PlatformMacros.h" #include "LulMain.h" diff --git a/mozglue/baseprofiler/moz.build b/mozglue/baseprofiler/moz.build index 2c75814e5ab93..d3f3a19fbc99f 100644 --- a/mozglue/baseprofiler/moz.build +++ b/mozglue/baseprofiler/moz.build @@ -75,8 +75,8 @@ GeneratedFile( EXPORTS += [ "!public/ProfilingCategoryList.h", "public/BaseProfiler.h", - "public/BaseProfilerSharedLibraries.h", "public/BaseProfilingCategory.h", + "public/SharedLibraries.h", ] EXPORTS.mozilla += [ diff --git a/mozglue/baseprofiler/public/BaseProfilerSharedLibraries.h b/mozglue/baseprofiler/public/SharedLibraries.h similarity index 98% rename from mozglue/baseprofiler/public/BaseProfilerSharedLibraries.h rename to mozglue/baseprofiler/public/SharedLibraries.h index 43eacdb8849ec..9dd2291dafbed 100644 --- a/mozglue/baseprofiler/public/BaseProfilerSharedLibraries.h +++ b/mozglue/baseprofiler/public/SharedLibraries.h @@ -4,8 +4,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef BASE_PROFILER_SHARED_LIBRARIES_H_ -#define BASE_PROFILER_SHARED_LIBRARIES_H_ +#ifndef SHARED_LIBRARIES_H_ +#define SHARED_LIBRARIES_H_ #include "BaseProfiler.h" @@ -189,4 +189,4 @@ class SharedLibraryInfo { friend struct IPC::ParamTraits; }; -#endif // BASE_PROFILER_SHARED_LIBRARIES_H_ +#endif // SHARED_LIBRARIES_H_ diff --git a/toolkit/components/backgroundhangmonitor/HangDetails.cpp b/toolkit/components/backgroundhangmonitor/HangDetails.cpp index 362decdc7fd95..8a240d6f9fc4f 100644 --- a/toolkit/components/backgroundhangmonitor/HangDetails.cpp +++ b/toolkit/components/backgroundhangmonitor/HangDetails.cpp @@ -20,7 +20,7 @@ #include "mozilla/GfxMessageUtils.h" // For ParamTraits #include "mozilla/ResultExtensions.h" #include "mozilla/Try.h" -#include "BaseProfilerSharedLibraries.h" +#include "SharedLibraries.h" static const char MAGIC[] = "permahangsavev1"; diff --git a/toolkit/components/telemetry/other/ProcessedStack.h b/toolkit/components/telemetry/other/ProcessedStack.h index beb6ef7a67378..77b203763e0d9 100644 --- a/toolkit/components/telemetry/other/ProcessedStack.h +++ b/toolkit/components/telemetry/other/ProcessedStack.h @@ -13,7 +13,7 @@ #include "mozilla/ipc/MessageChannel.h" #include "mozilla/Vector.h" #include "nsStringFwd.h" -#include "BaseProfilerSharedLibraries.h" +#include "SharedLibraries.h" namespace mozilla { namespace Telemetry { diff --git a/toolkit/components/telemetry/other/UntrustedModulesDataSerializer.cpp b/toolkit/components/telemetry/other/UntrustedModulesDataSerializer.cpp index 49645b1db972f..db732dfbe1b92 100644 --- a/toolkit/components/telemetry/other/UntrustedModulesDataSerializer.cpp +++ b/toolkit/components/telemetry/other/UntrustedModulesDataSerializer.cpp @@ -14,7 +14,7 @@ #include "nsITelemetry.h" #include "nsUnicharUtils.h" #include "nsXULAppAPI.h" -#include "BaseProfilerSharedLibraries.h" +#include "SharedLibraries.h" namespace mozilla { namespace Telemetry { diff --git a/tools/profiler/core/EHABIStackWalk.cpp b/tools/profiler/core/EHABIStackWalk.cpp index 6578ba349fb5b..46ff733ecfc98 100644 --- a/tools/profiler/core/EHABIStackWalk.cpp +++ b/tools/profiler/core/EHABIStackWalk.cpp @@ -24,7 +24,7 @@ #include "EHABIStackWalk.h" -#include "BaseProfilerSharedLibraries.h" +#include "SharedLibraries.h" #include "platform.h" #include "mozilla/Atomics.h" diff --git a/tools/profiler/core/platform.cpp b/tools/profiler/core/platform.cpp index d252bb0f66505..ca082156e834a 100644 --- a/tools/profiler/core/platform.cpp +++ b/tools/profiler/core/platform.cpp @@ -53,7 +53,7 @@ #include "nsDebug.h" #include "nsISupports.h" #include "nsXPCOM.h" -#include "BaseProfilerSharedLibraries.h" +#include "SharedLibraries.h" #include "VTuneProfiler.h" #include "ETWTools.h" diff --git a/tools/profiler/core/platform.h b/tools/profiler/core/platform.h index d1ed958540708..4a3835c33f8ab 100644 --- a/tools/profiler/core/platform.h +++ b/tools/profiler/core/platform.h @@ -44,7 +44,7 @@ #include "mozilla/UniquePtr.h" #include "mozilla/Vector.h" #include "nsString.h" -#include "BaseProfilerSharedLibraries.h" +#include "SharedLibraries.h" #include #include diff --git a/tools/profiler/gecko/nsProfiler.cpp b/tools/profiler/gecko/nsProfiler.cpp index 88d893b4bf870..119077c6772ac 100644 --- a/tools/profiler/gecko/nsProfiler.cpp +++ b/tools/profiler/gecko/nsProfiler.cpp @@ -37,7 +37,7 @@ #include "nsString.h" #include "nsThreadUtils.h" #include "platform.h" -#include "BaseProfilerSharedLibraries.h" +#include "SharedLibraries.h" #include "zlib.h" #ifndef ANDROID diff --git a/tools/profiler/lul/platform-linux-lul.cpp b/tools/profiler/lul/platform-linux-lul.cpp index c72de2bb4267b..cc6074eb01ae3 100644 --- a/tools/profiler/lul/platform-linux-lul.cpp +++ b/tools/profiler/lul/platform-linux-lul.cpp @@ -13,7 +13,7 @@ #include "platform.h" #include "PlatformMacros.h" #include "LulMain.h" -#include "BaseProfilerSharedLibraries.h" +#include "SharedLibraries.h" #include "AutoObjectMapper.h" // Contains miscellaneous helpers that are used to connect the Gecko Profiler diff --git a/tools/profiler/public/ProfileAdditionalInformation.h b/tools/profiler/public/ProfileAdditionalInformation.h index 2da41f4380245..1b9baeca0a424 100644 --- a/tools/profiler/public/ProfileAdditionalInformation.h +++ b/tools/profiler/public/ProfileAdditionalInformation.h @@ -14,7 +14,7 @@ #ifndef ProfileAdditionalInformation_h #define ProfileAdditionalInformation_h -#include "BaseProfilerSharedLibraries.h" +#include "SharedLibraries.h" #include "js/Value.h" #include "nsString.h" From 0a6112d539809d94a83b21f064a855c4f80fc057 Mon Sep 17 00:00:00 2001 From: Nika Layzell Date: Mon, 16 Sep 2024 21:11:30 +0000 Subject: [PATCH 017/115] Bug 1914191 - Part 1: Remove keepProcessesAlive.webIsolated.perOrigin, r=mccr8 Due to changes in how processes are selected when doing BFCached navigations, the process will be re-used for the navigation meaning we no longer need to add logic explicitly keeping it alive. This also tweaks the code which checks this to explicitly stop checking any keepProcessesAlive prefs for these origin-specific remote types. Differential Revision: https://phabricator.services.mozilla.com/D220191 --- .../performance/browser_preferences_usage.js | 9 +-------- dom/ipc/ContentParent.cpp | 10 ++-------- dom/xhr/tests/browser_xhr_onchange_leak.js | 16 +++++++++------- 3 files changed, 12 insertions(+), 23 deletions(-) diff --git a/browser/base/content/test/performance/browser_preferences_usage.js b/browser/base/content/test/performance/browser_preferences_usage.js index 46d17a2f7bc6d..4ad2f8c1f5418 100644 --- a/browser/base/content/test/performance/browser_preferences_usage.js +++ b/browser/base/content/test/performance/browser_preferences_usage.js @@ -156,8 +156,7 @@ add_task(async function navigate_around() { // Disable bfcache so that we can measure more accurately the number of // pref accesses in the child processes. // If bfcache is enabled on Fission - // dom.ipc.keepProcessesAlive.webIsolated.perOrigin and - // security.sandbox.content.force-namespace are accessed only a couple of + // security.sandbox.content.force-namespace is accessed only a couple of // times. ["browser.sessionhistory.max_total_viewers", 0], ], @@ -183,12 +182,6 @@ add_task(async function navigate_around() { min: 50, max: 51, }; - // This pref is only accessed in automation to speed up tests. - knownProblematicPrefs["dom.ipc.keepProcessesAlive.webIsolated.perOrigin"] = - { - min: 50, - max: 51, - }; if (AppConstants.platform == "linux") { // The following sandbox pref is covered by // https://bugzilla.mozilla.org/show_bug.cgi?id=1600189 diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 668ad02a634c9..6b0acc29b8c2a 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -2134,7 +2134,7 @@ bool ContentParent::MaybeBeginShutDown(bool aIgnoreKeepAlivePref) { // processes alive for performance reasons (e.g. test runs and privileged // content process for some about: pages). We don't want to alter behavior // if the pref is not set, so default to 0. - if (!aIgnoreKeepAlivePref && mIsInPool && + if (!aIgnoreKeepAlivePref && mIsInPool && !mRemoteType.Contains('=') && !AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) { auto* contentParents = sBrowserContentParents->Get(mRemoteType); MOZ_RELEASE_ASSERT( @@ -2142,13 +2142,7 @@ bool ContentParent::MaybeBeginShutDown(bool aIgnoreKeepAlivePref) { "mIsInPool, yet no entry for mRemoteType in sBrowserContentParents?"); nsAutoCString keepAlivePref("dom.ipc.keepProcessesAlive."); - if (StringBeginsWith(mRemoteType, FISSION_WEB_REMOTE_TYPE) && - xpc::IsInAutomation()) { - keepAlivePref.Append(FISSION_WEB_REMOTE_TYPE); - keepAlivePref.AppendLiteral(".perOrigin"); - } else { - keepAlivePref.Append(mRemoteType); - } + keepAlivePref.Append(mRemoteType); int32_t processesToKeepAlive = 0; if (NS_SUCCEEDED(Preferences::GetInt(keepAlivePref.get(), diff --git a/dom/xhr/tests/browser_xhr_onchange_leak.js b/dom/xhr/tests/browser_xhr_onchange_leak.js index 4d13e33ee4712..6c4dbcaf7f2e8 100644 --- a/dom/xhr/tests/browser_xhr_onchange_leak.js +++ b/dom/xhr/tests/browser_xhr_onchange_leak.js @@ -8,16 +8,11 @@ // turned off once it is closed. add_task(async function test() { - // We need to reuse the content process when we navigate so the entire process - // with the possible-leaking window doesn't get torn down. - await SpecialPowers.pushPrefEnv({ - set: [["dom.ipc.keepProcessesAlive.webIsolated.perOrigin", 1]], - }); - const url = "http://mochi.test:8888/browser/dom/xhr/tests/browser_xhr_onchange_leak.html"; let newTab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url); let browser = gBrowser.selectedBrowser; + let origContentProcessId = browser.frameLoader.remoteTab.contentProcessId; let pageShowPromise = BrowserTestUtils.waitForContentEvent( browser, "pageshow", @@ -26,6 +21,13 @@ add_task(async function test() { BrowserTestUtils.startLoadingURIString(browser, "http://mochi.test:8888/"); await pageShowPromise; - ok(pageShowPromise, "need to check something"); + is( + browser.frameLoader.remoteTab.contentProcessId, + origContentProcessId, + "we must still be in the same process after we navigate " + + "so the entire process with the possibly-leaking window " + + "doesn't get torn down" + ); + BrowserTestUtils.removeTab(newTab); }); From f6d683ff8e4ab8589839d40cc07a73d30aa1a8d9 Mon Sep 17 00:00:00 2001 From: Nika Layzell Date: Mon, 16 Sep 2024 21:11:30 +0000 Subject: [PATCH 018/115] Bug 1914191 - Part 2: Introduce the dom.ipc.processReuse.unusedGraceMs pref, r=smaug If set to a non-zero value, this pref will change the process shutdown logic to use an IdleTaskRunner to clean up a process when it is no longer in use, rather than immediately marking the process as unable to be re-used. This is most beneficial when runnning tests, which can sometimes rapidly cycle between processes, inefficiently starting up and shutting them down very rapidly. Due some test failures due to tests depending on the old process re-use behaviour, this pref is being landed disabled such that it can be enabled for specific test suites. Differential Revision: https://phabricator.services.mozilla.com/D220192 --- dom/ipc/ContentParent.cpp | 85 +++++++++++++++++++++--- dom/ipc/ContentParent.h | 14 ++-- modules/libpref/init/StaticPrefList.yaml | 7 ++ 3 files changed, 93 insertions(+), 13 deletions(-) diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 6b0acc29b8c2a..fbf6466de87c2 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -747,7 +747,9 @@ void ContentParent::ReleaseCachedProcesses() { } for (const auto& cp : fixArray) { - if (cp->MaybeBeginShutDown(/* aIgnoreKeepAlivePref */ true)) { + cp->MaybeBeginShutDown(/* aImmediate */ true, + /* aIgnoreKeepAlivePref */ true); + if (cp->IsDead()) { // Make sure that this process is no longer accessible from JS by its // message manager. cp->ShutDownMessageManager(); @@ -2093,8 +2095,19 @@ void ContentParent::ActorDestroy(ActorDestroyReason why) { UniqueContentParentKeepAlive ContentParent::TryAddKeepAlive( uint64_t aBrowserId) { - return UniqueContentParentKeepAliveFromThreadsafe( - mThreadsafeHandle->TryAddKeepAlive(aBrowserId)); + UniqueContentParentKeepAlive keepAlive = + UniqueContentParentKeepAliveFromThreadsafe( + mThreadsafeHandle->TryAddKeepAlive(aBrowserId)); + // If we successfully added a KeepAlive, we can cancel any pending + // MaybeBeginShutDown call (as it will no longer begin process shutdown due to + // outstanding KeepAlives). + // This is just an optimization and the MaybeBeginShutDown call will be a + // no-op if it is called with the KeepAlive held. + if (keepAlive && mMaybeBeginShutdownRunner) { + mMaybeBeginShutdownRunner->Cancel(); + mMaybeBeginShutdownRunner = nullptr; + } + return keepAlive; } UniqueContentParentKeepAlive ContentParent::AddKeepAlive(uint64_t aBrowserId) { @@ -2118,8 +2131,26 @@ void ContentParent::RemoveKeepAlive(uint64_t aBrowserId) { MaybeBeginShutDown(); } -bool ContentParent::MaybeBeginShutDown(bool aIgnoreKeepAlivePref) { +void ContentParent::MaybeBeginShutDown(bool aImmediate, + bool aIgnoreKeepAlivePref) { AssertIsOnMainThread(); + MOZ_ASSERT(!aIgnoreKeepAlivePref || aImmediate, + "aIgnoreKeepAlivePref requires aImmediate"); + + // Don't bother waiting, even if `aImmediate` is not true, if the process + // can no longer be re-used (e.g. because it is dead, or we're in shutdown). + bool immediate = + aImmediate || IsDead() || + AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed) || + StaticPrefs::dom_ipc_processReuse_unusedGraceMs() == 0; + + // Clean up any scheduled idle task unless we schedule a new one. + auto cancelIdleTask = MakeScopeExit([&] { + if (mMaybeBeginShutdownRunner) { + mMaybeBeginShutdownRunner->Cancel(); + mMaybeBeginShutdownRunner = nullptr; + } + }); { RecursiveMutexAutoLock lock(mThreadsafeHandle->mMutex); @@ -2127,7 +2158,7 @@ bool ContentParent::MaybeBeginShutDown(bool aIgnoreKeepAlivePref) { // down. Return. if (IsLaunching() || !mThreadsafeHandle->mKeepAlivesPerBrowserId.IsEmpty()) { - return false; + return; } // If we're not in main process shutdown, we might want to keep some content @@ -2151,14 +2182,51 @@ bool ContentParent::MaybeBeginShutDown(bool aIgnoreKeepAlivePref) { static_cast(processesToKeepAlive)) { // We're keeping this process alive even though there are no keepalives // for it due to the keepalive pref. - return false; + return; } } - // We're not keeping this process alive, begin shutdown. - mThreadsafeHandle->mShutdownStarted = true; + if (immediate) { + // We're not keeping this process alive, begin shutdown. + mThreadsafeHandle->mShutdownStarted = true; + } + } + + // If we're not beginning shutdown immediately, make sure an idle task runner + // is scheduled to call us back. This delay is intended to avoid unnecessary + // process churn when a process becomes momentarily unused (which can happen + // frequently when running tests). + if (!immediate) { + // We want an idle task to call us back, don't cancel it. + cancelIdleTask.release(); + + MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug, + ("MaybeBeginShutDown(%d) would begin shutdown, %s", OtherChildID(), + mMaybeBeginShutdownRunner ? "already delayed" : "delaying")); + + if (!mMaybeBeginShutdownRunner) { + TimeDuration startDelay = TimeDuration::FromMilliseconds( + StaticPrefs::dom_ipc_processReuse_unusedGraceMs()); + TimeDuration maxDelay = startDelay + TimeDuration::FromSeconds(1); + mMaybeBeginShutdownRunner = IdleTaskRunner::Create( + [self = RefPtr{this}](TimeStamp) -> bool { + MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug, + ("MaybeBeginShutDown(%d) resuming after delay", + self->OtherChildID())); + self->MaybeBeginShutDown(/* aImmediate */ true); + return true; + }, + "ContentParent::IdleMaybeBeginShutdown", startDelay, maxDelay, + /* aMinimumUsefulBudget */ TimeDuration::FromMilliseconds(3), + /* aRepeating */ false, [] { return false; }); + } + return; } + MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug, + ("MaybeBeginShutDown(%d) shutdown starting (%u bps)", OtherChildID(), + ManagedPBrowserParent().Count())); + MarkAsDead(); SignalImpendingShutdownToContentJS(); @@ -2171,7 +2239,6 @@ bool ContentParent::MaybeBeginShutDown(bool aIgnoreKeepAlivePref) { // All tabs are dead, we can fully begin shutting down. AsyncSendShutDownMessage(); } - return true; } void ContentParent::StartSendShutdownTimer() { diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h index f854b0e146dd4..c1ec40ee78711 100644 --- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -25,6 +25,7 @@ #include "mozilla/Attributes.h" #include "mozilla/DataMutex.h" #include "mozilla/HalTypes.h" +#include "mozilla/IdleTaskRunner.h" #include "mozilla/LinkedList.h" #include "mozilla/Maybe.h" #include "mozilla/MemoryReportingProcess.h" @@ -398,14 +399,17 @@ class ContentParent final : public PContentParent, * shutdown process. Automatically called whenever a KeepAlive is removed, or * a BrowserParent is removed. * - * Returns `true` if shutdown for the process has been started, and `false` - * otherwise. + * By default when a process becomes unused, it will be kept alive for a short + * time, potentially allowing the process to be re-used. * + * @param aImmediate If true, immediately begins shutdown if the process is + * eligible, without any grace period for process re-use. * @param aIgnoreKeepAlivePref If true, the dom.ipc.keepProcessesAlive.* * preferences will be ignored, for clean-up of - * cached processes. + * cached processes. Requires aImmediate. */ - bool MaybeBeginShutDown(bool aIgnoreKeepAlivePref = false); + void MaybeBeginShutDown(bool aImmediate = false, + bool aIgnoreKeepAlivePref = false); TestShellParent* CreateTestShell(); @@ -1615,6 +1619,8 @@ class ContentParent final : public PContentParent, // Cleared once startup is complete. UniquePtr mPrefSerializer; + RefPtr mMaybeBeginShutdownRunner; + static uint32_t sMaxContentProcesses; static uint32_t sPageLoadEventCounter; diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml index 8230e627efaeb..6da2d65491049 100644 --- a/modules/libpref/init/StaticPrefList.yaml +++ b/modules/libpref/init/StaticPrefList.yaml @@ -3010,6 +3010,13 @@ value: false mirror: always +# If non-zero, a grace delay (in milliseconds) during which unused content +# processes are kept available for re-use to avoid unnecessary process churn. +- name: dom.ipc.processReuse.unusedGraceMs + type: uint32_t + value: 0 + mirror: always + # Process launch delay (in milliseconds). - name: dom.ipc.processPrelaunch.delayMs type: uint32_t From b30c46e080d40c82906cc57103e27dded1948493 Mon Sep 17 00:00:00 2001 From: Nika Layzell Date: Mon, 16 Sep 2024 21:11:31 +0000 Subject: [PATCH 019/115] Bug 1914191 - Part 3: Switch WPT canvas tests to using the unusedGraceMs pref, r=smaug This test suite was previously using the keepProcessesAlive pref to reduce process churn, and is the original motivation behind the new change. As there are a number of test failures if we turn on the pref for all test suties, only turn it on for this specific test suite to allow the change to land sooner. Differential Revision: https://phabricator.services.mozilla.com/D221383 --- testing/web-platform/meta/html/canvas/__dir__.ini | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/testing/web-platform/meta/html/canvas/__dir__.ini b/testing/web-platform/meta/html/canvas/__dir__.ini index c8f88e829bccb..41856314e55a1 100644 --- a/testing/web-platform/meta/html/canvas/__dir__.ini +++ b/testing/web-platform/meta/html/canvas/__dir__.ini @@ -1,3 +1,2 @@ -prefs: - if not fission: [dom.ipc.keepProcessesAlive.web: 1] +prefs: [dom.ipc.processReuse.unusedGraceMs: 1000] tags: [canvas] From 40a61db38ba0334fbe90ad05b92669242b987f85 Mon Sep 17 00:00:00 2001 From: Ryan Safaeian Date: Mon, 16 Sep 2024 21:34:04 +0000 Subject: [PATCH 020/115] Bug 1914082 - Create LoginLine component for contextual password manager. r=credential-management-reviewers,fluent-reviewers,desktop-theme-reviewers,bolsson,dao,mtigley Differential Revision: https://phabricator.services.mozilla.com/D219706 --- .../satchel/megalist/content/LoginLine.css | 237 ++++++++++++++++++ .../satchel/megalist/content/LoginLine.mjs | 227 +++++++++++++++++ .../satchel/megalist/content/megalist.ftl | 32 +++ 3 files changed, 496 insertions(+) create mode 100644 toolkit/components/satchel/megalist/content/LoginLine.css create mode 100644 toolkit/components/satchel/megalist/content/LoginLine.mjs diff --git a/toolkit/components/satchel/megalist/content/LoginLine.css b/toolkit/components/satchel/megalist/content/LoginLine.css new file mode 100644 index 0000000000000..442e3f2e55c87 --- /dev/null +++ b/toolkit/components/satchel/megalist/content/LoginLine.css @@ -0,0 +1,237 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +:host { + --outer-border-radius: var(--border-radius-small); + --inner-border-radius: calc(var(--outer-border-radius) - 2px); + --alert-color: var(--icon-color-warning); + --input-field-color: var(--link-color); + --input-field-color-hover: var(--button-text-color-hover); + --copy-tansition: opacity 250ms linear; + background-color: var(--background-color-box); + color: inherit; + padding: 3px; +} + +:host([linetype="password"]) { + --alert-color: var(--icon-color-critical); +} + +:host([linetype="username"]) { + --alert-color: var(--icon-color-information); +} + +:host([linetype="password"]), +:host([linetype="username"]) { + /* We must give this component a fixed height because it will be used inside a virtual list which requires + * to know the height of its content. */ + --line-container-height: 48px; + --input-field-color: var(--button-text-color); + --input-field-color-hover: var(--input-field-color); +} + +:host([linetype="origin"]) { + --line-container-height: 44px; + border-radius: var(--outer-border-radius) var(--outer-border-radius) 0 0; + + .input-field { + text-decoration: underline; + } +} + +:host(login-line:focus-visible) { + > .line-container { + background-color: var(--button-background-color-hover); + } + + .input-field { + color: var(--input-field-color-hover); + } +} + +:host(concealed-login-line) { + display: flex; + padding: 0; + + > login-line { + flex-grow: 1; + + &:focus-visible { + z-index: 1; + } + } + + > .reveal-button-container { + display: flex; + justify-content: end; + align-items: center; + height: var(--line-container-height); + margin-inline-end: var(--space-small); + background-color: var(--background-color-box); + --button-text-color-ghost: var(--icon-color); + --button-text-color-ghost-hover: var(--icon-color); + + &:focus-visible { + z-index: 1; + } + + > moz-button:focus-within { + background-color: var(--button-background-color-ghost-hover); + border-color: var(--button-border-color-ghost-hover); + color: var(--button-text-color-ghost-hover); + } + } +} + +:host([linetype="username"]), +:host([linetype="password"]) { + > .line-container.copied { + &:hover, + &:focus-visible, + &:active { + background-color: var(--background-color-box); + } + + .input-label::after { + position: static; + visibility: visible; + opacity: 1; + } + + .copy-icon { + opacity: 0; + } + + .check-icon { + visibility: visible; + opacity: 1; + } + } + + .copy-container { + display: grid; + justify-items: center; + align-items: center; + height: 32px; + width: 32px; + + > .copy-icon { + grid-column: 1; + grid-row: 1; + height: var(--icon-size-default); + width: var(--icon-size-default); + -moz-context-properties: fill; + fill: var(--icon-color); + + @media not (prefers-reduced-motion) { + transition: var(--copy-tansition); + } + } + + > .check-icon { + grid-column: 1; + grid-row: 1; + height: var(--icon-size-default); + width: var(--icon-size-default); + -moz-context-properties: fill; + fill: var(--icon-color-success); + opacity: 0; + visibility: hidden; + + @media not (prefers-reduced-motion) { + transition: var(--copy-tansition); + } + } + } +} + +:host([alert]) .alert-icon { + display: block; + height: 12px; + width: 12px; + -moz-context-properties: fill, stroke; + fill: var(--alert-color); + stroke: var(--alert-color); +} + +.label-container { + display: flex; + column-gap: var(--space-xxsmall); + position: relative; +} + +.input-label { + display: block; + text-transform: uppercase; + color: var(--text-color); + font-size: 0.525em; + cursor: unset; + + &::after { + position: absolute; + content: " " attr(data-after); + visibility: hidden; + opacity: 0; + + @media not (prefers-reduced-motion) { + transition: var(--copy-tansition); + } + } +} + +.line-container { + height: var(--line-container-height); + border-radius: var(--inner-border-radius); + display: flex; + justify-content: space-between; + align-items: center; + cursor: pointer; + + &:hover, + &:focus-visible { + background: var(--button-background-color-hover); + + .input-field { + color: var(--input-field-color-hover); + } + } + + &:active { + background: var(---button-background-color-active); + + .input-field { + color: var(--input-field-color-hover); + } + } +} + +.input-container { + display: flex; + flex-direction: column; + row-gap: var(--space-xxsmall); + margin-inline-start: var(--space-medium); +} + +.value-container { + display: flex; + align-items: end; + column-gap: var(--space-small); +} + +.fav-icon { + margin: 0; + height: var(--icon-size-default); + width: var(--icon-size-default); + -moz-context-properties: fill; + fill: var(--icon-color); +} + +.input-field { + all: unset; + display: inline-block; + text-overflow: ellipsis; + overflow: hidden; + appearance: textfield; + color: var(--input-field-color); +} diff --git a/toolkit/components/satchel/megalist/content/LoginLine.mjs b/toolkit/components/satchel/megalist/content/LoginLine.mjs new file mode 100644 index 0000000000000..f345b8fdb30ee --- /dev/null +++ b/toolkit/components/satchel/megalist/content/LoginLine.mjs @@ -0,0 +1,227 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import { + html, + when, + ifDefined, +} from "chrome://global/content/vendor/lit.all.mjs"; +import { MozLitElement } from "chrome://global/content/lit-utils.mjs"; + +class LoginLine extends MozLitElement { + static shadowRootOptions = { + ...MozLitElement.shadowRootOptions, + delegatesFocus: true, + }; + + static properties = { + value: { type: String }, + labelL10nId: { type: String }, + lineType: { type: String }, + inputType: { type: String }, + favIcon: { type: String }, + alert: { type: Boolean }, + }; + + #copyTimeoutID; + + static get queries() { + return { + lineContainer: ".line-container", + }; + } + + #canCopy() { + return this.lineType !== "origin"; + } + + #addCopyAttr() { + return ifDefined(this.#canCopy() ? "data-after" : undefined); + } + + #handleLineClick() { + if (!this.#canCopy()) { + return; + } + if (!this.lineContainer.classList.contains("copied")) { + this.lineContainer.classList.add("copied"); + this.#copyTimeoutID = setTimeout(() => { + this.lineContainer.classList.remove("copied"); + this.#copyTimeoutID = null; + }, 4000); + } + } + + disconnectedCallback() { + super.disconnectedCallback(); + if (this.#copyTimeoutID) { + clearTimeout(this.#copyTimeoutID); + } + } + + constructor() { + super(); + this.favIcon = ""; + this.#copyTimeoutID = null; + } + + render() { + return html` + +
this.#handleLineClick()} + @keypress=${e => { + if (e.code == "Enter") { + this.#handleLineClick(); + } + }} + > +
+
+ + ${when( + this.alert, + () => + html` ` + )} +
+
+ ${when( + this.favIcon, + () => + html` ` + )} + +
+
+ ${when(this.#canCopy(), () => { + return html` +
+ + +
+ `; + })} +
+ `; + } +} + +class ConcealedLoginLine extends MozLitElement { + static properties = { + value: { type: String }, + labelL10nId: { type: String }, + alert: { type: Boolean }, + visible: { type: Boolean }, + onLineClick: { type: Function }, + onButtonClick: { type: Function }, + }; + + static CONCEALED_VALUE_TEXT = " ".repeat(8); + + static get queries() { + return { + loginLine: "login-line", + revealBtn: "moz-button", + }; + } + + get #inputType() { + return !this.visible ? "password" : "text"; + } + + get #displayValue() { + return !this.visible ? ConcealedLoginLine.CONCEALED_VALUE_TEXT : this.value; + } + + get #revealBtnLabel() { + return !this.visible ? "show-password-button" : "hide-password-button"; + } + + #revealIconSrc() { + return this.visible + ? /* eslint-disable-next-line mozilla/no-browser-refs-in-toolkit */ + "chrome://browser/content/aboutlogins/icons/password-hide.svg" + : /* eslint-disable-next-line mozilla/no-browser-refs-in-toolkit */ + "chrome://browser/content/aboutlogins/icons/password.svg"; + } + + render() { + return html` + { + if (e.key === "Enter") { + this.onLineClick(); + } + }} + > + +
+ e.preventDefault()} + @keypress=${e => { + if (e.key === "Enter") { + this.revealBtn.setAttribute("data-l10n-id", this.#revealBtnLabel); + this.loginLine.focus(); + this.onButtonClick(); + } + }} + @click=${() => { + this.revealBtn.setAttribute("data-l10n-id", this.#revealBtnLabel); + this.onButtonClick(); + }} + > +
`; + } +} + +customElements.define("login-line", LoginLine); +customElements.define("concealed-login-line", ConcealedLoginLine); diff --git a/toolkit/components/satchel/megalist/content/megalist.ftl b/toolkit/components/satchel/megalist/content/megalist.ftl index 5fa7df38aaefb..6fe455e658d99 100644 --- a/toolkit/components/satchel/megalist/content/megalist.ftl +++ b/toolkit/components/satchel/megalist/content/megalist.ftl @@ -156,6 +156,38 @@ passwords-origin-tooltip = Enter the exact address where you’ll sign in to thi passwords-username-tooltip = Enter the username, email address, or account number you use to sign in. passwords-password-tooltip = Enter the password used to sign in to this account. +website-icon = + .alt = Website Icon +copy-icon = + .alt = Copy +check-icon = + .alt = Copied +alert-icon = + .alt = Warning + +# Variables +# $url (string) - The url associated with the login +origin-login-line = + .aria-label = Visit { $url } + .title = Visit { $url } +# Variables +# $username (string) - The username associated with the login +username-login-line = + .aria-label = Copy Username { $username } + .title = Copy Username { $username } +password-login-line = + .aria-label = Copy Password + .title = Copy Password +edit-login-button = Edit + .tooltiptext = Edit Password + +show-password-button = + .aria-label = Show Password + .title = Show Password +hide-password-button = + .aria-label = Hide Password + .title = Hide Password + ## Payments payments-command-create = Add Payment Method From fef827b7b0818f5ee7d7166ab54fc47ca6ca8f79 Mon Sep 17 00:00:00 2001 From: Ryan Safaeian Date: Mon, 16 Sep 2024 21:34:04 +0000 Subject: [PATCH 021/115] Bug 1914082 - Use LoginLine component in new Password Card Component. r=fluent-reviewers,desktop-theme-reviewers,dao,mtigley,ayeddi Differential Revision: https://phabricator.services.mozilla.com/D219707 --- toolkit/components/satchel/jar.mn | 3 + .../megalist/MegalistViewModel.sys.mjs | 26 +- .../datasources/LoginDataSource.sys.mjs | 41 +-- .../megalist/content/MegalistAlpha.mjs | 8 +- .../satchel/megalist/content/PasswordCard.css | 29 ++ .../satchel/megalist/content/PasswordCard.mjs | 264 ++++++++++++++---- .../satchel/megalist/content/megalist.css | 6 - .../satchel/megalist/content/megalist.ftl | 6 +- .../browser/browser_passwords_sidebar.js | 88 +++++- .../megalist/content/tests/browser/head.js | 8 + 10 files changed, 361 insertions(+), 118 deletions(-) create mode 100644 toolkit/components/satchel/megalist/content/PasswordCard.css diff --git a/toolkit/components/satchel/jar.mn b/toolkit/components/satchel/jar.mn index 46d4d37720ecb..0c49308c1afa6 100644 --- a/toolkit/components/satchel/jar.mn +++ b/toolkit/components/satchel/jar.mn @@ -9,3 +9,6 @@ toolkit.jar: content/global/megalist/PasswordCard.mjs (megalist/content/PasswordCard.mjs) content/global/megalist/Dialog.mjs (megalist/content/Dialog.mjs) content/global/megalist/LoginFormComponent/login-form.css (megalist/content/LoginFormComponent/login-form.css) + content/global/megalist/PasswordCard.css (megalist/content/PasswordCard.css) + content/global/megalist/LoginLine.mjs (megalist/content/LoginLine.mjs) + content/global/megalist/LoginLine.css (megalist/content/LoginLine.css) diff --git a/toolkit/components/satchel/megalist/MegalistViewModel.sys.mjs b/toolkit/components/satchel/megalist/MegalistViewModel.sys.mjs index 7a2b0d1104135..12be17105301b 100644 --- a/toolkit/components/satchel/megalist/MegalistViewModel.sys.mjs +++ b/toolkit/components/satchel/megalist/MegalistViewModel.sys.mjs @@ -90,11 +90,12 @@ export class MegalistViewModel { snapshot.href = snapshotData.href; } - if (snapshotData.stickers) { - for (const sticker of snapshotData.stickers()) { - snapshot.stickers ??= []; - snapshot.stickers.push(sticker); - } + if ("breached" in snapshotData) { + snapshot.breached = snapshotData.breached; + } + + if ("vulnerable" in snapshotData) { + snapshot.vulnerable = snapshotData.vulnerable; } if ("toggleTooltip" in snapshotData) { @@ -171,11 +172,22 @@ export class MegalistViewModel { } } - async #verifyUser(promptMessage, prefName) { + async #verifyUser( + promptMessage, + prefName, + captionDialog = "", + parentWindow = null, + generateKeyIfNotAvailable = false + ) { if (!this.getOSAuthEnabled(prefName)) { promptMessage = false; } - let result = await lazy.OSKeyStore.ensureLoggedIn(promptMessage); + let result = await lazy.OSKeyStore.ensureLoggedIn( + promptMessage, + captionDialog, + parentWindow, + generateKeyIfNotAvailable + ); return result.authenticated; } diff --git a/toolkit/components/satchel/megalist/aggregator/datasources/LoginDataSource.sys.mjs b/toolkit/components/satchel/megalist/aggregator/datasources/LoginDataSource.sys.mjs index 6674e7258f099..fe384964e02df 100644 --- a/toolkit/components/satchel/megalist/aggregator/datasources/LoginDataSource.sys.mjs +++ b/toolkit/components/satchel/megalist/aggregator/datasources/LoginDataSource.sys.mjs @@ -28,11 +28,11 @@ const ALERT_VALUES = { none: 2, }; -const SUPPORT_URL = +export const SUPPORT_URL = Services.urlFormatter.formatURLPref("app.support.baseURL") + "password-manager-remember-delete-edit-logins"; -const PREFRENCES_URL = "about:preferences#privacy-logins"; +export const PREFERENCES_URL = "about:preferences#privacy-logins"; /** * Data source for Logins. @@ -90,10 +90,6 @@ export class LoginDataSource extends DataSourceBase { id: "DismissBreach", label: strings.dismissBreachCommandLabel, }; - const noOriginSticker = { type: "error", label: "😾 Missing origin" }; - const noPasswordSticker = { type: "error", label: "😾 Missing password" }; - const breachedSticker = { type: "warning", label: "BREACH" }; - const vulnerableSticker = { type: "risk", label: "🤮 Vulnerable" }; const tooltip = { expand: strings.expandSection, collapse: strings.collapseSection, @@ -126,9 +122,11 @@ export class LoginDataSource extends DataSourceBase { this.#header.executeImportFromBrowser = () => this.#importFromBrowser(); this.#header.executeRemoveAll = () => this.#removeAllPasswords(); - this.#header.executeSettings = () => this.#openMenuLink(PREFRENCES_URL); - this.#header.executeHelp = () => this.#openMenuLink(SUPPORT_URL); this.#header.executeExport = async () => this.#confirmExportLogins(); + this.#header.executeSettings = () => this.#openLink(PREFERENCES_URL); + this.#header.executeHelp = () => this.#openLink(SUPPORT_URL); + this.#header.executeExport = async () => this.#confirmExportLogins(); + this.#exportPasswordsStrings = { OSReauthMessage: strings.exportPasswordsOSReauthMessage, OSAuthDialogCaption: strings.passwordOSAuthDialogCaption, @@ -154,6 +152,8 @@ export class LoginDataSource extends DataSourceBase { } }; + const openOriginInNewTab = origin => this.#openLink(origin); + this.#originPrototype = this.prototypeDataLine({ field: { value: "origin" }, label: { value: strings.originLabel }, @@ -199,15 +199,9 @@ export class LoginDataSource extends DataSourceBase { this.setLayout({ id: "remove-login" }); }, }, - stickers: { - *value() { - if (this.isEditing() && !this.editingValue.length) { - yield noOriginSticker; - } - - if (this.breached) { - yield breachedSticker; - } + executeOpenLink: { + value() { + openOriginInNewTab(this.record.origin); }, }, }); @@ -253,17 +247,6 @@ export class LoginDataSource extends DataSourceBase { ); }, }, - stickers: { - *value() { - if (this.isEditing() && !this.editingValue.length) { - yield noPasswordSticker; - } - - if (this.vulnerable) { - yield vulnerableSticker; - } - }, - }, commands: { value: [ { ...copyCommand, verify: true }, @@ -482,7 +465,7 @@ export class LoginDataSource extends DataSourceBase { fp.open(fpCallback); } - #openMenuLink(url) { + #openLink(url) { const { BrowserWindowTracker } = ChromeUtils.importESModule( "resource:///modules/BrowserWindowTracker.sys.mjs" ); diff --git a/toolkit/components/satchel/megalist/content/MegalistAlpha.mjs b/toolkit/components/satchel/megalist/content/MegalistAlpha.mjs index 54c0e7deceeaa..c29ae127c9c1c 100644 --- a/toolkit/components/satchel/megalist/content/MegalistAlpha.mjs +++ b/toolkit/components/satchel/megalist/content/MegalistAlpha.mjs @@ -128,19 +128,21 @@ export class MegalistAlpha extends MozLitElement { // TODO: This should be passed to virtualized list with an explicit height. renderListItem({ origin: displayOrigin, username, password }) { - return html``; + > + `; } // TODO: Temporary. Should be rendered by the virtualized list. renderList() { return this.records.length ? html` -
+
${this.records.map(record => this.renderListItem(record))}
` diff --git a/toolkit/components/satchel/megalist/content/PasswordCard.css b/toolkit/components/satchel/megalist/content/PasswordCard.css new file mode 100644 index 0000000000000..b4882b5f1e069 --- /dev/null +++ b/toolkit/components/satchel/megalist/content/PasswordCard.css @@ -0,0 +1,29 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +:host { + background-color: var(--background-color-box); + border: var(--border-width) solid var(--border-color); + border-radius: var(--border-radius-small); + box-shadow: var(--box-shadow-10); + min-width: 255px; + display: grid; +} + +.line-item:focus-visible, +.edit-line-container:focus-visible { + z-index: 1; +} + +.edit-line-container { + height: 50px; + display: flex; + align-items: center; + justify-content: end; + border-radius: 0 0 var(--border-radius-small) var(--border-radius-small); + + > .edit-button { + margin: var(--space-small); + } +} diff --git a/toolkit/components/satchel/megalist/content/PasswordCard.mjs b/toolkit/components/satchel/megalist/content/PasswordCard.mjs index 354f76bf900b8..066dc9807c535 100644 --- a/toolkit/components/satchel/megalist/content/PasswordCard.mjs +++ b/toolkit/components/satchel/megalist/content/PasswordCard.mjs @@ -1,16 +1,20 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - import { html } from "chrome://global/content/vendor/lit.all.mjs"; import { MozLitElement } from "chrome://global/content/lit-utils.mjs"; -/* eslint-disable-next-line import/no-unassigned-import, mozilla/no-browser-refs-in-toolkit */ -import "chrome://browser/content/aboutlogins/components/input-field/login-origin-field.mjs"; -/* eslint-disable-next-line import/no-unassigned-import, mozilla/no-browser-refs-in-toolkit */ -import "chrome://browser/content/aboutlogins/components/input-field/login-username-field.mjs"; -/* eslint-disable-next-line import/no-unassigned-import, mozilla/no-browser-refs-in-toolkit */ -import "chrome://browser/content/aboutlogins/components/input-field/login-password-field.mjs"; +/* eslint-disable-next-line import/no-unassigned-import */ +import "chrome://global/content/megalist/LoginLine.mjs"; + +const DIRECTIONS = { + ArrowUp: -1, + ArrowLeft: -1, + ArrowDown: 1, + ArrowRight: 1, +}; + +const LOGIN_FIELDS_LENGTH = 3; export class PasswordCard extends MozLitElement { static properties = { @@ -20,12 +24,125 @@ export class PasswordCard extends MozLitElement { messageToViewModel: { type: Function }, }; - #revealIconSrc(concealed) { - return !concealed - ? /* eslint-disable-next-line mozilla/no-browser-refs-in-toolkit */ - "chrome://browser/content/aboutlogins/icons/password-hide.svg" - : /* eslint-disable-next-line mozilla/no-browser-refs-in-toolkit */ - "chrome://browser/content/aboutlogins/icons/password.svg"; + static shadowRootOptions = { + ...MozLitElement.shadowRootOptions, + delegatesFocus: true, + }; + + static get queries() { + return { + originLine: ".line-item[linetype='origin']", + usernameLine: ".line-item[linetype='username']", + passwordLine: "concealed-login-line", + editBtn: ".edit-button", + }; + } + + #focusableElementsList; + #focusableElementsMap; + + /** + * Returns the first focusable element of the next password card componenet. + * If the user is navigating down, then the next focusable element should be the edit button, + * and if the user is navigating up, then it should be the origin line. + * + * @param {string} keyCode - The code associated with a keypress event. Either 'ArrowUp' or 'ArrowDown'. + * @returns {HTMLDivElement | MozButton | null} The first focusable element of the next password-card. + */ + #getNextFocusableElement(keyCode) { + const cardIndex = Math.floor(this.origin.lineIndex / LOGIN_FIELDS_LENGTH); + const passwordCards = this.parentNode.querySelectorAll("password-card"); + const nextCardIndex = cardIndex + DIRECTIONS[keyCode]; + + if (nextCardIndex < 0 || nextCardIndex >= passwordCards.length) { + return null; + } + + const nextPasswordCard = passwordCards[nextCardIndex]; + return keyCode === "ArrowDown" + ? nextPasswordCard.originLine.lineContainer + : nextPasswordCard.editBtn; + } + + async firstUpdated() { + this.#focusableElementsMap = new Map(); + + let index = 0; + for (const el of this.shadowRoot.querySelectorAll(".line-item")) { + await el.updateComplete; + if (el === this.passwordLine) { + this.#focusableElementsMap.set(el.loginLine.lineContainer, index++); + this.#focusableElementsMap.set(el.revealBtn.buttonEl, index++); + } else { + this.#focusableElementsMap.set(el.lineContainer, index++); + } + } + + this.#focusableElementsMap.set(this.editBtn.buttonEl, index); + this.#focusableElementsList = Array.from(this.#focusableElementsMap.keys()); + } + + #handleKeydown(element, e) { + const targetIsPasswordLine = + this.passwordLine.loginLine.lineContainer === element; + const targetIsRevealButton = + this.passwordLine.revealBtn.buttonEl === element; + + const focusInternal = offset => { + const index = this.#focusableElementsMap.get(element); + this.#focusableElementsList[index + offset].focus(); + }; + + switch (e.code) { + case "ArrowUp": + if (this.#focusableElementsMap.get(element) === 0) { + const nextFocusableElement = this.#getNextFocusableElement(e.code); + nextFocusableElement?.focus(); + } else if (targetIsRevealButton) { + focusInternal(-2); + } else { + focusInternal(DIRECTIONS[e.code]); + } + break; + case "ArrowDown": + if ( + this.#focusableElementsMap.get(element) === + this.#focusableElementsList.length - 1 + ) { + const nextFocusableElement = this.#getNextFocusableElement(e.code); + nextFocusableElement?.focus(); + } else if (targetIsPasswordLine) { + focusInternal(2); + } else { + focusInternal(DIRECTIONS[e.code]); + } + break; + case "ArrowRight": + if (targetIsPasswordLine) { + focusInternal(DIRECTIONS[e.code]); + } + break; + case "ArrowLeft": + if (targetIsRevealButton) { + focusInternal(DIRECTIONS[e.code]); + } + break; + default: + return; + } + e.stopPropagation(); + } + + connectedCallback() { + super.connectedCallback(); + this.addEventListener( + "keydown", + e => { + const element = e.composedTarget; + this.#handleKeydown(element, e); + }, + { capture: true } + ); } handleCommand(commandId, lineIndex) { @@ -36,6 +153,10 @@ export class PasswordCard extends MozLitElement { // TODO: Implement me! } + #onOriginLineClick(lineIndex) { + this.handleCommand("OpenLink", lineIndex); + } + onCopyButtonClick(lineIndex) { this.handleCommand("Copy", lineIndex); } @@ -49,72 +170,95 @@ export class PasswordCard extends MozLitElement { } renderOriginField() { - return html` - this.onCopyButtonClick(this.origin.lineIndex)} - type="icon ghost" - iconSrc="chrome://global/skin/icons/edit-copy.svg" - > - `; + return html` + this.#onOriginLineClick(this.origin.lineIndex)} + @keypress=${e => { + if (e.key === "Enter") { + this.#onOriginLineClick(this.origin.lineIndex); + } + }} + > + + `; } renderUsernameField() { - return html` - this.onCopyButtonClick(this.username.lineIndex)} - @click=${this.onCopyButtonClick} - type="icon ghost" - iconSrc="chrome://global/skin/icons/edit-copy.svg" - > - `; + @keypress=${e => { + if (e.key === "Enter") { + this.onCopyButtonClick(this.username.lineIndex); + } + }} + > + + `; } renderPasswordField() { - return html` - + return html` + this.onCopyButtonClick(this.password.lineIndex)} + }} + .onButtonClick=${() => this.onPasswordRevealClick( this.password.concealed, this.password.lineIndex )} - type="icon ghost" - iconSrc=${this.#revealIconSrc(this.password.concealed)} - > - this.onCopyButtonClick(this.password.lineIndex)} - type="icon ghost" - iconSrc="chrome://global/skin/icons/edit-copy.svg" - > - `; + > + + `; } renderButton() { - return html``; + return html`
+ e.preventDefault()} + @click=${this.onEditButtonClick} + > +
`; } render() { - return html` - -
- ${this.renderOriginField()} ${this.renderUsernameField()} - ${this.renderPasswordField()} ${this.renderButton()} -
-
`; + ${this.renderOriginField()} ${this.renderUsernameField()} + ${this.renderPasswordField()} ${this.renderButton()} + `; } } diff --git a/toolkit/components/satchel/megalist/content/megalist.css b/toolkit/components/satchel/megalist/content/megalist.css index c5f26886e40e9..4a95b3209c3b4 100644 --- a/toolkit/components/satchel/megalist/content/megalist.css +++ b/toolkit/components/satchel/megalist/content/megalist.css @@ -284,12 +284,6 @@ password-card { flex-direction: column; } -.password-card-container { - display: grid; - grid-template-rows: 1fr 1fr 1fr; - grid-gap: var(--space-medium); -} - .edit-button { justify-self: end; } diff --git a/toolkit/components/satchel/megalist/content/megalist.ftl b/toolkit/components/satchel/megalist/content/megalist.ftl index 6fe455e658d99..a778fc8e46fa6 100644 --- a/toolkit/components/satchel/megalist/content/megalist.ftl +++ b/toolkit/components/satchel/megalist/content/megalist.ftl @@ -131,9 +131,13 @@ passwords-remove-all-message = *[other] This will remove your saved passwords and any breach alerts. You cannot undo this action. } -passwords-origin-label = Website address +passwords-origin-label = Website +# The attribute .data-after describes the text that should be displayed for the ::after pseudo-selector passwords-username-label = Username + .data-after = Copied +# The attribute .data-after describes the text that should be displayed for the ::after pseudo-selector passwords-password-label = Password + .data-after = Copied passwords-radiogroup-label = .aria-label = Filter passwords diff --git a/toolkit/components/satchel/megalist/content/tests/browser/browser_passwords_sidebar.js b/toolkit/components/satchel/megalist/content/tests/browser/browser_passwords_sidebar.js index 121fe29ebe5e1..767603f7732a0 100644 --- a/toolkit/components/satchel/megalist/content/tests/browser/browser_passwords_sidebar.js +++ b/toolkit/components/satchel/megalist/content/tests/browser/browser_passwords_sidebar.js @@ -7,21 +7,25 @@ const { SUPPORT_URL, PREFERENCES_URL } = ChromeUtils.importESModule( "resource://gre/modules/megalist/aggregator/datasources/LoginDataSource.sys.mjs" ); +const { OSKeyStoreTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/OSKeyStoreTestUtils.sys.mjs" +); + const EXPECTED_PASSWORD_CARD_VALUES = [ { - "login-origin-field": { value: "example1.com" }, - "login-username-field": { value: "bob" }, - "login-password-field": { value: "••••••••" }, + originLine: { value: "example1.com" }, + usernameLine: { value: "bob" }, + passwordLine: { value: "••••••••" }, }, { - "login-origin-field": { value: "example2.com" }, - "login-username-field": { value: "sally" }, - "login-password-field": { value: "••••••••" }, + originLine: { value: "example2.com" }, + usernameLine: { value: "sally" }, + passwordLine: { value: "••••••••" }, }, { - "login-origin-field": { value: "example3.com" }, - "login-username-field": { value: "ned" }, - "login-password-field": { value: "••••••••" }, + originLine: { value: "example3.com" }, + usernameLine: { value: "ned" }, + passwordLine: { value: "••••••••" }, }, ]; @@ -32,12 +36,11 @@ function checkPasswordCardFields(megalist) { for (let i = 0; i < EXPECTED_PASSWORD_CARD_VALUES.length; i++) { const card = cards[i]; const expectedCard = EXPECTED_PASSWORD_CARD_VALUES[i]; - for (let selector of Object.keys(expectedCard)) { - let actualValue = card.shadowRoot.querySelector(selector).value; + let actualValue = card[selector].value; const expectedValue = expectedCard[selector].value; - if (selector === "login-password-field") { + if (selector === "passwordLine") { // Skip since we don't expose password value continue; } @@ -80,6 +83,67 @@ add_task(async function test_passwords_sidebar() { const getShadowBtn = (menu, selector) => menu.querySelector(selector).shadowRoot.querySelector("button"); +add_task(async function test_login_line_commands() { + await addLocalOriginLogin(); + const passwordsSidebar = await openPasswordsSidebar(); + const list = passwordsSidebar.querySelector(".passwords-list"); + const card = list.querySelector("password-card"); + const expectedPasswordCard = { + originLine: { value: "about:preferences#privacy" }, + usernameLine: { value: "john" }, + passwordLine: { value: "pass4" }, + }; + const selectors = Object.keys(expectedPasswordCard); + + for (const selector of selectors) { + let loginLine = card[selector]; + if (selector === "originLine") { + const browserLoadedPromise = BrowserTestUtils.browserLoaded( + gBrowser.selectedBrowser, + false, + expectedPasswordCard[selector].value + ); + info(`click on ${selector}`); + loginLine.click(); + await browserLoadedPromise; + ok(true, "origin url loaded"); + } else if (selector === "usernameLine") { + await SimpleTest.promiseClipboardChange( + expectedPasswordCard[selector].value, + () => { + info(`click on ${selector}`); + loginLine.click(); + } + ); + } else if ( + OSKeyStoreTestUtils.canTestOSKeyStoreLogin() && + selector === "passwordLine" + ) { + const loginLine = card[selector].loginLine; + /* Once we pass the prompt message and pref to #verifyUser in MegalistViewModel, + * we will have to do something like this: + * let reauthObserved = Promise.resolve(); + * if (OSKeyStore.canReauth()) { + * reauthObserved = OSKeyStoreTestUtils.waitForOSKeyStoreLogin(true); + * } + * ... + * await reauthObserved; + */ + await SimpleTest.promiseClipboardChange( + expectedPasswordCard[selector].value, + () => { + info(`click on ${selector}`); + loginLine.click(); + } + ); + } + } + + BrowserTestUtils.addTab(gBrowser, "about:blank"); + BrowserTestUtils.removeTab(gBrowser.selectedTab); + SidebarController.hide(); +}); + add_task(async function test_passwords_menu_external_links() { const passwordsSidebar = await openPasswordsSidebar(); const menu = passwordsSidebar.querySelector("panel-list"); diff --git a/toolkit/components/satchel/megalist/content/tests/browser/head.js b/toolkit/components/satchel/megalist/content/tests/browser/head.js index 7b0384d1f79ad..504fbaeb4e3cf 100644 --- a/toolkit/components/satchel/megalist/content/tests/browser/head.js +++ b/toolkit/components/satchel/megalist/content/tests/browser/head.js @@ -138,3 +138,11 @@ async function checkAllLoginsRendered(megalist) { ok(true, `${logins.length} password cards are rendered.`); } + +async function addLocalOriginLogin() { + LoginTestUtils.addLogin({ + username: "john", + password: "pass4", + origin: "about:preferences#privacy", + }); +} From ab36ebb2627747b32d462aec5efa015d2c5980a4 Mon Sep 17 00:00:00 2001 From: Ryan Safaeian Date: Mon, 16 Sep 2024 21:34:04 +0000 Subject: [PATCH 022/115] Bug 1914082 - Add storybook for Password Card component. r=mtigley,credential-management-reviewers Differential Revision: https://phabricator.services.mozilla.com/D221535 --- .../megalist/content/PasswordCard.stories.mjs | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 toolkit/components/satchel/megalist/content/PasswordCard.stories.mjs diff --git a/toolkit/components/satchel/megalist/content/PasswordCard.stories.mjs b/toolkit/components/satchel/megalist/content/PasswordCard.stories.mjs new file mode 100644 index 0000000000000..94d6c40705d2b --- /dev/null +++ b/toolkit/components/satchel/megalist/content/PasswordCard.stories.mjs @@ -0,0 +1,66 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// eslint-disable-next-line import/no-unresolved +import { html } from "lit.all.mjs"; +import "./PasswordCard.mjs"; + +export default { + title: "Domain-specific UI Widgets/Credential Management/Password Card", + component: "PasswordCard", + argTypes: { + website: { control: { type: "object" } }, + username: { control: { type: "object" } }, + password: { control: { type: "object" } }, + }, +}; + +window.MozXULElement.insertFTLIfNeeded("preview/megalist.ftl"); + +const Template = ({ website, username, password }) => { + return html` + {}} + > + + `; +}; + +export const Default = Template.bind({}); +Default.args = { + website: { + value: "website.com", + breached: false, + valueIcon: "chrome://global/skin/icons/defaultFavicon.svg", + }, + username: { + value: "username", + }, + password: { + value: "password", + vulnerable: false, + concealed: true, + }, +}; + +export const AllAlertsOn = Template.bind({}); +AllAlertsOn.args = { + website: { + value: "website.com", + breached: true, + valueIcon: "chrome://global/skin/icons/defaultFavicon.svg", + }, + username: { + value: "", + }, + password: { + value: "password", + vulnerable: true, + concealed: true, + }, +}; From ac33fb14b282f7f09ef25612a652ff29f3f5f7c9 Mon Sep 17 00:00:00 2001 From: Amy Churchwell Date: Mon, 16 Sep 2024 21:50:25 +0000 Subject: [PATCH 023/115] =?UTF-8?q?Bug=201918444=20=E2=80=93=20create=20pl?= =?UTF-8?q?aceholder=20&=20loading=20styles=20for=20list=20feed=20cards.?= =?UTF-8?q?=20r=3Dhome-newtab-reviewers,nbarrett?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Differential Revision: https://phabricator.services.mozilla.com/D222319 --- .../DSCard/_DSCard.scss | 1 + .../ListFeed/ListFeed.jsx | 79 +++++++++++-------- .../ListFeed/_ListFeed.scss | 29 ++++++- .../components/newtab/css/activity-stream.css | 25 +++++- 4 files changed, 94 insertions(+), 40 deletions(-) diff --git a/browser/components/newtab/content-src/components/DiscoveryStreamComponents/DSCard/_DSCard.scss b/browser/components/newtab/content-src/components/DiscoveryStreamComponents/DSCard/_DSCard.scss index c9aef577fcedb..b7f3e9f77e6fe 100644 --- a/browser/components/newtab/content-src/components/DiscoveryStreamComponents/DSCard/_DSCard.scss +++ b/browser/components/newtab/content-src/components/DiscoveryStreamComponents/DSCard/_DSCard.scss @@ -31,6 +31,7 @@ $ds-card-image-gradient-solid: rgba(0, 0, 0, 100%); height: 100%; width: 100%; background: linear-gradient(90deg, rgba(255, 255, 255, 0%) 0%, var(--newtab-background-color-secondary) 50%, rgba(255, 255, 255, 0%) 100%); + z-index: 2; @media (prefers-reduced-motion: no-preference) { animation: loading 1.5s infinite; diff --git a/browser/components/newtab/content-src/components/DiscoveryStreamComponents/ListFeed/ListFeed.jsx b/browser/components/newtab/content-src/components/DiscoveryStreamComponents/ListFeed/ListFeed.jsx index 0e4edf2ad839b..008f2e2bd5a29 100644 --- a/browser/components/newtab/content-src/components/DiscoveryStreamComponents/ListFeed/ListFeed.jsx +++ b/browser/components/newtab/content-src/components/DiscoveryStreamComponents/ListFeed/ListFeed.jsx @@ -20,40 +20,51 @@ function ListFeed({ type, firstVisibleTimestamp, recs }) { role="menu" aria-labelledby="list-feed-title" > - {recs.map(rec => ( - - ))} + {recs.map(rec => { + if (!rec || rec.placeholder) { + return ( + + ); + } + return ( + + ); + })}
diff --git a/browser/components/newtab/content-src/components/DiscoveryStreamComponents/ListFeed/_ListFeed.scss b/browser/components/newtab/content-src/components/DiscoveryStreamComponents/ListFeed/_ListFeed.scss index 364081c204375..3316374c89d77 100644 --- a/browser/components/newtab/content-src/components/DiscoveryStreamComponents/ListFeed/_ListFeed.scss +++ b/browser/components/newtab/content-src/components/DiscoveryStreamComponents/ListFeed/_ListFeed.scss @@ -20,9 +20,8 @@ .icon-trending { margin-inline-end: var(--space-small); - -moz-context-properties: stroke; - stroke: currentColor; transform: none; + fill: var(--newtab-text-primary-color); } } @@ -31,12 +30,36 @@ padding-inline-start: 0; margin: 0; } + + .ds-card.placeholder.list-card-placeholder { + box-shadow: unset; + padding-inline-end: var(--space-large); + padding-block: var(--space-large) var(--space-small); + + .placeholder-image { + height: 75px; + width: 75px; + position: absolute; + border-radius: var(--border-radius-medium); + inset-inline-end: var(--space-large); + } + + .placeholder-label { + margin-bottom: unset; + } + + .placeholder-header, .placeholder-description { + width: 60%; + height: 20px; + } + } } + .ds-card-grid .list-feed-content .ds-card.list-feed-card { // overrides when using the DSCard component background-color: var(--newtab-background-color-secondary); - border-block-start: 1px solid var(--color-gray-50); + border-block-start: 1px solid light-dark(var(--color-gray-70), var(--color-gray-50)); border-radius: 0; box-shadow: none; flex-direction: row-reverse; diff --git a/browser/components/newtab/css/activity-stream.css b/browser/components/newtab/css/activity-stream.css index 9a4f0dbdc8a43..f96a9027bbaa9 100644 --- a/browser/components/newtab/css/activity-stream.css +++ b/browser/components/newtab/css/activity-stream.css @@ -4814,6 +4814,7 @@ main section { height: 100%; width: 100%; background: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, var(--newtab-background-color-secondary) 50%, rgba(255, 255, 255, 0) 100%); + z-index: 2; } @media (prefers-reduced-motion: no-preference) { .ds-card.placeholder-seen::before { @@ -6092,19 +6093,37 @@ main section { } .list-feed .list-feed-title .icon-trending { margin-inline-end: var(--space-small); - -moz-context-properties: stroke; - stroke: currentColor; transform: none; + fill: var(--newtab-text-primary-color); } .list-feed .list-feed-content { list-style: none; padding-inline-start: 0; margin: 0; } +.list-feed .ds-card.placeholder.list-card-placeholder { + box-shadow: unset; + padding-inline-end: var(--space-large); + padding-block: var(--space-large) var(--space-small); +} +.list-feed .ds-card.placeholder.list-card-placeholder .placeholder-image { + height: 75px; + width: 75px; + position: absolute; + border-radius: var(--border-radius-medium); + inset-inline-end: var(--space-large); +} +.list-feed .ds-card.placeholder.list-card-placeholder .placeholder-label { + margin-bottom: unset; +} +.list-feed .ds-card.placeholder.list-card-placeholder .placeholder-header, .list-feed .ds-card.placeholder.list-card-placeholder .placeholder-description { + width: 60%; + height: 20px; +} .ds-card-grid .list-feed-content .ds-card.list-feed-card { background-color: var(--newtab-background-color-secondary); - border-block-start: 1px solid var(--color-gray-50); + border-block-start: 1px solid light-dark(var(--color-gray-70), var(--color-gray-50)); border-radius: 0; box-shadow: none; flex-direction: row-reverse; From b0553602e66ab1bafa55a7f5384a142f21feee37 Mon Sep 17 00:00:00 2001 From: Markus Stange Date: Mon, 16 Sep 2024 21:50:55 +0000 Subject: [PATCH 024/115] Bug 1919127 - Use TypeId to track marker type tags. r=aabh,profiler-reviewers Differential Revision: https://phabricator.services.mozilla.com/D222357 --- .../src/marker/deserializer_tags_state.rs | 21 +++++++++---------- tools/profiler/rust-api/src/marker/mod.rs | 2 +- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/tools/profiler/rust-api/src/marker/deserializer_tags_state.rs b/tools/profiler/rust-api/src/marker/deserializer_tags_state.rs index f0e9a26a9fb54..8ff972e660541 100644 --- a/tools/profiler/rust-api/src/marker/deserializer_tags_state.rs +++ b/tools/profiler/rust-api/src/marker/deserializer_tags_state.rs @@ -5,6 +5,7 @@ use crate::json_writer::JSONWriter; use crate::marker::schema::MarkerSchema; use crate::marker::{transmute_and_stream, ProfilerMarker}; +use std::any::TypeId; use std::collections::HashMap; use std::sync::{RwLock, RwLockReadGuard}; @@ -16,11 +17,9 @@ lazy_static! { /// A state that keeps track of each marker types and their deserializer tags. /// They are added during the marker insertion and read during the marker serialization. pub struct DeserializerTagsState { - /// C++ side accepts only u8 values, but we only know usize values as the - /// unique marker type values. So, we need to keep track of each - /// "marker tag -> deserializer tag" conversions to directly get the - /// deserializer tags of the already added marker types. - pub marker_tag_to_deserializer_tag: HashMap, + /// Keep track of a a 1-based u8 tag per marker type. + /// This assumes that we don't have more than 255 different marker types. + pub marker_type_id_to_deserializer_tag: HashMap, /// Vector of marker type functions. /// 1-based, i.e.: [0] -> tag 1. Elements are pushed to the end of the vector /// whenever a new marker type is used in a Firefox session; the content is @@ -47,7 +46,7 @@ pub struct MarkerTypeFunctions { impl DeserializerTagsState { fn new() -> Self { DeserializerTagsState { - marker_tag_to_deserializer_tag: HashMap::new(), + marker_type_id_to_deserializer_tag: HashMap::new(), marker_type_functions_1_based: vec![], } } @@ -59,12 +58,12 @@ impl DeserializerTagsState { /// to change the uint8_t type for the deserializer tag as well. pub fn get_or_insert_deserializer_tag() -> u8 where - T: ProfilerMarker, + T: ProfilerMarker + 'static, { - let unique_marker_tag = T::marker_type_name as *const () as usize; + let type_id = TypeId::of::(); let mut state = DESERIALIZER_TAGS_STATE.write().unwrap(); - match state.marker_tag_to_deserializer_tag.get(&unique_marker_tag) { + match state.marker_type_id_to_deserializer_tag.get(&type_id) { None => { // It's impossible to have length more than u8. let deserializer_tag = state.marker_type_functions_1_based.len() as u8 + 1; @@ -75,8 +74,8 @@ where ); state - .marker_tag_to_deserializer_tag - .insert(unique_marker_tag, deserializer_tag); + .marker_type_id_to_deserializer_tag + .insert(type_id, deserializer_tag); state .marker_type_functions_1_based .push(MarkerTypeFunctions { diff --git a/tools/profiler/rust-api/src/marker/mod.rs b/tools/profiler/rust-api/src/marker/mod.rs index 3715e3bfc4690..4a89e660d1e1d 100644 --- a/tools/profiler/rust-api/src/marker/mod.rs +++ b/tools/profiler/rust-api/src/marker/mod.rs @@ -312,7 +312,7 @@ pub fn add_marker( mut options: MarkerOptions, payload: T, ) where - T: ProfilerMarker, + T: ProfilerMarker + 'static, { if !crate::profiler_state::can_accept_markers() { // Nothing to do. From 4984f1074bc06edea16a257c441f76274ec47466 Mon Sep 17 00:00:00 2001 From: Markus Stange Date: Mon, 16 Sep 2024 21:50:56 +0000 Subject: [PATCH 025/115] Bug 1919127 - Fix a typo: maker -> marker. r=aabh,profiler-reviewers Differential Revision: https://phabricator.services.mozilla.com/D222358 --- tools/profiler/rust-api/src/marker/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/profiler/rust-api/src/marker/mod.rs b/tools/profiler/rust-api/src/marker/mod.rs index 4a89e660d1e1d..be11012605535 100644 --- a/tools/profiler/rust-api/src/marker/mod.rs +++ b/tools/profiler/rust-api/src/marker/mod.rs @@ -321,7 +321,7 @@ pub fn add_marker( let encoded_payload: Vec = bincode::serialize(&payload).unwrap(); let payload_size = encoded_payload.len(); - let maker_tag = get_or_insert_deserializer_tag::(); + let marker_tag = get_or_insert_deserializer_tag::(); unsafe { bindings::gecko_profiler_add_marker( @@ -330,7 +330,7 @@ pub fn add_marker( category.to_cpp_enum_value(), options.timing.0.as_mut_ptr(), options.stack, - maker_tag, + marker_tag, encoded_payload.as_ptr(), payload_size, ) From 5b31e4e5082f2adbefe2d087d14e8e06755212a4 Mon Sep 17 00:00:00 2001 From: Markus Stange Date: Mon, 16 Sep 2024 21:54:11 +0000 Subject: [PATCH 026/115] Bug 1882182 - Land old tests from bug 1117304. r=ahale Differential Revision: https://phabricator.services.mozilla.com/D202760 --- layout/reftests/bugs/1117304-1-ref.html | 18 ++++++++++++++++++ layout/reftests/bugs/1117304-1.html | 20 ++++++++++++++++++++ layout/reftests/bugs/1117304-2-ref.html | 18 ++++++++++++++++++ layout/reftests/bugs/1117304-2.html | 20 ++++++++++++++++++++ layout/reftests/bugs/1117304-3-ref.html | 18 ++++++++++++++++++ layout/reftests/bugs/1117304-3.html | 20 ++++++++++++++++++++ layout/reftests/bugs/1117304-4-ref.html | 18 ++++++++++++++++++ layout/reftests/bugs/1117304-4.html | 20 ++++++++++++++++++++ layout/reftests/bugs/reftest.list | 4 ++++ 9 files changed, 156 insertions(+) create mode 100644 layout/reftests/bugs/1117304-1-ref.html create mode 100644 layout/reftests/bugs/1117304-1.html create mode 100644 layout/reftests/bugs/1117304-2-ref.html create mode 100644 layout/reftests/bugs/1117304-2.html create mode 100644 layout/reftests/bugs/1117304-3-ref.html create mode 100644 layout/reftests/bugs/1117304-3.html create mode 100644 layout/reftests/bugs/1117304-4-ref.html create mode 100644 layout/reftests/bugs/1117304-4.html diff --git a/layout/reftests/bugs/1117304-1-ref.html b/layout/reftests/bugs/1117304-1-ref.html new file mode 100644 index 0000000000000..703de547b71f7 --- /dev/null +++ b/layout/reftests/bugs/1117304-1-ref.html @@ -0,0 +1,18 @@ + + + +Bug 1117304 - Different surface formats for different input tiles in feTile filter + +
+ + + + + + + + diff --git a/layout/reftests/bugs/1117304-1.html b/layout/reftests/bugs/1117304-1.html new file mode 100644 index 0000000000000..a7366ef5b2459 --- /dev/null +++ b/layout/reftests/bugs/1117304-1.html @@ -0,0 +1,20 @@ + + + +Bug 1117304 - Different surface formats for different input tiles in feTile filter + +
+ + + + + + + + + + diff --git a/layout/reftests/bugs/1117304-2-ref.html b/layout/reftests/bugs/1117304-2-ref.html new file mode 100644 index 0000000000000..dba8c8a54b936 --- /dev/null +++ b/layout/reftests/bugs/1117304-2-ref.html @@ -0,0 +1,18 @@ + + + +Bug 1117304 - Different surface formats for different input tiles in feTile filter + +
+ + + + + + + + diff --git a/layout/reftests/bugs/1117304-2.html b/layout/reftests/bugs/1117304-2.html new file mode 100644 index 0000000000000..2cb1671e79d2c --- /dev/null +++ b/layout/reftests/bugs/1117304-2.html @@ -0,0 +1,20 @@ + + + +Bug 1117304 - Different surface formats for different input tiles in feTile filter + +
+ + + + + + + + + + diff --git a/layout/reftests/bugs/1117304-3-ref.html b/layout/reftests/bugs/1117304-3-ref.html new file mode 100644 index 0000000000000..1cb8712720331 --- /dev/null +++ b/layout/reftests/bugs/1117304-3-ref.html @@ -0,0 +1,18 @@ + + + +Bug 1117304 - Different surface formats for different input tiles in feTile filter + +
+ + + + + + + + diff --git a/layout/reftests/bugs/1117304-3.html b/layout/reftests/bugs/1117304-3.html new file mode 100644 index 0000000000000..d660bc31dee39 --- /dev/null +++ b/layout/reftests/bugs/1117304-3.html @@ -0,0 +1,20 @@ + + + +Bug 1117304 - Different surface formats for different input tiles in feTile filter + +
+ + + + + + + + + + diff --git a/layout/reftests/bugs/1117304-4-ref.html b/layout/reftests/bugs/1117304-4-ref.html new file mode 100644 index 0000000000000..e389b66022d21 --- /dev/null +++ b/layout/reftests/bugs/1117304-4-ref.html @@ -0,0 +1,18 @@ + + + +Bug 1117304 - Different surface formats for different input tiles in feTile filter + +
+ + + + + + + + diff --git a/layout/reftests/bugs/1117304-4.html b/layout/reftests/bugs/1117304-4.html new file mode 100644 index 0000000000000..15568178a90e5 --- /dev/null +++ b/layout/reftests/bugs/1117304-4.html @@ -0,0 +1,20 @@ + + + +Bug 1117304 - Different surface formats for different input tiles in feTile filter + +
+ + + + + + + + + + diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index e306dea8f6d8c..90b6e44888016 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -1887,6 +1887,10 @@ fuzzy(0-128,0-22) == 1155828-1.html 1155828-1-ref.html # bug 1646527 for WR fuzz fuzzy(0-7,0-84) == 1156129-1.html 1156129-1-ref.html pref(dom.use_xbl_scopes_for_remote_xul,true) HTTP(..) == 1157127-1.html 1157127-1-ref.html fuzzy-if(Android,0-6,0-6) fuzzy-if(appleSilicon,0-1,0-7) == 1169331-1.html 1169331-1-ref.html +== 1117304-1.html 1117304-1-ref.html +== 1117304-2.html 1117304-2-ref.html +== 1117304-3.html 1117304-3-ref.html +== 1117304-4.html 1117304-4-ref.html fuzzy(0-3,0-110) fails == 1174332-1.html 1174332-1-ref.html # bug 1312658, expected to fail w/ non-native theme because of bug 1699937 == 1179078-1.html 1179078-1-ref.html == 1179288-1.html 1179288-1-ref.html From 1162e998ab4a5cbda99f7b774975e2692476c84e Mon Sep 17 00:00:00 2001 From: Ting-Yu Lin Date: Mon, 16 Sep 2024 21:55:39 +0000 Subject: [PATCH 027/115] Bug 1918576 Part 1 - Apply min & max constraints only if block-size is definite in ComputeBSizeValueAsPercentageBasis(). r=dholbert That is, a definite max block-size and an auto block-size should not compute a definite percentage basis in the block axis. Note that we accidentally pass `testing/web-platform/tests/css/css-sizing/intrinsic-percent-replaced-017.html`. After applying this patch, the test starts to fail, but it will be fixed in the next part. Differential Revision: https://phabricator.services.mozilla.com/D222230 --- layout/generic/nsIFrame.cpp | 11 ++++--- .../aspect-ratio/block-aspect-ratio-058.html | 33 +++++++++++++++++++ 2 files changed, 39 insertions(+), 5 deletions(-) create mode 100644 testing/web-platform/tests/css/css-sizing/aspect-ratio/block-aspect-ratio-058.html diff --git a/layout/generic/nsIFrame.cpp b/layout/generic/nsIFrame.cpp index 2bbcbc7e349bd..867c79edfc1d6 100644 --- a/layout/generic/nsIFrame.cpp +++ b/layout/generic/nsIFrame.cpp @@ -6700,11 +6700,12 @@ nscoord nsIFrame::ComputeBSizeValueAsPercentageBasis( const StyleSize& aStyleBSize, const StyleSize& aStyleMinBSize, const StyleMaxSize& aStyleMaxBSize, nscoord aCBBSize, nscoord aContentEdgeToBoxSizingBSize) { - const nscoord bSize = nsLayoutUtils::IsAutoBSize(aStyleBSize, aCBBSize) - ? NS_UNCONSTRAINEDSIZE - : nsLayoutUtils::ComputeBSizeValue( - aCBBSize, aContentEdgeToBoxSizingBSize, - aStyleBSize.AsLengthPercentage()); + if (nsLayoutUtils::IsAutoBSize(aStyleBSize, aCBBSize)) { + return NS_UNCONSTRAINEDSIZE; + } + + const nscoord bSize = nsLayoutUtils::ComputeBSizeValue( + aCBBSize, aContentEdgeToBoxSizingBSize, aStyleBSize.AsLengthPercentage()); const nscoord minBSize = nsLayoutUtils::IsAutoBSize(aStyleMinBSize, aCBBSize) ? 0 diff --git a/testing/web-platform/tests/css/css-sizing/aspect-ratio/block-aspect-ratio-058.html b/testing/web-platform/tests/css/css-sizing/aspect-ratio/block-aspect-ratio-058.html new file mode 100644 index 0000000000000..b6d923f12bc42 --- /dev/null +++ b/testing/web-platform/tests/css/css-sizing/aspect-ratio/block-aspect-ratio-058.html @@ -0,0 +1,33 @@ + + + + + + + + + + + +

Test passes if there is a filled green square and no red.

+
+
+
+
From cdaa0285e97a9ebf0aacb7dd40e13cc755927709 Mon Sep 17 00:00:00 2001 From: Ting-Yu Lin Date: Mon, 16 Sep 2024 21:55:39 +0000 Subject: [PATCH 028/115] Bug 1918576 Part 2 - Mark a flex item's intrinsic inline size dirty if we override its block size. r=dholbert In a column-oriented flex container, if a flex item's intrinsic inline size or its descendants' inline size contributions depend on the item's block size, `NS_FRAME_DESCENDANT_INTRINSIC_ISIZE_DEPENDS_ON_BSIZE` will be set. In this case, when determining the flex item's cross-size, we need to mark the flex item's intrinsic inline size as dirty such that its (auto) inline size is recomputed when constructing its `ReflowInput`. `testing/web-platform/tests/css/css-sizing/intrinsic-percent-replaced-017.html` is the test coverage for this patch. Differential Revision: https://phabricator.services.mozilla.com/D222231 --- layout/generic/nsFlexContainerFrame.cpp | 14 ++++++++++++-- .../css-sizing/intrinsic-percent-replaced-017.html | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/layout/generic/nsFlexContainerFrame.cpp b/layout/generic/nsFlexContainerFrame.cpp index 9cf4899f13e5b..b716b96215e5e 100644 --- a/layout/generic/nsFlexContainerFrame.cpp +++ b/layout/generic/nsFlexContainerFrame.cpp @@ -2478,8 +2478,16 @@ bool FlexItem::CanMainSizeInfluenceCrossSize() const { if (IsInlineAxisCrossAxis()) { // If we get here, this function is really asking: "can changes to this - // item's block size have an influence on its inline size"? For blocks and - // tables, the answer is "no". + // item's block size have an influence on its inline size"? + + // If a flex item's intrinsic inline size or its descendants' inline size + // contributions depend on the item's block size, the answer is "yes". + if (mFrame->HasAnyStateBits( + NS_FRAME_DESCENDANT_INTRINSIC_ISIZE_DEPENDS_ON_BSIZE)) { + return true; + } + // For blocks and tables, the answer is "no" (aside from the above special + // case). if (mFrame->IsBlockFrame() || mFrame->IsTableWrapperFrame()) { // XXXdholbert (Maybe use an IsFrameOfType query or something more // general to test this across all frame types? For now, I'm just @@ -5296,6 +5304,8 @@ nsFlexContainerFrame::FlexLayoutResult nsFlexContainerFrame::DoFlexLayout( sizeOverrides.mStyleISize.emplace(item.StyleMainSize()); } else { sizeOverrides.mStyleBSize.emplace(item.StyleMainSize()); + nsLayoutUtils::MarkIntrinsicISizesDirtyIfDependentOnBSize( + item.Frame()); } FLEX_ITEM_LOG(item.Frame(), "Sizing item in cross axis"); FLEX_LOGV("Main size override: %d", item.MainSize()); diff --git a/testing/web-platform/tests/css/css-sizing/intrinsic-percent-replaced-017.html b/testing/web-platform/tests/css/css-sizing/intrinsic-percent-replaced-017.html index 190b2f8fe4435..d7e5d70e43af7 100644 --- a/testing/web-platform/tests/css/css-sizing/intrinsic-percent-replaced-017.html +++ b/testing/web-platform/tests/css/css-sizing/intrinsic-percent-replaced-017.html @@ -5,7 +5,7 @@ - + +
+ From 5bd52a5b9c9ba5d271fcda5d9bddb1ab4a681a4d Mon Sep 17 00:00:00 2001 From: Updatebot Date: Tue, 17 Sep 2024 10:19:32 +0000 Subject: [PATCH 071/115] Bug 1918647 - Update libjxl to v0.11.0 r=saschanaz Differential Revision: https://phabricator.services.mozilla.com/D222104 --- media/libjxl/moz.build | 2 +- media/libjxl/moz.yaml | 4 +- third_party/jpeg-xl/.clang-tidy | 5 +- third_party/jpeg-xl/AUTHORS | 5 + third_party/jpeg-xl/BUILD.bazel | 5 + third_party/jpeg-xl/CHANGELOG.md | 19 +- third_party/jpeg-xl/CMakeLists.txt | 51 +- third_party/jpeg-xl/MODULE.bazel | 12 +- third_party/jpeg-xl/MODULE.bazel.lock | 1527 +----- third_party/jpeg-xl/README.md | 10 +- third_party/jpeg-xl/WORKSPACE | 191 +- third_party/jpeg-xl/bash_test.sh | 9 +- third_party/jpeg-xl/ci.sh | 223 +- third_party/jpeg-xl/cmake/FindHWY.cmake | 34 +- third_party/jpeg-xl/debian/changelog | 6 +- third_party/jpeg-xl/debian/control | 1 - third_party/jpeg-xl/deps.sh | 7 +- third_party/jpeg-xl/examples/CMakeLists.txt | 3 + .../jpeg-xl/examples/decode_exif_metadata.cc | 7 +- .../jpeg-xl/examples/decode_oneshot.cc | 2 +- .../jpeg-xl/examples/decode_progressive.cc | 16 +- .../jpeg-xl/examples/encode_oneshot.cc | 4 +- third_party/jpeg-xl/examples/examples.cmake | 2 + third_party/jpeg-xl/flake.nix | 1 - third_party/jpeg-xl/lib/BUILD | 9 +- third_party/jpeg-xl/lib/CMakeLists.txt | 6 +- third_party/jpeg-xl/lib/extras/alpha_blend.cc | 20 +- third_party/jpeg-xl/lib/extras/alpha_blend.h | 3 +- third_party/jpeg-xl/lib/extras/codec.cc | 3 +- third_party/jpeg-xl/lib/extras/codec_test.cc | 91 +- third_party/jpeg-xl/lib/extras/common.cc | 1 + .../jpeg-xl/lib/extras/compressed_icc.cc | 53 + .../jpeg-xl/lib/extras/compressed_icc_test.cc | 47 + third_party/jpeg-xl/lib/extras/dec/apng.cc | 1534 +++--- third_party/jpeg-xl/lib/extras/dec/apng.h | 3 +- .../lib/extras/dec/color_description.cc | 40 +- third_party/jpeg-xl/lib/extras/dec/decode.cc | 9 + third_party/jpeg-xl/lib/extras/dec/decode.h | 8 +- third_party/jpeg-xl/lib/extras/dec/exr.cc | 70 +- third_party/jpeg-xl/lib/extras/dec/exr.h | 2 + third_party/jpeg-xl/lib/extras/dec/gif.cc | 59 +- third_party/jpeg-xl/lib/extras/dec/jpegli.cc | 47 +- third_party/jpeg-xl/lib/extras/dec/jpg.cc | 52 +- third_party/jpeg-xl/lib/extras/dec/jxl.cc | 70 +- third_party/jpeg-xl/lib/extras/dec/jxl.h | 7 +- third_party/jpeg-xl/lib/extras/dec/pgx.cc | 9 +- .../jpeg-xl/lib/extras/dec/pgx_test.cc | 11 +- third_party/jpeg-xl/lib/extras/dec/pnm.cc | 92 +- third_party/jpeg-xl/lib/extras/dec/pnm.h | 4 - third_party/jpeg-xl/lib/extras/enc/apng.cc | 124 +- third_party/jpeg-xl/lib/extras/enc/encode.cc | 8 + third_party/jpeg-xl/lib/extras/enc/encode.h | 2 + third_party/jpeg-xl/lib/extras/enc/jpegli.cc | 69 +- third_party/jpeg-xl/lib/extras/enc/jpg.cc | 13 +- third_party/jpeg-xl/lib/extras/enc/jxl.cc | 33 +- third_party/jpeg-xl/lib/extras/enc/jxl.h | 19 +- third_party/jpeg-xl/lib/extras/enc/npy.cc | 4 +- third_party/jpeg-xl/lib/extras/enc/pgx.cc | 4 +- third_party/jpeg-xl/lib/extras/enc/pnm.cc | 30 +- third_party/jpeg-xl/lib/extras/gain_map.cc | 231 + .../jpeg-xl/lib/extras/gain_map_test.cc | 173 + third_party/jpeg-xl/lib/extras/hlg.cc | 42 +- third_party/jpeg-xl/lib/extras/jpegli_test.cc | 34 +- third_party/jpeg-xl/lib/extras/metrics.cc | 15 +- third_party/jpeg-xl/lib/extras/mmap.h | 8 +- third_party/jpeg-xl/lib/extras/packed_image.h | 61 +- .../lib/extras/packed_image_convert.cc | 108 +- .../jpeg-xl/lib/extras/packed_image_convert.h | 7 +- third_party/jpeg-xl/lib/extras/time.cc | 2 +- .../jpeg-xl/lib/extras/tone_mapping.cc | 74 +- .../jpeg-xl/lib/extras/tone_mapping_gbench.cc | 40 +- .../jpeg-xl/lib/include/jxl/cms_interface.h | 4 +- .../lib/include/jxl/codestream_header.h | 4 +- .../jpeg-xl/lib/include/jxl/color_encoding.h | 18 +- .../jpeg-xl/lib/include/jxl/compressed_icc.h | 75 + third_party/jpeg-xl/lib/include/jxl/decode.h | 44 +- .../jpeg-xl/lib/include/jxl/decode_cxx.h | 2 +- third_party/jpeg-xl/lib/include/jxl/encode.h | 9 +- .../jpeg-xl/lib/include/jxl/encode_cxx.h | 2 +- .../jpeg-xl/lib/include/jxl/gain_map.h | 129 + .../jpeg-xl/lib/include/jxl/memory_manager.h | 7 +- .../jpeg-xl/lib/include/jxl/parallel_runner.h | 21 +- .../include/jxl/resizable_parallel_runner.h | 4 +- .../jxl/resizable_parallel_runner_cxx.h | 2 +- third_party/jpeg-xl/lib/include/jxl/stats.h | 4 +- .../lib/include/jxl/thread_parallel_runner.h | 4 +- .../include/jxl/thread_parallel_runner_cxx.h | 2 +- third_party/jpeg-xl/lib/include/jxl/types.h | 4 +- third_party/jpeg-xl/lib/jpegli.cmake | 1 - third_party/jpeg-xl/lib/jpegli/README.md | 3 + .../lib/jpegli/adaptive_quantization.cc | 12 +- .../jpeg-xl/lib/jpegli/color_quantize.cc | 9 +- .../jpeg-xl/lib/jpegli/color_transform.cc | 322 +- third_party/jpeg-xl/lib/jpegli/common.h | 11 +- .../jpeg-xl/lib/jpegli/common_internal.h | 26 +- third_party/jpeg-xl/lib/jpegli/dct-inl.h | 32 +- third_party/jpeg-xl/lib/jpegli/decode.cc | 62 +- third_party/jpeg-xl/lib/jpegli/decode.h | 7 +- .../jpeg-xl/lib/jpegli/decode_api_test.cc | 69 +- .../jpeg-xl/lib/jpegli/decode_internal.h | 23 +- .../jpeg-xl/lib/jpegli/decode_marker.cc | 58 +- third_party/jpeg-xl/lib/jpegli/decode_scan.cc | 4 +- .../jpeg-xl/lib/jpegli/destination_manager.cc | 4 +- third_party/jpeg-xl/lib/jpegli/downsample.cc | 9 +- third_party/jpeg-xl/lib/jpegli/encode.cc | 52 +- third_party/jpeg-xl/lib/jpegli/encode.h | 7 +- .../jpeg-xl/lib/jpegli/encode_api_test.cc | 62 +- .../jpeg-xl/lib/jpegli/encode_finish.cc | 10 +- .../jpeg-xl/lib/jpegli/encode_streaming.cc | 6 +- .../jpeg-xl/lib/jpegli/entropy_coding.cc | 35 +- third_party/jpeg-xl/lib/jpegli/error.cc | 2 +- third_party/jpeg-xl/lib/jpegli/error.h | 12 +- .../jpeg-xl/lib/jpegli/error_handling_test.cc | 111 +- third_party/jpeg-xl/lib/jpegli/fuzztest.h | 22 + third_party/jpeg-xl/lib/jpegli/huffman.cc | 1 + third_party/jpeg-xl/lib/jpegli/idct.cc | 26 +- third_party/jpeg-xl/lib/jpegli/idct.h | 4 +- .../lib/jpegli/input_suspension_test.cc | 91 +- .../jpeg-xl/lib/jpegli/libjpeg_test_util.cc | 80 +- .../jpeg-xl/lib/jpegli/libjpeg_wrapper.cc | 4 +- .../lib/jpegli/output_suspension_test.cc | 12 + third_party/jpeg-xl/lib/jpegli/render.cc | 23 +- .../jpeg-xl/lib/jpegli/source_manager.cc | 7 +- .../jpeg-xl/lib/jpegli/source_manager_test.cc | 17 +- .../jpeg-xl/lib/jpegli/streaming_test.cc | 46 +- .../jpeg-xl/lib/jpegli/test_utils-inl.h | 144 +- third_party/jpeg-xl/lib/jpegli/test_utils.cc | 159 +- third_party/jpeg-xl/lib/jpegli/test_utils.h | 21 +- third_party/jpeg-xl/lib/jpegli/testing.h | 26 +- .../jpeg-xl/lib/jpegli/transcode_api_test.cc | 14 +- third_party/jpeg-xl/lib/jpegli/types.h | 4 +- third_party/jpeg-xl/lib/jxl.cmake | 14 +- third_party/jpeg-xl/lib/jxl/ac_context.h | 11 +- third_party/jpeg-xl/lib/jxl/ac_strategy.cc | 15 +- third_party/jpeg-xl/lib/jxl/ac_strategy.h | 167 +- .../jpeg-xl/lib/jxl/ac_strategy_test.cc | 78 +- third_party/jpeg-xl/lib/jxl/alpha_test.cc | 151 +- third_party/jpeg-xl/lib/jxl/ans_common.cc | 58 +- third_party/jpeg-xl/lib/jxl/ans_common.h | 14 +- .../jpeg-xl/lib/jxl/ans_common_test.cc | 12 +- third_party/jpeg-xl/lib/jxl/ans_test.cc | 79 +- third_party/jpeg-xl/lib/jxl/base/common.h | 2 + .../jpeg-xl/lib/jxl/base/compiler_specific.h | 83 +- .../jpeg-xl/lib/jxl/base/data_parallel.h | 45 +- third_party/jpeg-xl/lib/jxl/base/exif.h | 6 +- third_party/jpeg-xl/lib/jxl/base/float.h | 4 +- .../jpeg-xl/lib/jxl/base/include_jpeglib.h | 20 + third_party/jpeg-xl/lib/jxl/base/matrix_ops.h | 84 +- third_party/jpeg-xl/lib/jxl/base/random.h | 2 +- third_party/jpeg-xl/lib/jxl/base/rect.h | 186 + .../jpeg-xl/lib/jxl/{ => base}/sanitizers.h | 37 +- .../jpeg-xl/lib/jxl/base/scope_guard.h | 3 +- third_party/jpeg-xl/lib/jxl/base/span.h | 12 +- third_party/jpeg-xl/lib/jxl/base/status.h | 226 +- .../jpeg-xl/lib/jxl/bit_reader_test.cc | 242 +- third_party/jpeg-xl/lib/jxl/bits_test.cc | 3 + third_party/jpeg-xl/lib/jxl/blending.cc | 203 +- third_party/jpeg-xl/lib/jxl/blending.h | 10 +- third_party/jpeg-xl/lib/jxl/blending_test.cc | 6 +- .../jpeg-xl/lib/jxl/box_content_decoder.cc | 11 +- .../lib/jxl/butteraugli/butteraugli.cc | 317 +- .../jpeg-xl/lib/jxl/butteraugli/butteraugli.h | 16 +- .../lib/jxl/butteraugli/butteraugli_test.cc | 67 +- third_party/jpeg-xl/lib/jxl/cache_aligned.cc | 158 - third_party/jpeg-xl/lib/jxl/cache_aligned.h | 67 - .../jpeg-xl/lib/jxl/chroma_from_luma.cc | 45 +- .../jpeg-xl/lib/jxl/chroma_from_luma.h | 70 +- .../jpeg-xl/lib/jxl/cms/color_encoding_cms.h | 69 +- third_party/jpeg-xl/lib/jxl/cms/jxl_cms.cc | 86 +- .../jpeg-xl/lib/jxl/cms/jxl_cms_internal.h | 229 +- .../jpeg-xl/lib/jxl/cms/opsin_params.h | 28 +- .../jpeg-xl/lib/jxl/cms/tone_mapping-inl.h | 6 +- .../jpeg-xl/lib/jxl/cms/tone_mapping.h | 59 +- .../jpeg-xl/lib/jxl/cms/tone_mapping_test.cc | 36 +- .../lib/jxl/cms/transfer_functions-inl.h | 38 +- .../jpeg-xl/lib/jxl/cms/transfer_functions.h | 4 +- .../lib/jxl/cms/transfer_functions_test.cc | 2 +- third_party/jpeg-xl/lib/jxl/codec_in_out.h | 54 +- third_party/jpeg-xl/lib/jxl/coeff_order.cc | 43 +- third_party/jpeg-xl/lib/jxl/coeff_order.h | 42 +- third_party/jpeg-xl/lib/jxl/coeff_order_fwd.h | 4 +- .../jpeg-xl/lib/jxl/coeff_order_test.cc | 23 +- .../lib/jxl/color_encoding_internal.cc | 19 +- .../jpeg-xl/lib/jxl/color_encoding_internal.h | 19 +- .../lib/jxl/color_encoding_internal_test.cc | 27 +- .../jpeg-xl/lib/jxl/color_management_test.cc | 238 +- third_party/jpeg-xl/lib/jxl/compressed_dc.cc | 30 +- third_party/jpeg-xl/lib/jxl/compressed_dc.h | 8 +- third_party/jpeg-xl/lib/jxl/convolve-inl.h | 50 +- third_party/jpeg-xl/lib/jxl/convolve.h | 40 +- .../jpeg-xl/lib/jxl/convolve_separable5.cc | 22 +- third_party/jpeg-xl/lib/jxl/convolve_slow.cc | 104 +- .../jpeg-xl/lib/jxl/convolve_symmetric3.cc | 23 +- .../jpeg-xl/lib/jxl/convolve_symmetric5.cc | 62 +- third_party/jpeg-xl/lib/jxl/convolve_test.cc | 154 +- .../jpeg-xl/lib/jxl/data_parallel_test.cc | 35 +- third_party/jpeg-xl/lib/jxl/dct-inl.h | 48 +- third_party/jpeg-xl/lib/jxl/dct_for_test.h | 9 +- third_party/jpeg-xl/lib/jxl/dct_scales.cc | 5 +- third_party/jpeg-xl/lib/jxl/dct_test.cc | 45 +- third_party/jpeg-xl/lib/jxl/dct_util.h | 11 +- third_party/jpeg-xl/lib/jxl/dec_ans.cc | 89 +- third_party/jpeg-xl/lib/jxl/dec_ans.h | 61 +- third_party/jpeg-xl/lib/jxl/dec_bit_reader.h | 47 +- third_party/jpeg-xl/lib/jxl/dec_cache.cc | 205 +- third_party/jpeg-xl/lib/jxl/dec_cache.h | 100 +- .../jpeg-xl/lib/jxl/dec_context_map.cc | 15 +- third_party/jpeg-xl/lib/jxl/dec_context_map.h | 12 +- .../jpeg-xl/lib/jxl/dec_external_image.cc | 435 +- .../lib/jxl/dec_external_image_gbench.cc | 29 +- third_party/jpeg-xl/lib/jxl/dec_frame.cc | 258 +- third_party/jpeg-xl/lib/jxl/dec_frame.h | 3 +- third_party/jpeg-xl/lib/jxl/dec_group.cc | 115 +- third_party/jpeg-xl/lib/jxl/dec_group.h | 6 +- .../jpeg-xl/lib/jxl/dec_group_border.cc | 9 +- .../jpeg-xl/lib/jxl/dec_group_border.h | 11 +- third_party/jpeg-xl/lib/jxl/dec_modular.cc | 339 +- third_party/jpeg-xl/lib/jxl/dec_modular.h | 63 +- third_party/jpeg-xl/lib/jxl/dec_noise.cc | 55 +- third_party/jpeg-xl/lib/jxl/dec_noise.h | 16 +- .../jpeg-xl/lib/jxl/dec_patch_dictionary.cc | 68 +- .../jpeg-xl/lib/jxl/dec_patch_dictionary.h | 40 +- .../jpeg-xl/lib/jxl/dec_transforms-inl.h | 16 +- .../lib/jxl/dec_transforms_testonly.cc | 5 +- .../jpeg-xl/lib/jxl/dec_transforms_testonly.h | 11 +- third_party/jpeg-xl/lib/jxl/dec_xyb-inl.h | 9 +- third_party/jpeg-xl/lib/jxl/dec_xyb.cc | 206 +- third_party/jpeg-xl/lib/jxl/dec_xyb.h | 20 +- third_party/jpeg-xl/lib/jxl/decode.cc | 208 +- third_party/jpeg-xl/lib/jxl/decode_test.cc | 449 +- third_party/jpeg-xl/lib/jxl/decode_to_jpeg.cc | 6 +- .../jpeg-xl/lib/jxl/enc_ac_strategy.cc | 505 +- third_party/jpeg-xl/lib/jxl/enc_ac_strategy.h | 32 +- .../lib/jxl/enc_adaptive_quantization.cc | 384 +- .../lib/jxl/enc_adaptive_quantization.h | 9 +- third_party/jpeg-xl/lib/jxl/enc_ans.cc | 570 +- third_party/jpeg-xl/lib/jxl/enc_ans.h | 34 +- .../jpeg-xl/lib/jxl/enc_ar_control_field.cc | 318 -- .../jpeg-xl/lib/jxl/enc_ar_control_field.h | 55 - third_party/jpeg-xl/lib/jxl/enc_aux_out.cc | 59 +- third_party/jpeg-xl/lib/jxl/enc_aux_out.h | 52 +- third_party/jpeg-xl/lib/jxl/enc_bit_writer.cc | 178 +- third_party/jpeg-xl/lib/jxl/enc_bit_writer.h | 105 +- .../lib/jxl/enc_butteraugli_comparator.cc | 9 +- third_party/jpeg-xl/lib/jxl/enc_cache.cc | 139 +- third_party/jpeg-xl/lib/jxl/enc_cache.h | 16 +- .../jpeg-xl/lib/jxl/enc_chroma_from_luma.cc | 120 +- .../jpeg-xl/lib/jxl/enc_chroma_from_luma.h | 36 +- third_party/jpeg-xl/lib/jxl/enc_cluster.cc | 49 +- third_party/jpeg-xl/lib/jxl/enc_cluster.h | 19 +- .../jpeg-xl/lib/jxl/enc_coeff_order.cc | 119 +- third_party/jpeg-xl/lib/jxl/enc_coeff_order.h | 42 +- third_party/jpeg-xl/lib/jxl/enc_comparator.cc | 48 +- third_party/jpeg-xl/lib/jxl/enc_comparator.h | 2 + .../jpeg-xl/lib/jxl/enc_context_map.cc | 119 +- third_party/jpeg-xl/lib/jxl/enc_context_map.h | 17 +- .../jpeg-xl/lib/jxl/enc_debug_image.cc | 29 +- third_party/jpeg-xl/lib/jxl/enc_debug_image.h | 4 +- .../jpeg-xl/lib/jxl/enc_detect_dots.cc | 122 +- third_party/jpeg-xl/lib/jxl/enc_detect_dots.h | 7 +- .../jpeg-xl/lib/jxl/enc_dot_dictionary.cc | 27 +- .../jpeg-xl/lib/jxl/enc_dot_dictionary.h | 6 +- .../jpeg-xl/lib/jxl/enc_entropy_coder.cc | 57 +- .../jpeg-xl/lib/jxl/enc_entropy_coder.h | 33 +- .../jpeg-xl/lib/jxl/enc_external_image.cc | 78 +- .../lib/jxl/enc_external_image_gbench.cc | 20 +- .../lib/jxl/enc_external_image_test.cc | 24 +- .../jpeg-xl/lib/jxl/enc_fast_lossless.cc | 393 +- .../jpeg-xl/lib/jxl/enc_fast_lossless.h | 8 +- third_party/jpeg-xl/lib/jxl/enc_fields.cc | 52 +- third_party/jpeg-xl/lib/jxl/enc_fields.h | 8 +- third_party/jpeg-xl/lib/jxl/enc_frame.cc | 965 ++-- third_party/jpeg-xl/lib/jxl/enc_frame.h | 9 +- third_party/jpeg-xl/lib/jxl/enc_gaborish.cc | 29 +- third_party/jpeg-xl/lib/jxl/enc_gaborish.h | 1 + .../jpeg-xl/lib/jxl/enc_gaborish_test.cc | 26 +- third_party/jpeg-xl/lib/jxl/enc_group.cc | 127 +- third_party/jpeg-xl/lib/jxl/enc_group.h | 7 +- third_party/jpeg-xl/lib/jxl/enc_heuristics.cc | 523 +- third_party/jpeg-xl/lib/jxl/enc_heuristics.h | 9 +- third_party/jpeg-xl/lib/jxl/enc_huffman.cc | 36 +- third_party/jpeg-xl/lib/jxl/enc_huffman.h | 10 +- .../jpeg-xl/lib/jxl/enc_huffman_tree.cc | 17 + third_party/jpeg-xl/lib/jxl/enc_icc_codec.cc | 176 +- third_party/jpeg-xl/lib/jxl/enc_icc_codec.h | 11 +- .../jpeg-xl/lib/jxl/enc_image_bundle.cc | 161 +- .../jpeg-xl/lib/jxl/enc_image_bundle.h | 1 + third_party/jpeg-xl/lib/jxl/enc_linalg.cc | 14 +- .../jpeg-xl/lib/jxl/enc_linalg_test.cc | 16 +- third_party/jpeg-xl/lib/jxl/enc_modular.cc | 757 +-- third_party/jpeg-xl/lib/jxl/enc_modular.h | 21 +- third_party/jpeg-xl/lib/jxl/enc_noise.cc | 35 +- third_party/jpeg-xl/lib/jxl/enc_noise.h | 7 +- third_party/jpeg-xl/lib/jxl/enc_optimize.cc | 163 - third_party/jpeg-xl/lib/jxl/enc_optimize.h | 23 - .../jpeg-xl/lib/jxl/enc_optimize_test.cc | 19 +- third_party/jpeg-xl/lib/jxl/enc_params.h | 5 + .../jpeg-xl/lib/jxl/enc_patch_dictionary.cc | 181 +- .../jpeg-xl/lib/jxl/enc_patch_dictionary.h | 19 +- .../jpeg-xl/lib/jxl/enc_photon_noise.h | 4 +- .../jpeg-xl/lib/jxl/enc_photon_noise_test.cc | 46 +- .../jpeg-xl/lib/jxl/enc_progressive_split.h | 38 +- .../jpeg-xl/lib/jxl/enc_quant_weights.cc | 106 +- .../jpeg-xl/lib/jxl/enc_quant_weights.h | 23 +- third_party/jpeg-xl/lib/jxl/enc_splines.cc | 32 +- third_party/jpeg-xl/lib/jxl/enc_splines.h | 8 +- third_party/jpeg-xl/lib/jxl/enc_toc.cc | 51 +- third_party/jpeg-xl/lib/jxl/enc_toc.h | 11 +- .../jpeg-xl/lib/jxl/enc_transforms-inl.h | 21 +- third_party/jpeg-xl/lib/jxl/enc_transforms.cc | 4 +- third_party/jpeg-xl/lib/jxl/enc_transforms.h | 10 +- third_party/jpeg-xl/lib/jxl/enc_xyb.cc | 261 +- third_party/jpeg-xl/lib/jxl/enc_xyb.h | 6 +- third_party/jpeg-xl/lib/jxl/encode.cc | 423 +- third_party/jpeg-xl/lib/jxl/encode_internal.h | 88 +- third_party/jpeg-xl/lib/jxl/encode_test.cc | 73 +- third_party/jpeg-xl/lib/jxl/entropy_coder.cc | 21 +- third_party/jpeg-xl/lib/jxl/entropy_coder.h | 10 +- .../jpeg-xl/lib/jxl/entropy_coder_test.cc | 2 +- third_party/jpeg-xl/lib/jxl/epf.cc | 25 +- third_party/jpeg-xl/lib/jxl/epf.h | 7 +- .../lib/jxl/fake_parallel_runner_testonly.h | 2 +- third_party/jpeg-xl/lib/jxl/fast_dct-inl.h | 239 - third_party/jpeg-xl/lib/jxl/fast_dct128-inl.h | 2137 -------- third_party/jpeg-xl/lib/jxl/fast_dct16-inl.h | 180 - third_party/jpeg-xl/lib/jxl/fast_dct256-inl.h | 4811 ----------------- third_party/jpeg-xl/lib/jxl/fast_dct32-inl.h | 419 -- third_party/jpeg-xl/lib/jxl/fast_dct64-inl.h | 985 ---- third_party/jpeg-xl/lib/jxl/fast_dct8-inl.h | 80 - third_party/jpeg-xl/lib/jxl/fast_dct_test.cc | 380 -- third_party/jpeg-xl/lib/jxl/fast_math_test.cc | 23 +- third_party/jpeg-xl/lib/jxl/field_encodings.h | 12 +- third_party/jpeg-xl/lib/jxl/fields.cc | 30 +- third_party/jpeg-xl/lib/jxl/fields.h | 24 +- third_party/jpeg-xl/lib/jxl/fields_test.cc | 148 +- .../jpeg-xl/lib/jxl/frame_dimensions.h | 2 +- third_party/jpeg-xl/lib/jxl/frame_header.cc | 9 +- third_party/jpeg-xl/lib/jxl/frame_header.h | 14 +- third_party/jpeg-xl/lib/jxl/fuzztest.h | 22 + third_party/jpeg-xl/lib/jxl/gradient_test.cc | 27 +- third_party/jpeg-xl/lib/jxl/headers.cc | 10 +- third_party/jpeg-xl/lib/jxl/icc_codec.cc | 121 +- third_party/jpeg-xl/lib/jxl/icc_codec.h | 11 +- .../jpeg-xl/lib/jxl/icc_codec_common.cc | 34 +- .../jpeg-xl/lib/jxl/icc_codec_common.h | 8 +- third_party/jpeg-xl/lib/jxl/icc_codec_test.cc | 13 +- third_party/jpeg-xl/lib/jxl/image.cc | 45 +- third_party/jpeg-xl/lib/jxl/image.h | 284 +- third_party/jpeg-xl/lib/jxl/image_bundle.cc | 90 +- third_party/jpeg-xl/lib/jxl/image_bundle.h | 49 +- .../jpeg-xl/lib/jxl/image_bundle_test.cc | 34 +- third_party/jpeg-xl/lib/jxl/image_metadata.cc | 14 +- third_party/jpeg-xl/lib/jxl/image_metadata.h | 14 +- third_party/jpeg-xl/lib/jxl/image_ops.cc | 39 +- third_party/jpeg-xl/lib/jxl/image_ops.h | 62 +- third_party/jpeg-xl/lib/jxl/image_ops_test.cc | 49 +- .../jpeg-xl/lib/jxl/image_test_utils.h | 27 +- third_party/jpeg-xl/lib/jxl/inverse_mtf-inl.h | 2 +- .../jpeg-xl/lib/jxl/jpeg/dec_jpeg_data.cc | 11 +- .../lib/jxl/jpeg/dec_jpeg_data_writer.cc | 22 +- .../lib/jxl/jpeg/dec_jpeg_output_chunk.h | 6 +- .../jpeg-xl/lib/jxl/jpeg/enc_jpeg_data.cc | 76 +- .../jpeg-xl/lib/jxl/jpeg/enc_jpeg_data.h | 6 +- .../lib/jxl/jpeg/enc_jpeg_data_reader.cc | 39 +- third_party/jpeg-xl/lib/jxl/jpeg/jpeg_data.cc | 32 +- third_party/jpeg-xl/lib/jxl/jpeg/jpeg_data.h | 11 +- third_party/jpeg-xl/lib/jxl/jxl_test.cc | 756 ++- third_party/jpeg-xl/lib/jxl/lehmer_code.h | 22 +- .../jpeg-xl/lib/jxl/lehmer_code_test.cc | 48 +- .../lib/jxl/memory_manager_internal.cc | 141 +- .../jpeg-xl/lib/jxl/memory_manager_internal.h | 156 +- .../jxl/modular/encoding/context_predict.h | 14 +- .../lib/jxl/modular/encoding/dec_ma.cc | 13 +- .../jpeg-xl/lib/jxl/modular/encoding/dec_ma.h | 8 +- .../jxl/modular/encoding/enc_debug_tree.cc | 18 +- .../lib/jxl/modular/encoding/enc_debug_tree.h | 8 - .../lib/jxl/modular/encoding/enc_encoding.cc | 273 +- .../lib/jxl/modular/encoding/enc_encoding.h | 17 +- .../lib/jxl/modular/encoding/enc_ma.cc | 91 +- .../jpeg-xl/lib/jxl/modular/encoding/enc_ma.h | 25 +- .../lib/jxl/modular/encoding/encoding.cc | 92 +- .../lib/jxl/modular/encoding/encoding.h | 20 +- .../jpeg-xl/lib/jxl/modular/modular_image.cc | 42 +- .../jpeg-xl/lib/jxl/modular/modular_image.h | 29 +- third_party/jpeg-xl/lib/jxl/modular/options.h | 4 +- .../lib/jxl/modular/transform/enc_palette.cc | 110 +- .../lib/jxl/modular/transform/enc_rct.cc | 7 +- .../lib/jxl/modular/transform/enc_squeeze.cc | 42 +- .../lib/jxl/modular/transform/palette.cc | 209 +- .../lib/jxl/modular/transform/palette.h | 20 +- .../jpeg-xl/lib/jxl/modular/transform/rct.cc | 33 +- .../lib/jxl/modular/transform/squeeze.cc | 73 +- .../lib/jxl/modular/transform/squeeze.h | 8 +- .../lib/jxl/modular/transform/transform.cc | 4 +- .../lib/jxl/modular/transform/transform.h | 8 +- third_party/jpeg-xl/lib/jxl/modular_test.cc | 261 +- third_party/jpeg-xl/lib/jxl/noise.h | 5 +- .../jpeg-xl/lib/jxl/opsin_image_test.cc | 33 +- .../jpeg-xl/lib/jxl/opsin_inverse_test.cc | 37 +- third_party/jpeg-xl/lib/jxl/opsin_params.cc | 22 +- third_party/jpeg-xl/lib/jxl/opsin_params.h | 5 +- third_party/jpeg-xl/lib/jxl/padded_bytes.h | 147 +- .../jpeg-xl/lib/jxl/padded_bytes_test.cc | 40 +- third_party/jpeg-xl/lib/jxl/passes_state.cc | 37 +- third_party/jpeg-xl/lib/jxl/passes_state.h | 31 +- third_party/jpeg-xl/lib/jxl/passes_test.cc | 198 +- .../lib/jxl/patch_dictionary_internal.h | 3 - .../jpeg-xl/lib/jxl/patch_dictionary_test.cc | 22 +- third_party/jpeg-xl/lib/jxl/preview_test.cc | 20 +- third_party/jpeg-xl/lib/jxl/quant_weights.cc | 174 +- third_party/jpeg-xl/lib/jxl/quant_weights.h | 146 +- .../jpeg-xl/lib/jxl/quant_weights_test.cc | 107 +- third_party/jpeg-xl/lib/jxl/quantizer.cc | 20 +- third_party/jpeg-xl/lib/jxl/quantizer.h | 30 +- third_party/jpeg-xl/lib/jxl/quantizer_test.cc | 44 +- .../lib/jxl/rational_polynomial_test.cc | 4 +- .../low_memory_render_pipeline.cc | 160 +- .../low_memory_render_pipeline.h | 19 +- .../jxl/render_pipeline/render_pipeline.cc | 28 +- .../lib/jxl/render_pipeline/render_pipeline.h | 28 +- .../render_pipeline/render_pipeline_stage.h | 4 +- .../render_pipeline/render_pipeline_test.cc | 129 +- .../render_pipeline/simple_render_pipeline.cc | 45 +- .../render_pipeline/simple_render_pipeline.h | 13 +- .../lib/jxl/render_pipeline/stage_blending.cc | 38 +- .../lib/jxl/render_pipeline/stage_cms.cc | 12 +- .../lib/jxl/render_pipeline/stage_epf.cc | 43 +- .../lib/jxl/render_pipeline/stage_epf.h | 12 +- .../jxl/render_pipeline/stage_from_linear.cc | 9 +- .../lib/jxl/render_pipeline/stage_gaborish.cc | 2 +- .../lib/jxl/render_pipeline/stage_noise.cc | 31 +- .../lib/jxl/render_pipeline/stage_noise.h | 13 +- .../lib/jxl/render_pipeline/stage_patches.cc | 33 +- .../lib/jxl/render_pipeline/stage_patches.h | 9 +- .../lib/jxl/render_pipeline/stage_splines.cc | 9 +- .../lib/jxl/render_pipeline/stage_spot.cc | 19 +- .../lib/jxl/render_pipeline/stage_spot.h | 5 +- .../jxl/render_pipeline/stage_to_linear.cc | 5 +- .../jxl/render_pipeline/stage_tone_mapping.cc | 40 +- .../jxl/render_pipeline/stage_upsampling.cc | 14 +- .../lib/jxl/render_pipeline/stage_write.cc | 119 +- .../lib/jxl/render_pipeline/stage_write.h | 16 +- .../lib/jxl/render_pipeline/stage_xyb.cc | 16 +- .../test_render_pipeline_stages.h | 16 +- third_party/jpeg-xl/lib/jxl/roundtrip_test.cc | 54 +- third_party/jpeg-xl/lib/jxl/simd_util.cc | 37 - third_party/jpeg-xl/lib/jxl/simd_util.h | 7 +- .../jpeg-xl/lib/jxl/speed_tier_test.cc | 12 +- third_party/jpeg-xl/lib/jxl/splines.cc | 128 +- third_party/jpeg-xl/lib/jxl/splines.h | 35 +- third_party/jpeg-xl/lib/jxl/splines_gbench.cc | 55 +- third_party/jpeg-xl/lib/jxl/splines_test.cc | 376 +- third_party/jpeg-xl/lib/jxl/test_image.cc | 93 +- third_party/jpeg-xl/lib/jxl/test_image.h | 20 +- .../jpeg-xl/lib/jxl/test_memory_manager.cc | 24 + .../jpeg-xl/lib/jxl/test_memory_manager.h | 19 + third_party/jpeg-xl/lib/jxl/test_utils.cc | 219 +- third_party/jpeg-xl/lib/jxl/test_utils.h | 33 +- third_party/jpeg-xl/lib/jxl/testing.h | 61 +- third_party/jpeg-xl/lib/jxl/tf_gbench.cc | 4 +- third_party/jpeg-xl/lib/jxl/toc.cc | 16 +- third_party/jpeg-xl/lib/jxl/toc.h | 7 +- third_party/jpeg-xl/lib/jxl/toc_test.cc | 53 +- third_party/jpeg-xl/lib/jxl/version.h.in | 2 +- .../jpeg-xl/lib/jxl/xorshift128plus-inl.h | 4 +- .../jpeg-xl/lib/jxl/xorshift128plus_test.cc | 98 +- third_party/jpeg-xl/lib/jxl_benchmark.cmake | 11 +- third_party/jpeg-xl/lib/jxl_cms.cmake | 2 +- third_party/jpeg-xl/lib/jxl_extras.cmake | 4 +- third_party/jpeg-xl/lib/jxl_lists.bzl | 31 +- third_party/jpeg-xl/lib/jxl_lists.cmake | 27 +- third_party/jpeg-xl/lib/jxl_tests.cmake | 4 +- third_party/jpeg-xl/lib/jxl_vars.bzl | 5 +- .../thread_parallel_runner_internal.cc | 72 +- .../threads/thread_parallel_runner_internal.h | 6 +- .../threads/thread_parallel_runner_test.cc | 69 +- .../jpeg-xl/plugins/gimp/file-jxl-load.cc | 52 +- .../jpeg-xl/plugins/gimp/file-jxl-save.cc | 12 +- third_party/jpeg-xl/third_party/dirent.cc | 2 +- 479 files changed, 16837 insertions(+), 23160 deletions(-) create mode 100644 third_party/jpeg-xl/lib/extras/compressed_icc.cc create mode 100644 third_party/jpeg-xl/lib/extras/compressed_icc_test.cc create mode 100644 third_party/jpeg-xl/lib/extras/gain_map.cc create mode 100644 third_party/jpeg-xl/lib/extras/gain_map_test.cc create mode 100644 third_party/jpeg-xl/lib/include/jxl/compressed_icc.h create mode 100644 third_party/jpeg-xl/lib/include/jxl/gain_map.h create mode 100644 third_party/jpeg-xl/lib/jpegli/fuzztest.h create mode 100644 third_party/jpeg-xl/lib/jxl/base/include_jpeglib.h create mode 100644 third_party/jpeg-xl/lib/jxl/base/rect.h rename third_party/jpeg-xl/lib/jxl/{ => base}/sanitizers.h (91%) delete mode 100644 third_party/jpeg-xl/lib/jxl/cache_aligned.cc delete mode 100644 third_party/jpeg-xl/lib/jxl/cache_aligned.h delete mode 100644 third_party/jpeg-xl/lib/jxl/enc_ar_control_field.cc delete mode 100644 third_party/jpeg-xl/lib/jxl/enc_ar_control_field.h delete mode 100644 third_party/jpeg-xl/lib/jxl/enc_optimize.cc delete mode 100644 third_party/jpeg-xl/lib/jxl/fast_dct-inl.h delete mode 100644 third_party/jpeg-xl/lib/jxl/fast_dct128-inl.h delete mode 100644 third_party/jpeg-xl/lib/jxl/fast_dct16-inl.h delete mode 100644 third_party/jpeg-xl/lib/jxl/fast_dct256-inl.h delete mode 100644 third_party/jpeg-xl/lib/jxl/fast_dct32-inl.h delete mode 100644 third_party/jpeg-xl/lib/jxl/fast_dct64-inl.h delete mode 100644 third_party/jpeg-xl/lib/jxl/fast_dct8-inl.h delete mode 100644 third_party/jpeg-xl/lib/jxl/fast_dct_test.cc create mode 100644 third_party/jpeg-xl/lib/jxl/fuzztest.h create mode 100644 third_party/jpeg-xl/lib/jxl/test_memory_manager.cc create mode 100644 third_party/jpeg-xl/lib/jxl/test_memory_manager.h diff --git a/media/libjxl/moz.build b/media/libjxl/moz.build index 886c2319ad60d..b493386d4113d 100644 --- a/media/libjxl/moz.build +++ b/media/libjxl/moz.build @@ -15,7 +15,6 @@ SOURCES += [ "/third_party/jpeg-xl/lib/jxl/alpha.cc", "/third_party/jpeg-xl/lib/jxl/ans_common.cc", "/third_party/jpeg-xl/lib/jxl/blending.cc", - "/third_party/jpeg-xl/lib/jxl/cache_aligned.cc", "/third_party/jpeg-xl/lib/jxl/chroma_from_luma.cc", "/third_party/jpeg-xl/lib/jxl/coeff_order.cc", "/third_party/jpeg-xl/lib/jxl/color_encoding_internal.cc", @@ -85,6 +84,7 @@ SOURCES += [ "/third_party/jpeg-xl/lib/jxl/render_pipeline/stage_ycbcr.cc", "/third_party/jpeg-xl/lib/jxl/simd_util.cc", "/third_party/jpeg-xl/lib/jxl/splines.cc", + "/third_party/jpeg-xl/lib/jxl/test_memory_manager.cc", "/third_party/jpeg-xl/lib/jxl/toc.cc", ] diff --git a/media/libjxl/moz.yaml b/media/libjxl/moz.yaml index 6798daeeda1a0..c70a47e8f60bf 100644 --- a/media/libjxl/moz.yaml +++ b/media/libjxl/moz.yaml @@ -10,9 +10,9 @@ origin: url: https://github.com/libjxl/libjxl - release: v0.10.3 (2024-06-27T14:10:08+02:00). + release: v0.11.0 (2024-09-13T07:31:05+02:00). - revision: v0.10.3 + revision: v0.11.0 license: Apache-2.0 diff --git a/third_party/jpeg-xl/.clang-tidy b/third_party/jpeg-xl/.clang-tidy index 42d386276be68..11c6d2bcdd6e7 100644 --- a/third_party/jpeg-xl/.clang-tidy +++ b/third_party/jpeg-xl/.clang-tidy @@ -25,17 +25,20 @@ Checks: >- modernize-*, performance-*, readability-*, - -bugprone-narrowing-conversions, -bugprone-branch-clone, -bugprone-easily-swappable-parameters, -bugprone-implicit-widening-of-multiplication-result, -bugprone-infinite-loop, + -bugprone-narrowing-conversions, -bugprone-unused-local-non-trivial-variable, -modernize-avoid-c-arrays, + -modernize-concat-nested-namespaces, -modernize-deprecated-headers, -modernize-return-braced-init-list, + -modernize-type-traits, -modernize-use-auto, -modernize-use-default-member-init, + -modernize-use-nodiscard, -modernize-use-trailing-return-type, -modernize-use-using, -performance-enum-size, diff --git a/third_party/jpeg-xl/AUTHORS b/third_party/jpeg-xl/AUTHORS index ed6d72db66116..44387a01c461a 100644 --- a/third_party/jpeg-xl/AUTHORS +++ b/third_party/jpeg-xl/AUTHORS @@ -39,9 +39,11 @@ Alistair Barrow Andrius Lukas Narbutas Aous Naman Artem Selishchev +Aryan Pingle Biswapriyo Nath CanadianBaconBoi Damiano Albani +Damon Townsend Daniel Novomeský David Burnett dependabot[bot] @@ -53,17 +55,20 @@ Dong Xu estrogently <41487185+estrogently@users.noreply.github.com> Even Rouault Fred Brennan +Gerhard Huber gi-man Gilles Devillers (GilDev) Heiko Becker Ivan Kokorev Jim Robinson +John Platts Jonathan Brown (Jonnyawsom3) Joshua Root Kai Hollberg Kerry Su Kleis Auke Wolthuizen L. E. Segovia +ledoge Leo Izen Lovell Fuller Maarten DB diff --git a/third_party/jpeg-xl/BUILD.bazel b/third_party/jpeg-xl/BUILD.bazel index d419e3d9969b4..45c5261a2ea47 100644 --- a/third_party/jpeg-xl/BUILD.bazel +++ b/third_party/jpeg-xl/BUILD.bazel @@ -1,3 +1,8 @@ +# Copyright (c) the JPEG XL Project Authors. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + package(default_visibility = ["//:__subpackages__"]) filegroup( diff --git a/third_party/jpeg-xl/CHANGELOG.md b/third_party/jpeg-xl/CHANGELOG.md index 24aa25fae33ff..d67fbe0f5e38a 100644 --- a/third_party/jpeg-xl/CHANGELOG.md +++ b/third_party/jpeg-xl/CHANGELOG.md @@ -5,10 +5,23 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [0.10.3] - 2024-06-27 +## [0.11.0] - 2024-09-13 -### Fixed - - fix decoding of some special images (#3662) +### Added + - Gain Map API (#3552 and #3628): `JxlGainMapBundle` struct and API functions + to read and write gain map bundles`JxlGainMapWriteBundle` and + `JxlGainMapReadBundle` as well as handling compressed ICC profiles: + `JxlICCProfileEncode` and `JxlICCProfileDecode`. + - decoder API: added `JXL_DEC_BOX_COMPLETE` event to signal that the output + buffer for the current box has received all contents. Previously, this was + to be determined from the fact that the decoder had moved on either to + `JXL_DEC_SUCCESS` or to another subsequent `JXL_DEC_BOX`. This change is + made backward-compatible by the fact that the new event must be explicitly + subscribed to, and that `JXL_DEC_SUCCESS` / `JXL_DEC_BOX` still occur + afterwards and still imply that the previous box must be complete. + +### Changed / clarified + - avoiding abort in release build (#3631 and #3639) ## [0.10.2] - 2024-03-08 diff --git a/third_party/jpeg-xl/CMakeLists.txt b/third_party/jpeg-xl/CMakeLists.txt index d6891ef79d66f..8b2ccb5719891 100644 --- a/third_party/jpeg-xl/CMakeLists.txt +++ b/third_party/jpeg-xl/CMakeLists.txt @@ -11,7 +11,7 @@ project(LIBJXL LANGUAGES C CXX) # TODO(sboukortt): remove once oss-fuzz passes -DBUILD_SHARED_LIBS=OFF if(JPEGXL_ENABLE_FUZZERS) - message(INFO "Fuzzer build detected, building static libs") + message(STATUS "Fuzzer build detected, building static libs") set(BUILD_SHARED_LIBS OFF) endif() @@ -21,6 +21,10 @@ check_cxx_compiler_flag("-fsanitize=fuzzer-no-link" CXX_FUZZERS_SUPPORTED) check_cxx_compiler_flag("-fmacro-prefix-map=OLD=NEW" CXX_MACRO_PREFIX_MAP) check_cxx_compiler_flag("-fno-rtti" CXX_NO_RTTI_SUPPORTED) +# Add "DebugOpt" CMake build type. Unlike builtin DEBUG it is optimized. +string(REGEX REPLACE "-DNDEBUG " "" CMAKE_CXX_FLAGS_DEBUGOPT "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -DDEBUG" ) +string(REGEX REPLACE "-DNDEBUG " "" CMAKE_C_FLAGS_DEBUGOPT "${CMAKE_C_FLAGS_RELWITHDEBINFO} -DDEBUG" ) + # Enabled PIE binaries by default if supported. include(CheckPIESupported OPTIONAL RESULT_VARIABLE CHECK_PIE_SUPPORTED) if(CHECK_PIE_SUPPORTED) @@ -86,6 +90,16 @@ if(EXISTS "${PROJECT_SOURCE_DIR}/third_party/libjpeg-turbo/jconfig.h.in") set(ENABLE_JPEGLI_DEFAULT YES) else() set(ENABLE_JPEGLI_DEFAULT NO) + message(STATUS "libjpeg-turbo submodule is absent; not enabling jpegli") +endif() + +include(TestBigEndian) +test_big_endian(ARCH_IS_BIG_ENDIAN) +if(ARCH_IS_BIG_ENDIAN) + set(ENABLE_SKCMS_DEFAULT NO) + message(STATUS "Big-endian architecture detected; defaulting to lcms2 instead of skcms") +else() + set(ENABLE_SKCMS_DEFAULT YES) endif() # Standard cmake naming for building shared libraries. @@ -124,7 +138,7 @@ set(JPEGXL_ENABLE_SJPEG true CACHE BOOL "Build JPEGXL with support for encoding with sjpeg.") set(JPEGXL_ENABLE_OPENEXR true CACHE BOOL "Build JPEGXL with support for OpenEXR if available.") -set(JPEGXL_ENABLE_SKCMS true CACHE BOOL +set(JPEGXL_ENABLE_SKCMS ${ENABLE_SKCMS_DEFAULT} CACHE BOOL "Build with skcms instead of lcms2.") set(JPEGXL_ENABLE_VIEWERS false CACHE BOOL "Build JPEGXL viewer tools for evaluation.") @@ -160,14 +174,14 @@ set(JPEGXL_ENABLE_AVX512_SPR false CACHE BOOL "Build with AVX-512FP16 support (faster on CPUs that support it, but larger binary size).") set(JPEGXL_ENABLE_AVX512_ZEN4 false CACHE BOOL "Build with Zen4-optimized AVX512 support (faster on CPUs that support it, but larger binary size).") -set(JPEGXL_ENABLE_WASM_TRHEADS true CACHE BOOL +set(JPEGXL_ENABLE_WASM_THREADS true CACHE BOOL "Builds WASM modules with threads support") # Force system dependencies. set(JPEGXL_FORCE_SYSTEM_BROTLI false CACHE BOOL "Force using system installed brotli instead of third_party/brotli source.") set(JPEGXL_FORCE_SYSTEM_GTEST false CACHE BOOL - "Force using system installed googletest (gtest/gmock) instead of third_party/googletest source.") + "Force using system installed googletest (gtest) instead of third_party/googletest source.") set(JPEGXL_FORCE_SYSTEM_LCMS2 false CACHE BOOL "Force using system installed lcms2 instead of third_party/lcms source.") set(JPEGXL_FORCE_SYSTEM_HWY false CACHE BOOL @@ -208,13 +222,20 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) if(JPEGXL_STATIC) set(BUILD_SHARED_LIBS 0) + + # https://learn.microsoft.com/en-us/cpp/build/reference/md-mt-ld-use-run-time-library?view=msvc-170 + # https://cmake.org/cmake/help/latest/variable/CMAKE_MSVC_RUNTIME_LIBRARY.html + set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded) + # Clang developers say that in case to use "static" we have to build stdlib # ourselves; for real use case we don't care about stdlib, as it is "granted", # so just linking all other libraries is fine. - if (NOT MSVC AND NOT APPLE) + if (NOT MSVC) + string(APPEND CMAKE_EXE_LINKER_FLAGS " -static") + endif() + if ((NOT WIN32 AND NOT APPLE) OR CYGWIN OR MINGW) set(CMAKE_FIND_LIBRARY_SUFFIXES .a) - set(CMAKE_EXE_LINKER_FLAGS - "${CMAKE_EXE_LINKER_FLAGS} -static -static-libgcc -static-libstdc++") + string(APPEND CMAKE_EXE_LINKER_FLAGS " -static-libgcc -static-libstdc++") endif() endif() # JPEGXL_STATIC @@ -224,7 +245,16 @@ find_package(Threads REQUIRED) # These settings are important to drive check_cxx_source_compiles # See CMP0067 (min cmake version is 3.10 anyway) -set(CMAKE_CXX_STANDARD 11) + +if ("cxx_std_17" IN_LIST CMAKE_CXX_COMPILE_FEATURES) + set(CMAKE_CXX_STANDARD 17) +else() + if ("cxx_std_14" IN_LIST CMAKE_CXX_COMPILE_FEATURES) + set(CMAKE_CXX_STANDARD 14) + else() + set(CMAKE_CXX_STANDARD 11) + endif() +endif() set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_CXX_STANDARD_REQUIRED YES) @@ -265,7 +295,7 @@ if(JPEGXL_STATIC) endif() endif() # JPEGXL_STATIC -if (EMSCRIPTEN AND JPEGXL_ENABLE_WASM_TRHEADS) +if (EMSCRIPTEN AND JPEGXL_ENABLE_WASM_THREADS) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pthread") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread") @@ -343,7 +373,6 @@ else () if(JPEGXL_ENABLE_COVERAGE) set(JPEGXL_COVERAGE_FLAGS -g -O0 -fprofile-arcs -ftest-coverage - -DJXL_ENABLE_ASSERT=0 -DJXL_ENABLE_CHECK=0 ) set(JPEGXL_COVERAGE_LINK_FLAGS --coverage @@ -431,7 +460,7 @@ if(JPEGXL_ENABLE_MANPAGES) find_program(ASCIIDOC a2x) if(ASCIIDOC) file(STRINGS "${ASCIIDOC}" ASCIIDOC_SHEBANG LIMIT_COUNT 1) - if(ASCIIDOC_SHEBANG MATCHES "/sh|/bash" OR MINGW) + if(ASCIIDOC_SHEBANG MATCHES "sh$" OR MINGW) set(ASCIIDOC_PY_FOUND ON) # Run the program directly and set ASCIIDOC as empty. set(ASCIIDOC_PY "${ASCIIDOC}") diff --git a/third_party/jpeg-xl/MODULE.bazel b/third_party/jpeg-xl/MODULE.bazel index c83838418536e..cc2397538dfbf 100644 --- a/third_party/jpeg-xl/MODULE.bazel +++ b/third_party/jpeg-xl/MODULE.bazel @@ -1,4 +1,12 @@ -bazel_dep(name = "bazel_skylib", version = "1.5.0") +# Copyright (c) the JPEG XL Project Authors. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +bazel_dep(name = "bazel_skylib", version = "1.7.1") +bazel_dep(name = "giflib", version = "5.2.1") bazel_dep(name = "googletest", version = "1.14.0") -bazel_dep(name = "openexr", version = "3.2.1") +bazel_dep(name = "libjpeg_turbo", version = "2.1.91") bazel_dep(name = "libpng", version = "1.6.40") +bazel_dep(name = "libwebp", version = "1.3.2") +bazel_dep(name = "openexr", version = "3.2.1") diff --git a/third_party/jpeg-xl/MODULE.bazel.lock b/third_party/jpeg-xl/MODULE.bazel.lock index 660e64e473a69..7ea00d853cbed 100644 --- a/third_party/jpeg-xl/MODULE.bazel.lock +++ b/third_party/jpeg-xl/MODULE.bazel.lock @@ -1,1438 +1,131 @@ { - "lockFileVersion": 3, - "moduleFileHash": "988082051d7ff14f970486f378ca8eb29edb2bb7e97a5cb2715f2794ab6b5d53", - "flags": { - "cmdRegistries": [ - "https://bcr.bazel.build/" - ], - "cmdModuleOverrides": {}, - "allowedYankedVersions": [], - "envVarAllowedYankedVersions": "", - "ignoreDevDependency": false, - "directDependenciesMode": "WARNING", - "compatibilityMode": "ERROR" - }, - "localOverrideHashes": { - "bazel_tools": "922ea6752dc9105de5af957f7a99a6933c0a6a712d23df6aad16a9c399f7e787" - }, - "moduleDepGraph": { - "": { - "name": "", - "version": "", - "key": "", - "repoName": "", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [], - "deps": { - "bazel_skylib": "bazel_skylib@1.5.0", - "googletest": "googletest@1.14.0", - "openexr": "openexr@3.2.1", - "libpng": "libpng@1.6.40", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - } - }, - "bazel_skylib@1.5.0": { - "name": "bazel_skylib", - "version": "1.5.0", - "key": "bazel_skylib@1.5.0", - "repoName": "bazel_skylib", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [ - "//toolchains/unittest:cmd_toolchain", - "//toolchains/unittest:bash_toolchain" - ], - "extensionUsages": [], - "deps": { - "platforms": "platforms@0.0.7", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "bazel_skylib~1.5.0", - "urls": [ - "https://github.com/bazelbuild/bazel-skylib/releases/download/1.5.0/bazel-skylib-1.5.0.tar.gz" - ], - "integrity": "sha256-zVWgYudjuTSZIfD124w5MyiNyLpPdt2UFqrGis7jy5Q=", - "strip_prefix": "", - "remote_patches": {}, - "remote_patch_strip": 0 - } - } - }, - "googletest@1.14.0": { - "name": "googletest", - "version": "1.14.0", - "key": "googletest@1.14.0", - "repoName": "googletest", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [], - "deps": { - "com_google_absl": "abseil-cpp@20230125.1", - "platforms": "platforms@0.0.7", - "rules_cc": "rules_cc@0.0.9", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "googletest~1.14.0", - "urls": [ - "https://github.com/google/googletest/archive/refs/tags/v1.14.0.tar.gz" - ], - "integrity": "sha256-itWYxzrXluDYKAsILOvYKmMNc+c808cAV5OKZQG7pdc=", - "strip_prefix": "googletest-1.14.0", - "remote_patches": { - "https://bcr.bazel.build/modules/googletest/1.14.0/patches/module_dot_bazel.patch": "sha256-CSomzvti38LCuURDG5EEoa3O1tQF3cKKt/mknnP1qcc=" - }, - "remote_patch_strip": 0 - } - } - }, - "openexr@3.2.1": { - "name": "openexr", - "version": "3.2.1", - "key": "openexr@3.2.1", - "repoName": "openexr", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [], - "deps": { - "bazel_skylib": "bazel_skylib@1.5.0", - "Imath": "imath@3.1.9", - "libdeflate": "libdeflate@1.19", - "platforms": "platforms@0.0.7", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "openexr~3.2.1", - "urls": [ - "https://github.com/AcademySoftwareFoundation/openexr/archive/refs/tags/v3.2.1.tar.gz" - ], - "integrity": "sha256-YeF1qiIDOZ+zyMIoh1L76jwmN2gNULbjBupfj/3Uaps=", - "strip_prefix": "openexr-3.2.1", - "remote_patches": { - "https://bcr.bazel.build/modules/openexr/3.2.1/patches/module_dot_bazel.patch": "sha256-vrTXqfriDPsjzpyEyU3vrkgFesn3i1NKSmSMJ0bQ//0=" - }, - "remote_patch_strip": 0 - } - } - }, - "libpng@1.6.40": { - "name": "libpng", - "version": "1.6.40", - "key": "libpng@1.6.40", - "repoName": "libpng", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [], - "deps": { - "platforms": "platforms@0.0.7", - "zlib": "zlib@1.3", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "libpng~1.6.40", - "urls": [ - "https://download.sourceforge.net/libpng/libpng-1.6.40.tar.gz" - ], - "integrity": "sha256-j3ILNjqghoPJvypWMjb0UxOvLFXVQrVIGuF92NGDu0I=", - "strip_prefix": "libpng-1.6.40", - "remote_patches": { - "https://bcr.bazel.build/modules/libpng/1.6.40/patches/add_build_file.patch": "sha256-IKBdDmPuuugv3ZFYMxKbKbJEdKd9c9FPxr5BBjkYnmI=", - "https://bcr.bazel.build/modules/libpng/1.6.40/patches/module_dot_bazel.patch": "sha256-I4/ZDMvlGjXSTRyHy9dvW8idDHIInWXZ8e6jDW0mq6o=" - }, - "remote_patch_strip": 0 - } - } - }, - "bazel_tools@_": { - "name": "bazel_tools", - "version": "", - "key": "bazel_tools@_", - "repoName": "bazel_tools", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [ - "@local_config_cc_toolchains//:all", - "@local_config_sh//:local_sh_toolchain" - ], - "extensionUsages": [ - { - "extensionBzlFile": "@bazel_tools//tools/cpp:cc_configure.bzl", - "extensionName": "cc_configure_extension", - "usingModule": "bazel_tools@_", - "location": { - "file": "@@bazel_tools//:MODULE.bazel", - "line": 17, - "column": 29 - }, - "imports": { - "local_config_cc": "local_config_cc", - "local_config_cc_toolchains": "local_config_cc_toolchains" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - }, - { - "extensionBzlFile": "@bazel_tools//tools/osx:xcode_configure.bzl", - "extensionName": "xcode_configure_extension", - "usingModule": "bazel_tools@_", - "location": { - "file": "@@bazel_tools//:MODULE.bazel", - "line": 21, - "column": 32 - }, - "imports": { - "local_config_xcode": "local_config_xcode" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - }, - { - "extensionBzlFile": "@rules_java//java:extensions.bzl", - "extensionName": "toolchains", - "usingModule": "bazel_tools@_", - "location": { - "file": "@@bazel_tools//:MODULE.bazel", - "line": 24, - "column": 32 - }, - "imports": { - "local_jdk": "local_jdk", - "remote_java_tools": "remote_java_tools", - "remote_java_tools_linux": "remote_java_tools_linux", - "remote_java_tools_windows": "remote_java_tools_windows", - "remote_java_tools_darwin_x86_64": "remote_java_tools_darwin_x86_64", - "remote_java_tools_darwin_arm64": "remote_java_tools_darwin_arm64" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - }, - { - "extensionBzlFile": "@bazel_tools//tools/sh:sh_configure.bzl", - "extensionName": "sh_configure_extension", - "usingModule": "bazel_tools@_", - "location": { - "file": "@@bazel_tools//:MODULE.bazel", - "line": 35, - "column": 39 - }, - "imports": { - "local_config_sh": "local_config_sh" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - }, - { - "extensionBzlFile": "@bazel_tools//tools/test:extensions.bzl", - "extensionName": "remote_coverage_tools_extension", - "usingModule": "bazel_tools@_", - "location": { - "file": "@@bazel_tools//:MODULE.bazel", - "line": 39, - "column": 48 - }, - "imports": { - "remote_coverage_tools": "remote_coverage_tools" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - }, - { - "extensionBzlFile": "@bazel_tools//tools/android:android_extensions.bzl", - "extensionName": "remote_android_tools_extensions", - "usingModule": "bazel_tools@_", - "location": { - "file": "@@bazel_tools//:MODULE.bazel", - "line": 42, - "column": 42 - }, - "imports": { - "android_gmaven_r8": "android_gmaven_r8", - "android_tools": "android_tools" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - } - ], - "deps": { - "rules_cc": "rules_cc@0.0.9", - "rules_java": "rules_java@7.1.0", - "rules_license": "rules_license@0.0.7", - "rules_proto": "rules_proto@4.0.0", - "rules_python": "rules_python@0.4.0", - "platforms": "platforms@0.0.7", - "com_google_protobuf": "protobuf@3.19.6", - "zlib": "zlib@1.3", - "build_bazel_apple_support": "apple_support@1.5.0", - "local_config_platform": "local_config_platform@_" - } - }, - "local_config_platform@_": { - "name": "local_config_platform", - "version": "", - "key": "local_config_platform@_", - "repoName": "local_config_platform", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [], - "deps": { - "platforms": "platforms@0.0.7", - "bazel_tools": "bazel_tools@_" - } - }, - "platforms@0.0.7": { - "name": "platforms", - "version": "0.0.7", - "key": "platforms@0.0.7", - "repoName": "platforms", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [], - "deps": { - "rules_license": "rules_license@0.0.7", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "platforms", - "urls": [ - "https://github.com/bazelbuild/platforms/releases/download/0.0.7/platforms-0.0.7.tar.gz" - ], - "integrity": "sha256-OlYcmee9vpFzqmU/1Xn+hJ8djWc5V4CrR3Cx84FDHVE=", - "strip_prefix": "", - "remote_patches": {}, - "remote_patch_strip": 0 - } - } - }, - "abseil-cpp@20230125.1": { - "name": "abseil-cpp", - "version": "20230125.1", - "key": "abseil-cpp@20230125.1", - "repoName": "abseil-cpp", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [], - "deps": { - "rules_cc": "rules_cc@0.0.9", - "platforms": "platforms@0.0.7", - "bazel_skylib": "bazel_skylib@1.5.0", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "abseil-cpp~20230125.1", - "urls": [ - "https://github.com/abseil/abseil-cpp/archive/refs/tags/20230125.1.tar.gz" - ], - "integrity": "sha256-gTEcF1mbNxIGne0gzKCaYqsL8qid+haZN4bIeCt+0UU=", - "strip_prefix": "abseil-cpp-20230125.1", - "remote_patches": { - "https://bcr.bazel.build/modules/abseil-cpp/20230125.1/patches/module_dot_bazel.patch": "sha256-L1wChhBmDOnRbPbD4MENVXHjOBT2KFrDxT6D+aoThxk=" - }, - "remote_patch_strip": 0 - } - } - }, - "rules_cc@0.0.9": { - "name": "rules_cc", - "version": "0.0.9", - "key": "rules_cc@0.0.9", - "repoName": "rules_cc", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [ - "@local_config_cc_toolchains//:all" - ], - "extensionUsages": [ - { - "extensionBzlFile": "@bazel_tools//tools/cpp:cc_configure.bzl", - "extensionName": "cc_configure_extension", - "usingModule": "rules_cc@0.0.9", - "location": { - "file": "https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel", - "line": 9, - "column": 29 - }, - "imports": { - "local_config_cc_toolchains": "local_config_cc_toolchains" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - } - ], - "deps": { - "platforms": "platforms@0.0.7", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_cc~0.0.9", - "urls": [ - "https://github.com/bazelbuild/rules_cc/releases/download/0.0.9/rules_cc-0.0.9.tar.gz" - ], - "integrity": "sha256-IDeHW5pEVtzkp50RKorohbvEqtlo5lh9ym5k86CQDN8=", - "strip_prefix": "rules_cc-0.0.9", - "remote_patches": { - "https://bcr.bazel.build/modules/rules_cc/0.0.9/patches/module_dot_bazel_version.patch": "sha256-mM+qzOI0SgAdaJBlWOSMwMPKpaA9b7R37Hj/tp5bb4g=" - }, - "remote_patch_strip": 0 - } - } - }, - "imath@3.1.9": { - "name": "imath", - "version": "3.1.9", - "key": "imath@3.1.9", - "repoName": "imath", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [], - "deps": { - "bazel_skylib": "bazel_skylib@1.5.0", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "imath~3.1.9", - "urls": [ - "https://github.com/AcademySoftwareFoundation/Imath/archive/refs/tags/v3.1.9.tar.gz" - ], - "integrity": "sha256-8diqzUav7ZWLq/ztMZDS08ggm2baRR9Var1tqUwWXPM=", - "strip_prefix": "Imath-3.1.9", - "remote_patches": { - "https://bcr.bazel.build/modules/imath/3.1.9/patches/add_build_file.patch": "sha256-hpm7m6W5MmXfxyJyZYcxHd4gHz93hu1jj5c8EHtM4WI=", - "https://bcr.bazel.build/modules/imath/3.1.9/patches/module_dot_bazel.patch": "sha256-Ze6qnPdaaDfi9Q+PlprFVGYxRfdlRfzsozWWnEGi9mc=" - }, - "remote_patch_strip": 0 - } - } - }, - "libdeflate@1.19": { - "name": "libdeflate", - "version": "1.19", - "key": "libdeflate@1.19", - "repoName": "libdeflate", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [], - "deps": { - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "libdeflate~1.19", - "urls": [ - "https://github.com/ebiggers/libdeflate/archive/refs/tags/v1.19.tar.gz" - ], - "integrity": "sha256-J79i1xzWRyj/Q6n+uS8qwvK/dImG2FYTPMHlGZJCjCU=", - "strip_prefix": "libdeflate-1.19", - "remote_patches": { - "https://bcr.bazel.build/modules/libdeflate/1.19/patches/add_build_file.patch": "sha256-L5cLd/VE0kOH29ifL5KdRkGX2KOldCTgKqTmNTWOTjg=", - "https://bcr.bazel.build/modules/libdeflate/1.19/patches/module_dot_bazel.patch": "sha256-GcCZeZoaXO2+nzQQlv8TqMYlyiAyoz1/f/CjSpUbd8Q=" - }, - "remote_patch_strip": 0 - } - } - }, - "zlib@1.3": { - "name": "zlib", - "version": "1.3", - "key": "zlib@1.3", - "repoName": "zlib", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [], - "deps": { - "platforms": "platforms@0.0.7", - "rules_cc": "rules_cc@0.0.9", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "zlib~1.3", - "urls": [ - "https://github.com/madler/zlib/releases/download/v1.3/zlib-1.3.tar.gz" - ], - "integrity": "sha256-/wukwpIBPbwnUws6geH5qBPNOd4Byl4Pi/NVcC76WT4=", - "strip_prefix": "zlib-1.3", - "remote_patches": { - "https://bcr.bazel.build/modules/zlib/1.3/patches/add_build_file.patch": "sha256-Ei+FYaaOo7A3jTKunMEodTI0Uw5NXQyZEcboMC8JskY=", - "https://bcr.bazel.build/modules/zlib/1.3/patches/module_dot_bazel.patch": "sha256-fPWLM+2xaF/kuy+kZc1YTfW6hNjrkG400Ho7gckuyJk=" - }, - "remote_patch_strip": 0 - } - } - }, - "rules_java@7.1.0": { - "name": "rules_java", - "version": "7.1.0", - "key": "rules_java@7.1.0", - "repoName": "rules_java", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [ - "//toolchains:all", - "@local_jdk//:runtime_toolchain_definition", - "@local_jdk//:bootstrap_runtime_toolchain_definition", - "@remotejdk11_linux_toolchain_config_repo//:all", - "@remotejdk11_linux_aarch64_toolchain_config_repo//:all", - "@remotejdk11_linux_ppc64le_toolchain_config_repo//:all", - "@remotejdk11_linux_s390x_toolchain_config_repo//:all", - "@remotejdk11_macos_toolchain_config_repo//:all", - "@remotejdk11_macos_aarch64_toolchain_config_repo//:all", - "@remotejdk11_win_toolchain_config_repo//:all", - "@remotejdk11_win_arm64_toolchain_config_repo//:all", - "@remotejdk17_linux_toolchain_config_repo//:all", - "@remotejdk17_linux_aarch64_toolchain_config_repo//:all", - "@remotejdk17_linux_ppc64le_toolchain_config_repo//:all", - "@remotejdk17_linux_s390x_toolchain_config_repo//:all", - "@remotejdk17_macos_toolchain_config_repo//:all", - "@remotejdk17_macos_aarch64_toolchain_config_repo//:all", - "@remotejdk17_win_toolchain_config_repo//:all", - "@remotejdk17_win_arm64_toolchain_config_repo//:all", - "@remotejdk21_linux_toolchain_config_repo//:all", - "@remotejdk21_linux_aarch64_toolchain_config_repo//:all", - "@remotejdk21_macos_toolchain_config_repo//:all", - "@remotejdk21_macos_aarch64_toolchain_config_repo//:all", - "@remotejdk21_win_toolchain_config_repo//:all" - ], - "extensionUsages": [ - { - "extensionBzlFile": "@rules_java//java:extensions.bzl", - "extensionName": "toolchains", - "usingModule": "rules_java@7.1.0", - "location": { - "file": "https://bcr.bazel.build/modules/rules_java/7.1.0/MODULE.bazel", - "line": 19, - "column": 27 - }, - "imports": { - "remote_java_tools": "remote_java_tools", - "remote_java_tools_linux": "remote_java_tools_linux", - "remote_java_tools_windows": "remote_java_tools_windows", - "remote_java_tools_darwin_x86_64": "remote_java_tools_darwin_x86_64", - "remote_java_tools_darwin_arm64": "remote_java_tools_darwin_arm64", - "local_jdk": "local_jdk", - "remotejdk11_linux_toolchain_config_repo": "remotejdk11_linux_toolchain_config_repo", - "remotejdk11_linux_aarch64_toolchain_config_repo": "remotejdk11_linux_aarch64_toolchain_config_repo", - "remotejdk11_linux_ppc64le_toolchain_config_repo": "remotejdk11_linux_ppc64le_toolchain_config_repo", - "remotejdk11_linux_s390x_toolchain_config_repo": "remotejdk11_linux_s390x_toolchain_config_repo", - "remotejdk11_macos_toolchain_config_repo": "remotejdk11_macos_toolchain_config_repo", - "remotejdk11_macos_aarch64_toolchain_config_repo": "remotejdk11_macos_aarch64_toolchain_config_repo", - "remotejdk11_win_toolchain_config_repo": "remotejdk11_win_toolchain_config_repo", - "remotejdk11_win_arm64_toolchain_config_repo": "remotejdk11_win_arm64_toolchain_config_repo", - "remotejdk17_linux_toolchain_config_repo": "remotejdk17_linux_toolchain_config_repo", - "remotejdk17_linux_aarch64_toolchain_config_repo": "remotejdk17_linux_aarch64_toolchain_config_repo", - "remotejdk17_linux_ppc64le_toolchain_config_repo": "remotejdk17_linux_ppc64le_toolchain_config_repo", - "remotejdk17_linux_s390x_toolchain_config_repo": "remotejdk17_linux_s390x_toolchain_config_repo", - "remotejdk17_macos_toolchain_config_repo": "remotejdk17_macos_toolchain_config_repo", - "remotejdk17_macos_aarch64_toolchain_config_repo": "remotejdk17_macos_aarch64_toolchain_config_repo", - "remotejdk17_win_toolchain_config_repo": "remotejdk17_win_toolchain_config_repo", - "remotejdk17_win_arm64_toolchain_config_repo": "remotejdk17_win_arm64_toolchain_config_repo", - "remotejdk21_linux_toolchain_config_repo": "remotejdk21_linux_toolchain_config_repo", - "remotejdk21_linux_aarch64_toolchain_config_repo": "remotejdk21_linux_aarch64_toolchain_config_repo", - "remotejdk21_macos_toolchain_config_repo": "remotejdk21_macos_toolchain_config_repo", - "remotejdk21_macos_aarch64_toolchain_config_repo": "remotejdk21_macos_aarch64_toolchain_config_repo", - "remotejdk21_win_toolchain_config_repo": "remotejdk21_win_toolchain_config_repo" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - } - ], - "deps": { - "platforms": "platforms@0.0.7", - "rules_cc": "rules_cc@0.0.9", - "bazel_skylib": "bazel_skylib@1.5.0", - "rules_proto": "rules_proto@4.0.0", - "rules_license": "rules_license@0.0.7", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0", - "urls": [ - "https://github.com/bazelbuild/rules_java/releases/download/7.1.0/rules_java-7.1.0.tar.gz" - ], - "integrity": "sha256-o3pOX2OrgnFuXdau75iO2EYcegC46TYnImKJn1h81OE=", - "strip_prefix": "", - "remote_patches": {}, - "remote_patch_strip": 0 - } - } - }, - "rules_license@0.0.7": { - "name": "rules_license", - "version": "0.0.7", - "key": "rules_license@0.0.7", - "repoName": "rules_license", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [], - "deps": { - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_license~0.0.7", - "urls": [ - "https://github.com/bazelbuild/rules_license/releases/download/0.0.7/rules_license-0.0.7.tar.gz" - ], - "integrity": "sha256-RTHezLkTY5ww5cdRKgVNXYdWmNrrddjPkPKEN1/nw2A=", - "strip_prefix": "", - "remote_patches": {}, - "remote_patch_strip": 0 - } - } - }, - "rules_proto@4.0.0": { - "name": "rules_proto", - "version": "4.0.0", - "key": "rules_proto@4.0.0", - "repoName": "rules_proto", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [], - "deps": { - "bazel_skylib": "bazel_skylib@1.5.0", - "rules_cc": "rules_cc@0.0.9", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_proto~4.0.0", - "urls": [ - "https://github.com/bazelbuild/rules_proto/archive/refs/tags/4.0.0.zip" - ], - "integrity": "sha256-Lr5z6xyuRA19pNtRYMGjKaynwQpck4H/lwYyVjyhoq4=", - "strip_prefix": "rules_proto-4.0.0", - "remote_patches": { - "https://bcr.bazel.build/modules/rules_proto/4.0.0/patches/module_dot_bazel.patch": "sha256-MclJO7tIAM2ElDAmscNId9pKTpOuDGHgVlW/9VBOIp0=" - }, - "remote_patch_strip": 0 - } - } - }, - "rules_python@0.4.0": { - "name": "rules_python", - "version": "0.4.0", - "key": "rules_python@0.4.0", - "repoName": "rules_python", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [ - "@bazel_tools//tools/python:autodetecting_toolchain" - ], - "extensionUsages": [ - { - "extensionBzlFile": "@rules_python//bzlmod:extensions.bzl", - "extensionName": "pip_install", - "usingModule": "rules_python@0.4.0", - "location": { - "file": "https://bcr.bazel.build/modules/rules_python/0.4.0/MODULE.bazel", - "line": 7, - "column": 28 - }, - "imports": { - "pypi__click": "pypi__click", - "pypi__pip": "pypi__pip", - "pypi__pip_tools": "pypi__pip_tools", - "pypi__pkginfo": "pypi__pkginfo", - "pypi__setuptools": "pypi__setuptools", - "pypi__wheel": "pypi__wheel" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - } - ], - "deps": { - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_python~0.4.0", - "urls": [ - "https://github.com/bazelbuild/rules_python/releases/download/0.4.0/rules_python-0.4.0.tar.gz" - ], - "integrity": "sha256-lUqom0kb5KCDMEosuDgBnIuMNyCnq7nEy4GseiQjDOo=", - "strip_prefix": "", - "remote_patches": { - "https://bcr.bazel.build/modules/rules_python/0.4.0/patches/propagate_pip_install_dependencies.patch": "sha256-v7S/dem/mixg63MF4KoRGDA4KEol9ab/tIVp+6Xq0D0=", - "https://bcr.bazel.build/modules/rules_python/0.4.0/patches/module_dot_bazel.patch": "sha256-kG4VIfWxQazzTuh50mvsx6pmyoRVA4lfH5rkto/Oq+Y=" - }, - "remote_patch_strip": 1 - } - } - }, - "protobuf@3.19.6": { - "name": "protobuf", - "version": "3.19.6", - "key": "protobuf@3.19.6", - "repoName": "protobuf", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [], - "extensionUsages": [], - "deps": { - "bazel_skylib": "bazel_skylib@1.5.0", - "zlib": "zlib@1.3", - "rules_python": "rules_python@0.4.0", - "rules_cc": "rules_cc@0.0.9", - "rules_proto": "rules_proto@4.0.0", - "rules_java": "rules_java@7.1.0", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "protobuf~3.19.6", - "urls": [ - "https://github.com/protocolbuffers/protobuf/archive/refs/tags/v3.19.6.zip" - ], - "integrity": "sha256-OH4sVZuyx8G8N5jE5s/wFTgaebJ1hpavy/johzC0c4k=", - "strip_prefix": "protobuf-3.19.6", - "remote_patches": { - "https://bcr.bazel.build/modules/protobuf/3.19.6/patches/relative_repo_names.patch": "sha256-w/5gw/zGv8NFId+669hcdw1Uus2lxgYpulATHIwIByI=", - "https://bcr.bazel.build/modules/protobuf/3.19.6/patches/remove_dependency_on_rules_jvm_external.patch": "sha256-THUTnVgEBmjA0W7fKzIyZOVG58DnW9HQTkr4D2zKUUc=", - "https://bcr.bazel.build/modules/protobuf/3.19.6/patches/add_module_dot_bazel_for_examples.patch": "sha256-s/b1gi3baK3LsXefI2rQilhmkb2R5jVJdnT6zEcdfHY=", - "https://bcr.bazel.build/modules/protobuf/3.19.6/patches/module_dot_bazel.patch": "sha256-S0DEni8zgx7rHscW3z/rCEubQnYec0XhNet640cw0h4=" - }, - "remote_patch_strip": 1 - } - } - }, - "apple_support@1.5.0": { - "name": "apple_support", - "version": "1.5.0", - "key": "apple_support@1.5.0", - "repoName": "build_bazel_apple_support", - "executionPlatformsToRegister": [], - "toolchainsToRegister": [ - "@local_config_apple_cc_toolchains//:all" - ], - "extensionUsages": [ - { - "extensionBzlFile": "@build_bazel_apple_support//crosstool:setup.bzl", - "extensionName": "apple_cc_configure_extension", - "usingModule": "apple_support@1.5.0", - "location": { - "file": "https://bcr.bazel.build/modules/apple_support/1.5.0/MODULE.bazel", - "line": 17, - "column": 35 - }, - "imports": { - "local_config_apple_cc": "local_config_apple_cc", - "local_config_apple_cc_toolchains": "local_config_apple_cc_toolchains" - }, - "devImports": [], - "tags": [], - "hasDevUseExtension": false, - "hasNonDevUseExtension": true - } - ], - "deps": { - "bazel_skylib": "bazel_skylib@1.5.0", - "platforms": "platforms@0.0.7", - "bazel_tools": "bazel_tools@_", - "local_config_platform": "local_config_platform@_" - }, - "repoSpec": { - "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "apple_support~1.5.0", - "urls": [ - "https://github.com/bazelbuild/apple_support/releases/download/1.5.0/apple_support.1.5.0.tar.gz" - ], - "integrity": "sha256-miM41vja0yRPgj8txghKA+TQ+7J8qJLclw5okNW0gYQ=", - "strip_prefix": "", - "remote_patches": {}, - "remote_patch_strip": 0 - } - } - } + "lockFileVersion": 11, + "registryFileHashes": { + "https://bcr.bazel.build/bazel_registry.json": "8a28e4aff06ee60aed2a8c281907fb8bcbf3b753c91fb5a5c57da3215d5b3497", + "https://bcr.bazel.build/modules/abseil-cpp/20210324.2/MODULE.bazel": "7cd0312e064fde87c8d1cd79ba06c876bd23630c83466e9500321be55c96ace2", + "https://bcr.bazel.build/modules/abseil-cpp/20211102.0/MODULE.bazel": "70390338f7a5106231d20620712f7cccb659cd0e9d073d1991c038eb9fc57589", + "https://bcr.bazel.build/modules/abseil-cpp/20230125.1/MODULE.bazel": "89047429cb0207707b2dface14ba7f8df85273d484c2572755be4bab7ce9c3a0", + "https://bcr.bazel.build/modules/abseil-cpp/20230125.1/source.json": "06cc0842d241da0c5edc755edb3c7d0d008d304330e57ecf2d6449fb0b633a82", + "https://bcr.bazel.build/modules/apple_support/1.5.0/MODULE.bazel": "50341a62efbc483e8a2a6aec30994a58749bd7b885e18dd96aa8c33031e558ef", + "https://bcr.bazel.build/modules/apple_support/1.5.0/source.json": "eb98a7627c0bc486b57f598ad8da50f6625d974c8f723e9ea71bd39f709c9862", + "https://bcr.bazel.build/modules/bazel_features/1.11.0/MODULE.bazel": "f9382337dd5a474c3b7d334c2f83e50b6eaedc284253334cf823044a26de03e8", + "https://bcr.bazel.build/modules/bazel_features/1.11.0/source.json": "c9320aa53cd1c441d24bd6b716da087ad7e4ff0d9742a9884587596edfe53015", + "https://bcr.bazel.build/modules/bazel_skylib/1.0.3/MODULE.bazel": "bcb0fd896384802d1ad283b4e4eb4d718eebd8cb820b0a2c3a347fb971afd9d8", + "https://bcr.bazel.build/modules/bazel_skylib/1.2.1/MODULE.bazel": "f35baf9da0efe45fa3da1696ae906eea3d615ad41e2e3def4aeb4e8bc0ef9a7a", + "https://bcr.bazel.build/modules/bazel_skylib/1.3.0/MODULE.bazel": "20228b92868bf5cfc41bda7afc8a8ba2a543201851de39d990ec957b513579c5", + "https://bcr.bazel.build/modules/bazel_skylib/1.4.1/MODULE.bazel": "a0dcb779424be33100dcae821e9e27e4f2901d9dfd5333efe5ac6a8d7ab75e1d", + "https://bcr.bazel.build/modules/bazel_skylib/1.4.2/MODULE.bazel": "3bd40978e7a1fac911d5989e6b09d8f64921865a45822d8b09e815eaa726a651", + "https://bcr.bazel.build/modules/bazel_skylib/1.5.0/MODULE.bazel": "32880f5e2945ce6a03d1fbd588e9198c0a959bb42297b2cfaf1685b7bc32e138", + "https://bcr.bazel.build/modules/bazel_skylib/1.6.1/MODULE.bazel": "8fdee2dbaace6c252131c00e1de4b165dc65af02ea278476187765e1a617b917", + "https://bcr.bazel.build/modules/bazel_skylib/1.7.1/MODULE.bazel": "3120d80c5861aa616222ec015332e5f8d3171e062e3e804a2a0253e1be26e59b", + "https://bcr.bazel.build/modules/bazel_skylib/1.7.1/source.json": "f121b43eeefc7c29efbd51b83d08631e2347297c95aac9764a701f2a6a2bb953", + "https://bcr.bazel.build/modules/buildozer/7.1.2/MODULE.bazel": "2e8dd40ede9c454042645fd8d8d0cd1527966aa5c919de86661e62953cd73d84", + "https://bcr.bazel.build/modules/buildozer/7.1.2/source.json": "c9028a501d2db85793a6996205c8de120944f50a0d570438fcae0457a5f9d1f8", + "https://bcr.bazel.build/modules/giflib/5.2.1/MODULE.bazel": "810dbc4275425c89ffe648dd78c537fe2eb1d2a9704d10e950b295263af03366", + "https://bcr.bazel.build/modules/giflib/5.2.1/source.json": "94215af981976c329eaec0083727b155ea89607e61debea50ed508e7963ef9a6", + "https://bcr.bazel.build/modules/googletest/1.11.0/MODULE.bazel": "3a83f095183f66345ca86aa13c58b59f9f94a2f81999c093d4eeaa2d262d12f4", + "https://bcr.bazel.build/modules/googletest/1.14.0/MODULE.bazel": "cfbcbf3e6eac06ef9d85900f64424708cc08687d1b527f0ef65aa7517af8118f", + "https://bcr.bazel.build/modules/googletest/1.14.0/source.json": "2478949479000fdd7de9a3d0107ba2c85bb5f961c3ecb1aa448f52549ce310b5", + "https://bcr.bazel.build/modules/imath/3.1.9/MODULE.bazel": "26fe47ee8137a4c605667fb0d26a5c12b8fb2e758824a376789b287b2f9d424d", + "https://bcr.bazel.build/modules/imath/3.1.9/source.json": "22b7d9e617d4d26626f5ac8fba3cd2bd7a87f7501c99fa847f8d9e2980416e8f", + "https://bcr.bazel.build/modules/libdeflate/1.19/MODULE.bazel": "b7396a2edfd5ce6669509fbdd10db5e8731d60954063699c546c3126c8156824", + "https://bcr.bazel.build/modules/libdeflate/1.19/source.json": "d4604a526efba9b5347309de49673bbe152da465f7c80c7f7ffe6800d8b504d1", + "https://bcr.bazel.build/modules/libjpeg_turbo/2.1.91/MODULE.bazel": "bcc23b7c4866af2d7777ee49db435603ca1e35b90ea0689f8051900fa8c73c6b", + "https://bcr.bazel.build/modules/libjpeg_turbo/2.1.91/source.json": "42ea85708058e2408f229075e1cbeaad13fa2719918ff9c505be5e22b57ef17b", + "https://bcr.bazel.build/modules/libpng/1.6.40/MODULE.bazel": "cc1952a9b5efd4df3dfdb9f9ba2b1c8d88b4fd9b0e474185cb81d90a31c7c453", + "https://bcr.bazel.build/modules/libpng/1.6.40/source.json": "2fe294bf161c2d3f1e04e7cecb6eb2e6c0c198698b23cabc1c4e6ff77d82a86a", + "https://bcr.bazel.build/modules/libwebp/1.3.2/MODULE.bazel": "c60edf34a913daebac9bd2cbe17b84048e4a7a5d3571f70be93c1b1227a69659", + "https://bcr.bazel.build/modules/libwebp/1.3.2/source.json": "e7b8d3047ad9758fda22fcf46bd8b57414b0eb5e7903f4ce888683d778633cf7", + "https://bcr.bazel.build/modules/openexr/3.2.1/MODULE.bazel": "5665fa95490825760943601d618e2d70eb45378ea3f2961c5ec18f23ae8a2106", + "https://bcr.bazel.build/modules/openexr/3.2.1/source.json": "afc17dda6614ff723cc1def634fa4f33534d3d29514b089fa4aa5eb47ba1c65b", + "https://bcr.bazel.build/modules/platforms/0.0.4/MODULE.bazel": "9b328e31ee156f53f3c416a64f8491f7eb731742655a47c9eec4703a71644aee", + "https://bcr.bazel.build/modules/platforms/0.0.5/MODULE.bazel": "5733b54ea419d5eaf7997054bb55f6a1d0b5ff8aedf0176fef9eea44f3acda37", + "https://bcr.bazel.build/modules/platforms/0.0.6/MODULE.bazel": "ad6eeef431dc52aefd2d77ed20a4b353f8ebf0f4ecdd26a807d2da5aa8cd0615", + "https://bcr.bazel.build/modules/platforms/0.0.7/MODULE.bazel": "72fd4a0ede9ee5c021f6a8dd92b503e089f46c227ba2813ff183b71616034814", + "https://bcr.bazel.build/modules/platforms/0.0.8/MODULE.bazel": "9f142c03e348f6d263719f5074b21ef3adf0b139ee4c5133e2aa35664da9eb2d", + "https://bcr.bazel.build/modules/platforms/0.0.9/MODULE.bazel": "4a87a60c927b56ddd67db50c89acaa62f4ce2a1d2149ccb63ffd871d5ce29ebc", + "https://bcr.bazel.build/modules/platforms/0.0.9/source.json": "cd74d854bf16a9e002fb2ca7b1a421f4403cda29f824a765acd3a8c56f8d43e6", + "https://bcr.bazel.build/modules/protobuf/21.7/MODULE.bazel": "a5a29bb89544f9b97edce05642fac225a808b5b7be74038ea3640fae2f8e66a7", + "https://bcr.bazel.build/modules/protobuf/21.7/source.json": "bbe500720421e582ff2d18b0802464205138c06056f443184de39fbb8187b09b", + "https://bcr.bazel.build/modules/protobuf/3.19.0/MODULE.bazel": "6b5fbb433f760a99a22b18b6850ed5784ef0e9928a72668b66e4d7ccd47db9b0", + "https://bcr.bazel.build/modules/protobuf/3.19.6/MODULE.bazel": "9233edc5e1f2ee276a60de3eaa47ac4132302ef9643238f23128fea53ea12858", + "https://bcr.bazel.build/modules/rules_cc/0.0.1/MODULE.bazel": "cb2aa0747f84c6c3a78dad4e2049c154f08ab9d166b1273835a8174940365647", + "https://bcr.bazel.build/modules/rules_cc/0.0.2/MODULE.bazel": "6915987c90970493ab97393024c156ea8fb9f3bea953b2f3ec05c34f19b5695c", + "https://bcr.bazel.build/modules/rules_cc/0.0.6/MODULE.bazel": "abf360251023dfe3efcef65ab9d56beefa8394d4176dd29529750e1c57eaa33f", + "https://bcr.bazel.build/modules/rules_cc/0.0.8/MODULE.bazel": "964c85c82cfeb6f3855e6a07054fdb159aced38e99a5eecf7bce9d53990afa3e", + "https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel": "836e76439f354b89afe6a911a7adf59a6b2518fafb174483ad78a2a2fde7b1c5", + "https://bcr.bazel.build/modules/rules_cc/0.0.9/source.json": "1f1ba6fea244b616de4a554a0f4983c91a9301640c8fe0dd1d410254115c8430", + "https://bcr.bazel.build/modules/rules_java/4.0.0/MODULE.bazel": "5a78a7ae82cd1a33cef56dc578c7d2a46ed0dca12643ee45edbb8417899e6f74", + "https://bcr.bazel.build/modules/rules_java/7.6.1/MODULE.bazel": "2f14b7e8a1aa2f67ae92bc69d1ec0fa8d9f827c4e17ff5e5f02e91caa3b2d0fe", + "https://bcr.bazel.build/modules/rules_java/7.6.1/source.json": "8f3f3076554e1558e8e468b2232991c510ecbcbed9e6f8c06ac31c93bcf38362", + "https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/MODULE.bazel": "a56b85e418c83eb1839819f0b515c431010160383306d13ec21959ac412d2fe7", + "https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/source.json": "a075731e1b46bc8425098512d038d416e966ab19684a10a34f4741295642fc35", + "https://bcr.bazel.build/modules/rules_license/0.0.3/MODULE.bazel": "627e9ab0247f7d1e05736b59dbb1b6871373de5ad31c3011880b4133cafd4bd0", + "https://bcr.bazel.build/modules/rules_license/0.0.7/MODULE.bazel": "088fbeb0b6a419005b89cf93fe62d9517c0a2b8bb56af3244af65ecfe37e7d5d", + "https://bcr.bazel.build/modules/rules_license/0.0.7/source.json": "355cc5737a0f294e560d52b1b7a6492d4fff2caf0bef1a315df5a298fca2d34a", + "https://bcr.bazel.build/modules/rules_pkg/0.7.0/MODULE.bazel": "df99f03fc7934a4737122518bb87e667e62d780b610910f0447665a7e2be62dc", + "https://bcr.bazel.build/modules/rules_pkg/0.7.0/source.json": "c2557066e0c0342223ba592510ad3d812d4963b9024831f7f66fd0584dd8c66c", + "https://bcr.bazel.build/modules/rules_proto/4.0.0/MODULE.bazel": "a7a7b6ce9bee418c1a760b3d84f83a299ad6952f9903c67f19e4edd964894e06", + "https://bcr.bazel.build/modules/rules_proto/5.3.0-21.7/MODULE.bazel": "e8dff86b0971688790ae75528fe1813f71809b5afd57facb44dad9e8eca631b7", + "https://bcr.bazel.build/modules/rules_proto/5.3.0-21.7/source.json": "d57902c052424dfda0e71646cb12668d39c4620ee0544294d9d941e7d12bc3a9", + "https://bcr.bazel.build/modules/rules_python/0.10.2/MODULE.bazel": "cc82bc96f2997baa545ab3ce73f196d040ffb8756fd2d66125a530031cd90e5f", + "https://bcr.bazel.build/modules/rules_python/0.22.1/MODULE.bazel": "26114f0c0b5e93018c0c066d6673f1a2c3737c7e90af95eff30cfee38d0bbac7", + "https://bcr.bazel.build/modules/rules_python/0.22.1/source.json": "57226905e783bae7c37c2dd662be078728e48fa28ee4324a7eabcafb5a43d014", + "https://bcr.bazel.build/modules/rules_python/0.4.0/MODULE.bazel": "9208ee05fd48bf09ac60ed269791cf17fb343db56c8226a720fbb1cdf467166c", + "https://bcr.bazel.build/modules/stardoc/0.5.1/MODULE.bazel": "1a05d92974d0c122f5ccf09291442580317cdd859f07a8655f1db9a60374f9f8", + "https://bcr.bazel.build/modules/stardoc/0.5.1/source.json": "a96f95e02123320aa015b956f29c00cb818fa891ef823d55148e1a362caacf29", + "https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/MODULE.bazel": "7298990c00040a0e2f121f6c32544bab27d4452f80d9ce51349b1a28f3005c43", + "https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/source.json": "f1ef7d3f9e0e26d4b23d1c39b5f5de71f584dd7d1b4ef83d9bbba6ec7a6a6459", + "https://bcr.bazel.build/modules/zlib/1.2.11/MODULE.bazel": "07b389abc85fdbca459b69e2ec656ae5622873af3f845e1c9d80fe179f3effa0", + "https://bcr.bazel.build/modules/zlib/1.2.12/MODULE.bazel": "3b1a8834ada2a883674be8cbd36ede1b6ec481477ada359cd2d3ddc562340b27", + "https://bcr.bazel.build/modules/zlib/1.3/MODULE.bazel": "6a9c02f19a24dcedb05572b2381446e27c272cd383aed11d41d99da9e3167a72", + "https://bcr.bazel.build/modules/zlib/1.3/source.json": "b6b43d0737af846022636e6e255fd4a96fee0d34f08f3830e6e0bac51465c37c" }, + "selectedYankedVersions": {}, "moduleExtensions": { - "@@apple_support~1.5.0//crosstool:setup.bzl%apple_cc_configure_extension": { + "@@apple_support~//crosstool:setup.bzl%apple_cc_configure_extension": { "general": { - "bzlTransitiveDigest": "pMLFCYaRPkgXPQ8vtuNkMfiHfPmRBy6QJfnid4sWfv0=", - "accumulatedFileDigests": {}, + "bzlTransitiveDigest": "PjIds3feoYE8SGbbIq2SFTZy3zmxeO2tQevJZNDo7iY=", + "usagesDigest": "aLmqbvowmHkkBPve05yyDNGN7oh7QE9kBADr3QIZTZs=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, "envVariables": {}, "generatedRepoSpecs": { "local_config_apple_cc": { - "bzlFile": "@@apple_support~1.5.0//crosstool:setup.bzl", + "bzlFile": "@@apple_support~//crosstool:setup.bzl", "ruleClassName": "_apple_cc_autoconf", - "attributes": { - "name": "apple_support~1.5.0~apple_cc_configure_extension~local_config_apple_cc" - } + "attributes": {} }, "local_config_apple_cc_toolchains": { - "bzlFile": "@@apple_support~1.5.0//crosstool:setup.bzl", + "bzlFile": "@@apple_support~//crosstool:setup.bzl", "ruleClassName": "_apple_cc_autoconf_toolchains", - "attributes": { - "name": "apple_support~1.5.0~apple_cc_configure_extension~local_config_apple_cc_toolchains" - } - } - } - } - }, - "@@bazel_tools//tools/cpp:cc_configure.bzl%cc_configure_extension": { - "general": { - "bzlTransitiveDigest": "O9sf6ilKWU9Veed02jG9o2HM/xgV/UAyciuFBuxrFRY=", - "accumulatedFileDigests": {}, - "envVariables": {}, - "generatedRepoSpecs": { - "local_config_cc": { - "bzlFile": "@@bazel_tools//tools/cpp:cc_configure.bzl", - "ruleClassName": "cc_autoconf", - "attributes": { - "name": "bazel_tools~cc_configure_extension~local_config_cc" - } - }, - "local_config_cc_toolchains": { - "bzlFile": "@@bazel_tools//tools/cpp:cc_configure.bzl", - "ruleClassName": "cc_autoconf_toolchains", - "attributes": { - "name": "bazel_tools~cc_configure_extension~local_config_cc_toolchains" - } - } - } - } - }, - "@@bazel_tools//tools/osx:xcode_configure.bzl%xcode_configure_extension": { - "general": { - "bzlTransitiveDigest": "Qh2bWTU6QW6wkrd87qrU4YeY+SG37Nvw3A0PR4Y0L2Y=", - "accumulatedFileDigests": {}, - "envVariables": {}, - "generatedRepoSpecs": { - "local_config_xcode": { - "bzlFile": "@@bazel_tools//tools/osx:xcode_configure.bzl", - "ruleClassName": "xcode_autoconf", - "attributes": { - "name": "bazel_tools~xcode_configure_extension~local_config_xcode", - "xcode_locator": "@bazel_tools//tools/osx:xcode_locator.m", - "remote_xcode": "" - } - } - } - } - }, - "@@bazel_tools//tools/sh:sh_configure.bzl%sh_configure_extension": { - "general": { - "bzlTransitiveDigest": "hp4NgmNjEg5+xgvzfh6L83bt9/aiiWETuNpwNuF1MSU=", - "accumulatedFileDigests": {}, - "envVariables": {}, - "generatedRepoSpecs": { - "local_config_sh": { - "bzlFile": "@@bazel_tools//tools/sh:sh_configure.bzl", - "ruleClassName": "sh_config", - "attributes": { - "name": "bazel_tools~sh_configure_extension~local_config_sh" - } + "attributes": {} } - } + }, + "recordedRepoMappingEntries": [ + [ + "apple_support~", + "bazel_tools", + "bazel_tools" + ] + ] } }, - "@@rules_java~7.1.0//java:extensions.bzl%toolchains": { + "@@platforms//host:extension.bzl%host_platform": { "general": { - "bzlTransitiveDigest": "iUIRqCK7tkhvcDJCAfPPqSd06IHG0a8HQD0xeQyVAqw=", - "accumulatedFileDigests": {}, + "bzlTransitiveDigest": "xelQcPZH8+tmuOHVjL9vDxMnnQNMlwj0SlvgoqBkm4U=", + "usagesDigest": "meSzxn3DUCcYEhq4HQwExWkWtU4EjriRBQLsZN+Q0SU=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, "envVariables": {}, "generatedRepoSpecs": { - "remotejdk21_linux_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk21_linux_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_21\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"21\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk21_linux//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk21_linux//:jdk\",\n)\n" - } - }, - "remotejdk17_linux_s390x_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_s390x_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:s390x\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_s390x//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:s390x\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_s390x//:jdk\",\n)\n" - } - }, - "remotejdk17_macos_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_macos_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_macos//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_macos//:jdk\",\n)\n" - } - }, - "remotejdk21_macos_aarch64_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk21_macos_aarch64_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_21\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"21\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk21_macos_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk21_macos_aarch64//:jdk\",\n)\n" - } - }, - "remotejdk17_linux_aarch64_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_aarch64_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_aarch64//:jdk\",\n)\n" - } - }, - "remotejdk21_macos_aarch64": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk21_macos_aarch64", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 21,\n)\n", - "sha256": "2a7a99a3ea263dbd8d32a67d1e6e363ba8b25c645c826f5e167a02bbafaff1fa", - "strip_prefix": "zulu21.28.85-ca-jdk21.0.0-macosx_aarch64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-macosx_aarch64.tar.gz", - "https://cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-macosx_aarch64.tar.gz" - ] - } - }, - "remotejdk17_linux_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux//:jdk\",\n)\n" - } - }, - "remotejdk17_macos_aarch64": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_macos_aarch64", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", - "sha256": "314b04568ec0ae9b36ba03c9cbd42adc9e1265f74678923b19297d66eb84dcca", - "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-macosx_aarch64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-macosx_aarch64.tar.gz", - "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-macosx_aarch64.tar.gz" - ] - } - }, - "remote_java_tools_windows": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remote_java_tools_windows", - "sha256": "c5c70c214a350f12cbf52da8270fa43ba629b795f3dd328028a38f8f0d39c2a1", - "urls": [ - "https://mirror.bazel.build/bazel_java_tools/releases/java/v13.1/java_tools_windows-v13.1.zip", - "https://github.com/bazelbuild/java_tools/releases/download/java_v13.1/java_tools_windows-v13.1.zip" - ] - } - }, - "remotejdk11_win": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_win", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", - "sha256": "43408193ce2fa0862819495b5ae8541085b95660153f2adcf91a52d3a1710e83", - "strip_prefix": "zulu11.66.15-ca-jdk11.0.20-win_x64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-win_x64.zip", - "https://cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-win_x64.zip" - ] - } - }, - "remotejdk11_win_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_win_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_win//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_win//:jdk\",\n)\n" - } - }, - "remotejdk11_linux_aarch64": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_aarch64", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", - "sha256": "54174439f2b3fddd11f1048c397fe7bb45d4c9d66d452d6889b013d04d21c4de", - "strip_prefix": "zulu11.66.15-ca-jdk11.0.20-linux_aarch64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-linux_aarch64.tar.gz", - "https://cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-linux_aarch64.tar.gz" - ] - } - }, - "remotejdk17_linux": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_linux", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", - "sha256": "b9482f2304a1a68a614dfacddcf29569a72f0fac32e6c74f83dc1b9a157b8340", - "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-linux_x64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-linux_x64.tar.gz", - "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-linux_x64.tar.gz" - ] - } - }, - "remotejdk11_linux_s390x_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_s390x_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:s390x\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_s390x//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:s390x\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_s390x//:jdk\",\n)\n" - } - }, - "remotejdk11_linux_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux//:jdk\",\n)\n" - } - }, - "remotejdk11_macos": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_macos", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", - "sha256": "bcaab11cfe586fae7583c6d9d311c64384354fb2638eb9a012eca4c3f1a1d9fd", - "strip_prefix": "zulu11.66.15-ca-jdk11.0.20-macosx_x64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-macosx_x64.tar.gz", - "https://cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-macosx_x64.tar.gz" - ] - } - }, - "remotejdk11_win_arm64": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_win_arm64", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", - "sha256": "b8a28e6e767d90acf793ea6f5bed0bb595ba0ba5ebdf8b99f395266161e53ec2", - "strip_prefix": "jdk-11.0.13+8", - "urls": [ - "https://mirror.bazel.build/aka.ms/download-jdk/microsoft-jdk-11.0.13.8.1-windows-aarch64.zip" - ] - } - }, - "remotejdk17_macos": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_macos", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", - "sha256": "640453e8afe8ffe0fb4dceb4535fb50db9c283c64665eebb0ba68b19e65f4b1f", - "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-macosx_x64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-macosx_x64.tar.gz", - "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-macosx_x64.tar.gz" - ] - } - }, - "remotejdk21_macos": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk21_macos", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 21,\n)\n", - "sha256": "9639b87db586d0c89f7a9892ae47f421e442c64b97baebdff31788fbe23265bd", - "strip_prefix": "zulu21.28.85-ca-jdk21.0.0-macosx_x64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-macosx_x64.tar.gz", - "https://cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-macosx_x64.tar.gz" - ] - } - }, - "remotejdk21_macos_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk21_macos_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_21\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"21\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk21_macos//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk21_macos//:jdk\",\n)\n" - } - }, - "remotejdk17_macos_aarch64_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_macos_aarch64_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_macos_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_macos_aarch64//:jdk\",\n)\n" - } - }, - "remotejdk17_win": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_win", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", - "sha256": "192f2afca57701de6ec496234f7e45d971bf623ff66b8ee4a5c81582054e5637", - "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-win_x64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-win_x64.zip", - "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-win_x64.zip" - ] - } - }, - "remotejdk11_macos_aarch64_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_macos_aarch64_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_macos_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_macos_aarch64//:jdk\",\n)\n" - } - }, - "remotejdk11_linux_ppc64le_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_ppc64le_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:ppc\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_ppc64le//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:ppc\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_ppc64le//:jdk\",\n)\n" - } - }, - "remotejdk21_linux": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk21_linux", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 21,\n)\n", - "sha256": "0c0eadfbdc47a7ca64aeab51b9c061f71b6e4d25d2d87674512e9b6387e9e3a6", - "strip_prefix": "zulu21.28.85-ca-jdk21.0.0-linux_x64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-linux_x64.tar.gz", - "https://cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-linux_x64.tar.gz" - ] - } - }, - "remote_java_tools_linux": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remote_java_tools_linux", - "sha256": "d134da9b04c9023fb6e56a5d4bffccee73f7bc9572ddc4e747778dacccd7a5a7", - "urls": [ - "https://mirror.bazel.build/bazel_java_tools/releases/java/v13.1/java_tools_linux-v13.1.zip", - "https://github.com/bazelbuild/java_tools/releases/download/java_v13.1/java_tools_linux-v13.1.zip" - ] - } - }, - "remotejdk21_win": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk21_win", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 21,\n)\n", - "sha256": "e9959d500a0d9a7694ac243baf657761479da132f0f94720cbffd092150bd802", - "strip_prefix": "zulu21.28.85-ca-jdk21.0.0-win_x64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-win_x64.zip", - "https://cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-win_x64.zip" - ] - } - }, - "remotejdk21_linux_aarch64": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk21_linux_aarch64", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 21,\n)\n", - "sha256": "1fb64b8036c5d463d8ab59af06bf5b6b006811e6012e3b0eb6bccf57f1c55835", - "strip_prefix": "zulu21.28.85-ca-jdk21.0.0-linux_aarch64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-linux_aarch64.tar.gz", - "https://cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-linux_aarch64.tar.gz" - ] - } - }, - "remotejdk11_linux_aarch64_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_aarch64_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_aarch64//:jdk\",\n)\n" - } - }, - "remotejdk11_linux_s390x": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_s390x", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", - "sha256": "a58fc0361966af0a5d5a31a2d8a208e3c9bb0f54f345596fd80b99ea9a39788b", - "strip_prefix": "jdk-11.0.15+10", - "urls": [ - "https://mirror.bazel.build/github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.15+10/OpenJDK11U-jdk_s390x_linux_hotspot_11.0.15_10.tar.gz", - "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.15+10/OpenJDK11U-jdk_s390x_linux_hotspot_11.0.15_10.tar.gz" - ] - } - }, - "remotejdk17_linux_aarch64": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_aarch64", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", - "sha256": "6531cef61e416d5a7b691555c8cf2bdff689201b8a001ff45ab6740062b44313", - "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-linux_aarch64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-linux_aarch64.tar.gz", - "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-linux_aarch64.tar.gz" - ] - } - }, - "remotejdk17_win_arm64_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_win_arm64_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:arm64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_win_arm64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:arm64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_win_arm64//:jdk\",\n)\n" - } - }, - "remotejdk11_linux": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_linux", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", - "sha256": "a34b404f87a08a61148b38e1416d837189e1df7a040d949e743633daf4695a3c", - "strip_prefix": "zulu11.66.15-ca-jdk11.0.20-linux_x64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-linux_x64.tar.gz", - "https://cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-linux_x64.tar.gz" - ] - } - }, - "remotejdk11_macos_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_macos_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_macos//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_macos//:jdk\",\n)\n" - } - }, - "remotejdk17_linux_ppc64le_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_ppc64le_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:ppc\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_ppc64le//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:ppc\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_ppc64le//:jdk\",\n)\n" - } - }, - "remotejdk17_win_arm64": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_win_arm64", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", - "sha256": "6802c99eae0d788e21f52d03cab2e2b3bf42bc334ca03cbf19f71eb70ee19f85", - "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-win_aarch64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-win_aarch64.zip", - "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-win_aarch64.zip" - ] - } - }, - "remote_java_tools_darwin_arm64": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remote_java_tools_darwin_arm64", - "sha256": "dab5bb87ec43e980faea6e1cec14bafb217b8e2f5346f53aa784fd715929a930", - "urls": [ - "https://mirror.bazel.build/bazel_java_tools/releases/java/v13.1/java_tools_darwin_arm64-v13.1.zip", - "https://github.com/bazelbuild/java_tools/releases/download/java_v13.1/java_tools_darwin_arm64-v13.1.zip" - ] - } - }, - "remotejdk17_linux_ppc64le": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_ppc64le", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", - "sha256": "00a4c07603d0218cd678461b5b3b7e25b3253102da4022d31fc35907f21a2efd", - "strip_prefix": "jdk-17.0.8.1+1", - "urls": [ - "https://mirror.bazel.build/github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.8.1%2B1/OpenJDK17U-jdk_ppc64le_linux_hotspot_17.0.8.1_1.tar.gz", - "https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.8.1%2B1/OpenJDK17U-jdk_ppc64le_linux_hotspot_17.0.8.1_1.tar.gz" - ] - } - }, - "remotejdk21_linux_aarch64_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk21_linux_aarch64_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_21\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"21\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk21_linux_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk21_linux_aarch64//:jdk\",\n)\n" - } - }, - "remotejdk11_win_arm64_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_win_arm64_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:arm64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_win_arm64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:arm64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_win_arm64//:jdk\",\n)\n" - } - }, - "local_jdk": { - "bzlFile": "@@rules_java~7.1.0//toolchains:local_java_repository.bzl", - "ruleClassName": "_local_java_repository_rule", - "attributes": { - "name": "rules_java~7.1.0~toolchains~local_jdk", - "java_home": "", - "version": "", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = {RUNTIME_VERSION},\n)\n" - } - }, - "remote_java_tools_darwin_x86_64": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remote_java_tools_darwin_x86_64", - "sha256": "0db40d8505a2b65ef0ed46e4256757807db8162f7acff16225be57c1d5726dbc", - "urls": [ - "https://mirror.bazel.build/bazel_java_tools/releases/java/v13.1/java_tools_darwin_x86_64-v13.1.zip", - "https://github.com/bazelbuild/java_tools/releases/download/java_v13.1/java_tools_darwin_x86_64-v13.1.zip" - ] - } - }, - "remote_java_tools": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remote_java_tools", - "sha256": "286bdbbd66e616fc4ed3f90101418729a73baa7e8c23a98ffbef558f74c0ad14", - "urls": [ - "https://mirror.bazel.build/bazel_java_tools/releases/java/v13.1/java_tools-v13.1.zip", - "https://github.com/bazelbuild/java_tools/releases/download/java_v13.1/java_tools-v13.1.zip" - ] - } - }, - "remotejdk17_linux_s390x": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_s390x", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", - "sha256": "ffacba69c6843d7ca70d572489d6cc7ab7ae52c60f0852cedf4cf0d248b6fc37", - "strip_prefix": "jdk-17.0.8.1+1", - "urls": [ - "https://mirror.bazel.build/github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.8.1%2B1/OpenJDK17U-jdk_s390x_linux_hotspot_17.0.8.1_1.tar.gz", - "https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.8.1%2B1/OpenJDK17U-jdk_s390x_linux_hotspot_17.0.8.1_1.tar.gz" - ] - } - }, - "remotejdk17_win_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk17_win_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_win//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_win//:jdk\",\n)\n" - } - }, - "remotejdk11_linux_ppc64le": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_ppc64le", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", - "sha256": "a8fba686f6eb8ae1d1a9566821dbd5a85a1108b96ad857fdbac5c1e4649fc56f", - "strip_prefix": "jdk-11.0.15+10", - "urls": [ - "https://mirror.bazel.build/github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.15+10/OpenJDK11U-jdk_ppc64le_linux_hotspot_11.0.15_10.tar.gz", - "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.15+10/OpenJDK11U-jdk_ppc64le_linux_hotspot_11.0.15_10.tar.gz" - ] - } - }, - "remotejdk11_macos_aarch64": { - "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", - "ruleClassName": "http_archive", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk11_macos_aarch64", - "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", - "sha256": "7632bc29f8a4b7d492b93f3bc75a7b61630894db85d136456035ab2a24d38885", - "strip_prefix": "zulu11.66.15-ca-jdk11.0.20-macosx_aarch64", - "urls": [ - "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-macosx_aarch64.tar.gz", - "https://cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-macosx_aarch64.tar.gz" - ] - } - }, - "remotejdk21_win_toolchain_config_repo": { - "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", - "ruleClassName": "_toolchain_config", - "attributes": { - "name": "rules_java~7.1.0~toolchains~remotejdk21_win_toolchain_config_repo", - "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_21\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"21\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk21_win//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk21_win//:jdk\",\n)\n" - } + "host_platform": { + "bzlFile": "@@platforms//host:extension.bzl", + "ruleClassName": "host_platform_repo", + "attributes": {} } - } + }, + "recordedRepoMappingEntries": [] } } } diff --git a/third_party/jpeg-xl/README.md b/third_party/jpeg-xl/README.md index bcea13ff23b31..877eabac8f94d 100644 --- a/third_party/jpeg-xl/README.md +++ b/third_party/jpeg-xl/README.md @@ -73,11 +73,14 @@ To decode a JPEG XL file run: djxl input.jxl output.png ``` -When possible `cjxl`/`djxl` are able to read/write the following -image formats: .exr, .gif, .jpeg/.jpg, .pfm, .pgm/.ppm, .pgx, .png. +When possible, `cjxl`/`djxl` are able to read/write the following image formats: +OpenEXR (`.exr`), GIF (`.gif`), JPEG (`.jpg`/`.jpeg`), NetPBM (`.pam`/`.pgm`/`.ppm`), +Portable FloatMap (`.pfm`), PGX Test Format (`.pgx`), Portable Network Graphics (`.png`), +Animated PNG (`.png`/`.apng`), and JPEG XL itself (`.jxl`). + Specifically for JPEG files, the default `cjxl` behavior is to apply lossless recompression and the default `djxl` behavior is to reconstruct the original -JPEG file (when the extension of the output file is .jpg). +JPEG file (when the extension of the output file is `.jpg`). ### Benchmarking @@ -127,6 +130,7 @@ format: Cloudinary and Google. * [Test coverage on Codecov.io](https://app.codecov.io/gh/libjxl/libjxl) - for developers * [libjxl documentation on readthedocs.io](https://libjxl.readthedocs.io/) +* The development of jpegli, the improved JPEG encoder and decoder, will continue at https://github.com/google/jpegli ### Contact diff --git a/third_party/jpeg-xl/WORKSPACE b/third_party/jpeg-xl/WORKSPACE index 2d8c24b5bda35..d8cd9a7495762 100644 --- a/third_party/jpeg-xl/WORKSPACE +++ b/third_party/jpeg-xl/WORKSPACE @@ -1,8 +1,13 @@ -load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository", "new_git_repository") -load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +# Copyright (c) the JPEG XL Project Authors. All rights reserved. +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. workspace(name = "libjxl") +load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository", "new_git_repository") +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + local_repository( name = "highway", path = "third_party/highway", @@ -30,185 +35,3 @@ cc_library( """, path = "third_party/skcms", ) - -new_git_repository( - name = "libjpeg_turbo", - build_file_content = """ -load("@bazel_skylib//rules:expand_template.bzl", "expand_template") -SUBSTITUTIONS = { - "@BUILD@" : "20230208", - "@CMAKE_PROJECT_NAME@" : "libjpeg-turbo", - "@COPYRIGHT_YEAR@" : "2023", - "@INLINE@" : "__inline__", - "@JPEG_LIB_VERSION@" : "62", - "@LIBJPEG_TURBO_VERSION_NUMBER@" : "2001091", - "@SIZE_T@" : "8", - "@THREAD_LOCAL@" : "__thread", - "@VERSION@" : "2.1.91", -} -YES_DEFINES = [ - "C_ARITH_CODING_SUPPORTED", "D_ARITH_CODING_SUPPORTED", - "HAVE_BUILTIN_CTZL", "MEM_SRCDST_SUPPORTED" -] -NO_DEFINES = [ - "WITH_SIMD", "RIGHT_SHIFT_IS_UNSIGNED", "HAVE_INTRIN_H" -] -SUBSTITUTIONS.update({ - "#cmakedefine " + key : "#define " + key for key in YES_DEFINES -}) -SUBSTITUTIONS.update({ - "#cmakedefine " + key : "// #define " + key for key in NO_DEFINES -}) -[ - expand_template( - name = "expand_" + src, - template = src + ".in", - out = src, - substitutions = SUBSTITUTIONS, - visibility = ["//visibility:public"], - ) for src in ["jconfig.h", "jconfigint.h", "jversion.h"] -] -JPEG16_SOURCES = [ - "jccolor.c", - "jcdiffct.c", - "jclossls.c", - "jcmainct.c", - "jcprepct.c", - "jcsample.c", - "jdcolor.c", - "jddiffct.c", - "jdlossls.c", - "jdmainct.c", - "jdmerge.c", - "jdpostct.c", - "jdsample.c", - "jquant1.c", - "jquant2.c", - "jutils.c", -] -JPEG12_SOURCES = JPEG16_SOURCES + [ - "jccoefct.c", - "jcdctmgr.c", - "jdcoefct.c", - "jddctmgr.c", - "jfdctfst.c", - "jfdctint.c", - "jidctflt.c", - "jidctfst.c", - "jidctint.c", - "jidctred.c", -] -JPEG_SOURCES = JPEG12_SOURCES + [ - "jaricom.c", - "jcapimin.c", - "jcapistd.c", - "jcarith.c", - "jchuff.c", - "jcicc.c", - "jcinit.c", - "jclhuff.c", - "jcmarker.c", - "jcmaster.c", - "jcomapi.c", - "jcparam.c", - "jcphuff.c", - "jdapimin.c", - "jdapistd.c", - "jdarith.c", - "jdatadst.c", - "jdatasrc.c", - "jdhuff.c", - "jdicc.c", - "jdinput.c", - "jdlhuff.c", - "jdmarker.c", - "jdmaster.c", - "jdphuff.c", - "jdtrans.c", - "jerror.c", - "jfdctflt.c", - "jmemmgr.c", - "jmemnobs.c", -] -JPEG_HEADERS = [ - "jccolext.c", - "jchuff.h", - "jcmaster.h", - "jconfig.h", - "jconfigint.h", - "jdcoefct.h", - "jdcol565.c", - "jdcolext.c", - "jdct.h", - "jdhuff.h", - "jdmainct.h", - "jdmaster.h", - "jdmerge.h", - "jdmrg565.c", - "jdmrgext.c", - "jdsample.h", - "jerror.h", - "jinclude.h", - "jlossls.h", - "jmemsys.h", - "jmorecfg.h", - "jpeg_nbits_table.h", - "jpegapicomp.h", - "jpegint.h", - "jpeglib.h", - "jsamplecomp.h", - "jsimd.h", - "jsimddct.h", - "jstdhuff.c", - "jversion.h", -] -cc_library( - name = "jpeg16", - srcs = JPEG16_SOURCES, - hdrs = JPEG_HEADERS, - local_defines = ["BITS_IN_JSAMPLE=16"], - visibility = ["//visibility:public"], -) -cc_library( - name = "jpeg12", - srcs = JPEG12_SOURCES, - hdrs = JPEG_HEADERS, - local_defines = ["BITS_IN_JSAMPLE=12"], - visibility = ["//visibility:public"], -) -cc_library( - name = "jpeg", - srcs = JPEG_SOURCES, - hdrs = JPEG_HEADERS, - deps = [":jpeg16", ":jpeg12"], - includes = ["."], - visibility = ["//visibility:public"], -) -exports_files([ - "jmorecfg.h", - "jpeglib.h", -]) - """, - remote = "https://github.com/libjpeg-turbo/libjpeg-turbo.git", - tag = "2.1.91", -) - -http_archive( - name = "gif", - build_file_content = """ -cc_library( - name = "gif", - srcs = [ - "dgif_lib.c", "egif_lib.c", "gifalloc.c", "gif_err.c", "gif_font.c", - "gif_hash.c", "openbsd-reallocarray.c", "gif_hash.h", - "gif_lib_private.h" - ], - hdrs = ["gif_lib.h"], - includes = ["."], - visibility = ["//visibility:public"], -) - """, - sha256 = "31da5562f44c5f15d63340a09a4fd62b48c45620cd302f77a6d9acf0077879bd", - strip_prefix = "giflib-5.2.1", - url = "https://netcologne.dl.sourceforge.net/project/giflib/giflib-5.2.1.tar.gz", -) diff --git a/third_party/jpeg-xl/bash_test.sh b/third_party/jpeg-xl/bash_test.sh index 9bd28f413b9b9..9472c85970bf6 100755 --- a/third_party/jpeg-xl/bash_test.sh +++ b/third_party/jpeg-xl/bash_test.sh @@ -7,7 +7,8 @@ # Tests implemented in bash. These typically will run checks about the source # code rather than the compiled one. -MYDIR=$(dirname $(realpath "$0")) +SELF=$(realpath "$0") +MYDIR=$(dirname "${SELF}") set -u @@ -106,12 +107,6 @@ test_printf_size_t() { ret=1 fi - if grep -n -E 'gmock\.h' \ - $(git ls-files | grep -E '(\.c|\.cc|\.cpp|\.h)$' | grep -v -F /testing.h); then - echo "Don't include gmock directly, instead include 'testing.h'. " >&2 - ret=1 - fi - local f for f in $(git ls-files | grep -E "\.cc$" | xargs grep 'PRI[udx]S' | cut -f 1 -d : | uniq); do diff --git a/third_party/jpeg-xl/ci.sh b/third_party/jpeg-xl/ci.sh index f33efd9693ff3..a2ad829cb7371 100755 --- a/third_party/jpeg-xl/ci.sh +++ b/third_party/jpeg-xl/ci.sh @@ -12,10 +12,13 @@ set -eu OS=`uname -s` -MYDIR=$(dirname $(realpath "$0")) +SELF=$(realpath "$0") +MYDIR=$(dirname "${SELF}") ### Environment parameters: TEST_STACK_LIMIT="${TEST_STACK_LIMIT:-256}" +BENCHMARK_NUM_THREADS="${BENCHMARK_NUM_THREADS:-0}" +BUILD_CONFIG=${BUILD_CONFIG:-} CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE:-RelWithDebInfo} CMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH:-} CMAKE_C_COMPILER_LAUNCHER=${CMAKE_C_COMPILER_LAUNCHER:-} @@ -79,6 +82,12 @@ if [[ "${ENABLE_WASM_SIMD}" -eq "2" ]]; then CMAKE_C_FLAGS="${CMAKE_C_FLAGS} -DHWY_WANT_WASM2" fi +if [[ -z "${BUILD_CONFIG}" ]]; then + TOOLS_DIR="${BUILD_DIR}/tools" +else + TOOLS_DIR="${BUILD_DIR}/tools/${BUILD_CONFIG}" +fi + if [[ ! -z "${HWY_BASELINE_TARGETS}" ]]; then CMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS} -DHWY_BASELINE_TARGETS=${HWY_BASELINE_TARGETS}" fi @@ -128,17 +137,34 @@ if [[ "${BUILD_TARGET%%-*}" != "arm" ]]; then ) fi -CLANG_TIDY_BIN=$(which clang-tidy-6.0 clang-tidy-7 clang-tidy-8 clang-tidy | head -n 1) +CLANG_TIDY_BIN_CANDIDATES=( + clang-tidy + clang-tidy-6.0 + clang-tidy-7 + clang-tidy-8 + clang-tidy-9 + clang-tidy-10 + clang-tidy-11 + clang-tidy-12 + clang-tidy-13 + clang-tidy-14 + clang-tidy-15 + clang-tidy-16 + clang-tidy-17 + clang-tidy-18 +) + +CLANG_TIDY_BIN=${CLANG_TIDY_BIN:-$(which ${CLANG_TIDY_BIN_CANDIDATES[@]} 2>/dev/null | tail -n 1)} # Default to "cat" if "colordiff" is not installed or if stdout is not a tty. if [[ -t 1 ]]; then - COLORDIFF_BIN=$(which colordiff cat | head -n 1) + COLORDIFF_BIN=$(which colordiff cat 2>/dev/null | head -n 1) else COLORDIFF_BIN="cat" fi -FIND_BIN=$(which gfind find | head -n 1) +FIND_BIN=$(which gfind find 2>/dev/null | head -n 1) # "false" will disable wine64 when not installed. This won't allow # cross-compiling. -WINE_BIN=$(which wine64 false | head -n 1) +WINE_BIN=$(which wine64 false 2>/dev/null | head -n 1) CLANG_VERSION="${CLANG_VERSION:-}" # Detect the clang version suffix and store it in CLANG_VERSION. For example, @@ -411,7 +437,7 @@ cmake_build_and_test() { if [[ "${PACK_TEST:-}" == "1" ]]; then (cd "${BUILD_DIR}" ${FIND_BIN} -name '*.cmake' -a '!' -path '*CMakeFiles*' - # gtest / gmock / gtest_main shared libs + # gtest / gtest_main shared libs ${FIND_BIN} lib/ -name 'libg*.so*' ${FIND_BIN} -type d -name tests -a '!' -path '*CMakeFiles*' ) | tar -C "${BUILD_DIR}" -cf "${BUILD_DIR}/tests.tar.xz" -T - \ @@ -459,7 +485,7 @@ strip_dead_code() { ### Externally visible commands cmd_debug() { - CMAKE_BUILD_TYPE="Debug" + CMAKE_BUILD_TYPE="DebugOpt" cmake_configure "$@" cmake_build_and_test } @@ -473,7 +499,7 @@ cmd_release() { cmd_opt() { CMAKE_BUILD_TYPE="RelWithDebInfo" - CMAKE_CXX_FLAGS+=" -DJXL_DEBUG_WARNING -DJXL_DEBUG_ON_ERROR" + CMAKE_CXX_FLAGS+=" -DJXL_IS_DEBUG_BUILD" cmake_configure "$@" cmake_build_and_test } @@ -553,6 +579,7 @@ cmd_msanfuzz() { # Install msan if needed before changing the flags. detect_clang_version local msan_prefix="${HOME}/.msan/${CLANG_VERSION}" + # TODO(eustas): why libc++abi.a is bad? if [[ ! -d "${msan_prefix}" || -e "${msan_prefix}/lib/libc++abi.a" ]]; then # Install msan libraries for this version if needed or if an older version # with libc++abi was installed. @@ -566,9 +593,9 @@ cmd_msanfuzz() { cmd_asan() { SANITIZER="asan" - CMAKE_C_FLAGS+=" -DJXL_ENABLE_ASSERT=1 -g -DADDRESS_SANITIZER \ + CMAKE_C_FLAGS+=" -g -DADDRESS_SANITIZER \ -fsanitize=address ${UBSAN_FLAGS[@]}" - CMAKE_CXX_FLAGS+=" -DJXL_ENABLE_ASSERT=1 -g -DADDRESS_SANITIZER \ + CMAKE_CXX_FLAGS+=" -g -DADDRESS_SANITIZER \ -fsanitize=address ${UBSAN_FLAGS[@]}" strip_dead_code cmake_configure "$@" -DJPEGXL_ENABLE_TCMALLOC=OFF @@ -578,16 +605,13 @@ cmd_asan() { cmd_tsan() { SANITIZER="tsan" local tsan_args=( - -DJXL_ENABLE_ASSERT=1 -g -DTHREAD_SANITIZER - ${UBSAN_FLAGS[@]} -fsanitize=thread ) CMAKE_C_FLAGS+=" ${tsan_args[@]}" CMAKE_CXX_FLAGS+=" ${tsan_args[@]}" - CMAKE_BUILD_TYPE="RelWithDebInfo" cmake_configure "$@" -DJPEGXL_ENABLE_TCMALLOC=OFF cmake_build_and_test } @@ -606,7 +630,6 @@ cmd_msan() { -fsanitize=memory -fno-omit-frame-pointer - -DJXL_ENABLE_ASSERT=1 -g -DMEMORY_SANITIZER @@ -639,16 +662,22 @@ cmd_msan() { -Wl,-rpath -Wl,"${msan_prefix}"/lib/ ) - CMAKE_C_FLAGS+=" ${msan_c_flags[@]} ${UBSAN_FLAGS[@]}" - CMAKE_CXX_FLAGS+=" ${msan_cxx_flags[@]} ${UBSAN_FLAGS[@]}" + CMAKE_C_FLAGS+=" ${msan_c_flags[@]}" + CMAKE_CXX_FLAGS+=" ${msan_cxx_flags[@]}" CMAKE_EXE_LINKER_FLAGS+=" ${msan_linker_flags[@]}" CMAKE_MODULE_LINKER_FLAGS+=" ${msan_linker_flags[@]}" CMAKE_SHARED_LINKER_FLAGS+=" ${msan_linker_flags[@]}" strip_dead_code + + # MSAN share of stack size is non-negligible. + TEST_STACK_LIMIT="none" + + # TODO(eustas): investigate why fuzzers do not link when MSAN libc++ is used cmake_configure "$@" \ -DCMAKE_CROSSCOMPILING=1 -DRUN_HAVE_STD_REGEX=0 -DRUN_HAVE_POSIX_REGEX=0 \ -DJPEGXL_ENABLE_TCMALLOC=OFF -DJPEGXL_WARNINGS_AS_ERRORS=OFF \ - -DCMAKE_REQUIRED_LINK_OPTIONS="${msan_linker_flags[@]}" + -DCMAKE_REQUIRED_LINK_OPTIONS="${msan_linker_flags[@]}" \ + -DJPEGXL_ENABLE_FUZZERS=OFF cmake_build_and_test } @@ -657,6 +686,8 @@ cmd_msan() { cmd_msan_install() { local tmpdir=$(mktemp -d) CLEANUP_FILES+=("${tmpdir}") + local msan_root="${HOME}/.msan" + mkdir -p "${msan_root}" # Detect the llvm to install: export CC="${CC:-clang}" export CXX="${CXX:-clang++}" @@ -664,23 +695,36 @@ cmd_msan_install() { # Allow overriding the LLVM checkout. local llvm_root="${LLVM_ROOT:-}" if [ -z "${llvm_root}" ]; then - local llvm_tag="llvmorg-${CLANG_VERSION}.0.0" - case "${CLANG_VERSION}" in - "6.0") - llvm_tag="llvmorg-6.0.1" - ;; - "7") - llvm_tag="llvmorg-7.0.1" - ;; - esac - local llvm_targz="${tmpdir}/${llvm_tag}.tar.gz" - curl -L --show-error -o "${llvm_targz}" \ - "https://github.com/llvm/llvm-project/archive/${llvm_tag}.tar.gz" + declare -A llvm_tag_by_version=( + ["6.0"]="6.0.1" + ["7"]="7.1.0" + ["8"]="8.0.1" + ["9"]="9.0.2" + ["10"]="10.0.1" + ["11"]="11.1.0" + ["12"]="12.0.1" + ["13"]="13.0.1" + ["14"]="14.0.6" + ["15"]="15.0.7" + ["16"]="16.0.6" + ["17"]="17.0.6" + ["18"]="18.1.6" + ) + local llvm_tag="${CLANG_VERSION}.0.0" + if [[ -n "${llvm_tag_by_version["${CLANG_VERSION}"]}" ]]; then + llvm_tag=${llvm_tag_by_version["${CLANG_VERSION}"]} + fi + llvm_tag="llvmorg-${llvm_tag}" + local llvm_targz="${msan_root}/${llvm_tag}.tar.gz" + if [ ! -f "${llvm_targz}" ]; then + curl -L --show-error -o "${llvm_targz}" \ + "https://github.com/llvm/llvm-project/archive/${llvm_tag}.tar.gz" + fi tar -C "${tmpdir}" -zxf "${llvm_targz}" llvm_root="${tmpdir}/llvm-project-${llvm_tag}" fi - local msan_prefix="${HOME}/.msan/${CLANG_VERSION}" + local msan_prefix="${msan_root}/${CLANG_VERSION}" rm -rf "${msan_prefix}" local TARGET_OPTS="" @@ -692,32 +736,29 @@ cmd_msan_install() { " fi - declare -A CMAKE_EXTRAS - CMAKE_EXTRAS[libcxx]="\ - -DLIBCXX_CXX_ABI=libstdc++ \ - -DLIBCXX_INSTALL_EXPERIMENTAL_LIBRARY=ON" - - for project in libcxx; do - local proj_build="${tmpdir}/build-${project}" - local proj_dir="${llvm_root}/${project}" - mkdir -p "${proj_build}" - cmake -B"${proj_build}" -H"${proj_dir}" \ - -G Ninja \ - -DCMAKE_BUILD_TYPE=Release \ - -DLLVM_USE_SANITIZER=Memory \ - -DLLVM_PATH="${llvm_root}/llvm" \ - -DLLVM_CONFIG_PATH="$(which llvm-config llvm-config-7 llvm-config-6.0 | \ - head -n1)" \ - -DCMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS}" \ - -DCMAKE_C_FLAGS="${CMAKE_C_FLAGS}" \ - -DCMAKE_EXE_LINKER_FLAGS="${CMAKE_EXE_LINKER_FLAGS}" \ - -DCMAKE_SHARED_LINKER_FLAGS="${CMAKE_SHARED_LINKER_FLAGS}" \ - -DCMAKE_INSTALL_PREFIX="${msan_prefix}" \ - ${TARGET_OPTS} \ - ${CMAKE_EXTRAS[${project}]} - cmake --build "${proj_build}" - ninja -C "${proj_build}" install - done + local build_dir="${tmpdir}/build-llvm" + mkdir -p "${build_dir}" + cd ${llvm_root} + cmake -B"${build_dir}" \ + -G Ninja \ + -S runtimes \ + -DCMAKE_BUILD_TYPE=Release \ + -DLLVM_USE_SANITIZER=Memory \ + -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libunwind;compiler-rt" \ + -DLIBCXXABI_ENABLE_SHARED=ON \ + -DLIBCXXABI_ENABLE_STATIC=OFF \ + -DLIBCXX_ENABLE_SHARED=ON \ + -DLIBCXX_ENABLE_STATIC=OFF \ + -DCMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS}" \ + -DCMAKE_C_FLAGS="${CMAKE_C_FLAGS}" \ + -DCMAKE_EXE_LINKER_FLAGS="${CMAKE_EXE_LINKER_FLAGS}" \ + -DCMAKE_SHARED_LINKER_FLAGS="${CMAKE_SHARED_LINKER_FLAGS}" \ + -DCMAKE_INSTALL_PREFIX="${msan_prefix}" \ + -DLLVM_PATH="${llvm_root}/llvm" \ + -DLLVM_CONFIG_PATH="$(which llvm-config-${CLANG_VERSION} llvm-config | head -n1)" \ + ${TARGET_OPTS} + cmake --build "${build_dir}" + ninja -C "${build_dir}" install } # Internal build step shared between all cmd_ossfuzz_* commands. @@ -791,9 +832,13 @@ cmd_ossfuzz_ninja() { cmd_fast_benchmark() { local small_corpus_tar="${BENCHMARK_CORPORA}/jyrki-full.tar" + local small_corpus_url="https://storage.googleapis.com/artifacts.jpegxl.appspot.com/corpora/jyrki-full.tar" mkdir -p "${BENCHMARK_CORPORA}" - curl --show-error -o "${small_corpus_tar}" -z "${small_corpus_tar}" \ - "https://storage.googleapis.com/artifacts.jpegxl.appspot.com/corpora/jyrki-full.tar" + if [ -f "${small_corpus_tar}" ]; then + curl --show-error -o "${small_corpus_tar}" -z "${small_corpus_tar}" "${small_corpus_url}" + else + curl --show-error -o "${small_corpus_tar}" "${small_corpus_url}" + fi local tmpdir=$(mktemp -d) CLEANUP_FILES+=("${tmpdir}") @@ -831,7 +876,7 @@ cmd_benchmark() { png_filename="${filename%.ppm}.png" png_filename=$(echo "${png_filename}" | tr '/' '_') sem --bg --id "${sem_id}" -j"${nprocs}" -- \ - "${BUILD_DIR}/tools/decode_and_encode" \ + "${TOOLS_DIR}/decode_and_encode" \ "${tmpdir}/${filename}" "${mode}" "${tmpdir}/${png_filename}" images+=( "${png_filename}" ) done < <(cd "${tmpdir}"; ${FIND_BIN} . -name '*.ppm' -type f) @@ -844,6 +889,8 @@ cmd_benchmark() { get_mem_available() { if [[ "${OS}" == "Darwin" ]]; then echo $(vm_stat | grep -F 'Pages free:' | awk '{print $3 * 4}') + elif [[ "${OS}" == MINGW* ]]; then + echo $(vmstat | tail -n 1 | awk '{print $4 * 4}') else echo $(grep -F MemAvailable: /proc/meminfo | awk '{print $2}') fi @@ -856,15 +903,24 @@ run_benchmark() { local output_dir="${BUILD_DIR}/benchmark_results" mkdir -p "${output_dir}" - # The memory available at the beginning of the benchmark run in kB. The number - # of threads depends on the available memory, and the passed memory per - # thread. We also add a 2 GiB of constant memory. - local mem_available="$(get_mem_available)" - # Check that we actually have a MemAvailable value. - [[ -n "${mem_available}" ]] - local num_threads=$(( (${mem_available} - 1048576) / ${mem_per_thread} )) - if [[ ${num_threads} -le 0 ]]; then - num_threads=1 + if [[ "${OS}" == MINGW* ]]; then + src_img_dir=`cygpath -w "${src_img_dir}"` + fi + + local num_threads=1 + if [[ ${BENCHMARK_NUM_THREADS} -gt 0 ]]; then + num_threads=${BENCHMARK_NUM_THREADS} + else + # The memory available at the beginning of the benchmark run in kB. The number + # of threads depends on the available memory, and the passed memory per + # thread. We also add a 2 GiB of constant memory. + local mem_available="$(get_mem_available)" + # Check that we actually have a MemAvailable value. + [[ -n "${mem_available}" ]] + num_threads=$(( (${mem_available} - 1048576) / ${mem_per_thread} )) + if [[ ${num_threads} -le 0 ]]; then + num_threads=1 + fi fi local benchmark_args=( @@ -873,20 +929,20 @@ run_benchmark() { --output_dir "${output_dir}" --show_progress --num_threads="${num_threads}" + --decode_reps=11 + --encode_reps=11 ) if [[ "${STORE_IMAGES}" == "1" ]]; then benchmark_args+=(--save_decompressed --save_compressed) fi ( [[ "${TEST_STACK_LIMIT}" == "none" ]] || ulimit -s "${TEST_STACK_LIMIT}" - "${BUILD_DIR}/tools/benchmark_xl" "${benchmark_args[@]}" | \ + "${TOOLS_DIR}/benchmark_xl" "${benchmark_args[@]}" | \ tee "${output_dir}/results.txt" - # Check error code for benckmark_xl command. This will exit if not. + # Check error code for benchmark_xl command. This will exit if not. return ${PIPESTATUS[0]} ) - - } # Helper function to wait for the CPU temperature to cool down on ARM. @@ -1027,7 +1083,7 @@ cmd_arm_benchmark() { local src_img for src_img in "${jpg_images[@]}" "${images[@]}"; do local src_img_hash=$(sha1sum "${src_img}" | cut -f 1 -d ' ') - local enc_binaries=("${BUILD_DIR}/tools/cjxl") + local enc_binaries=("${TOOLS_DIR}/cjxl") local src_ext="${src_img##*.}" for enc_binary in "${enc_binaries[@]}"; do local enc_binary_base=$(basename "${enc_binary}") @@ -1076,7 +1132,7 @@ cmd_arm_benchmark() { local dec_output wait_for_temp - dec_output=$("${BUILD_DIR}/tools/djxl" "${enc_file}" \ + dec_output=$("${TOOLS_DIR}/djxl" "${enc_file}" \ --num_reps=5 --num_threads="${num_threads}" 2>&1 | tee /dev/stderr | grep -E "M[BP]/s \[") local img_size=$(echo "${dec_output}" | cut -f 1 -d ',') @@ -1092,7 +1148,7 @@ cmd_arm_benchmark() { if [[ "${src_ext}" == "jpg" ]]; then wait_for_temp local dec_file="${BUILD_DIR}/arm_benchmark/${enc_file_hash}.jpg" - dec_output=$("${BUILD_DIR}/tools/djxl" "${enc_file}" \ + dec_output=$("${TOOLS_DIR}/djxl" "${enc_file}" \ "${dec_file}" --num_reps=5 --num_threads="${num_threads}" 2>&1 | \ tee /dev/stderr | grep -E "M[BP]/s \[") local jpeg_dec_mps_speed=$(_speed_from_output "${dec_output}") @@ -1122,12 +1178,12 @@ cmd_fuzz() { local fuzzer_crash_dir=$(realpath "${BUILD_DIR}/fuzzer_crash") mkdir -p "${corpus_dir}" "${fuzzer_crash_dir}" # Generate step. - "${BUILD_DIR}/tools/fuzzer_corpus" "${corpus_dir}" + "${TOOLS_DIR}/fuzzer_corpus" "${corpus_dir}" # Run step: local nprocs=$(nproc --all || echo 1) ( - cd "${BUILD_DIR}" - "tools/djxl_fuzzer" "${fuzzer_crash_dir}" "${corpus_dir}" \ + cd "${TOOLS_DIR}" + djxl_fuzzer "${fuzzer_crash_dir}" "${corpus_dir}" \ -max_total_time="${FUZZER_MAX_TIME}" -jobs=${nprocs} \ -artifact_prefix="${fuzzer_crash_dir}/" ) @@ -1154,7 +1210,7 @@ cmd_lint() { # It is ok, if buildifier is not installed. if which buildifier >/dev/null; then local buildifier_patch="${tmpdir}/buildifier.patch" - local bazel_files=`git -C ${MYDIR} ls-files | grep -E "/BUILD$|WORKSPACE|.bzl$"` + local bazel_files=`git -C "${MYDIR}" ls-files | grep -E "/BUILD$|WORKSPACE|.bzl$"` set -x buildifier -d ${bazel_files} >"${buildifier_patch}"|| true { set +x; } 2>/dev/null @@ -1167,6 +1223,15 @@ cmd_lint() { fi fi + # It is ok, if spell-checker is not installed. + if which typos >/dev/null; then + local src_ext="bazel|bzl|c|cc|cmake|gni|h|html|in|java|js|m|md|nix|py|rst|sh|ts|txt|yaml|yml" + local sources=`git -C "${MYDIR}" ls-files | grep -E "\.(${src_ext})$"` + typos -c "${MYDIR}/tools/scripts/typos.toml" ${sources} + else + echo "Consider installing https://github.com/crate-ci/typos for spell-checking" + fi + local installed=() local clang_patch local clang_format diff --git a/third_party/jpeg-xl/cmake/FindHWY.cmake b/third_party/jpeg-xl/cmake/FindHWY.cmake index c5a90fbc81e81..eab306a8b7826 100644 --- a/third_party/jpeg-xl/cmake/FindHWY.cmake +++ b/third_party/jpeg-xl/cmake/FindHWY.cmake @@ -10,7 +10,7 @@ if (PkgConfig_FOUND) endif () find_path(HWY_INCLUDE_DIR - NAMES hwy/highway.h + NAMES hwy/base.h hwy/highway.h HINTS ${PC_HWY_INCLUDEDIR} ${PC_HWY_INCLUDE_DIRS} ) @@ -19,21 +19,31 @@ find_library(HWY_LIBRARY HINTS ${PC_HWY_LIBDIR} ${PC_HWY_LIBRARY_DIRS} ) +# If version not found using pkg-config, try extracting it from header files if (HWY_INCLUDE_DIR AND NOT HWY_VERSION) - if (EXISTS "${HWY_INCLUDE_DIR}/hwy/highway.h") - file(READ "${HWY_INCLUDE_DIR}/hwy/highway.h" HWY_VERSION_CONTENT) + set(HWY_VERSION "") + set(HWY_POSSIBLE_HEADERS "${HWY_INCLUDE_DIR}/hwy/base.h" "${HWY_INCLUDE_DIR}/hwy/highway.h") + foreach(HWY_HEADER_FILE IN LISTS HWY_POSSIBLE_HEADERS) + if (EXISTS "${HWY_HEADER_FILE}") + file(READ "${HWY_HEADER_FILE}" HWY_VERSION_CONTENT) - string(REGEX MATCH "#define HWY_MAJOR +([0-9]+)" _sink "${HWY_VERSION_CONTENT}") - set(HWY_VERSION_MAJOR "${CMAKE_MATCH_1}") + string(REGEX MATCH "#define HWY_MAJOR +([0-9]+)" _sink "${HWY_VERSION_CONTENT}") + set(HWY_VERSION_MAJOR "${CMAKE_MATCH_1}") - string(REGEX MATCH "#define +HWY_MINOR +([0-9]+)" _sink "${HWY_VERSION_CONTENT}") - set(HWY_VERSION_MINOR "${CMAKE_MATCH_1}") + string(REGEX MATCH "#define +HWY_MINOR +([0-9]+)" _sink "${HWY_VERSION_CONTENT}") + set(HWY_VERSION_MINOR "${CMAKE_MATCH_1}") - string(REGEX MATCH "#define +HWY_PATCH +([0-9]+)" _sink "${HWY_VERSION_CONTENT}") - set(HWY_VERSION_PATCH "${CMAKE_MATCH_1}") - - set(HWY_VERSION "${HWY_VERSION_MAJOR}.${HWY_VERSION_MINOR}.${HWY_VERSION_PATCH}") - endif () + string(REGEX MATCH "#define +HWY_PATCH +([0-9]+)" _sink "${HWY_VERSION_CONTENT}") + set(HWY_VERSION_PATCH "${CMAKE_MATCH_1}") + if (NOT HWY_VERSION_MAJOR STREQUAL "" AND NOT HWY_VERSION_MINOR STREQUAL "" AND NOT HWY_VERSION_PATCH STREQUAL "") + set(HWY_VERSION "${HWY_VERSION_MAJOR}.${HWY_VERSION_MINOR}.${HWY_VERSION_PATCH}") + break() + endif() + endif () + endforeach () + if (NOT HWY_VERSION) + message(WARNING "Highway version not found.") + endif() endif () include(FindPackageHandleStandardArgs) diff --git a/third_party/jpeg-xl/debian/changelog b/third_party/jpeg-xl/debian/changelog index b4bd9b02b3cbb..06ae73f7921e7 100644 --- a/third_party/jpeg-xl/debian/changelog +++ b/third_party/jpeg-xl/debian/changelog @@ -1,8 +1,8 @@ -jpeg-xl (0.10.3) UNRELEASED; urgency=medium +jpeg-xl (0.11.0) unstable; urgency=medium - * Bump JPEG XL version to 0.10.3. + * Bump JPEG XL version to 0.11.0. - -- JPEG XL Maintainers Thu, 27 Jun 2024 12:23:45 +0200 + -- JPEG XL Maintainers Tue, 06 Aug 2024 14:35:34 +0200 jpeg-xl (0.10.2) unstable; urgency=medium diff --git a/third_party/jpeg-xl/debian/control b/third_party/jpeg-xl/debian/control index f5dc5ce0cc058..e0169a3488474 100644 --- a/third_party/jpeg-xl/debian/control +++ b/third_party/jpeg-xl/debian/control @@ -11,7 +11,6 @@ Build-Depends: libgdk-pixbuf-2.0-dev | libgdk-pixbuf2.0-dev, libgif-dev, libgimp2.0-dev, - libgmock-dev, libgoogle-perftools-dev, libgtest-dev, libhwy-dev (>= 1.0.0), diff --git a/third_party/jpeg-xl/deps.sh b/third_party/jpeg-xl/deps.sh index 6c51a5cd4a21d..069c721de1500 100755 --- a/third_party/jpeg-xl/deps.sh +++ b/third_party/jpeg-xl/deps.sh @@ -9,13 +9,15 @@ set -eu -MYDIR=$(dirname $(realpath "$0")) +SELF=$(realpath "$0") +MYDIR=$(dirname "${SELF}") # Git revisions we use for the given submodules. Update these whenever you # update a git submodule. TESTDATA="873045a9c42ed60721756e26e2a6b32e17415205" THIRD_PARTY_BROTLI="36533a866ed1ca4b75cf049f4521e4ec5fe24727" -THIRD_PARTY_HIGHWAY="58b52a717469e62b2d9b8eaa2f5dddb44d4a4cbf" +THIRD_PARTY_GOOGLETEST="58d77fa8070e8cec2dc1ed015d66b454c8d78850" +THIRD_PARTY_HIGHWAY="457c891775a7397bdb0376bb1031e6e027af1c48" THIRD_PARTY_SKCMS="42030a771244ba67f86b1c1c76a6493f873c5f91" THIRD_PARTY_SJPEG="e5ab13008bb214deb66d5f3e17ca2f8dbff150bf" THIRD_PARTY_ZLIB="51b7f2abdade71cd9bb0e7a373ef2610ec6f9daf" # v1.3.1 @@ -82,6 +84,7 @@ EOF # Sources downloaded from a tarball. download_github testdata libjxl/testdata download_github third_party/brotli google/brotli + download_github third_party/googletest google/googletest download_github third_party/highway google/highway download_github third_party/sjpeg webmproject/sjpeg download_github third_party/skcms \ diff --git a/third_party/jpeg-xl/examples/CMakeLists.txt b/third_party/jpeg-xl/examples/CMakeLists.txt index 8cdb09217e791..6b2b99c12459b 100644 --- a/third_party/jpeg-xl/examples/CMakeLists.txt +++ b/third_party/jpeg-xl/examples/CMakeLists.txt @@ -15,6 +15,9 @@ pkg_check_modules(Jxl REQUIRED IMPORTED_TARGET libjxl libjxl_cms libjxl_threads) # Build the example encoder/decoder binaries using the default shared libraries # installed. +add_executable(decode_exif_metadata decode_exif_metadata.cc) +target_link_libraries(decode_exif_metadata PkgConfig::Jxl) + add_executable(decode_oneshot decode_oneshot.cc) target_link_libraries(decode_oneshot PkgConfig::Jxl) diff --git a/third_party/jpeg-xl/examples/decode_exif_metadata.cc b/third_party/jpeg-xl/examples/decode_exif_metadata.cc index d5f11705bd046..c1609edde326a 100644 --- a/third_party/jpeg-xl/examples/decode_exif_metadata.cc +++ b/third_party/jpeg-xl/examples/decode_exif_metadata.cc @@ -22,7 +22,8 @@ bool DecodeJpegXlExif(const uint8_t* jxl, size_t size, // We're only interested in the Exif boxes in this example, so don't // subscribe to events related to pixel data. - if (JXL_DEC_SUCCESS != JxlDecoderSubscribeEvents(dec.get(), JXL_DEC_BOX)) { + if (JXL_DEC_SUCCESS != JxlDecoderSubscribeEvents( + dec.get(), JXL_DEC_BOX | JXL_DEC_BOX_COMPLETE)) { fprintf(stderr, "JxlDecoderSubscribeEvents failed\n"); return false; } @@ -72,7 +73,7 @@ bool DecodeJpegXlExif(const uint8_t* jxl, size_t size, exif->resize(exif->size() + kChunkSize); JxlDecoderSetBoxBuffer(dec.get(), exif->data() + output_pos, exif->size() - output_pos); - } else if (status == JXL_DEC_SUCCESS) { + } else if (status == JXL_DEC_BOX_COMPLETE) { if (!exif->empty()) { size_t remaining = JxlDecoderReleaseBoxBuffer(dec.get()); exif->resize(exif->size() - remaining); @@ -97,7 +98,7 @@ bool LoadFile(const char* filename, std::vector* out) { return false; } - long size = ftell(file); + long size = ftell(file); // NOLINT // Avoid invalid file or directory. if (size >= LONG_MAX || size < 0) { fclose(file); diff --git a/third_party/jpeg-xl/examples/decode_oneshot.cc b/third_party/jpeg-xl/examples/decode_oneshot.cc index a24bd73bfbd12..b7e17c21a497a 100644 --- a/third_party/jpeg-xl/examples/decode_oneshot.cc +++ b/third_party/jpeg-xl/examples/decode_oneshot.cc @@ -169,7 +169,7 @@ bool LoadFile(const char* filename, std::vector* out) { return false; } - long size = ftell(file); + long size = ftell(file); // NOLINT // Avoid invalid file or directory. if (size >= LONG_MAX || size < 0) { fclose(file); diff --git a/third_party/jpeg-xl/examples/decode_progressive.cc b/third_party/jpeg-xl/examples/decode_progressive.cc index fa7f3df663428..7a3a9aa33b702 100644 --- a/third_party/jpeg-xl/examples/decode_progressive.cc +++ b/third_party/jpeg-xl/examples/decode_progressive.cc @@ -6,16 +6,20 @@ // This C++ example decodes a JPEG XL image progressively (input bytes are // passed in chunks). The example outputs the intermediate steps to PAM files. -#include +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif + #include #include #include #include #include -#include -#include -#include +#include // PRIu64 +#include +#include +#include #include bool WritePAM(const char* filename, const uint8_t* buffer, size_t w, size_t h) { @@ -174,7 +178,7 @@ bool LoadFile(const char* filename, std::vector* out) { return false; } - long size = ftell(file); + long size = ftell(file); // NOLINT // Avoid invalid file or directory. if (size >= LONG_MAX || size < 0) { fclose(file); @@ -220,7 +224,7 @@ int main(int argc, char* argv[]) { } size_t chunksize = jxl.size(); if (argc > 3) { - long cs = atol(argv[3]); + long cs = atol(argv[3]); // NOLINT if (cs < 100) { fprintf(stderr, "Chunk size is too low, try at least 100 bytes\n"); return 1; diff --git a/third_party/jpeg-xl/examples/encode_oneshot.cc b/third_party/jpeg-xl/examples/encode_oneshot.cc index 1582570432c44..6c45a70411e63 100644 --- a/third_party/jpeg-xl/examples/encode_oneshot.cc +++ b/third_party/jpeg-xl/examples/encode_oneshot.cc @@ -48,7 +48,7 @@ bool ReadPFM(const char* filename, std::vector* pixels, uint32_t* xsize, return false; } - long size = ftell(file); + long size = ftell(file); // NOLINT // Avoid invalid file or directory. if (size >= LONG_MAX || size < 0) { fclose(file); @@ -64,7 +64,7 @@ bool ReadPFM(const char* filename, std::vector* pixels, uint32_t* xsize, data.resize(size); size_t readsize = fread(data.data(), 1, size, file); - if (static_cast(readsize) != size) { + if (static_cast(readsize) != size) { // NOLINT fclose(file); return false; } diff --git a/third_party/jpeg-xl/examples/examples.cmake b/third_party/jpeg-xl/examples/examples.cmake index fd159578bce1a..b13731ca3c1eb 100644 --- a/third_party/jpeg-xl/examples/examples.cmake +++ b/third_party/jpeg-xl/examples/examples.cmake @@ -3,6 +3,8 @@ # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. +add_executable(decode_exif_metadata ${CMAKE_CURRENT_LIST_DIR}/decode_exif_metadata.cc) +target_link_libraries(decode_exif_metadata jxl_dec jxl_threads) add_executable(decode_oneshot ${CMAKE_CURRENT_LIST_DIR}/decode_oneshot.cc) target_link_libraries(decode_oneshot jxl_dec jxl_threads) add_executable(decode_progressive ${CMAKE_CURRENT_LIST_DIR}/decode_progressive.cc) diff --git a/third_party/jpeg-xl/flake.nix b/third_party/jpeg-xl/flake.nix index 4832f5b144ad8..64a36311ab13b 100644 --- a/third_party/jpeg-xl/flake.nix +++ b/third_party/jpeg-xl/flake.nix @@ -19,7 +19,6 @@ cmake pkg-config gtest - gmock doxygen graphviz python3 diff --git a/third_party/jpeg-xl/lib/BUILD b/third_party/jpeg-xl/lib/BUILD index 1c08b11c3635c..3d48919f7775e 100644 --- a/third_party/jpeg-xl/lib/BUILD +++ b/third_party/jpeg-xl/lib/BUILD @@ -26,8 +26,8 @@ load( "libjxl_enc_sources", "libjxl_extras_for_tools_sources", "libjxl_extras_sources", - #'libjxl_gbench_sources', - "libjxl_jpegli_lib_version", + # "libjxl_gbench_sources", + # "libjxl_jpegli_lib_version", "libjxl_jpegli_libjpeg_helper_files", "libjxl_jpegli_sources", "libjxl_jpegli_testlib_files", @@ -54,7 +54,8 @@ load( "libjxl_deps_png", "libjxl_deps_runfiles", "libjxl_deps_skcms", - "libjxl_deps_testdata", + # "libjxl_deps_testdata", + # "libjxl_deps_webp", "libjxl_root_package", "libjxl_test_shards", "libjxl_test_timeouts", @@ -67,7 +68,7 @@ DEFAULT_COMPATIBILITY = [] INCLUDES_DIR = "include" package( - default_visibility = ["//:__subpackages__"], + default_visibility = DEFAULT_VISIBILITY, ) licenses(["notice"]) diff --git a/third_party/jpeg-xl/lib/CMakeLists.txt b/third_party/jpeg-xl/lib/CMakeLists.txt index 0f5c7c81797b5..8dff542f1f01e 100644 --- a/third_party/jpeg-xl/lib/CMakeLists.txt +++ b/third_party/jpeg-xl/lib/CMakeLists.txt @@ -4,8 +4,8 @@ # license that can be found in the LICENSE file. set(JPEGXL_MAJOR_VERSION 0) -set(JPEGXL_MINOR_VERSION 10) -set(JPEGXL_PATCH_VERSION 3) +set(JPEGXL_MINOR_VERSION 11) +set(JPEGXL_PATCH_VERSION 0) set(JPEGXL_LIBRARY_VERSION "${JPEGXL_MAJOR_VERSION}.${JPEGXL_MINOR_VERSION}.${JPEGXL_PATCH_VERSION}") @@ -15,7 +15,7 @@ set(JPEGXL_LIBRARY_VERSION # It is important to update this value when making incompatible API/ABI changes # so that programs that depend on libjxl can update their dependencies. Semantic # versioning allows 0.y.z to have incompatible changes in minor versions. -set(JPEGXL_SO_MINOR_VERSION 10) +set(JPEGXL_SO_MINOR_VERSION 11) if (JPEGXL_MAJOR_VERSION EQUAL 0) set(JPEGXL_LIBRARY_SOVERSION "${JPEGXL_MAJOR_VERSION}.${JPEGXL_SO_MINOR_VERSION}") diff --git a/third_party/jpeg-xl/lib/extras/alpha_blend.cc b/third_party/jpeg-xl/lib/extras/alpha_blend.cc index eca5f5dd69d46..8e34d56cecbb9 100644 --- a/third_party/jpeg-xl/lib/extras/alpha_blend.cc +++ b/third_party/jpeg-xl/lib/extras/alpha_blend.cc @@ -6,21 +6,23 @@ #include "lib/extras/alpha_blend.h" #include "lib/extras/packed_image.h" +#include "lib/jxl/base/status.h" namespace jxl { namespace extras { namespace { -void AlphaBlend(PackedFrame* frame, const float background[3]) { - if (!frame) return; +Status AlphaBlend(PackedFrame* frame, const float background[3]) { + if (!frame) return true; const PackedImage& im = frame->color; JxlPixelFormat format = im.format; if (format.num_channels != 2 && format.num_channels != 4) { - return; + return true; } --format.num_channels; - PackedImage blended(im.xsize, im.ysize, format); + JXL_ASSIGN_OR_RETURN(PackedImage blended, + PackedImage::Create(im.xsize, im.ysize, format)); // TODO(szabadka) SIMDify this and make it work for float16. for (size_t y = 0; y < im.ysize; ++y) { for (size_t x = 0; x < im.xsize; ++x) { @@ -44,19 +46,21 @@ void AlphaBlend(PackedFrame* frame, const float background[3]) { } } frame->color = blended.Copy(); + return true; } } // namespace -void AlphaBlend(PackedPixelFile* ppf, const float background[3]) { +Status AlphaBlend(PackedPixelFile* ppf, const float background[3]) { if (!ppf || ppf->info.alpha_bits == 0) { - return; + return true; } ppf->info.alpha_bits = 0; - AlphaBlend(ppf->preview_frame.get(), background); + JXL_RETURN_IF_ERROR(AlphaBlend(ppf->preview_frame.get(), background)); for (auto& frame : ppf->frames) { - AlphaBlend(&frame, background); + JXL_RETURN_IF_ERROR(AlphaBlend(&frame, background)); } + return true; } } // namespace extras diff --git a/third_party/jpeg-xl/lib/extras/alpha_blend.h b/third_party/jpeg-xl/lib/extras/alpha_blend.h index e49349393c97c..b388a5e22aa48 100644 --- a/third_party/jpeg-xl/lib/extras/alpha_blend.h +++ b/third_party/jpeg-xl/lib/extras/alpha_blend.h @@ -7,11 +7,12 @@ #define LIB_EXTRAS_ALPHA_BLEND_H_ #include "lib/extras/packed_image.h" +#include "lib/jxl/base/status.h" namespace jxl { namespace extras { -void AlphaBlend(PackedPixelFile* ppf, const float background[3]); +Status AlphaBlend(PackedPixelFile* ppf, const float background[3]); } // namespace extras } // namespace jxl diff --git a/third_party/jpeg-xl/lib/extras/codec.cc b/third_party/jpeg-xl/lib/extras/codec.cc index 3a1172125b83e..ba4bcfebbc475 100644 --- a/third_party/jpeg-xl/lib/extras/codec.cc +++ b/third_party/jpeg-xl/lib/extras/codec.cc @@ -17,7 +17,6 @@ #include "lib/extras/packed_image.h" #include "lib/extras/packed_image_convert.h" #include "lib/jxl/base/status.h" -#include "lib/jxl/image_bundle.h" namespace jxl { namespace { @@ -95,7 +94,7 @@ Status Encode(const extras::PackedPixelFile& ppf, const extras::Codec codec, } extras::EncodedImage encoded_image; JXL_RETURN_IF_ERROR(encoder->Encode(ppf, &encoded_image, pool)); - JXL_ASSERT(encoded_image.bitstreams.size() == 1); + JXL_ENSURE(encoded_image.bitstreams.size() == 1); *bytes = encoded_image.bitstreams[0]; return true; diff --git a/third_party/jpeg-xl/lib/extras/codec_test.cc b/third_party/jpeg-xl/lib/extras/codec_test.cc index c97e1b1d8c230..6cbed220975ef 100644 --- a/third_party/jpeg-xl/lib/extras/codec_test.cc +++ b/third_party/jpeg-xl/lib/extras/codec_test.cc @@ -7,11 +7,12 @@ #include #include #include -#include #include +#include #include #include +#include #include #include #include @@ -22,10 +23,11 @@ #include "lib/extras/common.h" #include "lib/extras/dec/color_hints.h" #include "lib/extras/dec/decode.h" -#include "lib/extras/dec/pnm.h" #include "lib/extras/enc/encode.h" #include "lib/extras/packed_image.h" #include "lib/jxl/base/byte_order.h" +#include "lib/jxl/base/compiler_specific.h" +#include "lib/jxl/base/data_parallel.h" #include "lib/jxl/base/random.h" #include "lib/jxl/base/span.h" #include "lib/jxl/base/status.h" @@ -35,16 +37,18 @@ namespace jxl { -using test::ThreadPoolForTests; +using ::jxl::test::ThreadPoolForTests; namespace extras { + +Status PnmParseSigned(Bytes str, double* v); +Status PnmParseUnsigned(Bytes str, size_t* v); + namespace { -using ::testing::AllOf; -using ::testing::Contains; -using ::testing::Field; -using ::testing::IsEmpty; -using ::testing::SizeIs; +Span MakeSpan(const char* str) { + return Bytes(reinterpret_cast(str), strlen(str)); +} std::string ExtensionFromCodec(Codec codec, const bool is_gray, const bool has_alpha, @@ -112,15 +116,15 @@ JxlColorEncoding CreateTestColorEncoding(bool is_gray) { // Roundtrip through internal color encoding to fill in primaries and white // point CIE xy coordinates. ColorEncoding c_internal; - JXL_CHECK(c_internal.FromExternal(c)); + EXPECT_TRUE(c_internal.FromExternal(c)); c = c_internal.ToExternal(); return c; } std::vector GenerateICC(JxlColorEncoding color_encoding) { ColorEncoding c; - JXL_CHECK(c.FromExternal(color_encoding)); - JXL_CHECK(!c.ICC().empty()); + EXPECT_TRUE(c.FromExternal(color_encoding)); + EXPECT_TRUE(!c.ICC().empty()); return c.ICC(); } @@ -233,13 +237,17 @@ void CreateTestImage(const TestImageParams& params, PackedPixelFile* ppf) { ppf->icc = GenerateICC(color_encoding); ppf->color_encoding = color_encoding; - PackedFrame frame(params.xsize, params.ysize, params.PixelFormat()); + JXL_TEST_ASSIGN_OR_DIE( + PackedFrame frame, + PackedFrame::Create(params.xsize, params.ysize, params.PixelFormat())); FillPackedImage(params.bits_per_sample, &frame.color); if (params.add_extra_channels) { for (size_t i = 0; i < 7; ++i) { JxlPixelFormat ec_format = params.PixelFormat(); ec_format.num_channels = 1; - PackedImage ec(params.xsize, params.ysize, ec_format); + JXL_TEST_ASSIGN_OR_DIE( + PackedImage ec, + PackedImage::Create(params.xsize, params.ysize, ec_format)); FillPackedImage(params.bits_per_sample, &ec); frame.extra_channels.emplace_back(std::move(ec)); PackedExtraChannel pec; @@ -335,10 +343,10 @@ TEST(CodecTest, TestRoundTrip) { params.add_alpha = add_alpha; params.big_endian = big_endian; params.add_extra_channels = false; - TestRoundTrip(params, &pool); + TestRoundTrip(params, pool.get()); if (codec == Codec::kPNM && add_alpha) { params.add_extra_channels = true; - TestRoundTrip(params, &pool); + TestRoundTrip(params, pool.get()); } } } @@ -371,7 +379,7 @@ TEST(CodecTest, LosslessPNMRoundtrip) { EncodedImage encoded; auto encoder = Encoder::FromExtension(extension); ASSERT_TRUE(encoder.get()); - ASSERT_TRUE(encoder->Encode(ppf, &encoded, &pool)); + ASSERT_TRUE(encoder->Encode(ppf, &encoded, pool.get())); ASSERT_EQ(encoded.bitstreams.size(), 1); ASSERT_EQ(orig.size(), encoded.bitstreams[0].size()); EXPECT_EQ(0, @@ -380,7 +388,40 @@ TEST(CodecTest, LosslessPNMRoundtrip) { } } -TEST(CodecTest, TestPNM) { TestCodecPNM(); } +TEST(CodecTest, TestPNM) { + size_t u = 77777; // Initialized to wrong value. + double d = 77.77; +// Failing to parse invalid strings results in a crash if `JXL_CRASH_ON_ERROR` +// is defined and hence the tests fail. Therefore we only run these tests if +// `JXL_CRASH_ON_ERROR` is not defined. +#if (!JXL_CRASH_ON_ERROR) + ASSERT_FALSE(PnmParseUnsigned(MakeSpan(""), &u)); + ASSERT_FALSE(PnmParseUnsigned(MakeSpan("+"), &u)); + ASSERT_FALSE(PnmParseUnsigned(MakeSpan("-"), &u)); + ASSERT_FALSE(PnmParseUnsigned(MakeSpan("A"), &u)); + + ASSERT_FALSE(PnmParseSigned(MakeSpan(""), &d)); + ASSERT_FALSE(PnmParseSigned(MakeSpan("+"), &d)); + ASSERT_FALSE(PnmParseSigned(MakeSpan("-"), &d)); + ASSERT_FALSE(PnmParseSigned(MakeSpan("A"), &d)); +#endif + ASSERT_TRUE(PnmParseUnsigned(MakeSpan("1"), &u)); + ASSERT_TRUE(u == 1); + + ASSERT_TRUE(PnmParseUnsigned(MakeSpan("32"), &u)); + ASSERT_TRUE(u == 32); + + ASSERT_TRUE(PnmParseSigned(MakeSpan("1"), &d)); + ASSERT_TRUE(d == 1.0); + ASSERT_TRUE(PnmParseSigned(MakeSpan("+2"), &d)); + ASSERT_TRUE(d == 2.0); + ASSERT_TRUE(PnmParseSigned(MakeSpan("-3"), &d)); + ASSERT_TRUE(std::abs(d - -3.0) < 1E-15); + ASSERT_TRUE(PnmParseSigned(MakeSpan("3.141592"), &d)); + ASSERT_TRUE(std::abs(d - 3.141592) < 1E-15); + ASSERT_TRUE(PnmParseSigned(MakeSpan("-3.141592"), &d)); + ASSERT_TRUE(std::abs(d - -3.141592) < 1E-15); +} TEST(CodecTest, FormatNegotiation) { const std::vector accepted_formats = { @@ -432,15 +473,17 @@ TEST(CodecTest, EncodeToPNG) { ASSERT_TRUE(extras::DecodeBytes(Bytes(original_png), ColorHints(), &ppf)); const JxlPixelFormat& format = ppf.frames.front().color.format; - ASSERT_THAT( - png_encoder->AcceptedFormats(), - Contains(AllOf(Field(&JxlPixelFormat::num_channels, format.num_channels), - Field(&JxlPixelFormat::data_type, format.data_type), - Field(&JxlPixelFormat::endianness, format.endianness)))); + const auto& format_matcher = [&format](const JxlPixelFormat& candidate) { + return (candidate.num_channels == format.num_channels) && + (candidate.data_type == format.data_type) && + (candidate.endianness == format.endianness); + }; + const auto formats = png_encoder->AcceptedFormats(); + ASSERT_TRUE(std::any_of(formats.begin(), formats.end(), format_matcher)); EncodedImage encoded_png; ASSERT_TRUE(png_encoder->Encode(ppf, &encoded_png, pool)); - EXPECT_THAT(encoded_png.icc, IsEmpty()); - ASSERT_THAT(encoded_png.bitstreams, SizeIs(1)); + EXPECT_TRUE(encoded_png.icc.empty()); + ASSERT_EQ(encoded_png.bitstreams.size(), 1); PackedPixelFile decoded_ppf; ASSERT_TRUE(extras::DecodeBytes(Bytes(encoded_png.bitstreams.front()), diff --git a/third_party/jpeg-xl/lib/extras/common.cc b/third_party/jpeg-xl/lib/extras/common.cc index e85b43a49800a..56abd13ea6699 100644 --- a/third_party/jpeg-xl/lib/extras/common.cc +++ b/third_party/jpeg-xl/lib/extras/common.cc @@ -27,6 +27,7 @@ Status SelectFormat(const std::vector& accepted_formats, for (;;) { for (const JxlPixelFormat& candidate : accepted_formats) { if (candidate.num_channels != num_channels) continue; + JXL_RETURN_IF_ERROR(PackedImage::ValidateDataType(candidate.data_type)); const size_t candidate_bit_depth = PackedImage::BitsPerChannel(candidate.data_type); if ( diff --git a/third_party/jpeg-xl/lib/extras/compressed_icc.cc b/third_party/jpeg-xl/lib/extras/compressed_icc.cc new file mode 100644 index 0000000000000..52d433d4f9d30 --- /dev/null +++ b/third_party/jpeg-xl/lib/extras/compressed_icc.cc @@ -0,0 +1,53 @@ +// Copyright (c) the JPEG XL Project Authors. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include + +#include "lib/jxl/base/span.h" +#include "lib/jxl/enc_aux_out.h" +#include "lib/jxl/enc_icc_codec.h" +#include "lib/jxl/icc_codec.h" + +JXL_BOOL JxlICCProfileEncode(const JxlMemoryManager* memory_manager, + const uint8_t* icc, size_t icc_size, + uint8_t** compressed_icc, + size_t* compressed_icc_size) { + JxlMemoryManager local_memory_manager; + if (!jxl::MemoryManagerInit(&local_memory_manager, memory_manager)) { + return JXL_FALSE; + } + jxl::BitWriter writer(&local_memory_manager); + JXL_RETURN_IF_ERROR(jxl::WriteICC(jxl::Span(icc, icc_size), + &writer, jxl::LayerType::Header, nullptr)); + writer.ZeroPadToByte(); + jxl::Bytes bytes = writer.GetSpan(); + *compressed_icc_size = bytes.size(); + *compressed_icc = static_cast( + jxl::MemoryManagerAlloc(&local_memory_manager, *compressed_icc_size)); + memcpy(*compressed_icc, bytes.data(), bytes.size()); + return JXL_TRUE; +} + +JXL_BOOL JxlICCProfileDecode(const JxlMemoryManager* memory_manager, + const uint8_t* compressed_icc, + size_t compressed_icc_size, uint8_t** icc, + size_t* icc_size) { + JxlMemoryManager local_memory_manager; + if (!jxl::MemoryManagerInit(&local_memory_manager, memory_manager)) { + return JXL_FALSE; + } + jxl::ICCReader icc_reader(&local_memory_manager); + jxl::PaddedBytes decompressed(&local_memory_manager); + jxl::BitReader bit_reader( + jxl::Span(compressed_icc, compressed_icc_size)); + JXL_RETURN_IF_ERROR(icc_reader.Init(&bit_reader)); + JXL_RETURN_IF_ERROR(icc_reader.Process(&bit_reader, &decompressed)); + JXL_RETURN_IF_ERROR(bit_reader.Close()); + *icc_size = decompressed.size(); + *icc = static_cast( + jxl::MemoryManagerAlloc(&local_memory_manager, *icc_size)); + memcpy(*icc, decompressed.data(), *icc_size); + return JXL_TRUE; +} diff --git a/third_party/jpeg-xl/lib/extras/compressed_icc_test.cc b/third_party/jpeg-xl/lib/extras/compressed_icc_test.cc new file mode 100644 index 0000000000000..2aa994d6e69e8 --- /dev/null +++ b/third_party/jpeg-xl/lib/extras/compressed_icc_test.cc @@ -0,0 +1,47 @@ +// Copyright (c) the JPEG XL Project Authors. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "jxl/compressed_icc.h" + +#include + +#include +#include +#include + +#include "lib/jxl/color_encoding_internal.h" +#include "lib/jxl/test_memory_manager.h" +#include "lib/jxl/test_utils.h" +#include "lib/jxl/testing.h" + +namespace jxl { +namespace { + +TEST(CompressedIccTest, Roundtrip) { + JxlMemoryManager* memory_manager = jxl::test::MemoryManager(); + uint8_t* compressed_icc; + size_t compressed_icc_size; + const IccBytes icc = jxl::test::GetIccTestProfile(); + ASSERT_TRUE(JxlICCProfileEncode(memory_manager, icc.data(), icc.size(), + &compressed_icc, &compressed_icc_size)); + + EXPECT_LT(compressed_icc_size, icc.size()); + + uint8_t* decompressed_icc; + size_t decompressed_icc_size; + ASSERT_TRUE(JxlICCProfileDecode(memory_manager, compressed_icc, + compressed_icc_size, &decompressed_icc, + &decompressed_icc_size)); + + ASSERT_EQ(decompressed_icc_size, icc.size()); + + EXPECT_EQ(0, memcmp(decompressed_icc, icc.data(), decompressed_icc_size)); + + memory_manager->free(memory_manager->opaque, compressed_icc); + memory_manager->free(memory_manager->opaque, decompressed_icc); +} + +} // namespace +} // namespace jxl diff --git a/third_party/jpeg-xl/lib/extras/dec/apng.cc b/third_party/jpeg-xl/lib/extras/dec/apng.cc index 46508ac683652..24b4795d03dc6 100644 --- a/third_party/jpeg-xl/lib/extras/dec/apng.cc +++ b/third_party/jpeg-xl/lib/extras/dec/apng.cc @@ -38,19 +38,27 @@ #include #include -#include +#include +#include +#include +#include +#include +#include #include #include #include +#include "lib/extras/packed_image.h" #include "lib/extras/size_constraints.h" #include "lib/jxl/base/byte_order.h" #include "lib/jxl/base/common.h" #include "lib/jxl/base/compiler_specific.h" #include "lib/jxl/base/printf_macros.h" -#include "lib/jxl/base/scope_guard.h" -#include "lib/jxl/sanitizers.h" +#include "lib/jxl/base/rect.h" +#include "lib/jxl/base/sanitizers.h" +#include "lib/jxl/base/span.h" +#include "lib/jxl/base/status.h" #if JPEGXL_ENABLE_APNG #include "png.h" /* original (unpatched) libpng is ok */ #endif @@ -58,39 +66,46 @@ namespace jxl { namespace extras { -#if JPEGXL_ENABLE_APNG -namespace { +#if !JPEGXL_ENABLE_APNG -constexpr unsigned char kExifSignature[6] = {0x45, 0x78, 0x69, - 0x66, 0x00, 0x00}; +bool CanDecodeAPNG() { return false; } +Status DecodeImageAPNG(const Span bytes, + const ColorHints& color_hints, PackedPixelFile* ppf, + const SizeConstraints* constraints) { + return false; +} -/* hIST chunk tail is not proccesed properly; skip this chunk completely; - see https://github.com/glennrp/libpng/pull/413 */ -const png_byte kIgnoredPngChunks[] = { - 104, 73, 83, 84, '\0' /* hIST */ -}; +#else // JPEGXL_ENABLE_APNG + +namespace { + +constexpr std::array kPngSignature = {137, 'P', 'N', 'G', + '\r', '\n', 26, '\n'}; // Returns floating-point value from the PNG encoding (times 10^5). double F64FromU32(const uint32_t x) { return static_cast(x) * 1E-5; } -Status DecodeSRGB(const unsigned char* payload, const size_t payload_size, - JxlColorEncoding* color_encoding) { - if (payload_size != 1) return JXL_FAILURE("Wrong sRGB size"); +/** Extract information from 'sRGB' chunk. */ +Status DecodeSrgbChunk(const Bytes payload, JxlColorEncoding* color_encoding) { + if (payload.size() != 1) return JXL_FAILURE("Wrong sRGB size"); + uint8_t ri = payload[0]; // (PNG uses the same values as ICC.) - if (payload[0] >= 4) return JXL_FAILURE("Invalid Rendering Intent"); + if (ri >= 4) return JXL_FAILURE("Invalid Rendering Intent"); color_encoding->white_point = JXL_WHITE_POINT_D65; color_encoding->primaries = JXL_PRIMARIES_SRGB; color_encoding->transfer_function = JXL_TRANSFER_FUNCTION_SRGB; - color_encoding->rendering_intent = - static_cast(payload[0]); + color_encoding->rendering_intent = static_cast(ri); return true; } -// If the cICP profile is not fully supported, return false and leave -// color_encoding unmodified. -Status DecodeCICP(const unsigned char* payload, const size_t payload_size, - JxlColorEncoding* color_encoding) { - if (payload_size != 4) return JXL_FAILURE("Wrong cICP size"); +/** + * Extract information from 'cICP' chunk. + * + * If the cICP profile is not fully supported, return `false` and leave + * `color_encoding` unmodified. + */ +Status DecodeCicpChunk(const Bytes payload, JxlColorEncoding* color_encoding) { + if (payload.size() != 4) return JXL_FAILURE("Wrong cICP size"); JxlColorEncoding color_enc = *color_encoding; // From https://www.itu.int/rec/T-REC-H.273-202107-I/en @@ -217,242 +232,294 @@ Status DecodeCICP(const unsigned char* payload, const size_t payload_size, return true; } -Status DecodeGAMA(const unsigned char* payload, const size_t payload_size, - JxlColorEncoding* color_encoding) { - if (payload_size != 4) return JXL_FAILURE("Wrong gAMA size"); +/** Extract information from 'gAMA' chunk. */ +Status DecodeGamaChunk(Bytes payload, JxlColorEncoding* color_encoding) { + if (payload.size() != 4) return JXL_FAILURE("Wrong gAMA size"); color_encoding->transfer_function = JXL_TRANSFER_FUNCTION_GAMMA; - color_encoding->gamma = F64FromU32(LoadBE32(payload)); + color_encoding->gamma = F64FromU32(LoadBE32(payload.data())); return true; } -Status DecodeCHRM(const unsigned char* payload, const size_t payload_size, - JxlColorEncoding* color_encoding) { - if (payload_size != 32) return JXL_FAILURE("Wrong cHRM size"); - +/** Extract information from 'cHTM' chunk. */ +Status DecodeChrmChunk(Bytes payload, JxlColorEncoding* color_encoding) { + if (payload.size() != 32) return JXL_FAILURE("Wrong cHRM size"); + const uint8_t* data = payload.data(); color_encoding->white_point = JXL_WHITE_POINT_CUSTOM; - color_encoding->white_point_xy[0] = F64FromU32(LoadBE32(payload + 0)); - color_encoding->white_point_xy[1] = F64FromU32(LoadBE32(payload + 4)); + color_encoding->white_point_xy[0] = F64FromU32(LoadBE32(data + 0)); + color_encoding->white_point_xy[1] = F64FromU32(LoadBE32(data + 4)); color_encoding->primaries = JXL_PRIMARIES_CUSTOM; - color_encoding->primaries_red_xy[0] = F64FromU32(LoadBE32(payload + 8)); - color_encoding->primaries_red_xy[1] = F64FromU32(LoadBE32(payload + 12)); - color_encoding->primaries_green_xy[0] = F64FromU32(LoadBE32(payload + 16)); - color_encoding->primaries_green_xy[1] = F64FromU32(LoadBE32(payload + 20)); - color_encoding->primaries_blue_xy[0] = F64FromU32(LoadBE32(payload + 24)); - color_encoding->primaries_blue_xy[1] = F64FromU32(LoadBE32(payload + 28)); + color_encoding->primaries_red_xy[0] = F64FromU32(LoadBE32(data + 8)); + color_encoding->primaries_red_xy[1] = F64FromU32(LoadBE32(data + 12)); + color_encoding->primaries_green_xy[0] = F64FromU32(LoadBE32(data + 16)); + color_encoding->primaries_green_xy[1] = F64FromU32(LoadBE32(data + 20)); + color_encoding->primaries_blue_xy[0] = F64FromU32(LoadBE32(data + 24)); + color_encoding->primaries_blue_xy[1] = F64FromU32(LoadBE32(data + 28)); return true; } -// Retrieves XMP and EXIF/IPTC from itext and text. -class BlobsReaderPNG { - public: - static Status Decode(const png_text_struct& info, PackedMetadata* metadata) { - // We trust these are properly null-terminated by libpng. - const char* key = info.key; - const char* value = info.text; - if (strstr(key, "XML:com.adobe.xmp")) { - metadata->xmp.resize(strlen(value)); // safe, see above - memcpy(metadata->xmp.data(), value, metadata->xmp.size()); - } - - std::string type; - std::vector bytes; +/** Extracts information from 'cLLi' chunk. */ +Status DecodeClliChunk(Bytes payload, float* max_content_light_level) { + if (payload.size() != 8) return JXL_FAILURE("Wrong cLLi size"); + const uint8_t* data = payload.data(); + const uint32_t maxcll_png = + Clamp1(png_get_uint_32(data), uint32_t{0}, uint32_t{10000 * 10000}); + // Ignore MaxFALL value. + *max_content_light_level = static_cast(maxcll_png) / 10000.f; + return true; +} - // Handle text chunks annotated with key "Raw profile type ####", with - // #### a type, which may contain metadata. - const char* kKey = "Raw profile type "; - if (strncmp(key, kKey, strlen(kKey)) != 0) return false; +/** Returns false if invalid. */ +JXL_INLINE Status DecodeHexNibble(const char c, uint32_t* JXL_RESTRICT nibble) { + if ('a' <= c && c <= 'f') { + *nibble = 10 + c - 'a'; + } else if ('0' <= c && c <= '9') { + *nibble = c - '0'; + } else { + *nibble = 0; + return JXL_FAILURE("Invalid metadata nibble"); + } + JXL_ENSURE(*nibble < 16); + return true; +} - if (!MaybeDecodeBase16(key, value, &type, &bytes)) { - JXL_WARNING("Couldn't parse 'Raw format type' text chunk"); - return false; - } - if (type == "exif") { - // Remove "Exif\0\0" prefix if present - if (bytes.size() >= sizeof kExifSignature && - memcmp(bytes.data(), kExifSignature, sizeof kExifSignature) == 0) { - bytes.erase(bytes.begin(), bytes.begin() + sizeof kExifSignature); - } - if (!metadata->exif.empty()) { - JXL_WARNING("overwriting EXIF (%" PRIuS " bytes) with base16 (%" PRIuS - " bytes)", - metadata->exif.size(), bytes.size()); - } - metadata->exif = std::move(bytes); - } else if (type == "iptc") { - // TODO(jon): Deal with IPTC in some way - } else if (type == "8bim") { - // TODO(jon): Deal with 8bim in some way - } else if (type == "xmp") { - if (!metadata->xmp.empty()) { - JXL_WARNING("overwriting XMP (%" PRIuS " bytes) with base16 (%" PRIuS - " bytes)", - metadata->xmp.size(), bytes.size()); +/** Returns false if invalid. */ +JXL_INLINE Status DecodeDecimal(const char** pos, const char* end, + uint32_t* JXL_RESTRICT value) { + size_t len = 0; + *value = 0; + while (*pos < end) { + char next = **pos; + if (next >= '0' && next <= '9') { + *value = (*value * 10) + static_cast(next - '0'); + len++; + if (len > 8) { + break; } - metadata->xmp = std::move(bytes); } else { - JXL_WARNING("Unknown type in 'Raw format type' text chunk: %s: %" PRIuS - " bytes", - type.c_str(), bytes.size()); + // Do not consume terminator (non-decimal digit). + break; } - return true; + (*pos)++; } + if (len == 0 || len > 8) { + return JXL_FAILURE("Failed to parse decimal"); + } + return true; +} - private: - // Returns false if invalid. - static JXL_INLINE Status DecodeNibble(const char c, - uint32_t* JXL_RESTRICT nibble) { - if ('a' <= c && c <= 'f') { - *nibble = 10 + c - 'a'; - } else if ('0' <= c && c <= '9') { - *nibble = c - '0'; - } else { - *nibble = 0; - return JXL_FAILURE("Invalid metadata nibble"); +/** + * Parses a PNG text chunk with key of the form "Raw profile type ####", with + * #### a type. + * + * Returns whether it could successfully parse the content. + * We trust key and encoded are null-terminated because they come from + * libpng. + */ +Status MaybeDecodeBase16(const char* key, const char* encoded, + std::string* type, std::vector* bytes) { + const char* encoded_end = encoded + strlen(encoded); + + const char* kKey = "Raw profile type "; + if (strncmp(key, kKey, strlen(kKey)) != 0) return false; + *type = key + strlen(kKey); + const size_t kMaxTypeLen = 20; + if (type->length() > kMaxTypeLen) return false; // Type too long + + // Header: freeform string and number of bytes + // Expected format is: + // \n + // profile name/description\n + // 40\n (the number of bytes after hex-decoding) + // 01234566789abcdef....\n (72 bytes per line max). + // 012345667\n (last line) + const char* pos = encoded; + + if (*(pos++) != '\n') return false; + while (pos < encoded_end && *pos != '\n') { + pos++; + } + if (pos == encoded_end) return false; + // We parsed so far a \n, some number of non \n characters and are now + // pointing at a \n. + if (*(pos++) != '\n') return false; + // Skip leading spaces + while (pos < encoded_end && *pos == ' ') { + pos++; + } + uint32_t bytes_to_decode = 0; + JXL_RETURN_IF_ERROR(DecodeDecimal(&pos, encoded_end, &bytes_to_decode)); + + // We need 2*bytes for the hex values plus 1 byte every 36 values, + // plus terminal \n for length. + size_t tail = static_cast(encoded_end - pos); + bool ok = ((tail / 2) >= bytes_to_decode); + if (ok) tail -= 2 * static_cast(bytes_to_decode); + ok = ok && (tail == 1 + DivCeil(bytes_to_decode, 36)); + if (!ok) { + return JXL_FAILURE("Not enough bytes to parse %d bytes in hex", + bytes_to_decode); + } + JXL_ENSURE(bytes->empty()); + bytes->reserve(bytes_to_decode); + + // Encoding: base16 with newline after 72 chars. + // pos points to the \n before the first line of hex values. + for (size_t i = 0; i < bytes_to_decode; ++i) { + if (i % 36 == 0) { + if (pos + 1 >= encoded_end) return false; // Truncated base16 1 + if (*pos != '\n') return false; // Expected newline + ++pos; } - JXL_ASSERT(*nibble < 16); - return true; + + if (pos + 2 >= encoded_end) return false; // Truncated base16 2; + uint32_t nibble0; + uint32_t nibble1; + JXL_RETURN_IF_ERROR(DecodeHexNibble(pos[0], &nibble0)); + JXL_RETURN_IF_ERROR(DecodeHexNibble(pos[1], &nibble1)); + bytes->push_back(static_cast((nibble0 << 4) + nibble1)); + pos += 2; } + if (pos + 1 != encoded_end) return false; // Too many encoded bytes + if (pos[0] != '\n') return false; // Incorrect metadata terminator + return true; +} - // Returns false if invalid. - static JXL_INLINE Status DecodeDecimal(const char** pos, const char* end, - uint32_t* JXL_RESTRICT value) { - size_t len = 0; - *value = 0; - while (*pos < end) { - char next = **pos; - if (next >= '0' && next <= '9') { - *value = (*value * 10) + static_cast(next - '0'); - len++; - if (len > 8) { - break; - } - } else { - // Do not consume terminator (non-decimal digit). - break; - } - (*pos)++; - } - if (len == 0 || len > 8) { - return JXL_FAILURE("Failed to parse decimal"); - } - return true; +/** Retrieves XMP and EXIF/IPTC from itext and text. */ +Status DecodeBlob(const png_text_struct& info, PackedMetadata* metadata) { + // We trust these are properly null-terminated by libpng. + const char* key = info.key; + const char* value = info.text; + if (strstr(key, "XML:com.adobe.xmp")) { + metadata->xmp.resize(strlen(value)); // safe, see above + memcpy(metadata->xmp.data(), value, metadata->xmp.size()); } - // Parses a PNG text chunk with key of the form "Raw profile type ####", with - // #### a type. - // Returns whether it could successfully parse the content. - // We trust key and encoded are null-terminated because they come from - // libpng. - static Status MaybeDecodeBase16(const char* key, const char* encoded, - std::string* type, - std::vector* bytes) { - const char* encoded_end = encoded + strlen(encoded); - - const char* kKey = "Raw profile type "; - if (strncmp(key, kKey, strlen(kKey)) != 0) return false; - *type = key + strlen(kKey); - const size_t kMaxTypeLen = 20; - if (type->length() > kMaxTypeLen) return false; // Type too long - - // Header: freeform string and number of bytes - // Expected format is: - // \n - // profile name/description\n - // 40\n (the number of bytes after hex-decoding) - // 01234566789abcdef....\n (72 bytes per line max). - // 012345667\n (last line) - const char* pos = encoded; - - if (*(pos++) != '\n') return false; - while (pos < encoded_end && *pos != '\n') { - pos++; - } - if (pos == encoded_end) return false; - // We parsed so far a \n, some number of non \n characters and are now - // pointing at a \n. - if (*(pos++) != '\n') return false; - // Skip leading spaces - while (pos < encoded_end && *pos == ' ') { - pos++; + std::string type; + std::vector bytes; + + // Handle text chunks annotated with key "Raw profile type ####", with + // #### a type, which may contain metadata. + const char* kKey = "Raw profile type "; + if (strncmp(key, kKey, strlen(kKey)) != 0) return false; + + if (!MaybeDecodeBase16(key, value, &type, &bytes)) { + JXL_WARNING("Couldn't parse 'Raw format type' text chunk"); + return false; + } + if (type == "exif") { + // Remove prefix if present. + constexpr std::array kExifPrefix = {'E', 'x', 'i', 'f', 0, 0}; + if (bytes.size() >= kExifPrefix.size() && + memcmp(bytes.data(), kExifPrefix.data(), kExifPrefix.size()) == 0) { + bytes.erase(bytes.begin(), bytes.begin() + kExifPrefix.size()); } - uint32_t bytes_to_decode = 0; - JXL_RETURN_IF_ERROR(DecodeDecimal(&pos, encoded_end, &bytes_to_decode)); - - // We need 2*bytes for the hex values plus 1 byte every 36 values, - // plus terminal \n for length. - const unsigned long needed_bytes = - bytes_to_decode * 2 + 1 + DivCeil(bytes_to_decode, 36); - if (needed_bytes != static_cast(encoded_end - pos)) { - return JXL_FAILURE("Not enough bytes to parse %d bytes in hex", - bytes_to_decode); + if (!metadata->exif.empty()) { + JXL_DEBUG_V(2, + "overwriting EXIF (%" PRIuS " bytes) with base16 (%" PRIuS + " bytes)", + metadata->exif.size(), bytes.size()); } - JXL_ASSERT(bytes->empty()); - bytes->reserve(bytes_to_decode); - - // Encoding: base16 with newline after 72 chars. - // pos points to the \n before the first line of hex values. - for (size_t i = 0; i < bytes_to_decode; ++i) { - if (i % 36 == 0) { - if (pos + 1 >= encoded_end) return false; // Truncated base16 1 - if (*pos != '\n') return false; // Expected newline - ++pos; - } - - if (pos + 2 >= encoded_end) return false; // Truncated base16 2; - uint32_t nibble0; - uint32_t nibble1; - JXL_RETURN_IF_ERROR(DecodeNibble(pos[0], &nibble0)); - JXL_RETURN_IF_ERROR(DecodeNibble(pos[1], &nibble1)); - bytes->push_back(static_cast((nibble0 << 4) + nibble1)); - pos += 2; + metadata->exif = std::move(bytes); + } else if (type == "iptc") { + // TODO(jon): Deal with IPTC in some way + } else if (type == "8bim") { + // TODO(jon): Deal with 8bim in some way + } else if (type == "xmp") { + if (!metadata->xmp.empty()) { + JXL_DEBUG_V(2, + "overwriting XMP (%" PRIuS " bytes) with base16 (%" PRIuS + " bytes)", + metadata->xmp.size(), bytes.size()); } - if (pos + 1 != encoded_end) return false; // Too many encoded bytes - if (pos[0] != '\n') return false; // Incorrect metadata terminator - return true; + metadata->xmp = std::move(bytes); + } else { + JXL_DEBUG_V( + 2, "Unknown type in 'Raw format type' text chunk: %s: %" PRIuS " bytes", + type.c_str(), bytes.size()); } -}; + return true; +} constexpr bool isAbc(char c) { return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); } -constexpr uint32_t kId_IHDR = 0x52444849; -constexpr uint32_t kId_acTL = 0x4C546361; -constexpr uint32_t kId_fcTL = 0x4C546366; -constexpr uint32_t kId_IDAT = 0x54414449; -constexpr uint32_t kId_fdAT = 0x54416466; -constexpr uint32_t kId_IEND = 0x444E4549; -constexpr uint32_t kId_cICP = 0x50434963; -constexpr uint32_t kId_iCCP = 0x50434369; -constexpr uint32_t kId_sRGB = 0x42475273; -constexpr uint32_t kId_gAMA = 0x414D4167; -constexpr uint32_t kId_cHRM = 0x4D524863; -constexpr uint32_t kId_eXIf = 0x66495865; - -struct APNGFrame { - std::vector pixels; +/** Wrap 4-char tag name into ID. */ +constexpr uint32_t MakeTag(uint8_t a, uint8_t b, uint8_t c, uint8_t d) { + return a | (b << 8) | (c << 16) | (d << 24); +} + +/** Reusable image data container. */ +struct Pixels { + // Use array instead of vector to avoid memory initialization. + std::unique_ptr pixels; + size_t pixels_size = 0; std::vector rows; - unsigned int w, h, delay_num, delay_den; + std::atomic has_error{false}; + + Status Resize(size_t row_bytes, size_t num_rows) { + size_t new_size = row_bytes * num_rows; // it is assumed size is sane + if (new_size > pixels_size) { + pixels.reset(new uint8_t[new_size]); + if (!pixels) { + // TODO(szabadka): use specialized OOM error code + return JXL_FAILURE("Failed to allocate memory for image buffer"); + } + pixels_size = new_size; + } + rows.resize(num_rows); + for (size_t y = 0; y < num_rows; y++) { + rows[y] = pixels.get() + y * row_bytes; + } + return true; + } }; +/** + * Helper that chunks in-memory input. + */ struct Reader { - const uint8_t* next; - const uint8_t* last; - bool Read(void* data, size_t len) { - size_t cap = last - next; + explicit Reader(Span data) : data_(data) {} + + const Span data_; + size_t offset_ = 0; + + Bytes Peek(size_t len) const { + size_t cap = data_.size() - offset_; size_t to_copy = std::min(cap, len); - memcpy(data, next, to_copy); - next += to_copy; - return (len == to_copy); + return {data_.data() + offset_, to_copy}; + } + + Bytes Read(size_t len) { + Bytes result = Peek(len); + offset_ += result.size(); + return result; + } + + /* Returns empty Span on error. */ + Bytes ReadChunk() { + Bytes len = Peek(4); + if (len.size() != 4) { + return Bytes(); + } + const auto size = png_get_uint_32(len.data()); + // NB: specification allows 2^31 - 1 + constexpr size_t kMaxPNGChunkSize = 1u << 30; // 1 GB + // Check first, to avoid overflow. + if (size > kMaxPNGChunkSize) { + JXL_WARNING("APNG chunk size is too big"); + return Bytes(); + } + size_t full_size = size + 12; // size does not include itself, tag and CRC. + Bytes result = Read(full_size); + return (result.size() == full_size) ? result : Bytes(); } - bool Eof() const { return next == last; } -}; -const unsigned long cMaxPNGSize = 1000000UL; -const size_t kMaxPNGChunkSize = 1lu << 30; // 1 GB + bool Eof() const { return offset_ == data_.size(); } +}; -void info_fn(png_structp png_ptr, png_infop info_ptr) { +void ProgressiveRead_OnInfo(png_structp png_ptr, png_infop info_ptr) { png_set_expand(png_ptr); png_set_palette_to_rgb(png_ptr); png_set_tRNS_to_alpha(png_ptr); @@ -460,319 +527,486 @@ void info_fn(png_structp png_ptr, png_infop info_ptr) { png_read_update_info(png_ptr, info_ptr); } -void row_fn(png_structp png_ptr, png_bytep new_row, png_uint_32 row_num, - int pass) { - APNGFrame* frame = - reinterpret_cast(png_get_progressive_ptr(png_ptr)); - JXL_CHECK(frame); - JXL_CHECK(row_num < frame->rows.size()); - JXL_CHECK(frame->rows[row_num] < frame->pixels.data() + frame->pixels.size()); +void ProgressiveRead_OnRow(png_structp png_ptr, png_bytep new_row, + png_uint_32 row_num, int pass) { + Pixels* frame = reinterpret_cast(png_get_progressive_ptr(png_ptr)); + if (!frame) { + JXL_DEBUG_ABORT("Internal logic error"); + return; + } + if (row_num >= frame->rows.size()) { + frame->has_error = true; + return; + } png_progressive_combine_row(png_ptr, frame->rows[row_num], new_row); } -inline unsigned int read_chunk(Reader* r, std::vector* pChunk) { - unsigned char len[4]; - if (r->Read(&len, 4)) { - const auto size = png_get_uint_32(len); - // Check first, to avoid overflow. - if (size > kMaxPNGChunkSize) { - JXL_WARNING("APNG chunk size is too big"); - return 0; - } - pChunk->resize(size + 12); - memcpy(pChunk->data(), len, 4); - if (r->Read(pChunk->data() + 4, pChunk->size() - 4)) { - return LoadLE32(pChunk->data() + 4); - } +// Holds intermediate state during parsing APNG file. +struct Context { + ~Context() { + // Make sure png memory is released in any case. + ResetPngDecoder(); } - return 0; -} -int processing_start(png_structp& png_ptr, png_infop& info_ptr, void* frame_ptr, - bool hasInfo, std::vector& chunkIHDR, - std::vector>& chunksInfo) { - unsigned char header[8] = {137, 80, 78, 71, 13, 10, 26, 10}; + bool CreatePngDecoder() { + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, + nullptr); + info_ptr = png_create_info_struct(png_ptr); + return (png_ptr != nullptr && info_ptr != nullptr); + } - // Cleanup prior decoder, if any. - png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); - // Just in case. Not all versions on libpng wipe-out the pointers. - png_ptr = nullptr; - info_ptr = nullptr; + /** + * Initialize PNG decoder. + * + * TODO(eustas): add details + */ + bool InitPngDecoder(const std::vector& chunksInfo, + const RectT& viewport) { + ResetPngDecoder(); + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, + nullptr); + info_ptr = png_create_info_struct(png_ptr); + if (png_ptr == nullptr || info_ptr == nullptr) { + return false; + } - png_ptr = - png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); - info_ptr = png_create_info_struct(png_ptr); - if (!png_ptr || !info_ptr) return 1; + if (setjmp(png_jmpbuf(png_ptr))) { + return false; + } - if (setjmp(png_jmpbuf(png_ptr))) { - return 1; - } + /* hIST chunk tail is not processed properly; skip this chunk completely; + see https://github.com/glennrp/libpng/pull/413 */ + constexpr std::array kIgnoredChunks = {'h', 'I', 'S', 'T', 0}; + png_set_keep_unknown_chunks(png_ptr, 1, kIgnoredChunks.data(), + static_cast(kIgnoredChunks.size() / 5)); + + png_set_crc_action(png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE); + png_set_progressive_read_fn(png_ptr, static_cast(&frameRaw), + ProgressiveRead_OnInfo, ProgressiveRead_OnRow, + nullptr); + + png_process_data(png_ptr, info_ptr, + const_cast(kPngSignature.data()), + kPngSignature.size()); + + // Patch dimensions. + png_save_uint_32(ihdr.data() + 8, static_cast(viewport.xsize())); + png_save_uint_32(ihdr.data() + 12, static_cast(viewport.ysize())); + png_process_data(png_ptr, info_ptr, ihdr.data(), ihdr.size()); + + for (const auto& chunk : chunksInfo) { + png_process_data(png_ptr, info_ptr, const_cast(chunk.data()), + chunk.size()); + } - png_set_keep_unknown_chunks(png_ptr, 1, kIgnoredPngChunks, - static_cast(sizeof(kIgnoredPngChunks) / 5)); + return true; + } - png_set_crc_action(png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE); - png_set_progressive_read_fn(png_ptr, frame_ptr, info_fn, row_fn, nullptr); + /** + * Pass chunk to PNG decoder. + */ + bool FeedChunks(const Bytes& chunk1, const Bytes& chunk2 = Bytes()) { + // TODO(eustas): turn to DCHECK + if (!png_ptr || !info_ptr) return false; - png_process_data(png_ptr, info_ptr, header, 8); - png_process_data(png_ptr, info_ptr, chunkIHDR.data(), chunkIHDR.size()); + if (setjmp(png_jmpbuf(png_ptr))) { + return false; + } - if (hasInfo) { - for (auto& chunk : chunksInfo) { - png_process_data(png_ptr, info_ptr, chunk.data(), chunk.size()); + for (const auto& chunk : {chunk1, chunk2}) { + if (!chunk.empty()) { + png_process_data(png_ptr, info_ptr, const_cast(chunk.data()), + chunk.size()); + } } + return true; } - return 0; -} -int processing_data(png_structp png_ptr, png_infop info_ptr, unsigned char* p, - unsigned int size) { - if (!png_ptr || !info_ptr) return 1; + bool FinalizeStream(PackedMetadata* metadata) { + // TODO(eustas): turn to DCHECK + if (!png_ptr || !info_ptr) return false; + + if (setjmp(png_jmpbuf(png_ptr))) { + return false; + } + + const std::array kFooter = {0, 0, 0, 0, 73, 69, + 78, 68, 174, 66, 96, 130}; + png_process_data(png_ptr, info_ptr, const_cast(kFooter.data()), + kFooter.size()); + // before destroying: check if we encountered any metadata chunks + png_textp text_ptr = nullptr; + int num_text = 0; + if (png_get_text(png_ptr, info_ptr, &text_ptr, &num_text) != 0) { + msan::UnpoisonMemory(text_ptr, sizeof(png_text_struct) * num_text); + for (int i = 0; i < num_text; i++) { + Status result = DecodeBlob(text_ptr[i], metadata); + // Ignore unknown / malformed blob. + (void)result; + } + } - if (setjmp(png_jmpbuf(png_ptr))) { - return 1; + return true; } - png_process_data(png_ptr, info_ptr, p, size); - return 0; -} + void ResetPngDecoder() { + png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); + // Just in case. Not all versions on libpng wipe-out the pointers. + png_ptr = nullptr; + info_ptr = nullptr; + } -int processing_finish(png_structp png_ptr, png_infop info_ptr, - PackedMetadata* metadata) { - unsigned char footer[12] = {0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130}; + std::array ihdr; // (modified) copy of file IHDR chunk + png_structp png_ptr = nullptr; + png_infop info_ptr = nullptr; + Pixels frameRaw = {}; +}; - if (!png_ptr || !info_ptr) return 1; +enum class DisposeOp : uint8_t { NONE = 0, BACKGROUND = 1, PREVIOUS = 2 }; - if (setjmp(png_jmpbuf(png_ptr))) { - return 1; - } +constexpr uint8_t kLastDisposeOp = static_cast(DisposeOp::PREVIOUS); - png_process_data(png_ptr, info_ptr, footer, 12); - // before destroying: check if we encountered any metadata chunks - png_textp text_ptr; - int num_text; - png_get_text(png_ptr, info_ptr, &text_ptr, &num_text); - for (int i = 0; i < num_text; i++) { - (void)BlobsReaderPNG::Decode(text_ptr[i], metadata); +enum class BlendOp : uint8_t { SOURCE = 0, OVER = 1 }; + +constexpr uint8_t kLastBlendOp = static_cast(BlendOp::OVER); + +// fcTL +struct FrameControl { + uint32_t delay_num; + uint32_t delay_den; + RectT viewport; + DisposeOp dispose_op; + BlendOp blend_op; +}; + +struct Frame { + PackedImage pixels; + FrameControl metadata; +}; + +bool ValidateViewport(const RectT& r) { + constexpr uint32_t kMaxPngDim = 1000000UL; + return (r.xsize() <= kMaxPngDim) && (r.ysize() <= kMaxPngDim); +} + +/** + * Setup #channels, bpp, colorspace, etc. from PNG values. + */ +void SetColorData(PackedPixelFile* ppf, uint8_t color_type, uint8_t bit_depth, + png_color_8p sig_bits, uint32_t has_transparency) { + bool palette_used = ((color_type & 1) != 0); + bool color_used = ((color_type & 2) != 0); + bool alpha_channel_used = ((color_type & 4) != 0); + if (palette_used) { + if (!color_used || alpha_channel_used) { + JXL_DEBUG_V(2, "Unexpected PNG color type"); + } } - return 0; + ppf->info.bits_per_sample = bit_depth; + + if (palette_used) { + // palette will actually be 8-bit regardless of the index bitdepth + ppf->info.bits_per_sample = 8; + } + if (color_used) { + ppf->info.num_color_channels = 3; + ppf->color_encoding.color_space = JXL_COLOR_SPACE_RGB; + if (sig_bits) { + if (sig_bits->red == sig_bits->green && + sig_bits->green == sig_bits->blue) { + ppf->info.bits_per_sample = sig_bits->red; + } else { + int maxbps = + std::max(sig_bits->red, std::max(sig_bits->green, sig_bits->blue)); + JXL_DEBUG_V(2, + "sBIT chunk: bit depths for R, G, and B are not the same " + "(%i %i %i), while in JPEG XL they have to be the same. " + "Setting RGB bit depth to %i.", + sig_bits->red, sig_bits->green, sig_bits->blue, maxbps); + ppf->info.bits_per_sample = maxbps; + } + } + } else { + ppf->info.num_color_channels = 1; + ppf->color_encoding.color_space = JXL_COLOR_SPACE_GRAY; + if (sig_bits) ppf->info.bits_per_sample = sig_bits->gray; + } + if (alpha_channel_used || has_transparency) { + ppf->info.alpha_bits = ppf->info.bits_per_sample; + if (sig_bits && sig_bits->alpha != ppf->info.bits_per_sample) { + JXL_DEBUG_V(2, + "sBIT chunk: bit depths for RGBA are inconsistent " + "(%i %i %i %i). Setting A bitdepth to %i.", + sig_bits->red, sig_bits->green, sig_bits->blue, + sig_bits->alpha, ppf->info.bits_per_sample); + } + } else { + ppf->info.alpha_bits = 0; + } + ppf->color_encoding.color_space = (ppf->info.num_color_channels == 1) + ? JXL_COLOR_SPACE_GRAY + : JXL_COLOR_SPACE_RGB; } +// Color profile chunks: cICP has the highest priority, followed by +// iCCP and sRGB (which shouldn't co-exist, but if they do, we use +// iCCP), followed finally by gAMA and cHRM. +enum class ColorInfoType { + NONE = 0, + GAMA_OR_CHRM = 1, + ICCP_OR_SRGB = 2, + CICP = 3 +}; + } // namespace -#endif -bool CanDecodeAPNG() { -#if JPEGXL_ENABLE_APNG - return true; -#else - return false; -#endif -} +bool CanDecodeAPNG() { return true; } +/** + * Parse and decode PNG file. + * + * Useful PNG chunks: + * acTL : animation control (#frames, loop count) + * fcTL : frame control (seq#, viewport, delay, disposal blending) + * bKGD : preferable background + * IDAT : "default image" + * if single fcTL goes before IDAT, then it is also first frame + * fdAT : seq# + IDAT-like content + * PLTE : palette + * cICP : coding-independent code points for video signal type identification + * iCCP : embedded ICC profile + * sRGB : standard RGB colour space + * eXIf : exchangeable image file profile + * gAMA : image gamma + * cHRM : primary chromaticities and white point + * tRNS : transparency + * + * PNG chunk ordering: + * - IHDR first + * - IEND last + * - acTL, cHRM, cICP, gAMA, iCCP, sRGB, bKGD, eXIf, PLTE before IDAT + * - fdAT after IDAT + * + * More rules: + * - iCCP and sRGB are exclusive + * - fcTL and fdAT seq# must be in order fro 0, with no gaps or duplicates + * - fcTL before corresponding IDAT / fdAT + */ Status DecodeImageAPNG(const Span bytes, const ColorHints& color_hints, PackedPixelFile* ppf, const SizeConstraints* constraints) { -#if JPEGXL_ENABLE_APNG - Reader r; - unsigned char sig[8]; - png_structp png_ptr = nullptr; - png_infop info_ptr = nullptr; - std::vector chunk; - std::vector chunkIHDR; - std::vector> chunksInfo; - bool isAnimated = false; - bool hasInfo = false; - bool seenFctl = false; - APNGFrame frameRaw = {}; - uint32_t num_channels; - JxlPixelFormat format; - unsigned int bytes_per_pixel = 0; - - struct FrameInfo { - PackedImage data; - uint32_t duration; - size_t x0, xsize; - size_t y0, ysize; - uint32_t dispose_op; - uint32_t blend_op; - }; - - std::vector frames; + // Initialize output (default settings in case e.g. only gAMA is given). + ppf->frames.clear(); + ppf->info.exponent_bits_per_sample = 0; + ppf->info.alpha_exponent_bits = 0; + ppf->info.orientation = JXL_ORIENT_IDENTITY; + ppf->color_encoding.color_space = JXL_COLOR_SPACE_RGB; + ppf->color_encoding.white_point = JXL_WHITE_POINT_D65; + ppf->color_encoding.primaries = JXL_PRIMARIES_SRGB; + ppf->color_encoding.transfer_function = JXL_TRANSFER_FUNCTION_SRGB; + ppf->color_encoding.rendering_intent = JXL_RENDERING_INTENT_RELATIVE; + + Reader input(bytes); + + // Check signature. + Bytes sig = input.Read(kPngSignature.size()); + if (sig.size() != 8 || + memcmp(sig.data(), kPngSignature.data(), kPngSignature.size()) != 0) { + return false; // Return silently if it is not a PNG + } - // Make sure png memory is released in any case. - auto scope_guard = MakeScopeGuard([&]() { - png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); - // Just in case. Not all versions on libpng wipe-out the pointers. - png_ptr = nullptr; - info_ptr = nullptr; - }); + // Check IHDR chunk. + Context ctx; + Bytes ihdr = input.ReadChunk(); + if (ihdr.size() != ctx.ihdr.size()) { + return JXL_FAILURE("Unexpected first chunk payload size"); + } + memcpy(ctx.ihdr.data(), ihdr.data(), ihdr.size()); + uint32_t id = LoadLE32(ihdr.data() + 4); + if (id != MakeTag('I', 'H', 'D', 'R')) { + return JXL_FAILURE("First chunk is not IHDR"); + } + const RectT image_rect(0, 0, png_get_uint_32(ihdr.data() + 8), + png_get_uint_32(ihdr.data() + 12)); + if (!ValidateViewport(image_rect)) { + return JXL_FAILURE("PNG image dimensions are too large"); + } - r = {bytes.data(), bytes.data() + bytes.size()}; - // Not a PNG => not an error - unsigned char png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; - if (!r.Read(sig, 8) || memcmp(sig, png_signature, 8) != 0) { - return false; + // Chunks we supply to PNG decoder for every animation frame. + std::vector passthrough_chunks; + if (!ctx.InitPngDecoder(passthrough_chunks, image_rect)) { + return JXL_FAILURE("Failed to initialize PNG decoder"); } - unsigned int id = read_chunk(&r, &chunkIHDR); - ppf->info.exponent_bits_per_sample = 0; - ppf->info.alpha_exponent_bits = 0; - ppf->info.orientation = JXL_ORIENT_IDENTITY; + // Marker that this PNG is animated. + bool seen_actl = false; + // First IDAT is a very important milestone; at this moment we freeze + // gathered metadata. + bool seen_idat = false; + // fCTL can occur multiple times, but only once before IDAT. + bool seen_fctl = false; + // Logical EOF. + bool seen_iend = false; - ppf->frames.clear(); + ColorInfoType color_info_type = ColorInfoType::NONE; - bool have_color = false; - bool have_cicp = false; - bool have_iccp = false; - bool have_srgb = false; - bool errorstate = true; - if (id == kId_IHDR && chunkIHDR.size() == 25) { - unsigned int x0 = 0; - unsigned int y0 = 0; - unsigned int delay_num = 1; - unsigned int delay_den = 10; - unsigned int dop = 0; - unsigned int bop = 0; - - unsigned int w = png_get_uint_32(chunkIHDR.data() + 8); - unsigned int h = png_get_uint_32(chunkIHDR.data() + 12); - unsigned int w0 = w; - unsigned int h0 = h; - if (w > cMaxPNGSize || h > cMaxPNGSize) { - return false; + // Flag that we processed some IDAT / fDAT after image / frame start. + bool seen_pixel_data = false; + + uint32_t num_channels; + JxlPixelFormat format = {}; + size_t bytes_per_pixel = 0; + std::vector frames; + FrameControl current_frame = {/*delay_num=*/1, /*delay_den=*/10, image_rect, + DisposeOp::NONE, BlendOp::SOURCE}; + + // Copies frame pixels / metadata from temporary storage. + // TODO(eustas): avoid copying. + const auto finalize_frame = [&]() -> Status { + if (!seen_pixel_data) { + return JXL_FAILURE("Frame / image without fdAT / IDAT chunks"); + } + if (!ctx.FinalizeStream(&ppf->metadata)) { + return JXL_FAILURE("Failed to finalize PNG substream"); + } + if (ctx.frameRaw.has_error) { + return JXL_FAILURE("Internal error"); } + // Allocates the frame buffer. + const RectT& vp = current_frame.viewport; + size_t xsize = static_cast(vp.xsize()); + size_t ysize = static_cast(vp.ysize()); + JXL_ASSIGN_OR_RETURN(PackedImage image, + PackedImage::Create(xsize, ysize, format)); + for (size_t y = 0; y < ysize; ++y) { + // TODO(eustas): ensure multiplication is safe + memcpy(static_cast(image.pixels()) + image.stride * y, + ctx.frameRaw.rows[y], bytes_per_pixel * xsize); + } + frames.push_back(Frame{std::move(image), current_frame}); + seen_pixel_data = false; + return true; + }; - // default settings in case e.g. only gAMA is given - ppf->color_encoding.color_space = JXL_COLOR_SPACE_RGB; - ppf->color_encoding.white_point = JXL_WHITE_POINT_D65; - ppf->color_encoding.primaries = JXL_PRIMARIES_SRGB; - ppf->color_encoding.transfer_function = JXL_TRANSFER_FUNCTION_SRGB; - ppf->color_encoding.rendering_intent = JXL_RENDERING_INTENT_RELATIVE; - - if (!processing_start(png_ptr, info_ptr, static_cast(&frameRaw), - hasInfo, chunkIHDR, chunksInfo)) { - while (!r.Eof()) { - id = read_chunk(&r, &chunk); - if (!id) break; - seenFctl |= (id == kId_fcTL); - - if (id == kId_acTL && !hasInfo && !isAnimated) { - isAnimated = true; - ppf->info.have_animation = JXL_TRUE; - ppf->info.animation.tps_numerator = 1000; - ppf->info.animation.tps_denominator = 1; - } else if (id == kId_IEND || - (id == kId_fcTL && (!hasInfo || isAnimated))) { - if (hasInfo) { - if (!processing_finish(png_ptr, info_ptr, &ppf->metadata)) { - // Allocates the frame buffer. - uint32_t duration = delay_num * 1000 / delay_den; - frames.push_back(FrameInfo{PackedImage(w0, h0, format), duration, - x0, w0, y0, h0, dop, bop}); - auto& frame = frames.back().data; - for (size_t y = 0; y < h0; ++y) { - memcpy(static_cast(frame.pixels()) + frame.stride * y, - frameRaw.rows[y], bytes_per_pixel * w0); - } - } else { - break; - } - } + while (!input.Eof()) { + if (seen_iend) { + return JXL_FAILURE("Exuberant input after IEND chunk"); + } + Bytes chunk = input.ReadChunk(); + if (chunk.empty()) { + return JXL_FAILURE("Malformed chunk"); + } + Bytes type(chunk.data() + 4, 4); + id = LoadLE32(type.data()); + // Cut 'size' and 'type' at front and 'CRC' at the end. + Bytes payload(chunk.data() + 8, chunk.size() - 12); + + if (!isAbc(type[0]) || !isAbc(type[1]) || !isAbc(type[2]) || + !isAbc(type[3])) { + return JXL_FAILURE("Exotic PNG chunk"); + } - if (id == kId_IEND) { - errorstate = false; - break; - } - if (chunk.size() < 34) { - return JXL_FAILURE("Received a chunk that is too small (%" PRIuS - "B)", - chunk.size()); - } - // At this point the old frame is done. Let's start a new one. - w0 = png_get_uint_32(chunk.data() + 12); - h0 = png_get_uint_32(chunk.data() + 16); - x0 = png_get_uint_32(chunk.data() + 20); - y0 = png_get_uint_32(chunk.data() + 24); - delay_num = png_get_uint_16(chunk.data() + 28); - delay_den = png_get_uint_16(chunk.data() + 30); - dop = chunk[32]; - bop = chunk[33]; - - if (!delay_den) delay_den = 100; - - if (w0 > cMaxPNGSize || h0 > cMaxPNGSize || x0 > cMaxPNGSize || - y0 > cMaxPNGSize || x0 + w0 > w || y0 + h0 > h || dop > 2 || - bop > 1) { - break; - } + switch (id) { + case MakeTag('a', 'c', 'T', 'L'): + if (seen_idat) { + JXL_DEBUG_V(2, "aCTL after IDAT ignored"); + continue; + } + if (seen_actl) { + JXL_DEBUG_V(2, "Duplicate aCTL chunk ignored"); + continue; + } + seen_actl = true; + ppf->info.have_animation = JXL_TRUE; + // TODO(eustas): decode from chunk? + ppf->info.animation.tps_numerator = 1000; + ppf->info.animation.tps_denominator = 1; + continue; + + case MakeTag('I', 'E', 'N', 'D'): + seen_iend = true; + JXL_RETURN_IF_ERROR(finalize_frame()); + continue; + + case MakeTag('f', 'c', 'T', 'L'): { + if (payload.size() != 26) { + return JXL_FAILURE("Unexpected fcTL payload size: %u", + static_cast(payload.size())); + } + if (seen_fctl && !seen_idat) { + return JXL_FAILURE("More than one fcTL before IDAT"); + } + if (seen_idat && !seen_actl) { + return JXL_FAILURE("fcTL after IDAT, but without acTL"); + } + seen_fctl = true; + + // TODO(eustas): check order? + // sequence_number = png_get_uint_32(payload.data()); + RectT raw_viewport(png_get_uint_32(payload.data() + 12), + png_get_uint_32(payload.data() + 16), + png_get_uint_32(payload.data() + 4), + png_get_uint_32(payload.data() + 8)); + uint8_t dispose_op = payload[24]; + if (dispose_op > kLastDisposeOp) { + return JXL_FAILURE("Invalid DisposeOp"); + } + uint8_t blend_op = payload[25]; + if (blend_op > kLastBlendOp) { + return JXL_FAILURE("Invalid BlendOp"); + } + FrameControl next_frame = { + /*delay_num=*/png_get_uint_16(payload.data() + 20), + /*delay_den=*/png_get_uint_16(payload.data() + 22), raw_viewport, + static_cast(dispose_op), static_cast(blend_op)}; + + if (!raw_viewport.Intersection(image_rect).IsSame(raw_viewport)) { + // Cropping happened. + return JXL_FAILURE("PNG frame is outside of image rect"); + } - if (hasInfo) { - memcpy(chunkIHDR.data() + 8, chunk.data() + 12, 8); - if (processing_start(png_ptr, info_ptr, - static_cast(&frameRaw), hasInfo, - chunkIHDR, chunksInfo)) { - break; - } + if (!seen_idat) { + // "Default" image is the first animation frame. Its viewport must + // cover the whole image area. + if (!raw_viewport.IsSame(image_rect)) { + return JXL_FAILURE( + "If the first animation frame is default image, its viewport " + "must cover full image"); } - } else if (id == kId_IDAT) { - // First IDAT chunk means we now have all header info - if (seenFctl) { - // `fcTL` chunk must appear after all `IDAT` chunks - return JXL_FAILURE("IDAT chunk after fcTL chunk"); - } - hasInfo = true; - JXL_CHECK(w == png_get_image_width(png_ptr, info_ptr)); - JXL_CHECK(h == png_get_image_height(png_ptr, info_ptr)); - int colortype = png_get_color_type(png_ptr, info_ptr); - int png_bit_depth = png_get_bit_depth(png_ptr, info_ptr); - ppf->info.bits_per_sample = png_bit_depth; - png_color_8p sigbits = nullptr; - png_get_sBIT(png_ptr, info_ptr, &sigbits); - if (colortype & 1) { - // palette will actually be 8-bit regardless of the index bitdepth - ppf->info.bits_per_sample = 8; - } - if (colortype & 2) { - ppf->info.num_color_channels = 3; - ppf->color_encoding.color_space = JXL_COLOR_SPACE_RGB; - if (sigbits && sigbits->red == sigbits->green && - sigbits->green == sigbits->blue) { - ppf->info.bits_per_sample = sigbits->red; - } else if (sigbits) { - int maxbps = std::max(sigbits->red, - std::max(sigbits->green, sigbits->blue)); - JXL_WARNING( - "sBIT chunk: bit depths for R, G, and B are not the same (%i " - "%i %i), while in JPEG XL they have to be the same. Setting " - "RGB bit depth to %i.", - sigbits->red, sigbits->green, sigbits->blue, maxbps); - ppf->info.bits_per_sample = maxbps; - } - } else { - ppf->info.num_color_channels = 1; - ppf->color_encoding.color_space = JXL_COLOR_SPACE_GRAY; - if (sigbits) ppf->info.bits_per_sample = sigbits->gray; - } - if (colortype & 4 || - png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { - ppf->info.alpha_bits = ppf->info.bits_per_sample; - if (sigbits && sigbits->alpha != ppf->info.bits_per_sample) { - JXL_WARNING( - "sBIT chunk: bit depths for RGBA are inconsistent " - "(%i %i %i %i). Setting A bitdepth to %i.", - sigbits->red, sigbits->green, sigbits->blue, sigbits->alpha, - ppf->info.bits_per_sample); - } - } else { - ppf->info.alpha_bits = 0; + } else { + JXL_RETURN_IF_ERROR(finalize_frame()); + if (!ctx.InitPngDecoder(passthrough_chunks, next_frame.viewport)) { + return JXL_FAILURE("Failed to initialize PNG decoder"); } - ppf->color_encoding.color_space = - (ppf->info.num_color_channels == 1 ? JXL_COLOR_SPACE_GRAY - : JXL_COLOR_SPACE_RGB); - ppf->info.xsize = w; - ppf->info.ysize = h; - JXL_RETURN_IF_ERROR(VerifyDimensions(constraints, w, h)); + } + current_frame = next_frame; + continue; + } + + case MakeTag('I', 'D', 'A', 'T'): { + if (!frames.empty()) { + return JXL_FAILURE("IDAT after default image is over"); + } + if (!seen_idat) { + // First IDAT means that all metadata is ready. + seen_idat = true; + JXL_ENSURE(image_rect.xsize() == + png_get_image_width(ctx.png_ptr, ctx.info_ptr)); + JXL_ENSURE(image_rect.ysize() == + png_get_image_height(ctx.png_ptr, ctx.info_ptr)); + JXL_RETURN_IF_ERROR(VerifyDimensions(constraints, image_rect.xsize(), + image_rect.ysize())); + ppf->info.xsize = image_rect.xsize(); + ppf->info.ysize = image_rect.ysize(); + + png_color_8p sig_bits = nullptr; + // Error is OK -> sig_bits remains nullptr. + png_get_sBIT(ctx.png_ptr, ctx.info_ptr, &sig_bits); + SetColorData(ppf, png_get_color_type(ctx.png_ptr, ctx.info_ptr), + png_get_bit_depth(ctx.png_ptr, ctx.info_ptr), sig_bits, + png_get_valid(ctx.png_ptr, ctx.info_ptr, PNG_INFO_tRNS)); num_channels = ppf->info.num_color_channels + (ppf->info.alpha_bits ? 1 : 0); format = { @@ -782,165 +1016,219 @@ Status DecodeImageAPNG(const Span bytes, /*endianness=*/JXL_BIG_ENDIAN, /*align=*/0, }; - if (png_bit_depth > 8 && format.data_type == JXL_TYPE_UINT8) { - png_set_strip_16(png_ptr); - } bytes_per_pixel = num_channels * (format.data_type == JXL_TYPE_UINT16 ? 2 : 1); - unsigned int rowbytes = w * bytes_per_pixel; - unsigned int imagesize = h * rowbytes; - frameRaw.pixels.resize(imagesize); - frameRaw.rows.resize(h); - for (unsigned int j = 0; j < h; j++) { - frameRaw.rows[j] = frameRaw.pixels.data() + j * rowbytes; + // TODO(eustas): ensure multiplication is safe + uint64_t row_bytes = + static_cast(image_rect.xsize()) * bytes_per_pixel; + uint64_t max_rows = std::numeric_limits::max() / row_bytes; + if (image_rect.ysize() > max_rows) { + return JXL_FAILURE("Image too big."); } + // TODO(eustas): drop frameRaw + JXL_RETURN_IF_ERROR( + ctx.frameRaw.Resize(row_bytes, image_rect.ysize())); + } - if (processing_data(png_ptr, info_ptr, chunk.data(), chunk.size())) { - break; - } - } else if (id == kId_fdAT && isAnimated) { - if (!hasInfo) { - return JXL_FAILURE("fDAT chunk before iDAT"); - } - png_save_uint_32(chunk.data() + 4, chunk.size() - 16); - memcpy(chunk.data() + 8, "IDAT", 4); - if (processing_data(png_ptr, info_ptr, chunk.data() + 4, - chunk.size() - 4)) { - break; - } - } else if (id == kId_cICP) { - // Color profile chunks: cICP has the highest priority, followed by - // iCCP and sRGB (which shouldn't co-exist, but if they do, we use - // iCCP), followed finally by gAMA and cHRM. - if (DecodeCICP(chunk.data() + 8, chunk.size() - 12, - &ppf->color_encoding)) { - have_cicp = true; - have_color = true; - ppf->icc.clear(); - ppf->primary_color_representation = - PackedPixelFile::kColorEncodingIsPrimary; - } - } else if (!have_cicp && id == kId_iCCP) { - if (processing_data(png_ptr, info_ptr, chunk.data(), chunk.size())) { - JXL_WARNING("Corrupt iCCP chunk"); - break; - } + if (!ctx.FeedChunks(chunk)) { + return JXL_FAILURE("Decoding IDAT failed"); + } + seen_pixel_data = true; + continue; + } - // TODO(jon): catch special case of PQ and synthesize color encoding - // in that case - int compression_type; - png_bytep profile; - png_charp name; - png_uint_32 proflen = 0; - auto ok = png_get_iCCP(png_ptr, info_ptr, &name, &compression_type, - &profile, &proflen); - if (ok && proflen) { - ppf->icc.assign(profile, profile + proflen); - ppf->primary_color_representation = PackedPixelFile::kIccIsPrimary; - have_color = true; - have_iccp = true; - } else { - // TODO(eustas): JXL_WARNING? - } - } else if (!have_cicp && !have_iccp && id == kId_sRGB) { - JXL_RETURN_IF_ERROR(DecodeSRGB(chunk.data() + 8, chunk.size() - 12, - &ppf->color_encoding)); - have_srgb = true; - have_color = true; - } else if (!have_cicp && !have_srgb && !have_iccp && id == kId_gAMA) { - JXL_RETURN_IF_ERROR(DecodeGAMA(chunk.data() + 8, chunk.size() - 12, - &ppf->color_encoding)); - have_color = true; - } else if (!have_cicp && !have_srgb && !have_iccp && id == kId_cHRM) { - JXL_RETURN_IF_ERROR(DecodeCHRM(chunk.data() + 8, chunk.size() - 12, - &ppf->color_encoding)); - have_color = true; - } else if (id == kId_eXIf) { - ppf->metadata.exif.resize(chunk.size() - 12); - memcpy(ppf->metadata.exif.data(), chunk.data() + 8, - chunk.size() - 12); - } else if (!isAbc(chunk[4]) || !isAbc(chunk[5]) || !isAbc(chunk[6]) || - !isAbc(chunk[7])) { - break; - } else { - if (processing_data(png_ptr, info_ptr, chunk.data(), chunk.size())) { - break; - } - if (!hasInfo) { - chunksInfo.push_back(chunk); - continue; - } + case MakeTag('f', 'd', 'A', 'T'): { + if (!seen_idat) { + return JXL_FAILURE("fdAT chunk before IDAT"); + } + if (!seen_actl) { + return JXL_FAILURE("fdAT chunk before acTL"); } + /* The 'fdAT' chunk has... the same structure as an 'IDAT' chunk, + * except preceded by a sequence number. */ + if (payload.size() < 4) { + return JXL_FAILURE("Corrupted fdAT chunk"); + } + // Turn 'fdAT' to 'IDAT' by cutting sequence number and replacing tag. + std::array preamble; + png_save_uint_32(preamble.data(), payload.size() - 4); + memcpy(preamble.data() + 4, "IDAT", 4); + // Cut-off 'size', 'type' and 'sequence_number' + Bytes chunk_tail(chunk.data() + 12, chunk.size() - 12); + if (!ctx.FeedChunks(Bytes(preamble), chunk_tail)) { + return JXL_FAILURE("Decoding fdAT failed"); + } + seen_pixel_data = true; + continue; } - } - JXL_RETURN_IF_ERROR(ApplyColorHints( - color_hints, have_color, ppf->info.num_color_channels == 1, ppf)); + case MakeTag('c', 'I', 'C', 'P'): + if (color_info_type == ColorInfoType::CICP) { + JXL_DEBUG_V(2, "Excessive colorspace definition; cICP chunk ignored"); + continue; + } + JXL_RETURN_IF_ERROR(DecodeCicpChunk(payload, &ppf->color_encoding)); + ppf->icc.clear(); + ppf->primary_color_representation = + PackedPixelFile::kColorEncodingIsPrimary; + color_info_type = ColorInfoType::CICP; + continue; + + case MakeTag('i', 'C', 'C', 'P'): { + if (color_info_type == ColorInfoType::ICCP_OR_SRGB) { + return JXL_FAILURE("Repeated iCCP / sRGB chunk"); + } + if (color_info_type > ColorInfoType::ICCP_OR_SRGB) { + JXL_DEBUG_V(2, "Excessive colorspace definition; iCCP chunk ignored"); + continue; + } + // Let PNG decoder deal with chunk processing. + if (!ctx.FeedChunks(chunk)) { + return JXL_FAILURE("Corrupt iCCP chunk"); + } + + // TODO(jon): catch special case of PQ and synthesize color encoding + // in that case + int compression_type = 0; + png_bytep profile = nullptr; + png_charp name = nullptr; + png_uint_32 profile_len = 0; + png_uint_32 ok = + png_get_iCCP(ctx.png_ptr, ctx.info_ptr, &name, &compression_type, + &profile, &profile_len); + if (!ok || !profile_len) { + return JXL_FAILURE("Malformed / incomplete iCCP chunk"); + } + ppf->icc.assign(profile, profile + profile_len); + ppf->primary_color_representation = PackedPixelFile::kIccIsPrimary; + color_info_type = ColorInfoType::ICCP_OR_SRGB; + continue; + } + + case MakeTag('s', 'R', 'G', 'B'): + if (color_info_type == ColorInfoType::ICCP_OR_SRGB) { + return JXL_FAILURE("Repeated iCCP / sRGB chunk"); + } + if (color_info_type > ColorInfoType::ICCP_OR_SRGB) { + JXL_DEBUG_V(2, "Excessive colorspace definition; sRGB chunk ignored"); + continue; + } + JXL_RETURN_IF_ERROR(DecodeSrgbChunk(payload, &ppf->color_encoding)); + color_info_type = ColorInfoType::ICCP_OR_SRGB; + continue; + + case MakeTag('g', 'A', 'M', 'A'): + if (color_info_type >= ColorInfoType::GAMA_OR_CHRM) { + JXL_DEBUG_V(2, "Excessive colorspace definition; gAMA chunk ignored"); + continue; + } + JXL_RETURN_IF_ERROR(DecodeGamaChunk(payload, &ppf->color_encoding)); + color_info_type = ColorInfoType::GAMA_OR_CHRM; + continue; + + case MakeTag('c', 'H', 'R', 'M'): + if (color_info_type >= ColorInfoType::GAMA_OR_CHRM) { + JXL_DEBUG_V(2, "Excessive colorspace definition; cHRM chunk ignored"); + continue; + } + JXL_RETURN_IF_ERROR(DecodeChrmChunk(payload, &ppf->color_encoding)); + color_info_type = ColorInfoType::GAMA_OR_CHRM; + continue; + + case MakeTag('c', 'L', 'L', 'i'): + JXL_RETURN_IF_ERROR( + DecodeClliChunk(payload, &ppf->info.intensity_target)); + continue; + + case MakeTag('e', 'X', 'I', 'f'): + // TODO(eustas): next eXIF chunk overwrites current; is it ok? + ppf->metadata.exif.resize(payload.size()); + memcpy(ppf->metadata.exif.data(), payload.data(), payload.size()); + continue; + + default: + // We don't know what is that, just pass through. + if (!ctx.FeedChunks(chunk)) { + return JXL_FAILURE("PNG decoder failed to process chunk"); + } + // If it happens before IDAT, we consider it metadata and pass to all + // sub-decoders. + if (!seen_idat) { + passthrough_chunks.push_back(chunk); + } + continue; + } } - if (errorstate) return false; + bool color_is_already_set = (color_info_type != ColorInfoType::NONE); + bool is_gray = (ppf->info.num_color_channels == 1); + JXL_RETURN_IF_ERROR( + ApplyColorHints(color_hints, color_is_already_set, is_gray, ppf)); + + if (ppf->color_encoding.transfer_function != JXL_TRANSFER_FUNCTION_PQ) { + // Reset intensity target, in case we set it from cLLi but TF is not PQ. + ppf->info.intensity_target = 0.f; + } bool has_nontrivial_background = false; bool previous_frame_should_be_cleared = false; - enum { - DISPOSE_OP_NONE = 0, - DISPOSE_OP_BACKGROUND = 1, - DISPOSE_OP_PREVIOUS = 2, - }; - enum { - BLEND_OP_SOURCE = 0, - BLEND_OP_OVER = 1, - }; for (size_t i = 0; i < frames.size(); i++) { - auto& frame = frames[i]; - JXL_ASSERT(frame.data.xsize == frame.xsize); - JXL_ASSERT(frame.data.ysize == frame.ysize); - - // Before encountering a DISPOSE_OP_NONE frame, the canvas is filled with 0, - // so DISPOSE_OP_BACKGROUND and DISPOSE_OP_PREVIOUS are equivalent. - if (frame.dispose_op == DISPOSE_OP_NONE) { + Frame& frame = frames[i]; + const FrameControl& fc = frame.metadata; + const RectT vp = fc.viewport; + const auto& pixels = frame.pixels; + size_t xsize = pixels.xsize; + size_t ysize = pixels.ysize; + JXL_ENSURE(xsize == vp.xsize()); + JXL_ENSURE(ysize == vp.ysize()); + + // Before encountering a DISPOSE_OP_NONE frame, the canvas is filled with + // 0, so DISPOSE_OP_BACKGROUND and DISPOSE_OP_PREVIOUS are equivalent. + if (fc.dispose_op == DisposeOp::NONE) { has_nontrivial_background = true; } - bool should_blend = frame.blend_op == BLEND_OP_OVER; + bool should_blend = fc.blend_op == BlendOp::OVER; bool use_for_next_frame = - has_nontrivial_background && frame.dispose_op != DISPOSE_OP_PREVIOUS; - size_t x0 = frame.x0; - size_t y0 = frame.y0; - size_t xsize = frame.data.xsize; - size_t ysize = frame.data.ysize; + has_nontrivial_background && fc.dispose_op != DisposeOp::PREVIOUS; + size_t x0 = vp.x0(); + size_t y0 = vp.y0(); if (previous_frame_should_be_cleared) { - size_t px0 = frames[i - 1].x0; - size_t py0 = frames[i - 1].y0; - size_t pxs = frames[i - 1].xsize; - size_t pys = frames[i - 1].ysize; + const auto& pvp = frames[i - 1].metadata.viewport; + size_t px0 = pvp.x0(); + size_t py0 = pvp.y0(); + size_t pxs = pvp.xsize(); + size_t pys = pvp.ysize(); if (px0 >= x0 && py0 >= y0 && px0 + pxs <= x0 + xsize && - py0 + pys <= y0 + ysize && frame.blend_op == BLEND_OP_SOURCE && + py0 + pys <= y0 + ysize && fc.blend_op == BlendOp::SOURCE && use_for_next_frame) { - // If the previous frame is entirely contained in the current frame and - // we are using BLEND_OP_SOURCE, nothing special needs to be done. - ppf->frames.emplace_back(std::move(frame.data)); + // If the previous frame is entirely contained in the current frame + // and we are using BLEND_OP_SOURCE, nothing special needs to be done. + ppf->frames.emplace_back(std::move(frame.pixels)); } else if (px0 == x0 && py0 == y0 && px0 + pxs == x0 + xsize && py0 + pys == y0 + ysize && use_for_next_frame) { // If the new frame has the same size as the old one, but we are // blending, we can instead just not blend. should_blend = false; - ppf->frames.emplace_back(std::move(frame.data)); + ppf->frames.emplace_back(std::move(frame.pixels)); } else if (px0 <= x0 && py0 <= y0 && px0 + pxs >= x0 + xsize && py0 + pys >= y0 + ysize && use_for_next_frame) { // If the new frame is contained within the old frame, we can pad the // new frame with zeros and not blend. - PackedImage new_data(pxs, pys, frame.data.format); + JXL_ASSIGN_OR_RETURN(PackedImage new_data, + PackedImage::Create(pxs, pys, pixels.format)); memset(new_data.pixels(), 0, new_data.pixels_size); for (size_t y = 0; y < ysize; y++) { + JXL_RETURN_IF_ERROR( + PackedImage::ValidateDataType(new_data.format.data_type)); size_t bytes_per_pixel = PackedImage::BitsPerChannel(new_data.format.data_type) * new_data.format.num_channels / 8; - memcpy(static_cast(new_data.pixels()) + - new_data.stride * (y + y0 - py0) + - bytes_per_pixel * (x0 - px0), - static_cast(frame.data.pixels()) + - frame.data.stride * y, - xsize * bytes_per_pixel); + memcpy( + static_cast(new_data.pixels()) + + new_data.stride * (y + y0 - py0) + + bytes_per_pixel * (x0 - px0), + static_cast(pixels.pixels()) + pixels.stride * y, + xsize * bytes_per_pixel); } x0 = px0; @@ -951,7 +1239,8 @@ Status DecodeImageAPNG(const Span bytes, ppf->frames.emplace_back(std::move(new_data)); } else { // If all else fails, insert a placeholder blank frame with kReplace. - PackedImage blank(pxs, pys, frame.data.format); + JXL_ASSIGN_OR_RETURN(PackedImage blank, + PackedImage::Create(pxs, pys, pixels.format)); memset(blank.pixels(), 0, blank.pixels_size); ppf->frames.emplace_back(std::move(blank)); auto& pframe = ppf->frames.back(); @@ -966,10 +1255,10 @@ Status DecodeImageAPNG(const Span bytes, pframe.frame_info.layer_info.blend_info.blendmode = JXL_BLEND_REPLACE; pframe.frame_info.layer_info.blend_info.source = 1; pframe.frame_info.layer_info.save_as_reference = 1; - ppf->frames.emplace_back(std::move(frame.data)); + ppf->frames.emplace_back(std::move(frame.pixels)); } } else { - ppf->frames.emplace_back(std::move(frame.data)); + ppf->frames.emplace_back(std::move(frame.pixels)); } auto& pframe = ppf->frames.back(); @@ -977,7 +1266,8 @@ Status DecodeImageAPNG(const Span bytes, pframe.frame_info.layer_info.crop_y0 = y0; pframe.frame_info.layer_info.xsize = xsize; pframe.frame_info.layer_info.ysize = ysize; - pframe.frame_info.duration = frame.duration; + pframe.frame_info.duration = + fc.delay_num * 1000 / (fc.delay_den ? fc.delay_den : 100); pframe.frame_info.layer_info.blend_info.blendmode = should_blend ? JXL_BLEND_BLEND : JXL_BLEND_REPLACE; bool is_full_size = x0 == 0 && y0 == 0 && xsize == ppf->info.xsize && @@ -988,16 +1278,16 @@ Status DecodeImageAPNG(const Span bytes, pframe.frame_info.layer_info.save_as_reference = use_for_next_frame ? 1 : 0; previous_frame_should_be_cleared = - has_nontrivial_background && frame.dispose_op == DISPOSE_OP_BACKGROUND; + has_nontrivial_background && (fc.dispose_op == DisposeOp::BACKGROUND); } + if (ppf->frames.empty()) return JXL_FAILURE("No frames decoded"); ppf->frames.back().frame_info.is_last = JXL_TRUE; return true; -#else - return false; -#endif } +#endif // JPEGXL_ENABLE_APNG + } // namespace extras } // namespace jxl diff --git a/third_party/jpeg-xl/lib/extras/dec/apng.h b/third_party/jpeg-xl/lib/extras/dec/apng.h index d91364b1e61e6..7ebc2ee7c8ae1 100644 --- a/third_party/jpeg-xl/lib/extras/dec/apng.h +++ b/third_party/jpeg-xl/lib/extras/dec/apng.h @@ -8,11 +8,10 @@ // Decodes APNG images in memory. -#include +#include #include "lib/extras/dec/color_hints.h" #include "lib/extras/packed_image.h" -#include "lib/jxl/base/data_parallel.h" #include "lib/jxl/base/span.h" #include "lib/jxl/base/status.h" diff --git a/third_party/jpeg-xl/lib/extras/dec/color_description.cc b/third_party/jpeg-xl/lib/extras/dec/color_description.cc index bf229632d06d3..ce0c4adf3242a 100644 --- a/third_party/jpeg-xl/lib/extras/dec/color_description.cc +++ b/third_party/jpeg-xl/lib/extras/dec/color_description.cc @@ -164,7 +164,7 @@ Status ParsePrimaries(Tokenizer* tokenizer, JxlColorEncoding* c) { JXL_RETURN_IF_ERROR(ParseDouble(&xy_tokenizer, c->primaries_blue_xy + 1)); c->primaries = JXL_PRIMARIES_CUSTOM; - return JXL_FAILURE("Invalid primaries %s", str.c_str()); + return true; } Status ParseRenderingIntent(Tokenizer* tokenizer, JxlColorEncoding* c) { @@ -203,12 +203,38 @@ Status ParseTransferFunction(Tokenizer* tokenizer, JxlColorEncoding* c) { Status ParseDescription(const std::string& description, JxlColorEncoding* c) { *c = {}; - Tokenizer tokenizer(&description, '_'); - JXL_RETURN_IF_ERROR(ParseColorSpace(&tokenizer, c)); - JXL_RETURN_IF_ERROR(ParseWhitePoint(&tokenizer, c)); - JXL_RETURN_IF_ERROR(ParsePrimaries(&tokenizer, c)); - JXL_RETURN_IF_ERROR(ParseRenderingIntent(&tokenizer, c)); - JXL_RETURN_IF_ERROR(ParseTransferFunction(&tokenizer, c)); + if (description == "sRGB") { + c->color_space = JXL_COLOR_SPACE_RGB; + c->white_point = JXL_WHITE_POINT_D65; + c->primaries = JXL_PRIMARIES_SRGB; + c->transfer_function = JXL_TRANSFER_FUNCTION_SRGB; + c->rendering_intent = JXL_RENDERING_INTENT_PERCEPTUAL; + } else if (description == "DisplayP3") { + c->color_space = JXL_COLOR_SPACE_RGB; + c->white_point = JXL_WHITE_POINT_D65; + c->primaries = JXL_PRIMARIES_P3; + c->transfer_function = JXL_TRANSFER_FUNCTION_SRGB; + c->rendering_intent = JXL_RENDERING_INTENT_PERCEPTUAL; + } else if (description == "Rec2100PQ") { + c->color_space = JXL_COLOR_SPACE_RGB; + c->white_point = JXL_WHITE_POINT_D65; + c->primaries = JXL_PRIMARIES_2100; + c->transfer_function = JXL_TRANSFER_FUNCTION_PQ; + c->rendering_intent = JXL_RENDERING_INTENT_RELATIVE; + } else if (description == "Rec2100HLG") { + c->color_space = JXL_COLOR_SPACE_RGB; + c->white_point = JXL_WHITE_POINT_D65; + c->primaries = JXL_PRIMARIES_2100; + c->transfer_function = JXL_TRANSFER_FUNCTION_HLG; + c->rendering_intent = JXL_RENDERING_INTENT_RELATIVE; + } else { + Tokenizer tokenizer(&description, '_'); + JXL_RETURN_IF_ERROR(ParseColorSpace(&tokenizer, c)); + JXL_RETURN_IF_ERROR(ParseWhitePoint(&tokenizer, c)); + JXL_RETURN_IF_ERROR(ParsePrimaries(&tokenizer, c)); + JXL_RETURN_IF_ERROR(ParseRenderingIntent(&tokenizer, c)); + JXL_RETURN_IF_ERROR(ParseTransferFunction(&tokenizer, c)); + } return true; } diff --git a/third_party/jpeg-xl/lib/extras/dec/decode.cc b/third_party/jpeg-xl/lib/extras/dec/decode.cc index 3546cb65c0380..2581d53f633c0 100644 --- a/third_party/jpeg-xl/lib/extras/dec/decode.cc +++ b/third_party/jpeg-xl/lib/extras/dec/decode.cc @@ -91,6 +91,15 @@ bool CanDecode(Codec codec) { } } +std::string ListOfDecodeCodecs() { + std::string list_of_codecs("JXL, PPM, PNM, PFM, PAM, PGX"); + if (CanDecode(Codec::kPNG)) list_of_codecs.append(", PNG, APNG"); + if (CanDecode(Codec::kGIF)) list_of_codecs.append(", GIF"); + if (CanDecode(Codec::kJPG)) list_of_codecs.append(", JPEG"); + if (CanDecode(Codec::kEXR)) list_of_codecs.append(", EXR"); + return list_of_codecs; +} + Status DecodeBytes(const Span bytes, const ColorHints& color_hints, extras::PackedPixelFile* ppf, const SizeConstraints* constraints, Codec* orig_codec) { diff --git a/third_party/jpeg-xl/lib/extras/dec/decode.h b/third_party/jpeg-xl/lib/extras/dec/decode.h index 1a90f4c6a33ea..bbffc7e0f0a33 100644 --- a/third_party/jpeg-xl/lib/extras/dec/decode.h +++ b/third_party/jpeg-xl/lib/extras/dec/decode.h @@ -8,11 +8,9 @@ // Facade for image decoders (PNG, PNM, ...). -#include -#include - +#include +#include #include -#include #include "lib/extras/dec/color_hints.h" #include "lib/jxl/base/span.h" @@ -38,6 +36,8 @@ enum class Codec : uint32_t { bool CanDecode(Codec codec); +std::string ListOfDecodeCodecs(); + // If and only if extension is ".pfm", *bits_per_sample is updated to 32 so // that Encode() would encode to PFM instead of PPM. Codec CodecFromPath(const std::string& path, diff --git a/third_party/jpeg-xl/lib/extras/dec/exr.cc b/third_party/jpeg-xl/lib/extras/dec/exr.cc index 4a6fe5043a6d7..59edd63eb863f 100644 --- a/third_party/jpeg-xl/lib/extras/dec/exr.cc +++ b/third_party/jpeg-xl/lib/extras/dec/exr.cc @@ -5,19 +5,51 @@ #include "lib/extras/dec/exr.h" -#if JPEGXL_ENABLE_EXR +#include + +#include "lib/extras/dec/color_hints.h" +#include "lib/extras/packed_image.h" +#include "lib/jxl/base/common.h" +#include "lib/jxl/base/span.h" +#include "lib/jxl/base/status.h" + +#if !JPEGXL_ENABLE_EXR + +namespace jxl { +namespace extras { +bool CanDecodeEXR() { return false; } + +Status DecodeImageEXR(Span bytes, const ColorHints& color_hints, + PackedPixelFile* ppf, + const SizeConstraints* constraints) { + (void)bytes; + (void)color_hints; + (void)ppf; + (void)constraints; + return JXL_FAILURE("EXR is not supported"); +} +} // namespace extras +} // namespace jxl + +#else // JPEGXL_ENABLE_EXR + #include #include #include #include -#endif #include +#ifdef __EXCEPTIONS +#include +#define JXL_EXR_THROW_LENGTH_ERROR() throw std::length_error(""); +#else // __EXCEPTIONS +#define JXL_EXR_THROW_LENGTH_ERROR() JXL_CRASH() +#endif // __EXCEPTIONS + namespace jxl { namespace extras { -#if JPEGXL_ENABLE_EXR namespace { namespace OpenEXR = OPENEXR_IMF_NAMESPACE; @@ -39,7 +71,9 @@ class InMemoryIStream : public OpenEXR::IStream { bool isMemoryMapped() const override { return true; } char* readMemoryMapped(const int n) override { - JXL_ASSERT(pos_ + n <= bytes_.size()); + if (pos_ + n < pos_ || pos_ + n > bytes_.size()) { + JXL_EXR_THROW_LENGTH_ERROR(); + } char* const result = const_cast(reinterpret_cast(bytes_.data() + pos_)); pos_ += n; @@ -52,7 +86,9 @@ class InMemoryIStream : public OpenEXR::IStream { ExrInt64 tellg() override { return pos_; } void seekg(const ExrInt64 pos) override { - JXL_ASSERT(pos + 1 <= bytes_.size()); + if (pos >= bytes_.size()) { + JXL_EXR_THROW_LENGTH_ERROR(); + } pos_ = pos; } @@ -62,26 +98,18 @@ class InMemoryIStream : public OpenEXR::IStream { }; } // namespace -#endif -bool CanDecodeEXR() { -#if JPEGXL_ENABLE_EXR - return true; -#else - return false; -#endif -} +bool CanDecodeEXR() { return true; } Status DecodeImageEXR(Span bytes, const ColorHints& color_hints, PackedPixelFile* ppf, const SizeConstraints* constraints) { -#if JPEGXL_ENABLE_EXR InMemoryIStream is(bytes); #ifdef __EXCEPTIONS std::unique_ptr input_ptr; try { - input_ptr.reset(new OpenEXR::RgbaInputFile(is)); + input_ptr = jxl::make_unique(is); } catch (...) { // silently return false if it is not an EXR file return false; @@ -121,7 +149,12 @@ Status DecodeImageEXR(Span bytes, const ColorHints& color_hints, }; ppf->frames.clear(); // Allocates the frame buffer. - ppf->frames.emplace_back(image_size.x, image_size.y, format); + { + JXL_ASSIGN_OR_RETURN( + PackedFrame frame, + PackedFrame::Create(image_size.x, image_size.y, format)); + ppf->frames.emplace_back(std::move(frame)); + } const auto& frame = ppf->frames.back(); const int row_size = input.dataWindow().size().x + 1; @@ -192,10 +225,9 @@ Status DecodeImageEXR(Span bytes, const ColorHints& color_hints, } ppf->info.intensity_target = intensity_target; return true; -#else - return false; -#endif } } // namespace extras } // namespace jxl + +#endif // JPEGXL_ENABLE_EXR diff --git a/third_party/jpeg-xl/lib/extras/dec/exr.h b/third_party/jpeg-xl/lib/extras/dec/exr.h index 0605cbba06ee2..65078d030ff97 100644 --- a/third_party/jpeg-xl/lib/extras/dec/exr.h +++ b/third_party/jpeg-xl/lib/extras/dec/exr.h @@ -8,6 +8,8 @@ // Decodes OpenEXR images in memory. +#include + #include "lib/extras/dec/color_hints.h" #include "lib/extras/packed_image.h" #include "lib/jxl/base/data_parallel.h" diff --git a/third_party/jpeg-xl/lib/extras/dec/gif.cc b/third_party/jpeg-xl/lib/extras/dec/gif.cc index d35202377391f..a87beb901acf7 100644 --- a/third_party/jpeg-xl/lib/extras/dec/gif.cc +++ b/third_party/jpeg-xl/lib/extras/dec/gif.cc @@ -5,19 +5,22 @@ #include "lib/extras/dec/gif.h" +#include "lib/jxl/base/status.h" + #if JPEGXL_ENABLE_GIF #include #endif #include -#include +#include #include #include #include #include "lib/extras/size_constraints.h" #include "lib/jxl/base/compiler_specific.h" -#include "lib/jxl/sanitizers.h" +#include "lib/jxl/base/rect.h" +#include "lib/jxl/base/sanitizers.h" namespace jxl { namespace extras { @@ -42,19 +45,22 @@ struct PackedRgb { uint8_t r, g, b; }; -void ensure_have_alpha(PackedFrame* frame) { - if (!frame->extra_channels.empty()) return; +Status ensure_have_alpha(PackedFrame* frame) { + if (!frame->extra_channels.empty()) return true; const JxlPixelFormat alpha_format{ /*num_channels=*/1u, /*data_type=*/JXL_TYPE_UINT8, /*endianness=*/JXL_NATIVE_ENDIAN, /*align=*/0, }; - frame->extra_channels.emplace_back(frame->color.xsize, frame->color.ysize, - alpha_format); + JXL_ASSIGN_OR_RETURN(PackedImage image, + PackedImage::Create(frame->color.xsize, + frame->color.ysize, alpha_format)); + frame->extra_channels.emplace_back(std::move(image)); // We need to set opaque-by-default. std::fill_n(static_cast(frame->extra_channels[0].pixels()), frame->color.xsize * frame->color.ysize, 255u); + return true; } } // namespace #endif @@ -81,7 +87,7 @@ Status DecodeImageGIF(Span bytes, const ColorHints& color_hints, n = state->bytes.size(); } memcpy(bytes, state->bytes.data(), n); - state->bytes.remove_prefix(n); + if (!state->bytes.remove_prefix(n)) return 0; return n; }; GifUniquePtr gif(DGifOpen(&state, ReadFromSpan, &error)); @@ -137,7 +143,7 @@ Status DecodeImageGIF(Span bytes, const ColorHints& color_hints, if (gif->ImageCount > 1) { ppf->info.have_animation = JXL_TRUE; - // Delays in GIF are specified in 100ths of a second. + // Delays in GIF are specified in censiseconds. ppf->info.animation.tps_numerator = 100; ppf->info.animation.tps_denominator = 1; } @@ -186,7 +192,9 @@ Status DecodeImageGIF(Span bytes, const ColorHints& color_hints, } const PackedRgba background_rgba{background_color.Red, background_color.Green, background_color.Blue, 0}; - PackedFrame canvas(gif->SWidth, gif->SHeight, canvas_format); + JXL_ASSIGN_OR_RETURN( + PackedFrame canvas, + PackedFrame::Create(gif->SWidth, gif->SHeight, canvas_format)); std::fill_n(static_cast(canvas.color.pixels()), canvas.color.xsize * canvas.color.ysize, background_rgba); Rect canvas_rect{0, 0, canvas.color.xsize, canvas.color.ysize}; @@ -230,26 +238,33 @@ Status DecodeImageGIF(Span bytes, const ColorHints& color_hints, } // Allocates the frame buffer. - ppf->frames.emplace_back(total_rect.xsize(), total_rect.ysize(), - packed_frame_format); + { + JXL_ASSIGN_OR_RETURN( + PackedFrame frame, + PackedFrame::Create(total_rect.xsize(), total_rect.ysize(), + packed_frame_format)); + ppf->frames.emplace_back(std::move(frame)); + } + PackedFrame* frame = &ppf->frames.back(); // We cannot tell right from the start whether there will be a // need for an alpha channel. This is discovered only as soon as // we see a transparent pixel. We hence initialize alpha lazily. - auto set_pixel_alpha = [&frame](size_t x, size_t y, uint8_t a) { + auto set_pixel_alpha = [&frame](size_t x, size_t y, uint8_t a) -> Status { // If we do not have an alpha-channel and a==255 (fully opaque), // we can skip setting this pixel-value and rely on // "no alpha channel = no transparency". - if (a == 255 && !frame->extra_channels.empty()) return; - ensure_have_alpha(frame); + if (a == 255 && !frame->extra_channels.empty()) return true; + JXL_RETURN_IF_ERROR(ensure_have_alpha(frame)); static_cast( frame->extra_channels[0].pixels())[y * frame->color.xsize + x] = a; + return true; }; const ColorMapObject* const color_map = image.ImageDesc.ColorMap ? image.ImageDesc.ColorMap : gif->SColorMap; - JXL_CHECK(color_map); + JXL_ENSURE(color_map); msan::UnpoisonMemory(color_map, sizeof(*color_map)); msan::UnpoisonMemory(color_map->Colors, sizeof(*color_map->Colors) * color_map->ColorCount); @@ -301,8 +316,10 @@ Status DecodeImageGIF(Span bytes, const ColorHints& color_hints, } // Update the canvas by creating a copy first. - PackedImage new_canvas_image(canvas.color.xsize, canvas.color.ysize, - canvas.color.format); + JXL_ASSIGN_OR_RETURN( + PackedImage new_canvas_image, + PackedImage::Create(canvas.color.xsize, canvas.color.ysize, + canvas.color.format)); memcpy(new_canvas_image.pixels(), canvas.color.pixels(), new_canvas_image.pixels_size); for (size_t y = 0, byte_index = 0; y < image_rect.ysize(); ++y) { @@ -338,7 +355,7 @@ Status DecodeImageGIF(Span bytes, const ColorHints& color_hints, row_out[x].r = row_in[x].r; row_out[x].g = row_in[x].g; row_out[x].b = row_in[x].b; - set_pixel_alpha(x, y, row_in[x].a); + JXL_RETURN_IF_ERROR(set_pixel_alpha(x, y, row_in[x].a)); } } } else { @@ -355,14 +372,14 @@ Status DecodeImageGIF(Span bytes, const ColorHints& color_hints, row[x].r = 0; row[x].g = 0; row[x].b = 0; - set_pixel_alpha(x, y, 0); + JXL_RETURN_IF_ERROR(set_pixel_alpha(x, y, 0)); continue; } GifColorType color = color_map->Colors[byte]; row[x].r = color.Red; row[x].g = color.Green; row[x].b = color.Blue; - set_pixel_alpha(x, y, 255); + JXL_RETURN_IF_ERROR(set_pixel_alpha(x, y, 255)); } } } @@ -402,7 +419,7 @@ Status DecodeImageGIF(Span bytes, const ColorHints& color_hints, } if (seen_alpha) { for (PackedFrame& frame : ppf->frames) { - ensure_have_alpha(&frame); + JXL_RETURN_IF_ERROR(ensure_have_alpha(&frame)); } } return true; diff --git a/third_party/jpeg-xl/lib/extras/dec/jpegli.cc b/third_party/jpeg-xl/lib/extras/dec/jpegli.cc index 957c405023e8a..c307105139173 100644 --- a/third_party/jpeg-xl/lib/extras/dec/jpegli.cc +++ b/third_party/jpeg-xl/lib/extras/dec/jpegli.cc @@ -6,16 +6,17 @@ #include "lib/extras/dec/jpegli.h" #include -#include #include -#include +#include +#include #include #include #include "lib/jpegli/decode.h" +#include "lib/jxl/base/compiler_specific.h" +#include "lib/jxl/base/sanitizers.h" #include "lib/jxl/base/status.h" -#include "lib/jxl/sanitizers.h" namespace jxl { namespace extras { @@ -114,25 +115,26 @@ void MyErrorExit(j_common_ptr cinfo) { } void MyOutputMessage(j_common_ptr cinfo) { -#if JXL_DEBUG_WARNING == 1 - char buf[JMSG_LENGTH_MAX + 1]; - (*cinfo->err->format_message)(cinfo, buf); - buf[JMSG_LENGTH_MAX] = 0; - JXL_WARNING("%s", buf); -#endif + if (JXL_IS_DEBUG_BUILD) { + char buf[JMSG_LENGTH_MAX + 1]; + (*cinfo->err->format_message)(cinfo, buf); + buf[JMSG_LENGTH_MAX] = 0; + JXL_WARNING("%s", buf); + } } -void UnmapColors(uint8_t* row, size_t xsize, int components, - JSAMPARRAY colormap, size_t num_colors) { - JXL_CHECK(colormap != nullptr); +Status UnmapColors(uint8_t* row, size_t xsize, int components, + JSAMPARRAY colormap, size_t num_colors) { + JXL_ENSURE(colormap != nullptr); std::vector tmp(xsize * components); for (size_t x = 0; x < xsize; ++x) { - JXL_CHECK(row[x] < num_colors); + JXL_ENSURE(row[x] < num_colors); for (int c = 0; c < components; ++c) { tmp[x * components + c] = colormap[c][row[x]]; } } memcpy(row, tmp.data(), tmp.size()); + return true; } } // namespace @@ -181,7 +183,9 @@ Status DecodeJpeg(const std::vector& compressed, } int nbcomp = cinfo.num_components; if (nbcomp != 1 && nbcomp != 3) { - return failure("unsupported number of components in JPEG"); + std::string msg = + "unsupported number of components in JPEG: " + std::to_string(nbcomp); + return failure(msg.c_str()); } if (dparams.force_rgb) { cinfo.out_color_space = JCS_RGB; @@ -246,11 +250,17 @@ Status DecodeJpeg(const std::vector& compressed, }; ppf->frames.clear(); // Allocates the frame buffer. - ppf->frames.emplace_back(cinfo.image_width, cinfo.image_height, format); + { + JXL_ASSIGN_OR_RETURN( + PackedFrame frame, + PackedFrame::Create(cinfo.image_width, cinfo.image_height, format)); + ppf->frames.emplace_back(std::move(frame)); + } const auto& frame = ppf->frames.back(); - JXL_ASSERT(sizeof(JSAMPLE) * cinfo.out_color_components * + JXL_ENSURE(sizeof(JSAMPLE) * cinfo.out_color_components * cinfo.image_width <= frame.color.stride); + if (dparams.num_colors > 0) JXL_ENSURE(cinfo.colormap != nullptr); for (size_t y = 0; y < cinfo.image_height; ++y) { JSAMPROW rows[] = {reinterpret_cast( @@ -258,8 +268,9 @@ Status DecodeJpeg(const std::vector& compressed, frame.color.stride * y)}; jpegli_read_scanlines(&cinfo, rows, 1); if (dparams.num_colors > 0) { - UnmapColors(rows[0], cinfo.output_width, cinfo.out_color_components, - cinfo.colormap, cinfo.actual_number_of_colors); + JXL_RETURN_IF_ERROR( + UnmapColors(rows[0], cinfo.output_width, cinfo.out_color_components, + cinfo.colormap, cinfo.actual_number_of_colors)); } } diff --git a/third_party/jpeg-xl/lib/extras/dec/jpg.cc b/third_party/jpeg-xl/lib/extras/dec/jpg.cc index f938006968432..35f7b51e0c68a 100644 --- a/third_party/jpeg-xl/lib/extras/dec/jpg.cc +++ b/third_party/jpeg-xl/lib/extras/dec/jpg.cc @@ -6,19 +6,19 @@ #include "lib/extras/dec/jpg.h" #if JPEGXL_ENABLE_JPEG -#include -#include +#include "lib/jxl/base/include_jpeglib.h" // NOLINT #endif -#include #include +#include #include #include #include #include "lib/extras/size_constraints.h" +#include "lib/jxl/base/compiler_specific.h" +#include "lib/jxl/base/sanitizers.h" #include "lib/jxl/base/status.h" -#include "lib/jxl/sanitizers.h" namespace jxl { namespace extras { @@ -110,7 +110,7 @@ Status ReadICCProfile(jpeg_decompress_struct* const cinfo, } if (seen_markers_count != num_markers) { - JXL_DASSERT(has_num_markers); + JXL_ENSURE(has_num_markers); return JXL_FAILURE("Incomplete set of ICC chunks"); } @@ -156,25 +156,26 @@ void MyErrorExit(j_common_ptr cinfo) { } void MyOutputMessage(j_common_ptr cinfo) { -#if JXL_DEBUG_WARNING == 1 - char buf[JMSG_LENGTH_MAX + 1]; - (*cinfo->err->format_message)(cinfo, buf); - buf[JMSG_LENGTH_MAX] = 0; - JXL_WARNING("%s", buf); -#endif + if (JXL_IS_DEBUG_BUILD) { + char buf[JMSG_LENGTH_MAX + 1]; + (*cinfo->err->format_message)(cinfo, buf); + buf[JMSG_LENGTH_MAX] = 0; + JXL_WARNING("%s", buf); + } } -void UnmapColors(uint8_t* row, size_t xsize, int components, - JSAMPARRAY colormap, size_t num_colors) { - JXL_CHECK(colormap != nullptr); +Status UnmapColors(uint8_t* row, size_t xsize, int components, + JSAMPARRAY colormap, size_t num_colors) { + JXL_ENSURE(colormap != nullptr); std::vector tmp(xsize * components); for (size_t x = 0; x < xsize; ++x) { - JXL_CHECK(row[x] < num_colors); + JXL_ENSURE(row[x] < num_colors); for (int c = 0; c < components; ++c) { tmp[x * components + c] = colormap[c][row[x]]; } } memcpy(row, tmp.data(), tmp.size()); + return true; } } // namespace @@ -268,7 +269,7 @@ Status DecodeImageJPG(const Span bytes, ppf->info.ysize = cinfo.image_height; // Original data is uint, so exponent_bits_per_sample = 0. ppf->info.bits_per_sample = BITS_IN_JSAMPLE; - JXL_ASSERT(BITS_IN_JSAMPLE == 8 || BITS_IN_JSAMPLE == 16); + static_assert(BITS_IN_JSAMPLE == 8 || BITS_IN_JSAMPLE == 16); ppf->info.exponent_bits_per_sample = 0; ppf->info.uses_original_profile = JXL_TRUE; @@ -287,7 +288,7 @@ Status DecodeImageJPG(const Span bytes, } jpeg_start_decompress(&cinfo); - JXL_ASSERT(cinfo.out_color_components == nbcomp); + JXL_ENSURE(cinfo.out_color_components == nbcomp); JxlDataType data_type = ppf->info.bits_per_sample <= 8 ? JXL_TYPE_UINT8 : JXL_TYPE_UINT16; @@ -299,9 +300,14 @@ Status DecodeImageJPG(const Span bytes, }; ppf->frames.clear(); // Allocates the frame buffer. - ppf->frames.emplace_back(cinfo.image_width, cinfo.image_height, format); + { + JXL_ASSIGN_OR_RETURN( + PackedFrame frame, + PackedFrame::Create(cinfo.image_width, cinfo.image_height, format)); + ppf->frames.emplace_back(std::move(frame)); + } const auto& frame = ppf->frames.back(); - JXL_ASSERT(sizeof(JSAMPLE) * cinfo.out_color_components * + JXL_ENSURE(sizeof(JSAMPLE) * cinfo.out_color_components * cinfo.image_width <= frame.color.stride); @@ -315,6 +321,9 @@ Status DecodeImageJPG(const Span bytes, cinfo.actual_number_of_colors * sizeof(JSAMPLE)); } } + if (dparams && dparams->num_colors > 0) { + JXL_ENSURE(cinfo.colormap != nullptr); + } for (size_t y = 0; y < cinfo.image_height; ++y) { JSAMPROW rows[] = {reinterpret_cast( static_cast(frame.color.pixels()) + @@ -323,8 +332,9 @@ Status DecodeImageJPG(const Span bytes, msan::UnpoisonMemory(rows[0], sizeof(JSAMPLE) * cinfo.output_components * cinfo.image_width); if (dparams && dparams->num_colors > 0) { - UnmapColors(rows[0], cinfo.output_width, cinfo.out_color_components, - cinfo.colormap, cinfo.actual_number_of_colors); + JXL_RETURN_IF_ERROR( + UnmapColors(rows[0], cinfo.output_width, cinfo.out_color_components, + cinfo.colormap, cinfo.actual_number_of_colors)); } } diff --git a/third_party/jpeg-xl/lib/extras/dec/jxl.cc b/third_party/jpeg-xl/lib/extras/dec/jxl.cc index 576c8f900f48e..1120dedc30cdb 100644 --- a/third_party/jpeg-xl/lib/extras/dec/jxl.cc +++ b/third_party/jpeg-xl/lib/extras/dec/jxl.cc @@ -6,14 +6,21 @@ #include "lib/extras/dec/jxl.h" #include +#include #include #include #include -#include +#include // PRIu32 +#include +#include +#include +#include +#include #include "lib/extras/common.h" #include "lib/extras/dec/color_description.h" +#include "lib/jxl/base/common.h" #include "lib/jxl/base/exif.h" #include "lib/jxl/base/printf_macros.h" #include "lib/jxl/base/status.h" @@ -22,17 +29,27 @@ namespace jxl { namespace extras { namespace { +#define QUIT(M) \ + fprintf(stderr, "%s\n", M); \ + return false; + struct BoxProcessor { explicit BoxProcessor(JxlDecoder* dec) : dec_(dec) { Reset(); } - void InitializeOutput(std::vector* out) { - JXL_ASSERT(out != nullptr); + bool InitializeOutput(std::vector* out) { + if (out == nullptr) { + fprintf(stderr, "internal: out == nullptr\n"); + return false; + } box_data_ = out; - AddMoreOutput(); + return AddMoreOutput(); } bool AddMoreOutput() { - JXL_ASSERT(box_data_ != nullptr); + if (box_data_ == nullptr) { + fprintf(stderr, "internal: box_data_ == nullptr\n"); + return false; + } Flush(); static const size_t kBoxOutputChunkSize = 1 << 16; box_data_->resize(box_data_->size() + kBoxOutputChunkSize); @@ -118,7 +135,7 @@ bool DecodeImageJXL(const uint8_t* bytes, size_t bytes_size, // silently return false if this is not a JXL file if (sig == JXL_SIG_INVALID) return false; - auto decoder = JxlDecoderMake(/*memory_manager=*/nullptr); + auto decoder = JxlDecoderMake(dparams.memory_manager); JxlDecoder* dec = decoder.get(); ppf->frames.clear(); @@ -211,7 +228,7 @@ bool DecodeImageJXL(const uint8_t* bytes, size_t bytes_size, return false; } uint32_t progression_index = 0; - bool codestream_done = accepted_formats.empty(); + bool codestream_done = jpeg_bytes == nullptr && accepted_formats.empty(); BoxProcessor boxes(dec); for (;;) { JxlDecoderStatus status = JxlDecoderProcessInput(dec); @@ -252,14 +269,20 @@ bool DecodeImageJXL(const uint8_t* bytes, size_t bytes_size, box_data = &ppf->metadata.iptc; } else if (memcmp(box_type, "jumb", 4) == 0) { box_data = &ppf->metadata.jumbf; + } else if (memcmp(box_type, "jhgm", 4) == 0) { + box_data = &ppf->metadata.jhgm; } else if (memcmp(box_type, "xml ", 4) == 0) { box_data = &ppf->metadata.xmp; } if (box_data) { - boxes.InitializeOutput(box_data); + if (!boxes.InitializeOutput(box_data)) { + return false; + } } } else if (status == JXL_DEC_BOX_NEED_MORE_OUTPUT) { - boxes.AddMoreOutput(); + if (!boxes.AddMoreOutput()) { + return false; + } } else if (status == JXL_DEC_JPEG_RECONSTRUCTION) { can_reconstruct_jpeg = true; // Decoding to JPEG. @@ -270,7 +293,10 @@ bool DecodeImageJXL(const uint8_t* bytes, size_t bytes_size, return false; } } else if (status == JXL_DEC_JPEG_NEED_MORE_OUTPUT) { - JXL_ASSERT(jpeg_bytes != nullptr); // Help clang-tidy. + if (jpeg_bytes == nullptr) { + fprintf(stderr, "internal: jpeg_bytes == nullptr\n"); + return false; + } // Decoded a chunk to JPEG. size_t used_jpeg_output = jpeg_data_chunk.size() - JxlDecoderReleaseJPEGBuffer(dec); @@ -392,7 +418,12 @@ bool DecodeImageJXL(const uint8_t* bytes, size_t bytes_size, } } } else if (status == JXL_DEC_FRAME) { - jxl::extras::PackedFrame frame(ppf->info.xsize, ppf->info.ysize, format); + auto frame_or = jxl::extras::PackedFrame::Create(ppf->info.xsize, + ppf->info.ysize, format); + JXL_ASSIGN_OR_QUIT(jxl::extras::PackedFrame frame, + jxl::extras::PackedFrame::Create( + ppf->info.xsize, ppf->info.ysize, format), + "Failed to create image frame."); if (JXL_DEC_SUCCESS != JxlDecoderGetFrameHeader(dec, &frame.frame_info)) { fprintf(stderr, "JxlDecoderGetFrameHeader failed\n"); return false; @@ -431,9 +462,13 @@ bool DecodeImageJXL(const uint8_t* bytes, size_t bytes_size, fprintf(stderr, "JxlDecoderPreviewOutBufferSize failed\n"); return false; } - ppf->preview_frame = std::unique_ptr( - new jxl::extras::PackedFrame(ppf->info.preview.xsize, - ppf->info.preview.ysize, format)); + JXL_ASSIGN_OR_QUIT( + jxl::extras::PackedImage preview_image, + jxl::extras::PackedImage::Create(ppf->info.preview.xsize, + ppf->info.preview.ysize, format), + "Failed to create preview image."); + ppf->preview_frame = + jxl::make_unique(std::move(preview_image)); if (buffer_size != ppf->preview_frame->color.pixels_size) { fprintf(stderr, "Invalid out buffer size %" PRIuS " %" PRIuS "\n", buffer_size, ppf->preview_frame->color.pixels_size); @@ -500,8 +535,11 @@ bool DecodeImageJXL(const uint8_t* bytes, size_t bytes_size, JxlPixelFormat ec_format = format; ec_format.num_channels = 1; for (auto& eci : ppf->extra_channels_info) { - frame.extra_channels.emplace_back(ppf->info.xsize, ppf->info.ysize, - ec_format); + JXL_ASSIGN_OR_QUIT(jxl::extras::PackedImage image, + jxl::extras::PackedImage::Create( + ppf->info.xsize, ppf->info.ysize, ec_format), + "Failed to create extra channel image."); + frame.extra_channels.emplace_back(std::move(image)); auto& ec = frame.extra_channels.back(); size_t buffer_size; if (JXL_DEC_SUCCESS != JxlDecoderExtraChannelBufferSize( diff --git a/third_party/jpeg-xl/lib/extras/dec/jxl.h b/third_party/jpeg-xl/lib/extras/dec/jxl.h index 5f4ed7f683800..7c80280c033ad 100644 --- a/third_party/jpeg-xl/lib/extras/dec/jxl.h +++ b/third_party/jpeg-xl/lib/extras/dec/jxl.h @@ -8,10 +8,12 @@ // Decodes JPEG XL images in memory. +#include #include #include -#include +#include +#include #include #include #include @@ -38,6 +40,9 @@ struct JXLDecompressParams { JxlParallelRunner runner; void* runner_opaque = nullptr; + // If memory_manager is set, decoder uses it. + JxlMemoryManager* memory_manager = nullptr; + // Whether truncated input should be treated as an error. bool allow_partial_input = false; diff --git a/third_party/jpeg-xl/lib/extras/dec/pgx.cc b/third_party/jpeg-xl/lib/extras/dec/pgx.cc index 76a6f06413aba..4499069d7708b 100644 --- a/third_party/jpeg-xl/lib/extras/dec/pgx.cc +++ b/third_party/jpeg-xl/lib/extras/dec/pgx.cc @@ -150,7 +150,7 @@ Status DecodeImagePGX(const Span bytes, const SizeConstraints* constraints) { Parser parser(bytes); HeaderPGX header = {}; - const uint8_t* pos; + const uint8_t* pos = nullptr; if (!parser.ParseHeader(&header, &pos)) return false; JXL_RETURN_IF_ERROR( VerifyDimensions(constraints, header.xsize, header.ysize)); @@ -188,7 +188,12 @@ Status DecodeImagePGX(const Span bytes, }; ppf->frames.clear(); // Allocates the frame buffer. - ppf->frames.emplace_back(header.xsize, header.ysize, format); + { + JXL_ASSIGN_OR_RETURN( + PackedFrame frame, + PackedFrame::Create(header.xsize, header.ysize, format)); + ppf->frames.emplace_back(std::move(frame)); + } const auto& frame = ppf->frames.back(); size_t pgx_remaining_size = bytes.data() + bytes.size() - pos; if (pgx_remaining_size < frame.color.pixels_size) { diff --git a/third_party/jpeg-xl/lib/extras/dec/pgx_test.cc b/third_party/jpeg-xl/lib/extras/dec/pgx_test.cc index 5dbc3149a2cd7..9370e5d5ae2bf 100644 --- a/third_party/jpeg-xl/lib/extras/dec/pgx_test.cc +++ b/third_party/jpeg-xl/lib/extras/dec/pgx_test.cc @@ -5,10 +5,17 @@ #include "lib/extras/dec/pgx.h" +#include #include +#include +#include "lib/extras/packed_image.h" #include "lib/extras/packed_image_convert.h" +#include "lib/jxl/base/span.h" #include "lib/jxl/image_bundle.h" +#include "lib/jxl/image_ops.h" +#include "lib/jxl/test_memory_manager.h" +#include "lib/jxl/test_utils.h" #include "lib/jxl/testing.h" namespace jxl { @@ -26,7 +33,7 @@ TEST(CodecPGXTest, Test8bits) { ThreadPool* pool = nullptr; EXPECT_TRUE(DecodeImagePGX(MakeSpan(pgx.c_str()), ColorHints(), &ppf)); - CodecInOut io; + CodecInOut io{jxl::test::MemoryManager()}; EXPECT_TRUE(ConvertPackedPixelFileToCodecInOut(ppf, pool, &io)); ScaleImage(255.f, io.Main().color()); @@ -53,7 +60,7 @@ TEST(CodecPGXTest, Test16bits) { ThreadPool* pool = nullptr; EXPECT_TRUE(DecodeImagePGX(MakeSpan(pgx.c_str()), ColorHints(), &ppf)); - CodecInOut io; + CodecInOut io{jxl::test::MemoryManager()}; EXPECT_TRUE(ConvertPackedPixelFileToCodecInOut(ppf, pool, &io)); ScaleImage(255.f, io.Main().color()); diff --git a/third_party/jpeg-xl/lib/extras/dec/pnm.cc b/third_party/jpeg-xl/lib/extras/dec/pnm.cc index a2a66d36d9c6e..587cd189a9d04 100644 --- a/third_party/jpeg-xl/lib/extras/dec/pnm.cc +++ b/third_party/jpeg-xl/lib/extras/dec/pnm.cc @@ -5,17 +5,18 @@ #include "lib/extras/dec/pnm.h" -#include -#include +#include #include +#include #include -#include +#include +#include -#include "jxl/encode.h" #include "lib/extras/size_constraints.h" #include "lib/jxl/base/bits.h" -#include "lib/jxl/base/compiler_specific.h" +#include "lib/jxl/base/c_callback_support.h" +#include "lib/jxl/base/span.h" #include "lib/jxl/base/status.h" namespace jxl { @@ -226,6 +227,10 @@ class Parser { header->ec_types.push_back(JXL_CHANNEL_CFA); } else if (MatchString("Thermal")) { header->ec_types.push_back(JXL_CHANNEL_THERMAL); + } else if (MatchString("Unknown")) { + header->ec_types.push_back(JXL_CHANNEL_UNKNOWN); + } else if (MatchString("Optional")) { + header->ec_types.push_back(JXL_CHANNEL_OPTIONAL); } else { return JXL_FAILURE("PAM: unknown TUPLTYPE"); } @@ -314,10 +319,6 @@ class Parser { const uint8_t* const end_; }; -Span MakeSpan(const char* str) { - return Bytes(reinterpret_cast(str), strlen(str)); -} - } // namespace struct PNMChunkedInputFrame { @@ -332,7 +333,7 @@ struct PNMChunkedInputFrame { METHOD_TO_C_CALLBACK(&PNMChunkedInputFrame::ReleaseCurrentData)}; } - void GetColorChannelsPixelFormat(JxlPixelFormat* pixel_format) { + void /* NOLINT */ GetColorChannelsPixelFormat(JxlPixelFormat* pixel_format) { *pixel_format = format; } @@ -349,13 +350,18 @@ struct PNMChunkedInputFrame { void GetExtraChannelPixelFormat(size_t ec_index, JxlPixelFormat* pixel_format) { - JXL_ABORT("Not implemented"); + (void)this; + *pixel_format = {}; + JXL_DEBUG_ABORT("Not implemented"); } const void* GetExtraChannelDataAt(size_t ec_index, size_t xpos, size_t ypos, size_t xsize, size_t ysize, size_t* row_offset) { - JXL_ABORT("Not implemented"); + (void)this; + *row_offset = 0; + JXL_DEBUG_ABORT("Not implemented"); + return nullptr; } void ReleaseCurrentData(const void* buffer) {} @@ -391,8 +397,8 @@ StatusOr ChunkedPNMDecoder::Init(const char* path) { const size_t num_channels = dec.header_.is_gray ? 1 : 3; const size_t bytes_per_pixel = num_channels * bytes_per_channel; size_t row_size = dec.header_.xsize * bytes_per_pixel; - if (header.ysize * row_size + dec.data_start_ < size) { - return JXL_FAILURE("Invalid ppm"); + if (size < header.ysize * row_size + dec.data_start_) { + return JXL_FAILURE("PNM file too small"); } return dec; } @@ -473,7 +479,7 @@ Status DecodeImagePNM(const Span bytes, ppf->info.num_extra_channels = num_alpha_channels + header.ec_types.size(); for (auto type : header.ec_types) { - PackedExtraChannel pec; + PackedExtraChannel pec = {}; pec.ec_info.bits_per_sample = ppf->info.bits_per_sample; pec.ec_info.type = type; ppf->extra_channels_info.emplace_back(std::move(pec)); @@ -499,10 +505,18 @@ Status DecodeImagePNM(const Span bytes, }; const JxlPixelFormat ec_format{1, format.data_type, format.endianness, 0}; ppf->frames.clear(); - ppf->frames.emplace_back(header.xsize, header.ysize, format); + { + JXL_ASSIGN_OR_RETURN( + PackedFrame frame, + PackedFrame::Create(header.xsize, header.ysize, format)); + ppf->frames.emplace_back(std::move(frame)); + } auto* frame = &ppf->frames.back(); for (size_t i = 0; i < header.ec_types.size(); ++i) { - frame->extra_channels.emplace_back(header.xsize, header.ysize, ec_format); + JXL_ASSIGN_OR_RETURN( + PackedImage ec, + PackedImage::Create(header.xsize, header.ysize, ec_format)); + frame->extra_channels.emplace_back(std::move(ec)); } size_t pnm_remaining_size = bytes.data() + bytes.size() - pos; if (pnm_remaining_size < frame->color.pixels_size) { @@ -523,6 +537,7 @@ Status DecodeImagePNM(const Span bytes, memcpy(row_out, row_in, frame->color.stride); } } else { + JXL_RETURN_IF_ERROR(PackedImage::ValidateDataType(data_type)); size_t pwidth = PackedImage::BitsPerChannel(data_type) / 8; for (size_t y = 0; y < header.ysize; ++y) { for (size_t x = 0; x < header.xsize; ++x) { @@ -537,42 +552,19 @@ Status DecodeImagePNM(const Span bytes, } } } + if (ppf->info.exponent_bits_per_sample == 0) { + ppf->input_bitdepth.type = JXL_BIT_DEPTH_FROM_CODESTREAM; + } return true; } -void TestCodecPNM() { - size_t u = 77777; // Initialized to wrong value. - double d = 77.77; -// Failing to parse invalid strings results in a crash if `JXL_CRASH_ON_ERROR` -// is defined and hence the tests fail. Therefore we only run these tests if -// `JXL_CRASH_ON_ERROR` is not defined. -#ifndef JXL_CRASH_ON_ERROR - JXL_CHECK(false == Parser(MakeSpan("")).ParseUnsigned(&u)); - JXL_CHECK(false == Parser(MakeSpan("+")).ParseUnsigned(&u)); - JXL_CHECK(false == Parser(MakeSpan("-")).ParseUnsigned(&u)); - JXL_CHECK(false == Parser(MakeSpan("A")).ParseUnsigned(&u)); - - JXL_CHECK(false == Parser(MakeSpan("")).ParseSigned(&d)); - JXL_CHECK(false == Parser(MakeSpan("+")).ParseSigned(&d)); - JXL_CHECK(false == Parser(MakeSpan("-")).ParseSigned(&d)); - JXL_CHECK(false == Parser(MakeSpan("A")).ParseSigned(&d)); -#endif - JXL_CHECK(true == Parser(MakeSpan("1")).ParseUnsigned(&u)); - JXL_CHECK(u == 1); - - JXL_CHECK(true == Parser(MakeSpan("32")).ParseUnsigned(&u)); - JXL_CHECK(u == 32); - - JXL_CHECK(true == Parser(MakeSpan("1")).ParseSigned(&d)); - JXL_CHECK(d == 1.0); - JXL_CHECK(true == Parser(MakeSpan("+2")).ParseSigned(&d)); - JXL_CHECK(d == 2.0); - JXL_CHECK(true == Parser(MakeSpan("-3")).ParseSigned(&d)); - JXL_CHECK(std::abs(d - -3.0) < 1E-15); - JXL_CHECK(true == Parser(MakeSpan("3.141592")).ParseSigned(&d)); - JXL_CHECK(std::abs(d - 3.141592) < 1E-15); - JXL_CHECK(true == Parser(MakeSpan("-3.141592")).ParseSigned(&d)); - JXL_CHECK(std::abs(d - -3.141592) < 1E-15); +// Exposed for testing. +Status PnmParseSigned(Bytes str, double* v) { + return Parser(str).ParseSigned(v); +} + +Status PnmParseUnsigned(Bytes str, size_t* v) { + return Parser(str).ParseUnsigned(v); } } // namespace extras diff --git a/third_party/jpeg-xl/lib/extras/dec/pnm.h b/third_party/jpeg-xl/lib/extras/dec/pnm.h index b740a79af511b..a6ad14fdc8f6b 100644 --- a/third_party/jpeg-xl/lib/extras/dec/pnm.h +++ b/third_party/jpeg-xl/lib/extras/dec/pnm.h @@ -13,12 +13,10 @@ // TODO(janwas): workaround for incorrect Win64 codegen (cause unknown) #include -#include #include "lib/extras/dec/color_hints.h" #include "lib/extras/mmap.h" #include "lib/extras/packed_image.h" -#include "lib/jxl/base/data_parallel.h" #include "lib/jxl/base/span.h" #include "lib/jxl/base/status.h" @@ -34,8 +32,6 @@ Status DecodeImagePNM(Span bytes, const ColorHints& color_hints, PackedPixelFile* ppf, const SizeConstraints* constraints = nullptr); -void TestCodecPNM(); - struct HeaderPNM { size_t xsize; size_t ysize; diff --git a/third_party/jpeg-xl/lib/extras/enc/apng.cc b/third_party/jpeg-xl/lib/extras/enc/apng.cc index 40aa876e84b32..72139032af020 100644 --- a/third_party/jpeg-xl/lib/extras/enc/apng.cc +++ b/third_party/jpeg-xl/lib/extras/enc/apng.cc @@ -36,8 +36,7 @@ * */ -#include - +#include #include #include @@ -62,7 +61,8 @@ class APNGEncoder : public Encoder { std::vector AcceptedFormats() const override { std::vector formats; for (const uint32_t num_channels : {1, 2, 3, 4}) { - for (const JxlDataType data_type : {JXL_TYPE_UINT8, JXL_TYPE_UINT16}) { + for (const JxlDataType data_type : + {JXL_TYPE_UINT8, JXL_TYPE_UINT16, JXL_TYPE_FLOAT}) { for (JxlEndianness endianness : {JXL_BIG_ENDIAN, JXL_LITTLE_ENDIAN}) { formats.push_back( JxlPixelFormat{num_channels, data_type, endianness, /*align=*/0}); @@ -73,17 +73,30 @@ class APNGEncoder : public Encoder { } Status Encode(const PackedPixelFile& ppf, EncodedImage* encoded_image, ThreadPool* pool) const override { + // Encode main image frames JXL_RETURN_IF_ERROR(VerifyBasicInfo(ppf.info)); encoded_image->icc.clear(); encoded_image->bitstreams.resize(1); - return EncodePackedPixelFileToAPNG(ppf, pool, - &encoded_image->bitstreams.front()); + JXL_RETURN_IF_ERROR(EncodePackedPixelFileToAPNG( + ppf, pool, &encoded_image->bitstreams.front())); + + // Encode extra channels + for (size_t i = 0; i < ppf.extra_channels_info.size(); ++i) { + encoded_image->extra_channel_bitstreams.emplace_back(); + auto& ec_bitstreams = encoded_image->extra_channel_bitstreams.back(); + ec_bitstreams.emplace_back(); + JXL_RETURN_IF_ERROR(EncodePackedPixelFileToAPNG( + ppf, pool, &ec_bitstreams.back(), true, i)); + } + return true; } private: Status EncodePackedPixelFileToAPNG(const PackedPixelFile& ppf, ThreadPool* pool, - std::vector* bytes) const; + std::vector* bytes, + bool encode_extra_channels = false, + size_t extra_channel_index = 0) const; }; void PngWrite(png_structp png_ptr, png_bytep data, png_size_t length) { @@ -127,9 +140,14 @@ class BlobsWriterPNG { } private: + // TODO(eustas): use array static JXL_INLINE char EncodeNibble(const uint8_t nibble) { - JXL_ASSERT(nibble < 16); - return (nibble < 10) ? '0' + nibble : 'a' + nibble - 10; + if (nibble < 16) { + return (nibble < 10) ? '0' + nibble : 'a' + nibble - 10; + } else { + JXL_DEBUG_ABORT("Internal logic error"); + return 0; + } } static Status EncodeBase16(const std::string& type, @@ -146,7 +164,7 @@ class BlobsWriterPNG { base16.push_back(EncodeNibble(bytes[i] & 0x0F)); } base16.push_back('\n'); - JXL_ASSERT(base16.length() == base16_size); + JXL_ENSURE(base16.length() == base16_size); char key[30]; snprintf(key, sizeof(key), "Raw profile type %s", type.c_str()); @@ -247,13 +265,10 @@ void MaybeAddCLLi(const JxlColorEncoding& c_enc, const float intensity_target, png_structp png_ptr, png_infop info_ptr) { if (c_enc.transfer_function != JXL_TRANSFER_FUNCTION_PQ) return; - const uint32_t max_cll = + const uint32_t max_content_light_level = static_cast(10000.f * Clamp1(intensity_target, 0.f, 10000.f)); png_byte chunk_data[8] = {}; - chunk_data[0] = (max_cll >> 24) & 0xFF; - chunk_data[1] = (max_cll >> 16) & 0xFF; - chunk_data[2] = (max_cll >> 8) & 0xFF; - chunk_data[3] = max_cll & 0xFF; + png_save_uint_32(chunk_data, max_content_light_level); // Leave MaxFALL set to 0. png_unknown_chunk chunk; memcpy(chunk.name, "cLLi", 5); @@ -266,15 +281,21 @@ void MaybeAddCLLi(const JxlColorEncoding& c_enc, const float intensity_target, } Status APNGEncoder::EncodePackedPixelFileToAPNG( - const PackedPixelFile& ppf, ThreadPool* pool, - std::vector* bytes) const { - size_t xsize = ppf.info.xsize; - size_t ysize = ppf.info.ysize; - bool has_alpha = ppf.info.alpha_bits != 0; - bool is_gray = ppf.info.num_color_channels == 1; - size_t color_channels = ppf.info.num_color_channels; + const PackedPixelFile& ppf, ThreadPool* pool, std::vector* bytes, + bool encode_extra_channels, size_t extra_channel_index) const { + JxlExtraChannelInfo ec_info{}; + if (encode_extra_channels) { + if (ppf.extra_channels_info.size() <= extra_channel_index) { + return JXL_FAILURE("Invalid index for extra channel"); + } + ec_info = ppf.extra_channels_info[extra_channel_index].ec_info; + } + + bool has_alpha = !encode_extra_channels && (ppf.info.alpha_bits != 0); + bool is_gray = encode_extra_channels || (ppf.info.num_color_channels == 1); + size_t color_channels = + encode_extra_channels ? 1 : ppf.info.num_color_channels; size_t num_channels = color_channels + (has_alpha ? 1 : 0); - size_t num_samples = num_channels * xsize * ysize; if (!ppf.info.have_animation && ppf.frames.size() != 1) { return JXL_FAILURE("Invalid number of frames"); @@ -284,11 +305,27 @@ Status APNGEncoder::EncodePackedPixelFileToAPNG( size_t anim_chunks = 0; for (const auto& frame : ppf.frames) { - JXL_RETURN_IF_ERROR(VerifyPackedImage(frame.color, ppf.info)); - - const PackedImage& color = frame.color; + const PackedImage& color = encode_extra_channels + ? frame.extra_channels[extra_channel_index] + : frame.color; + + size_t xsize = color.xsize; + size_t ysize = color.ysize; + size_t num_samples = num_channels * xsize * ysize; + + uint32_t bits_per_sample = encode_extra_channels ? ec_info.bits_per_sample + : ppf.info.bits_per_sample; + if (!encode_extra_channels) { + JXL_RETURN_IF_ERROR(VerifyPackedImage(color, ppf.info)); + } else { + JXL_RETURN_IF_ERROR(VerifyFormat(color.format)); + JXL_RETURN_IF_ERROR(VerifyBitDepth(color.format.data_type, + bits_per_sample, + ec_info.exponent_bits_per_sample)); + } const JxlPixelFormat format = color.format; const uint8_t* in = reinterpret_cast(color.pixels()); + JXL_RETURN_IF_ERROR(PackedImage::ValidateDataType(format.data_type)); size_t data_bits_per_sample = PackedImage::BitsPerChannel(format.data_type); size_t bytes_per_sample = data_bits_per_sample / 8; size_t out_bytes_per_sample = bytes_per_sample > 1 ? 2 : 1; @@ -297,28 +334,41 @@ Status APNGEncoder::EncodePackedPixelFileToAPNG( std::vector out(out_size); if (format.data_type == JXL_TYPE_UINT8) { - if (ppf.info.bits_per_sample < 8) { - float mul = 255.0 / ((1u << ppf.info.bits_per_sample) - 1); + if (bits_per_sample < 8) { + float mul = 255.0 / ((1u << bits_per_sample) - 1); for (size_t i = 0; i < num_samples; ++i) { - out[i] = static_cast(in[i] * mul + 0.5); + out[i] = static_cast(std::lroundf(in[i] * mul)); } } else { memcpy(out.data(), in, out_size); } } else if (format.data_type == JXL_TYPE_UINT16) { - if (ppf.info.bits_per_sample < 16 || - format.endianness != JXL_BIG_ENDIAN) { - float mul = 65535.0 / ((1u << ppf.info.bits_per_sample) - 1); + if (bits_per_sample < 16 || format.endianness != JXL_BIG_ENDIAN) { + float mul = 65535.0 / ((1u << bits_per_sample) - 1); const uint8_t* p_in = in; uint8_t* p_out = out.data(); for (size_t i = 0; i < num_samples; ++i, p_in += 2, p_out += 2) { uint32_t val = (format.endianness == JXL_BIG_ENDIAN ? LoadBE16(p_in) : LoadLE16(p_in)); - StoreBE16(static_cast(val * mul + 0.5), p_out); + StoreBE16(static_cast(std::lroundf(val * mul)), p_out); } } else { memcpy(out.data(), in, out_size); } + } else if (format.data_type == JXL_TYPE_FLOAT) { + constexpr float kMul = 65535.0; + const uint8_t* p_in = in; + uint8_t* p_out = out.data(); + for (size_t i = 0; i < num_samples; + ++i, p_in += sizeof(float), p_out += 2) { + float val = + Clamp1(format.endianness == JXL_BIG_ENDIAN ? LoadBEFloat(p_in) + : format.endianness == JXL_LITTLE_ENDIAN + ? LoadLEFloat(p_in) + : *reinterpret_cast(p_in), + 0.f, 1.f); + StoreBE16(static_cast(std::lroundf(val * kMul)), p_out); + } } png_structp png_ptr; png_infop info_ptr; @@ -344,7 +394,7 @@ Status APNGEncoder::EncodePackedPixelFileToAPNG( png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - if (count == 0) { + if (count == 0 && !encode_extra_channels) { if (!MaybeAddSRGB(ppf.color_encoding, png_ptr, info_ptr)) { MaybeAddCICP(ppf.color_encoding, png_ptr, info_ptr); if (!ppf.icc.empty()) { @@ -415,10 +465,10 @@ Status APNGEncoder::EncodePackedPixelFileToAPNG( size_t p = pos; while (p + 8 < bytes->size()) { size_t len = png_get_uint_32(bytes->data() + p); - JXL_ASSERT(bytes->operator[](p + 4) == 'I'); - JXL_ASSERT(bytes->operator[](p + 5) == 'D'); - JXL_ASSERT(bytes->operator[](p + 6) == 'A'); - JXL_ASSERT(bytes->operator[](p + 7) == 'T'); + JXL_ENSURE(bytes->operator[](p + 4) == 'I'); + JXL_ENSURE(bytes->operator[](p + 5) == 'D'); + JXL_ENSURE(bytes->operator[](p + 6) == 'A'); + JXL_ENSURE(bytes->operator[](p + 7) == 'T'); fdata.insert(fdata.end(), bytes->data() + p + 8, bytes->data() + p + 8 + len); p += len + 12; diff --git a/third_party/jpeg-xl/lib/extras/enc/encode.cc b/third_party/jpeg-xl/lib/extras/enc/encode.cc index c5e22d8c7e245..71be78e36cc22 100644 --- a/third_party/jpeg-xl/lib/extras/enc/encode.cc +++ b/third_party/jpeg-xl/lib/extras/enc/encode.cc @@ -134,5 +134,13 @@ std::unique_ptr Encoder::FromExtension(std::string extension) { return nullptr; } +std::string ListOfEncodeCodecs() { + std::string list_of_codecs("PPM, PNM, PFM, PAM, PGX"); + if (GetAPNGEncoder()) list_of_codecs.append(", PNG, APNG"); + if (GetJPEGEncoder()) list_of_codecs.append(", JPEG"); + if (GetEXREncoder()) list_of_codecs.append(", EXR"); + return list_of_codecs; +} + } // namespace extras } // namespace jxl diff --git a/third_party/jpeg-xl/lib/extras/enc/encode.h b/third_party/jpeg-xl/lib/extras/enc/encode.h index 2502d9976b622..a71f3b220fc7b 100644 --- a/third_party/jpeg-xl/lib/extras/enc/encode.h +++ b/third_party/jpeg-xl/lib/extras/enc/encode.h @@ -82,6 +82,8 @@ class Encoder { std::unordered_map options_; }; +std::string ListOfEncodeCodecs(); + } // namespace extras } // namespace jxl diff --git a/third_party/jpeg-xl/lib/extras/enc/jpegli.cc b/third_party/jpeg-xl/lib/extras/enc/jpegli.cc index af9c149d7f113..52de317399a6e 100644 --- a/third_party/jpeg-xl/lib/extras/enc/jpegli.cc +++ b/third_party/jpeg-xl/lib/extras/enc/jpegli.cc @@ -9,11 +9,11 @@ #include #include #include -#include #include #include #include +#include #include #include #include @@ -33,7 +33,6 @@ #include "lib/jxl/base/status.h" #include "lib/jxl/color_encoding_internal.h" #include "lib/jxl/enc_xyb.h" -#include "lib/jxl/image.h" #include "lib/jxl/simd_util.h" namespace jxl { @@ -54,6 +53,10 @@ Status VerifyInput(const PackedPixelFile& ppf) { if (ppf.frames.size() != 1) { return JXL_FAILURE("JPEG input must have exactly one frame."); } + if (info.num_color_channels != 1 && info.num_color_channels != 3) { + return JXL_FAILURE("Invalid number of color channels %d", + info.num_color_channels); + } const PackedImage& image = ppf.frames[0].color; JXL_RETURN_IF_ERROR(Encoder::VerifyImageSize(image, info)); if (image.format.data_type == JXL_TYPE_FLOAT16) { @@ -249,32 +252,48 @@ JpegliEndianness ConvertEndianness(JxlEndianness endianness) { } } -void ToFloatRow(const uint8_t* row_in, JxlPixelFormat format, size_t len, - float* row_out) { +void ToFloatRow(const uint8_t* row_in, JxlPixelFormat format, size_t xsize, + size_t c_out, float* row_out) { bool is_little_endian = (format.endianness == JXL_LITTLE_ENDIAN || (format.endianness == JXL_NATIVE_ENDIAN && IsLittleEndian())); static constexpr double kMul8 = 1.0 / 255.0; static constexpr double kMul16 = 1.0 / 65535.0; + const size_t c_in = format.num_channels; if (format.data_type == JXL_TYPE_UINT8) { - for (size_t x = 0; x < len; ++x) { - row_out[x] = row_in[x] * kMul8; + for (size_t x = 0; x < xsize; ++x) { + for (size_t c = 0; c < c_out; ++c) { + const size_t ix = c_in * x + c; + row_out[c_out * x + c] = row_in[ix] * kMul8; + } } } else if (format.data_type == JXL_TYPE_UINT16 && is_little_endian) { - for (size_t x = 0; x < len; ++x) { - row_out[x] = LoadLE16(&row_in[2 * x]) * kMul16; + for (size_t x = 0; x < xsize; ++x) { + for (size_t c = 0; c < c_out; ++c) { + const size_t ix = c_in * x + c; + row_out[c_out * x + c] = LoadLE16(&row_in[2 * ix]) * kMul16; + } } } else if (format.data_type == JXL_TYPE_UINT16 && !is_little_endian) { - for (size_t x = 0; x < len; ++x) { - row_out[x] = LoadBE16(&row_in[2 * x]) * kMul16; + for (size_t x = 0; x < xsize; ++x) { + for (size_t c = 0; c < c_out; ++c) { + const size_t ix = c_in * x + c; + row_out[c_out * x + c] = LoadBE16(&row_in[2 * ix]) * kMul16; + } } } else if (format.data_type == JXL_TYPE_FLOAT && is_little_endian) { - for (size_t x = 0; x < len; ++x) { - row_out[x] = LoadLEFloat(&row_in[4 * x]); + for (size_t x = 0; x < xsize; ++x) { + for (size_t c = 0; c < c_out; ++c) { + const size_t ix = c_in * x + c; + row_out[c_out * x + c] = LoadLEFloat(&row_in[4 * ix]); + } } } else if (format.data_type == JXL_TYPE_FLOAT && !is_little_endian) { - for (size_t x = 0; x < len; ++x) { - row_out[x] = LoadBEFloat(&row_in[4 * x]); + for (size_t x = 0; x < xsize; ++x) { + for (size_t c = 0; c < c_out; ++c) { + const size_t ix = c_in * x + c; + row_out[c_out * x + c] = LoadBEFloat(&row_in[4 * ix]); + } } } } @@ -353,9 +372,6 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings, ColorSpaceTransform c_transform(*JxlGetDefaultCms()); ColorEncoding xyb_encoding; if (jpeg_settings.xyb) { - if (ppf.info.num_color_channels != 3) { - return JXL_FAILURE("Only RGB input is supported in XYB mode."); - } if (HasICCProfile(jpeg_settings.app_data)) { return JXL_FAILURE("APP data ICC profile is not supported in XYB mode."); } @@ -373,13 +389,14 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings, // before the call to setjmp(). std::vector pixels; unsigned char* output_buffer = nullptr; - unsigned long output_size = 0; + unsigned long output_size = 0; // NOLINT std::vector row_bytes; - size_t rowlen = RoundUpTo(ppf.info.xsize, MaxVectorSize()); + const size_t max_vector_size = MaxVectorSize(); + size_t rowlen = RoundUpTo(ppf.info.xsize, max_vector_size); hwy::AlignedFreeUniquePtr xyb_tmp = hwy::AllocateAligned(6 * rowlen); hwy::AlignedFreeUniquePtr premul_absorb = - hwy::AllocateAligned(MaxVectorSize() * 12); + hwy::AllocateAligned(max_vector_size * 12); ComputePremulAbsorb(255.0f, premul_absorb.get()); jpeg_compress_struct cinfo; @@ -402,6 +419,8 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings, cinfo.input_components == 1 ? JCS_GRAYSCALE : JCS_RGB; if (jpeg_settings.xyb) { jpegli_set_xyb_mode(&cinfo); + cinfo.input_components = 3; + cinfo.in_color_space = JCS_RGB; } else if (jpeg_settings.use_std_quant_tables) { jpegli_use_standard_quant_tables(&cinfo); } @@ -435,6 +454,10 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings, cinfo.comp_info[i].h_samp_factor = 1; cinfo.comp_info[i].v_samp_factor = 1; } + } else if (!jpeg_settings.xyb) { + // Default is no chroma subsampling. + cinfo.comp_info[0].h_samp_factor = 1; + cinfo.comp_info[0].v_samp_factor = 1; } jpegli_enable_adaptive_quantization( &cinfo, TO_JXL_BOOL(jpeg_settings.use_adaptive_quantization)); @@ -477,8 +500,8 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings, float* dst_buf = c_transform.BufDst(0); for (size_t y = 0; y < image.ysize; ++y) { // convert to float - ToFloatRow(&pixels[y * image.stride], image.format, 3 * image.xsize, - src_buf); + ToFloatRow(&pixels[y * image.stride], image.format, image.xsize, + info.num_color_channels, src_buf); // convert to linear srgb if (!c_transform.Run(0, src_buf, dst_buf, image.xsize)) { return false; @@ -517,6 +540,8 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings, } } else { for (size_t y = 0; y < info.ysize; ++y) { + JXL_RETURN_IF_ERROR( + PackedImage::ValidateDataType(image.format.data_type)); int bytes_per_channel = PackedImage::BitsPerChannel(image.format.data_type) / 8; int bytes_per_pixel = cinfo.num_components * bytes_per_channel; diff --git a/third_party/jpeg-xl/lib/extras/enc/jpg.cc b/third_party/jpeg-xl/lib/extras/enc/jpg.cc index de0228fc0de97..9b6a83ad05c9e 100644 --- a/third_party/jpeg-xl/lib/extras/enc/jpg.cc +++ b/third_party/jpeg-xl/lib/extras/enc/jpg.cc @@ -6,26 +6,23 @@ #include "lib/extras/enc/jpg.h" #if JPEGXL_ENABLE_JPEG -#include -#include +#include "lib/jxl/base/include_jpeglib.h" // NOLINT #endif -#include #include #include #include +#include #include -#include #include -#include #include #include #include #include "lib/extras/exif.h" #include "lib/jxl/base/common.h" +#include "lib/jxl/base/sanitizers.h" #include "lib/jxl/base/status.h" -#include "lib/jxl/sanitizers.h" #if JPEGXL_ENABLE_SJPEG #include "sjpeg.h" #include "sjpegi.h" @@ -276,7 +273,7 @@ Status EncodeWithLibJpeg(const PackedImage& image, const JxlBasicInfo& info, cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); unsigned char* buffer = nullptr; - unsigned long size = 0; + unsigned long size = 0; // NOLINT jpeg_mem_dest(&cinfo, &buffer, &size); cinfo.image_width = image.xsize; cinfo.image_height = image.ysize; @@ -476,7 +473,7 @@ Status EncodeWithSJpeg(const PackedImage& image, const JxlBasicInfo& info, param.tolerance = params.search_tolerance; param.qmin = params.search_q_min; param.qmax = params.search_q_max; - hook.reset(new MySearchHook()); + hook = jxl::make_unique(); hook->ReadBaseTables(params.custom_base_quant_fn); hook->q_start = params.search_q_start; hook->q_precision = params.search_q_precision; diff --git a/third_party/jpeg-xl/lib/extras/enc/jxl.cc b/third_party/jpeg-xl/lib/extras/enc/jxl.cc index 7787e25bd4179..15f62673161da 100644 --- a/third_party/jpeg-xl/lib/extras/enc/jxl.cc +++ b/third_party/jpeg-xl/lib/extras/enc/jxl.cc @@ -5,10 +5,18 @@ #include "lib/extras/enc/jxl.h" +#include #include #include #include +#include +#include +#include +#include +#include + +#include "lib/extras/packed_image.h" #include "lib/jxl/base/exif.h" namespace jxl { @@ -112,7 +120,7 @@ bool ReadCompressedOutput(JxlEncoder* enc, std::vector* compressed) { bool EncodeImageJXL(const JXLCompressParams& params, const PackedPixelFile& ppf, const std::vector* jpeg_bytes, std::vector* compressed) { - auto encoder = JxlEncoderMake(/*memory_manager=*/nullptr); + auto encoder = JxlEncoderMake(params.memory_manager); JxlEncoder* enc = encoder.get(); if (params.allow_expert_options) { @@ -153,7 +161,8 @@ bool EncodeImageJXL(const JXLCompressParams& params, const PackedPixelFile& ppf, bool has_jpeg_bytes = (jpeg_bytes != nullptr); bool use_boxes = !ppf.metadata.exif.empty() || !ppf.metadata.xmp.empty() || - !ppf.metadata.jumbf.empty() || !ppf.metadata.iptc.empty(); + !ppf.metadata.jhgm.empty() || !ppf.metadata.jumbf.empty() || + !ppf.metadata.iptc.empty(); bool use_container = params.use_container || use_boxes || (has_jpeg_bytes && params.jpeg_store_metadata); @@ -202,7 +211,7 @@ bool EncodeImageJXL(const JXLCompressParams& params, const PackedPixelFile& ppf, fprintf(stderr, "JPEG bitstream reconstruction data could not be created. " "Possibly there is too much tail data.\n" - "Try using --jpeg_store_metadata 0, to losslessly " + "Try using --allow_jpeg_reconstruction 0, to losslessly " "recompress the JPEG image data without bitstream " "reconstruction data.\n"); } else { @@ -223,7 +232,14 @@ bool EncodeImageJXL(const JXLCompressParams& params, const PackedPixelFile& ppf, std::max(num_alpha_channels, ppf.info.num_extra_channels); basic_info.num_color_channels = ppf.info.num_color_channels; const bool lossless = (params.distance == 0); - basic_info.uses_original_profile = TO_JXL_BOOL(lossless); + auto non_perceptual_option = std::find_if( + params.options.begin(), params.options.end(), [](JXLOption option) { + return option.id == + JXL_ENC_FRAME_SETTING_DISABLE_PERCEPTUAL_HEURISTICS; + }); + const bool non_perceptual = non_perceptual_option != params.options.end() && + non_perceptual_option->ival == 1; + basic_info.uses_original_profile = TO_JXL_BOOL(lossless || non_perceptual); if (params.override_bitdepth != 0) { basic_info.bits_per_sample = params.override_bitdepth; basic_info.exponent_bits_per_sample = @@ -245,7 +261,7 @@ bool EncodeImageJXL(const JXLCompressParams& params, const PackedPixelFile& ppf, return false; } if (JXL_ENC_SUCCESS != - JxlEncoderSetFrameBitDepth(settings, ¶ms.input_bitdepth)) { + JxlEncoderSetFrameBitDepth(settings, &ppf.input_bitdepth)) { fprintf(stderr, "JxlEncoderSetFrameBitDepth() failed.\n"); return false; } @@ -291,10 +307,9 @@ bool EncodeImageJXL(const JXLCompressParams& params, const PackedPixelFile& ppf, const char* type; const std::vector& bytes; } boxes[] = { - {"Exif", exif_with_offset}, - {"xml ", ppf.metadata.xmp}, - {"jumb", ppf.metadata.jumbf}, - {"xml ", ppf.metadata.iptc}, + {"Exif", exif_with_offset}, {"xml ", ppf.metadata.xmp}, + {"jumb", ppf.metadata.jumbf}, {"xml ", ppf.metadata.iptc}, + {"jhgm", ppf.metadata.jhgm}, }; for (auto box : boxes) { if (!box.bytes.empty()) { diff --git a/third_party/jpeg-xl/lib/extras/enc/jxl.h b/third_party/jpeg-xl/lib/extras/enc/jxl.h index 186f5f41aa65b..a6573eb129ffa 100644 --- a/third_party/jpeg-xl/lib/extras/enc/jxl.h +++ b/third_party/jpeg-xl/lib/extras/enc/jxl.h @@ -7,11 +7,13 @@ #define LIB_EXTRAS_ENC_JXL_H_ #include +#include #include #include #include -#include +#include +#include #include #include "lib/extras/packed_image.h" @@ -36,32 +38,41 @@ struct JXLOption { struct JXLCompressParams { std::vector options; + // Target butteraugli distance, 0.0 means lossless. float distance = 1.0f; float alpha_distance = 0.0f; + // If set to true, forces container mode. bool use_container = false; + // Whether to enable/disable byte-exact jpeg reconstruction for jpeg inputs. bool jpeg_store_metadata = true; bool jpeg_strip_exif = false; bool jpeg_strip_xmp = false; bool jpeg_strip_jumbf = false; + // Whether to create brob boxes. bool compress_boxes = true; + // Upper bound on the intensity level present in the image in nits (zero means // that the library chooses a default). float intensity_target = 0; int already_downsampled = 1; int upsampling_mode = -1; + // Overrides for bitdepth, codestream level and alpha premultiply. size_t override_bitdepth = 0; int32_t codestream_level = -1; int32_t premultiply = -1; - // Override input buffer interpretation. - JxlBitDepth input_bitdepth = {JXL_BIT_DEPTH_FROM_PIXEL_FORMAT, 0, 0}; - // If runner_opaque is set, the decoder uses this parallel runner. + + // If runner_opaque is set, the encoder uses this parallel runner. JxlParallelRunner runner = JxlThreadParallelRunner; void* runner_opaque = nullptr; + + // If memory_manager is set, encoder uses it. + JxlMemoryManager* memory_manager = nullptr; + JxlEncoderOutputProcessor output_processor = {}; JxlDebugImageCallback debug_image = nullptr; void* debug_image_opaque = nullptr; diff --git a/third_party/jpeg-xl/lib/extras/enc/npy.cc b/third_party/jpeg-xl/lib/extras/enc/npy.cc index 8d9954ef316ad..38777a3535412 100644 --- a/third_party/jpeg-xl/lib/extras/enc/npy.cc +++ b/third_party/jpeg-xl/lib/extras/enc/npy.cc @@ -254,14 +254,14 @@ bool WriteFrameToNPYArray(size_t xsize, size_t ysize, const PackedFrame& frame, size_t sample_size = color.pixel_stride(); size_t offset = y * color.stride + x * sample_size; uint8_t* pixels = reinterpret_cast(color.pixels()); - JXL_ASSERT(offset + sample_size <= color.pixels_size); + JXL_ENSURE(offset + sample_size <= color.pixels_size); Append(out, pixels + offset, sample_size); } for (const auto& ec : frame.extra_channels) { size_t sample_size = ec.pixel_stride(); size_t offset = y * ec.stride + x * sample_size; uint8_t* pixels = reinterpret_cast(ec.pixels()); - JXL_ASSERT(offset + sample_size <= ec.pixels_size); + JXL_ENSURE(offset + sample_size <= ec.pixels_size); Append(out, pixels + offset, sample_size); } } diff --git a/third_party/jpeg-xl/lib/extras/enc/pgx.cc b/third_party/jpeg-xl/lib/extras/enc/pgx.cc index eb8eab4271722..fb47b3e1a97d5 100644 --- a/third_party/jpeg-xl/lib/extras/enc/pgx.cc +++ b/third_party/jpeg-xl/lib/extras/enc/pgx.cc @@ -6,7 +6,8 @@ #include "lib/extras/enc/pgx.h" #include -#include + +#include #include "lib/extras/packed_image.h" #include "lib/jxl/base/byte_order.h" @@ -49,6 +50,7 @@ Status EncodeImagePGX(const PackedFrame& frame, const JxlBasicInfo& info, const PackedImage& color = frame.color; const JxlPixelFormat format = color.format; const uint8_t* in = reinterpret_cast(color.pixels()); + JXL_RETURN_IF_ERROR(PackedImage::ValidateDataType(format.data_type)); size_t data_bits_per_sample = PackedImage::BitsPerChannel(format.data_type); size_t bytes_per_sample = data_bits_per_sample / kBitsPerByte; size_t num_samples = info.xsize * info.ysize; diff --git a/third_party/jpeg-xl/lib/extras/enc/pnm.cc b/third_party/jpeg-xl/lib/extras/enc/pnm.cc index 966611cfca1a2..c4aa8d12eb4d6 100644 --- a/third_party/jpeg-xl/lib/extras/enc/pnm.cc +++ b/third_party/jpeg-xl/lib/extras/enc/pnm.cc @@ -5,28 +5,23 @@ #include "lib/extras/enc/pnm.h" -#include - +#include +#include +#include +#include #include #include #include "lib/extras/packed_image.h" -#include "lib/jxl/base/byte_order.h" -#include "lib/jxl/base/compiler_specific.h" +#include "lib/jxl/base/common.h" #include "lib/jxl/base/printf_macros.h" #include "lib/jxl/base/status.h" -#include "lib/jxl/dec_external_image.h" -#include "lib/jxl/enc_external_image.h" -#include "lib/jxl/enc_image_bundle.h" -#include "lib/jxl/fields.h" // AllDefault -#include "lib/jxl/image.h" -#include "lib/jxl/image_bundle.h" namespace jxl { namespace extras { namespace { -constexpr size_t kMaxHeaderSize = 200; +constexpr size_t kMaxHeaderSize = 2000; class BasePNMEncoder : public Encoder { public: @@ -87,8 +82,8 @@ class PNMEncoder : public BasePNMEncoder { } private: - Status EncodeImage(const PackedImage& image, size_t bits_per_sample, - std::vector* bytes) const { + static Status EncodeImage(const PackedImage& image, size_t bits_per_sample, + std::vector* bytes) { uint32_t maxval = (1u << bits_per_sample) - 1; char type = image.format.num_channels == 1 ? '5' : '6'; char header[kMaxHeaderSize]; @@ -161,8 +156,8 @@ class PFMEncoder : public BasePNMEncoder { } private: - Status EncodeImage(const PackedImage& image, - std::vector* bytes) const { + static Status EncodeImage(const PackedImage& image, + std::vector* bytes) { char type = image.format.num_channels == 1 ? 'f' : 'F'; double scale = image.format.endianness == JXL_LITTLE_ENDIAN ? -1.0 : 1.0; char header[kMaxHeaderSize]; @@ -262,6 +257,7 @@ class PAMEncoder : public BasePNMEncoder { reinterpret_cast(frame.extra_channels[i].pixels()); } uint8_t* out = bytes->data() + pos; + JXL_RETURN_IF_ERROR(PackedImage::ValidateDataType(color.format.data_type)); size_t pwidth = PackedImage::BitsPerChannel(color.format.data_type) / 8; for (size_t y = 0; y < color.ysize; ++y) { for (size_t x = 0; x < color.xsize; ++x) { @@ -299,6 +295,10 @@ class PAMEncoder : public BasePNMEncoder { return std::string("CFA"); case JXL_CHANNEL_THERMAL: return std::string("Thermal"); + case JXL_CHANNEL_UNKNOWN: + return std::string("Unknown"); + case JXL_CHANNEL_OPTIONAL: + return std::string("Optional"); default: return std::string("UNKNOWN"); } diff --git a/third_party/jpeg-xl/lib/extras/gain_map.cc b/third_party/jpeg-xl/lib/extras/gain_map.cc new file mode 100644 index 0000000000000..8cce67161bb84 --- /dev/null +++ b/third_party/jpeg-xl/lib/extras/gain_map.cc @@ -0,0 +1,231 @@ +// Copyright (c) the JPEG XL Project Authors. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include + +#include +#include +#include +#include + +#include "lib/jxl/base/byte_order.h" +#include "lib/jxl/base/common.h" +#include "lib/jxl/color_encoding_internal.h" +#include "lib/jxl/dec_bit_reader.h" +#include "lib/jxl/enc_aux_out.h" +#include "lib/jxl/enc_bit_writer.h" +#include "lib/jxl/fields.h" +#include "lib/jxl/memory_manager_internal.h" + +namespace { + +template +class FixedSizeMemoryManager { + public: + FixedSizeMemoryManager() = default; + + JxlMemoryManager* memory_manager() { return &manager_; } + + private: + static void* FixedSizeMemoryManagerAlloc(void* opaque, size_t capacity) { + auto manager = static_cast*>(opaque); + if (capacity > N + jxl::memory_manager_internal::kAlias) { + return nullptr; + } + return manager->memory_; + } + static void FixedSizeMemoryManagerFree(void* opaque, void* pointer) {} + + uint8_t memory_[N + jxl::memory_manager_internal::kAlias]; + JxlMemoryManager manager_ = { + /*opaque=*/this, + /*alloc=*/&FixedSizeMemoryManagerAlloc, + /*free=*/&FixedSizeMemoryManagerFree, + }; +}; + +} // namespace + +JXL_BOOL JxlGainMapGetBundleSize(const JxlGainMapBundle* map_bundle, + size_t* bundle_size) { + if (map_bundle == nullptr) return JXL_FALSE; + + jxl::ColorEncoding internal_color_encoding; + size_t color_encoding_size = 0; + size_t extension_bits = 0; + if (map_bundle->has_color_encoding) { + JXL_RETURN_IF_ERROR( + internal_color_encoding.FromExternal(map_bundle->color_encoding)); + if (!jxl::Bundle::CanEncode(internal_color_encoding, &extension_bits, + &color_encoding_size)) { + return JXL_FALSE; + } + } + + *bundle_size = + 1 + // size of jhgm_version + 2 + // size_of gain_map_metadata_size + map_bundle->gain_map_metadata_size + // size of gain_map_metadata + 1 + // size of color_encoding_size + jxl::DivCeil(color_encoding_size, 8) + // size of the color_encoding + 4 + // size of compressed_icc_size + map_bundle->alt_icc_size + // size of compressed_icc + map_bundle->gain_map_size; // size of gain map + return JXL_TRUE; +} + +JXL_BOOL JxlGainMapWriteBundle(const JxlGainMapBundle* map_bundle, + uint8_t* output_buffer, + size_t output_buffer_size, + size_t* bytes_written) { + if (map_bundle == nullptr) return JXL_FALSE; + + uint8_t jhgm_version = map_bundle->jhgm_version; + + FixedSizeMemoryManager memory_manager; + jxl::ColorEncoding internal_color_encoding; + jxl::BitWriter color_encoding_writer(memory_manager.memory_manager()); + if (map_bundle->has_color_encoding) { + JXL_RETURN_IF_ERROR( + internal_color_encoding.FromExternal(map_bundle->color_encoding)); + if (!jxl::Bundle::Write(internal_color_encoding, &color_encoding_writer, + jxl::LayerType::Header, nullptr)) { + return JXL_FALSE; + } + } + + color_encoding_writer.ZeroPadToByte(); + + uint64_t cursor = 0; + uint64_t next_cursor = 0; + +#define SAFE_CURSOR_UPDATE(n) \ + do { \ + cursor = next_cursor; \ + if (!jxl::SafeAdd(cursor, n, next_cursor) || \ + next_cursor > output_buffer_size) { \ + return JXL_FALSE; \ + } \ + } while (false) + + SAFE_CURSOR_UPDATE(1); + memcpy(output_buffer + cursor, &jhgm_version, 1); + + SAFE_CURSOR_UPDATE(2); + StoreBE16(map_bundle->gain_map_metadata_size, output_buffer + cursor); + + SAFE_CURSOR_UPDATE(map_bundle->gain_map_metadata_size); + memcpy(output_buffer + cursor, map_bundle->gain_map_metadata, + map_bundle->gain_map_metadata_size); + + jxl::Bytes bytes = color_encoding_writer.GetSpan(); + uint8_t color_enc_size = static_cast(bytes.size()); + if (color_enc_size != bytes.size()) return JXL_FALSE; + SAFE_CURSOR_UPDATE(1); + memcpy(output_buffer + cursor, &color_enc_size, 1); + + SAFE_CURSOR_UPDATE(color_enc_size); + memcpy(output_buffer + cursor, bytes.data(), color_enc_size); + + SAFE_CURSOR_UPDATE(4); + StoreBE32(map_bundle->alt_icc_size, output_buffer + cursor); + + SAFE_CURSOR_UPDATE(map_bundle->alt_icc_size); + memcpy(output_buffer + cursor, map_bundle->alt_icc, map_bundle->alt_icc_size); + + SAFE_CURSOR_UPDATE(map_bundle->gain_map_size); + memcpy(output_buffer + cursor, map_bundle->gain_map, + map_bundle->gain_map_size); + +#undef SAFE_CURSOR_UPDATE + + cursor = next_cursor; + + if (bytes_written != nullptr) + *bytes_written = cursor; // Ensure size_t compatibility + return cursor == output_buffer_size ? JXL_TRUE : JXL_FALSE; +} + +JXL_BOOL JxlGainMapReadBundle(JxlGainMapBundle* map_bundle, + const uint8_t* input_buffer, + const size_t input_buffer_size, + size_t* bytes_read) { + if (map_bundle == nullptr || input_buffer == nullptr || + input_buffer_size == 0) { + return JXL_FALSE; + } + + uint64_t cursor = 0; + uint64_t next_cursor = 0; + +#define SAFE_CURSOR_UPDATE(n) \ + do { \ + cursor = next_cursor; \ + if (!jxl::SafeAdd(cursor, n, next_cursor) || \ + next_cursor > input_buffer_size) { \ + return JXL_FALSE; \ + } \ + } while (false) + + // Read the version byte + SAFE_CURSOR_UPDATE(1); + map_bundle->jhgm_version = input_buffer[cursor]; + + // Read gain_map_metadata_size + SAFE_CURSOR_UPDATE(2); + uint16_t gain_map_metadata_size = LoadBE16(input_buffer + cursor); + + SAFE_CURSOR_UPDATE(gain_map_metadata_size); + map_bundle->gain_map_metadata_size = gain_map_metadata_size; + map_bundle->gain_map_metadata = input_buffer + cursor; + + // Read compressed_color_encoding_size + SAFE_CURSOR_UPDATE(1); + uint8_t compressed_color_encoding_size; + memcpy(&compressed_color_encoding_size, input_buffer + cursor, 1); + + map_bundle->has_color_encoding = (compressed_color_encoding_size > 0); + if (map_bundle->has_color_encoding) { + SAFE_CURSOR_UPDATE(compressed_color_encoding_size); + // Decode color encoding + jxl::Span color_encoding_span( + input_buffer + cursor, compressed_color_encoding_size); + jxl::BitReader color_encoding_reader(color_encoding_span); + jxl::ColorEncoding internal_color_encoding; + if (!jxl::Bundle::Read(&color_encoding_reader, &internal_color_encoding)) { + return JXL_FALSE; + } + JXL_RETURN_IF_ERROR(color_encoding_reader.Close()); + map_bundle->color_encoding = internal_color_encoding.ToExternal(); + } + + // Read compressed_icc_size + SAFE_CURSOR_UPDATE(4); + uint32_t compressed_icc_size = LoadBE32(input_buffer + cursor); + + SAFE_CURSOR_UPDATE(compressed_icc_size); + map_bundle->alt_icc_size = compressed_icc_size; + map_bundle->alt_icc = input_buffer + cursor; + + // Calculate remaining bytes for gain map + cursor = next_cursor; + // This calculation is guaranteed not to underflow because `cursor` is always + // updated to a position within or at the end of `input_buffer` (not beyond). + // Thus, subtracting `cursor` from `input_buffer_size` (the total size of the + // buffer) will always result in a non-negative integer representing the + // remaining buffer size. + map_bundle->gain_map_size = input_buffer_size - cursor; + SAFE_CURSOR_UPDATE(map_bundle->gain_map_size); + map_bundle->gain_map = input_buffer + cursor; + +#undef SAFE_CURSOR_UPDATE + + cursor = next_cursor; + + if (bytes_read != nullptr) { + *bytes_read = cursor; + } + return JXL_TRUE; +} diff --git a/third_party/jpeg-xl/lib/extras/gain_map_test.cc b/third_party/jpeg-xl/lib/extras/gain_map_test.cc new file mode 100644 index 0000000000000..7b4864974c07a --- /dev/null +++ b/third_party/jpeg-xl/lib/extras/gain_map_test.cc @@ -0,0 +1,173 @@ +// Copyright (c) the JPEG XL Project Authors. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "jxl/gain_map.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "lib/jxl/test_utils.h" +#include "lib/jxl/testing.h" + +namespace { + +std::vector GoldenTestGainMap(bool has_icc, bool has_color_encoding) { + // Define the parts of the gain map + uint8_t jhgm_version = 0x00; + std::vector gain_map_metadata_size = {0x00, 0x58}; // 88 in decimal + // TODO(firsching): Replace with more realistic data + std::string first_placeholder = + "placeholder gain map metadata, fill with actual example after (ISO " + "21496-1) is finalized"; + + uint8_t color_encoding_size = has_color_encoding ? 3 : 0; + std::vector color_encoding = {0x50, 0xb4, 0x00}; + + std::vector icc_size = {0x00, 0x00, 0x00, 0x00}; + if (has_icc) { + icc_size = {0x00, 0x00, 0x00, 0x88}; // 136 in decimal + } + std::vector icc_data = jxl::test::GetCompressedIccTestProfile(); + std::string second_placeholder = + "placeholder for an actual naked JPEG XL codestream"; + + // Assemble the gain map + std::vector gain_map; + gain_map.push_back(jhgm_version); + gain_map.insert(gain_map.end(), gain_map_metadata_size.begin(), + gain_map_metadata_size.end()); + gain_map.insert(gain_map.end(), first_placeholder.begin(), + first_placeholder.end()); + gain_map.push_back(color_encoding_size); + if (has_color_encoding) { + gain_map.insert(gain_map.end(), color_encoding.begin(), + color_encoding.end()); + } + gain_map.insert(gain_map.end(), icc_size.begin(), icc_size.end()); + if (has_icc) { + gain_map.insert(gain_map.end(), icc_data.begin(), icc_data.end()); + } + gain_map.insert(gain_map.end(), second_placeholder.begin(), + second_placeholder.end()); + + return gain_map; +} + +} // namespace + +namespace jxl { +namespace { + +struct GainMapTestParams { + bool has_color_encoding; + std::vector icc_data; +}; + +class GainMapTest : public ::testing::TestWithParam {}; + +TEST_P(GainMapTest, GainMapRoundtrip) { + size_t bundle_size; + const GainMapTestParams& params = GetParam(); + std::vector golden_gain_map = + GoldenTestGainMap(!params.icc_data.empty(), params.has_color_encoding); + + JxlGainMapBundle orig_bundle; + // Initialize the bundle with some test data + orig_bundle.jhgm_version = 0; + const char* metadata_str = + "placeholder gain map metadata, fill with actual example after (ISO " + "21496-1) is finalized"; + std::vector gain_map_metadata(metadata_str, + metadata_str + strlen(metadata_str)); + orig_bundle.gain_map_metadata_size = gain_map_metadata.size(); + orig_bundle.gain_map_metadata = gain_map_metadata.data(); + + // Use the ICC profile from the parameter + orig_bundle.has_color_encoding = TO_JXL_BOOL(params.has_color_encoding); + if (orig_bundle.has_color_encoding) { + JxlColorEncoding color_encoding = {}; + JxlColorEncodingSetToLinearSRGB(&color_encoding, /*is_gray=*/JXL_FALSE); + orig_bundle.color_encoding = color_encoding; + } + + std::vector alt_icc(params.icc_data.begin(), params.icc_data.end()); + orig_bundle.alt_icc = alt_icc.data(); + orig_bundle.alt_icc_size = alt_icc.size(); + + const char* gain_map_str = + "placeholder for an actual naked JPEG XL codestream"; + std::vector gain_map(gain_map_str, + gain_map_str + strlen(gain_map_str)); + orig_bundle.gain_map_size = gain_map.size(); + orig_bundle.gain_map = gain_map.data(); + + ASSERT_TRUE(JxlGainMapGetBundleSize(&orig_bundle, &bundle_size)); + EXPECT_EQ(bundle_size, golden_gain_map.size()); + + std::vector buffer(bundle_size); + size_t bytes_written; + ASSERT_TRUE(JxlGainMapWriteBundle(&orig_bundle, buffer.data(), buffer.size(), + &bytes_written)); + EXPECT_EQ(bytes_written, bundle_size); + EXPECT_EQ(buffer[0], orig_bundle.jhgm_version); + EXPECT_EQ(buffer.size(), golden_gain_map.size()); + EXPECT_TRUE( + std::equal(buffer.begin(), buffer.end(), golden_gain_map.begin())); + + JxlGainMapBundle output_bundle; + size_t bytes_read; + ASSERT_TRUE(JxlGainMapReadBundle(&output_bundle, buffer.data(), buffer.size(), + &bytes_read)); + + EXPECT_EQ(output_bundle.gain_map_size, orig_bundle.gain_map_size); + EXPECT_EQ(output_bundle.gain_map_metadata_size, + orig_bundle.gain_map_metadata_size); + EXPECT_EQ(output_bundle.alt_icc_size, orig_bundle.alt_icc_size); + EXPECT_EQ(output_bundle.has_color_encoding, params.has_color_encoding); + EXPECT_EQ(output_bundle.jhgm_version, orig_bundle.jhgm_version); + std::vector output_gain_map_metadata( + output_bundle.gain_map_metadata, + output_bundle.gain_map_metadata + output_bundle.gain_map_metadata_size); + std::vector output_alt_icc( + output_bundle.alt_icc, + output_bundle.alt_icc + output_bundle.alt_icc_size); + std::vector output_gain_map( + output_bundle.gain_map, + output_bundle.gain_map + output_bundle.gain_map_size); + EXPECT_TRUE(std::equal(output_gain_map_metadata.begin(), + output_gain_map_metadata.end(), + gain_map_metadata.begin())); + EXPECT_TRUE(std::equal(output_alt_icc.begin(), output_alt_icc.end(), + alt_icc.begin())); + EXPECT_TRUE(std::equal(output_gain_map.begin(), output_gain_map.end(), + gain_map.begin())); +} + +JXL_GTEST_INSTANTIATE_TEST_SUITE_P( + GainMapTestCases, GainMapTest, + ::testing::Values( + GainMapTestParams{true, std::vector()}, + GainMapTestParams{true, test::GetCompressedIccTestProfile()}, + GainMapTestParams{false, test::GetCompressedIccTestProfile()}, + GainMapTestParams{false, std::vector()}), + [](const testing::TestParamInfo& info) { + std::string name = + "HasColorEncoding" + std::to_string(info.param.has_color_encoding); + + name += "ICCSize" + std::to_string(info.param.icc_data.size()); + + return name; + }); + +} // namespace +} // namespace jxl diff --git a/third_party/jpeg-xl/lib/extras/hlg.cc b/third_party/jpeg-xl/lib/extras/hlg.cc index 125005542b001..d92272052b969 100644 --- a/third_party/jpeg-xl/lib/extras/hlg.cc +++ b/third_party/jpeg-xl/lib/extras/hlg.cc @@ -26,27 +26,27 @@ Status HlgOOTF(ImageBundle* ib, const float gamma, ThreadPool* pool) { JXL_RETURN_IF_ERROR( ib->TransformTo(linear_rec2020, *JxlGetDefaultCms(), pool)); - JXL_RETURN_IF_ERROR(RunOnPool( - pool, 0, ib->ysize(), ThreadPool::NoInit, - [&](const int y, const int thread) { - float* const JXL_RESTRICT rows[3] = {ib->color()->PlaneRow(0, y), - ib->color()->PlaneRow(1, y), - ib->color()->PlaneRow(2, y)}; - for (size_t x = 0; x < ib->xsize(); ++x) { - float& red = rows[0][x]; - float& green = rows[1][x]; - float& blue = rows[2][x]; - const float luminance = - 0.2627f * red + 0.6780f * green + 0.0593f * blue; - const float ratio = std::pow(luminance, gamma - 1); - if (std::isfinite(ratio)) { - red *= ratio; - green *= ratio; - blue *= ratio; - } - } - }, - "HlgOOTF")); + const auto process_row = [&](const int y, const int thread) -> Status { + float* const JXL_RESTRICT rows[3] = {ib->color()->PlaneRow(0, y), + ib->color()->PlaneRow(1, y), + ib->color()->PlaneRow(2, y)}; + for (size_t x = 0; x < ib->xsize(); ++x) { + float& red = rows[0][x]; + float& green = rows[1][x]; + float& blue = rows[2][x]; + const float luminance = 0.2627f * red + 0.6780f * green + 0.0593f * blue; + const float ratio = std::pow(luminance, gamma - 1); + if (std::isfinite(ratio)) { + red *= ratio; + green *= ratio; + blue *= ratio; + } + } + return true; + }; + + JXL_RETURN_IF_ERROR(RunOnPool(pool, 0, ib->ysize(), ThreadPool::NoInit, + process_row, "HlgOOTF")); return true; } diff --git a/third_party/jpeg-xl/lib/extras/jpegli_test.cc b/third_party/jpeg-xl/lib/extras/jpegli_test.cc index a29af1ced725b..d22afd0e851d3 100644 --- a/third_party/jpeg-xl/lib/extras/jpegli_test.cc +++ b/third_party/jpeg-xl/lib/extras/jpegli_test.cc @@ -9,7 +9,6 @@ #include #include -#include #include #include @@ -40,9 +39,9 @@ namespace jxl { namespace extras { namespace { -using test::Butteraugli3Norm; -using test::ButteraugliDistance; -using test::TestImage; +using ::jxl::test::Butteraugli3Norm; +using ::jxl::test::ButteraugliDistance; +using ::jxl::test::TestImage; Status ReadTestImage(const std::string& pathname, PackedPixelFile* ppf) { const std::vector encoded = jxl::test::ReadTestData(pathname); @@ -93,7 +92,7 @@ Status EncodeWithLibjpeg(const PackedPixelFile& ppf, int quality, std::string Description(const JxlColorEncoding& color_encoding) { ColorEncoding c_enc; - JXL_CHECK(c_enc.FromExternal(color_encoding)); + EXPECT_TRUE(c_enc.FromExternal(color_encoding)); return Description(c_enc); } @@ -156,8 +155,8 @@ TEST(JpegliTest, JpegliXYBEncodeTest) { PackedPixelFile ppf_out; ASSERT_TRUE(DecodeWithLibjpeg(compressed, &ppf_out)); - EXPECT_THAT(BitsPerPixel(ppf_in, compressed), IsSlightlyBelow(1.45f)); - EXPECT_THAT(ButteraugliDistance(ppf_in, ppf_out), IsSlightlyBelow(1.32f)); + EXPECT_SLIGHTLY_BELOW(BitsPerPixel(ppf_in, compressed), 1.45f); + EXPECT_SLIGHTLY_BELOW(ButteraugliDistance(ppf_in, ppf_out), 1.32f); } TEST(JpegliTest, JpegliDecodeTestLargeSmoothArea) { @@ -165,9 +164,10 @@ TEST(JpegliTest, JpegliDecodeTestLargeSmoothArea) { TestImage t; const size_t xsize = 2070; const size_t ysize = 1063; - t.SetDimensions(xsize, ysize).SetChannels(3); + ASSERT_TRUE(t.SetDimensions(xsize, ysize)); + ASSERT_TRUE(t.SetChannels(3)); t.SetAllBitDepths(8).SetEndianness(JXL_NATIVE_ENDIAN); - TestImage::Frame frame = t.AddFrame(); + JXL_TEST_ASSIGN_OR_DIE(TestImage::Frame frame, t.AddFrame()); frame.RandomFill(); // Create a large smooth area in the top half of the image. This is to test // that the bias statistics calculation can handle many blocks with all-zero @@ -175,7 +175,7 @@ TEST(JpegliTest, JpegliDecodeTestLargeSmoothArea) { for (size_t y = 0; y < ysize / 2; ++y) { for (size_t x = 0; x < xsize; ++x) { for (size_t c = 0; c < 3; ++c) { - frame.SetValue(y, x, c, 0.5f); + ASSERT_TRUE(frame.SetValue(y, x, c, 0.5f)); } } } @@ -205,8 +205,8 @@ TEST(JpegliTest, JpegliYUVEncodeTest) { PackedPixelFile ppf_out; ASSERT_TRUE(DecodeWithLibjpeg(compressed, &ppf_out)); - EXPECT_THAT(BitsPerPixel(ppf_in, compressed), IsSlightlyBelow(1.7f)); - EXPECT_THAT(ButteraugliDistance(ppf_in, ppf_out), IsSlightlyBelow(1.32f)); + EXPECT_SLIGHTLY_BELOW(BitsPerPixel(ppf_in, compressed), 1.7f); + EXPECT_SLIGHTLY_BELOW(ButteraugliDistance(ppf_in, ppf_out), 1.32f); } TEST(JpegliTest, JpegliYUVChromaSubsamplingEncodeTest) { @@ -247,15 +247,15 @@ TEST(JpegliTest, JpegliYUVEncodeTestNoAq) { PackedPixelFile ppf_out; ASSERT_TRUE(DecodeWithLibjpeg(compressed, &ppf_out)); - EXPECT_THAT(BitsPerPixel(ppf_in, compressed), IsSlightlyBelow(1.85f)); - EXPECT_THAT(ButteraugliDistance(ppf_in, ppf_out), IsSlightlyBelow(1.25f)); + EXPECT_SLIGHTLY_BELOW(BitsPerPixel(ppf_in, compressed), 1.85f); + EXPECT_SLIGHTLY_BELOW(ButteraugliDistance(ppf_in, ppf_out), 1.25f); } TEST(JpegliTest, JpegliHDRRoundtripTest) { std::string testimage = "jxl/hdr_room.png"; PackedPixelFile ppf_in; ASSERT_TRUE(ReadTestImage(testimage, &ppf_in)); - EXPECT_EQ("RGB_D65_202_Rel_HLG", Description(ppf_in.color_encoding)); + EXPECT_EQ("Rec2100HLG", Description(ppf_in.color_encoding)); EXPECT_EQ(16, ppf_in.info.bits_per_sample); std::vector compressed; @@ -267,8 +267,8 @@ TEST(JpegliTest, JpegliHDRRoundtripTest) { JpegDecompressParams dparams; dparams.output_data_type = JXL_TYPE_UINT16; ASSERT_TRUE(DecodeJpeg(compressed, dparams, nullptr, &ppf_out)); - EXPECT_THAT(BitsPerPixel(ppf_in, compressed), IsSlightlyBelow(2.95f)); - EXPECT_THAT(ButteraugliDistance(ppf_in, ppf_out), IsSlightlyBelow(1.05f)); + EXPECT_SLIGHTLY_BELOW(BitsPerPixel(ppf_in, compressed), 2.95f); + EXPECT_SLIGHTLY_BELOW(ButteraugliDistance(ppf_in, ppf_out), 1.05f); } TEST(JpegliTest, JpegliSetAppData) { diff --git a/third_party/jpeg-xl/lib/extras/metrics.cc b/third_party/jpeg-xl/lib/extras/metrics.cc index 4259d3c375754..55c1130944480 100644 --- a/third_party/jpeg-xl/lib/extras/metrics.cc +++ b/third_party/jpeg-xl/lib/extras/metrics.cc @@ -16,6 +16,7 @@ #include #include "lib/jxl/base/compiler_specific.h" +#include "lib/jxl/base/rect.h" #include "lib/jxl/base/status.h" #include "lib/jxl/color_encoding_internal.h" HWY_BEFORE_NAMESPACE(); @@ -125,23 +126,27 @@ double ComputeDistanceP(const ImageF& distmap, const ButteraugliParams& params, void ComputeSumOfSquares(const ImageBundle& ib1, const ImageBundle& ib2, const JxlCmsInterface& cms, double sum_of_squares[3]) { + sum_of_squares[0] = sum_of_squares[1] = sum_of_squares[2] = + std::numeric_limits::max(); // Convert to sRGB - closer to perception than linear. const Image3F* srgb1 = &ib1.color(); Image3F copy1; if (!ib1.IsSRGB()) { - JXL_CHECK( - ib1.CopyTo(Rect(ib1), ColorEncoding::SRGB(ib1.IsGray()), cms, ©1)); + if (!ib1.CopyTo(Rect(ib1), ColorEncoding::SRGB(ib1.IsGray()), cms, ©1)) + return; srgb1 = ©1; } const Image3F* srgb2 = &ib2.color(); Image3F copy2; if (!ib2.IsSRGB()) { - JXL_CHECK( - ib2.CopyTo(Rect(ib2), ColorEncoding::SRGB(ib2.IsGray()), cms, ©2)); + if (!ib2.CopyTo(Rect(ib2), ColorEncoding::SRGB(ib2.IsGray()), cms, ©2)) + return; srgb2 = ©2; } - JXL_CHECK(SameSize(*srgb1, *srgb2)); + if (!SameSize(*srgb1, *srgb2)) return; + + sum_of_squares[0] = sum_of_squares[1] = sum_of_squares[2] = 0.0; // TODO(veluca): SIMD. float yuvmatrix[3][3] = {{0.299, 0.587, 0.114}, diff --git a/third_party/jpeg-xl/lib/extras/mmap.h b/third_party/jpeg-xl/lib/extras/mmap.h index 8bc023dec0f35..60cc215993eea 100644 --- a/third_party/jpeg-xl/lib/extras/mmap.h +++ b/third_party/jpeg-xl/lib/extras/mmap.h @@ -18,10 +18,10 @@ class MemoryMappedFile { static StatusOr Init(const char* path); const uint8_t* data() const; size_t size() const; - MemoryMappedFile(); - ~MemoryMappedFile(); - MemoryMappedFile(MemoryMappedFile&&) noexcept; - MemoryMappedFile& operator=(MemoryMappedFile&&) noexcept; + MemoryMappedFile(); // NOLINT + ~MemoryMappedFile(); // NOLINT + MemoryMappedFile(MemoryMappedFile&&) noexcept; // NOLINT + MemoryMappedFile& operator=(MemoryMappedFile&&) noexcept; // NOLINT private: std::unique_ptr impl_; diff --git a/third_party/jpeg-xl/lib/extras/packed_image.h b/third_party/jpeg-xl/lib/extras/packed_image.h index b0570dbd31225..8a88af618811a 100644 --- a/third_party/jpeg-xl/lib/extras/packed_image.h +++ b/third_party/jpeg-xl/lib/extras/packed_image.h @@ -12,22 +12,19 @@ #include #include #include -#include -#include -#include -#include #include #include +#include +#include +#include +#include #include #include -#include -#include #include #include #include "lib/jxl/base/byte_order.h" -#include "lib/jxl/base/c_callback_support.h" #include "lib/jxl/base/common.h" #include "lib/jxl/base/status.h" @@ -37,11 +34,18 @@ namespace extras { // Class representing an interleaved image with a bunch of channels. class PackedImage { public: - PackedImage(size_t xsize, size_t ysize, const JxlPixelFormat& format) - : PackedImage(xsize, ysize, format, CalcStride(format, xsize)) {} + static StatusOr Create(size_t xsize, size_t ysize, + const JxlPixelFormat& format) { + PackedImage image(xsize, ysize, format, CalcStride(format, xsize)); + if (!image.pixels()) { + // TODO(szabadka): use specialized OOM error code + return JXL_FAILURE("Failed to allocate memory for image"); + } + return image; + } PackedImage Copy() const { - PackedImage copy(xsize, ysize, format); + PackedImage copy(xsize, ysize, format, CalcStride(format, xsize)); memcpy(reinterpret_cast(copy.pixels()), reinterpret_cast(pixels()), pixels_size); return copy; @@ -73,6 +77,15 @@ class PackedImage { size_t pixel_stride() const { return pixel_stride_; } + static Status ValidateDataType(JxlDataType data_type) { + if ((data_type != JXL_TYPE_UINT8) && (data_type != JXL_TYPE_UINT16) && + (data_type != JXL_TYPE_FLOAT) && (data_type != JXL_TYPE_FLOAT16)) { + return JXL_FAILURE("Unhandled data type: %d", + static_cast(data_type)); + } + return true; + } + static size_t BitsPerChannel(JxlDataType data_type) { switch (data_type) { case JXL_TYPE_UINT8: @@ -84,7 +97,8 @@ class PackedImage { case JXL_TYPE_FLOAT16: return 16; default: - JXL_ABORT("Unhandled JxlDataType"); + JXL_DEBUG_ABORT("Unreachable"); + return 0; } } @@ -104,7 +118,8 @@ class PackedImage { return swap_endianness_ ? BSwapFloat(val) : val; } default: - JXL_ABORT("Unhandled JxlDataType"); + JXL_DEBUG_ABORT("Unreachable"); + return 0.0f; } } @@ -130,7 +145,7 @@ class PackedImage { break; } default: - JXL_ABORT("Unhandled JxlDataType"); + JXL_DEBUG_ABORT("Unreachable"); } } @@ -169,11 +184,20 @@ class PackedImage { // as all other frames in the same image. class PackedFrame { public: - template - explicit PackedFrame(Args&&... args) : color(std::forward(args)...) {} + explicit PackedFrame(PackedImage&& image) : color(std::move(image)) {} + + static StatusOr Create(size_t xsize, size_t ysize, + const JxlPixelFormat& format) { + JXL_ASSIGN_OR_RETURN(PackedImage image, + PackedImage::Create(xsize, ysize, format)); + PackedFrame frame(std::move(image)); + return frame; + } - PackedFrame Copy() const { - PackedFrame copy(color.xsize, color.ysize, color.format); + StatusOr Copy() const { + JXL_ASSIGN_OR_RETURN( + PackedFrame copy, + PackedFrame::Create(color.xsize, color.ysize, color.format)); copy.frame_info = frame_info; copy.name = name; copy.color = color.Copy(); @@ -224,6 +248,7 @@ class PackedMetadata { public: std::vector exif; std::vector iptc; + std::vector jhgm; std::vector jumbf; std::vector xmp; }; @@ -261,6 +286,8 @@ class PackedPixelFile { // The icc profile of the original image. std::vector orig_icc; + JxlBitDepth input_bitdepth = {JXL_BIT_DEPTH_FROM_PIXEL_FORMAT, 0, 0}; + std::unique_ptr preview_frame; std::vector frames; mutable std::vector chunked_frames; diff --git a/third_party/jpeg-xl/lib/extras/packed_image_convert.cc b/third_party/jpeg-xl/lib/extras/packed_image_convert.cc index 6dba0d602c285..7bdb3cdf64a3d 100644 --- a/third_party/jpeg-xl/lib/extras/packed_image_convert.cc +++ b/third_party/jpeg-xl/lib/extras/packed_image_convert.cc @@ -7,10 +7,14 @@ #include #include +#include #include #include +#include +#include "lib/extras/packed_image.h" +#include "lib/jxl/base/rect.h" #include "lib/jxl/base/status.h" #include "lib/jxl/color_encoding_internal.h" #include "lib/jxl/dec_external_image.h" @@ -22,25 +26,31 @@ namespace jxl { namespace extras { Status ConvertPackedFrameToImageBundle(const JxlBasicInfo& info, + const JxlBitDepth& input_bitdepth, const PackedFrame& frame, const CodecInOut& io, ThreadPool* pool, ImageBundle* bundle) { - JXL_ASSERT(frame.color.pixels() != nullptr); - const bool float_in = frame.color.format.data_type == JXL_TYPE_FLOAT16 || - frame.color.format.data_type == JXL_TYPE_FLOAT; - size_t frame_bits_per_sample = - float_in ? PackedImage::BitsPerChannel(frame.color.format.data_type) - : info.bits_per_sample; - JXL_ASSERT(frame_bits_per_sample != 0); + JxlMemoryManager* memory_manager = io.memory_manager; + JXL_ENSURE(frame.color.pixels() != nullptr); + size_t frame_bits_per_sample; + if (input_bitdepth.type == JXL_BIT_DEPTH_FROM_PIXEL_FORMAT) { + JXL_RETURN_IF_ERROR( + PackedImage::ValidateDataType(frame.color.format.data_type)); + frame_bits_per_sample = + PackedImage::BitsPerChannel(frame.color.format.data_type); + } else { + frame_bits_per_sample = info.bits_per_sample; + } + JXL_ENSURE(frame_bits_per_sample != 0); // It is ok for the frame.color.format.num_channels to not match the // number of channels on the image. - JXL_ASSERT(1 <= frame.color.format.num_channels && + JXL_ENSURE(1 <= frame.color.format.num_channels && frame.color.format.num_channels <= 4); const Span span( static_cast(frame.color.pixels()), frame.color.pixels_size); - JXL_ASSERT(Rect(frame.frame_info.layer_info.crop_x0, + JXL_ENSURE(Rect(frame.frame_info.layer_info.crop_x0, frame.frame_info.layer_info.crop_y0, frame.frame_info.layer_info.xsize, frame.frame_info.layer_info.ysize) @@ -54,7 +64,7 @@ Status ConvertPackedFrameToImageBundle(const JxlBasicInfo& info, bundle->origin.y0 = frame.frame_info.layer_info.crop_y0; } bundle->name = frame.name; // frame.frame_info.name_length is ignored here. - JXL_ASSERT(io.metadata.m.color_encoding.IsGray() == + JXL_ENSURE(io.metadata.m.color_encoding.IsGray() == (frame.color.format.num_channels <= 2)); JXL_RETURN_IF_ERROR(ConvertFromExternal( @@ -64,31 +74,33 @@ Status ConvertPackedFrameToImageBundle(const JxlBasicInfo& info, bundle->extra_channels().resize(io.metadata.m.extra_channel_info.size()); for (size_t i = 0; i < frame.extra_channels.size(); i++) { const auto& ppf_ec = frame.extra_channels[i]; - JXL_ASSIGN_OR_RETURN(bundle->extra_channels()[i], - ImageF::Create(ppf_ec.xsize, ppf_ec.ysize)); - JXL_CHECK(BufferToImageF(ppf_ec.format, ppf_ec.xsize, ppf_ec.ysize, - ppf_ec.pixels(), ppf_ec.pixels_size, pool, - &bundle->extra_channels()[i])); + JXL_ASSIGN_OR_RETURN( + bundle->extra_channels()[i], + ImageF::Create(memory_manager, ppf_ec.xsize, ppf_ec.ysize)); + JXL_RETURN_IF_ERROR(BufferToImageF( + ppf_ec.format, ppf_ec.xsize, ppf_ec.ysize, ppf_ec.pixels(), + ppf_ec.pixels_size, pool, &bundle->extra_channels()[i])); } return true; } Status ConvertPackedPixelFileToCodecInOut(const PackedPixelFile& ppf, ThreadPool* pool, CodecInOut* io) { + JxlMemoryManager* memory_manager = io->memory_manager; const bool has_alpha = ppf.info.alpha_bits != 0; - JXL_ASSERT(!ppf.frames.empty()); + JXL_ENSURE(!ppf.frames.empty()); if (has_alpha) { - JXL_ASSERT(ppf.info.alpha_bits == ppf.info.bits_per_sample); - JXL_ASSERT(ppf.info.alpha_exponent_bits == + JXL_ENSURE(ppf.info.alpha_bits == ppf.info.bits_per_sample); + JXL_ENSURE(ppf.info.alpha_exponent_bits == ppf.info.exponent_bits_per_sample); } const bool is_gray = (ppf.info.num_color_channels == 1); - JXL_ASSERT(ppf.info.num_color_channels == 1 || + JXL_ENSURE(ppf.info.num_color_channels == 1 || ppf.info.num_color_channels == 3); // Convert the image metadata - io->SetSize(ppf.info.xsize, ppf.info.ysize); + JXL_RETURN_IF_ERROR(io->SetSize(ppf.info.xsize, ppf.info.ysize)); io->metadata.m.bit_depth.bits_per_sample = ppf.info.bits_per_sample; io->metadata.m.bit_depth.exponent_bits_per_sample = ppf.info.exponent_bits_per_sample; @@ -103,11 +115,11 @@ Status ConvertPackedPixelFileToCodecInOut(const PackedPixelFile& ppf, if (alpha) alpha->bit_depth = io->metadata.m.bit_depth; io->metadata.m.xyb_encoded = !FROM_JXL_BOOL(ppf.info.uses_original_profile); - JXL_ASSERT(ppf.info.orientation > 0 && ppf.info.orientation <= 8); + JXL_ENSURE(ppf.info.orientation > 0 && ppf.info.orientation <= 8); io->metadata.m.orientation = ppf.info.orientation; // Convert animation metadata - JXL_ASSERT(ppf.frames.size() == 1 || ppf.info.have_animation); + JXL_ENSURE(ppf.frames.size() == 1 || ppf.info.have_animation); io->metadata.m.have_animation = FROM_JXL_BOOL(ppf.info.have_animation); io->metadata.m.animation.tps_numerator = ppf.info.animation.tps_numerator; io->metadata.m.animation.tps_denominator = ppf.info.animation.tps_denominator; @@ -141,6 +153,7 @@ Status ConvertPackedPixelFileToCodecInOut(const PackedPixelFile& ppf, // Convert the extra blobs io->blobs.exif = ppf.metadata.exif; io->blobs.iptc = ppf.metadata.iptc; + io->blobs.jhgm = ppf.metadata.jhgm; io->blobs.jumbf = ppf.metadata.jumbf; io->blobs.xmp = ppf.metadata.xmp; @@ -171,15 +184,16 @@ Status ConvertPackedPixelFileToCodecInOut(const PackedPixelFile& ppf, JXL_RETURN_IF_ERROR( io->metadata.m.preview_size.Set(preview_xsize, preview_ysize)); JXL_RETURN_IF_ERROR(ConvertPackedFrameToImageBundle( - ppf.info, *ppf.preview_frame, *io, pool, &io->preview_frame)); + ppf.info, ppf.input_bitdepth, *ppf.preview_frame, *io, pool, + &io->preview_frame)); } // Convert the pixels io->frames.clear(); for (const auto& frame : ppf.frames) { - ImageBundle bundle(&io->metadata.m); - JXL_RETURN_IF_ERROR( - ConvertPackedFrameToImageBundle(ppf.info, frame, *io, pool, &bundle)); + ImageBundle bundle(memory_manager, &io->metadata.m); + JXL_RETURN_IF_ERROR(ConvertPackedFrameToImageBundle( + ppf.info, ppf.input_bitdepth, frame, *io, pool, &bundle)); io->frames.push_back(std::move(bundle)); } @@ -192,18 +206,18 @@ Status ConvertPackedPixelFileToCodecInOut(const PackedPixelFile& ppf, } else { SetIntensityTarget(&io->metadata.m); } - io->CheckMetadata(); + JXL_RETURN_IF_ERROR(io->CheckMetadata()); return true; } -PackedPixelFile ConvertImage3FToPackedPixelFile(const Image3F& image, - const ColorEncoding& c_enc, - JxlPixelFormat format, - ThreadPool* pool) { - PackedPixelFile ppf; +StatusOr ConvertImage3FToPackedPixelFile( + const Image3F& image, const ColorEncoding& c_enc, JxlPixelFormat format, + ThreadPool* pool) { + PackedPixelFile ppf{}; ppf.info.xsize = image.xsize(); ppf.info.ysize = image.ysize(); ppf.info.num_color_channels = 3; + JXL_RETURN_IF_ERROR(PackedImage::ValidateDataType(format.data_type)); ppf.info.bits_per_sample = PackedImage::BitsPerChannel(format.data_type); ppf.info.exponent_bits_per_sample = format.data_type == JXL_TYPE_FLOAT ? 8 : format.data_type == JXL_TYPE_FLOAT16 @@ -211,13 +225,15 @@ PackedPixelFile ConvertImage3FToPackedPixelFile(const Image3F& image, : 0; ppf.color_encoding = c_enc.ToExternal(); ppf.frames.clear(); - PackedFrame frame(image.xsize(), image.ysize(), format); + JXL_ASSIGN_OR_RETURN( + PackedFrame frame, + PackedFrame::Create(image.xsize(), image.ysize(), format)); const ImageF* channels[3]; for (int c = 0; c < 3; ++c) { channels[c] = &image.Plane(c); } bool float_samples = ppf.info.exponent_bits_per_sample > 0; - JXL_CHECK(ConvertChannelsToExternal( + JXL_RETURN_IF_ERROR(ConvertChannelsToExternal( channels, 3, ppf.info.bits_per_sample, float_samples, format.endianness, frame.color.stride, pool, frame.color.pixels(0, 0, 0), frame.color.pixels_size, PixelCallback(), Orientation::kIdentity)); @@ -231,14 +247,15 @@ Status ConvertCodecInOutToPackedPixelFile(const CodecInOut& io, const ColorEncoding& c_desired, ThreadPool* pool, PackedPixelFile* ppf) { + JxlMemoryManager* memory_manager = io.memory_manager; const bool has_alpha = io.metadata.m.HasAlpha(); - JXL_ASSERT(!io.frames.empty()); + JXL_ENSURE(!io.frames.empty()); if (has_alpha) { - JXL_ASSERT(io.metadata.m.GetAlphaBits() == + JXL_ENSURE(io.metadata.m.GetAlphaBits() == io.metadata.m.bit_depth.bits_per_sample); const auto* alpha_channel = io.metadata.m.Find(ExtraChannel::kAlpha); - JXL_ASSERT(alpha_channel->bit_depth.exponent_bits_per_sample == + JXL_ENSURE(alpha_channel->bit_depth.exponent_bits_per_sample == io.metadata.m.bit_depth.exponent_bits_per_sample); ppf->info.alpha_bits = alpha_channel->bit_depth.bits_per_sample; ppf->info.alpha_exponent_bits = @@ -262,13 +279,13 @@ Status ConvertCodecInOutToPackedPixelFile(const CodecInOut& io, TO_JXL_BOOL(io.metadata.m.tone_mapping.relative_to_max_display); ppf->info.uses_original_profile = TO_JXL_BOOL(!io.metadata.m.xyb_encoded); - JXL_ASSERT(0 < io.metadata.m.orientation && io.metadata.m.orientation <= 8); + JXL_ENSURE(0 < io.metadata.m.orientation && io.metadata.m.orientation <= 8); ppf->info.orientation = static_cast(io.metadata.m.orientation); ppf->info.num_color_channels = io.metadata.m.color_encoding.Channels(); // Convert animation metadata - JXL_ASSERT(io.frames.size() == 1 || io.metadata.m.have_animation); + JXL_ENSURE(io.frames.size() == 1 || io.metadata.m.have_animation); ppf->info.have_animation = TO_JXL_BOOL(io.metadata.m.have_animation); ppf->info.animation.tps_numerator = io.metadata.m.animation.tps_numerator; ppf->info.animation.tps_denominator = io.metadata.m.animation.tps_denominator; @@ -284,6 +301,7 @@ Status ConvertCodecInOutToPackedPixelFile(const CodecInOut& io, // Convert the extra blobs ppf->metadata.exif = io.blobs.exif; ppf->metadata.iptc = io.blobs.iptc; + ppf->metadata.jhgm = io.blobs.jhgm; ppf->metadata.jumbf = io.blobs.jumbf; ppf->metadata.xmp = io.blobs.xmp; const bool float_out = pixel_format.data_type == JXL_TYPE_FLOAT || @@ -291,7 +309,7 @@ Status ConvertCodecInOutToPackedPixelFile(const CodecInOut& io, // Convert the pixels ppf->frames.clear(); for (const auto& frame : io.frames) { - JXL_ASSERT(frame.metadata()->bit_depth.bits_per_sample != 0); + JXL_ENSURE(frame.metadata()->bit_depth.bits_per_sample != 0); // It is ok for the frame.color().kNumPlanes to not match the // number of channels on the image. const uint32_t alpha_channels = has_alpha ? 1 : 0; @@ -302,8 +320,10 @@ Status ConvertCodecInOutToPackedPixelFile(const CodecInOut& io, /*endianness=*/pixel_format.endianness, /*align=*/pixel_format.align}; - PackedFrame packed_frame(frame.oriented_xsize(), frame.oriented_ysize(), - format); + JXL_ASSIGN_OR_RETURN(PackedFrame packed_frame, + PackedFrame::Create(frame.oriented_xsize(), + frame.oriented_ysize(), format)); + JXL_RETURN_IF_ERROR(PackedImage::ValidateDataType(pixel_format.data_type)); const size_t bits_per_sample = float_out ? packed_frame.color.BitsPerChannel(pixel_format.data_type) : ppf->info.bits_per_sample; @@ -313,7 +333,7 @@ Status ConvertCodecInOutToPackedPixelFile(const CodecInOut& io, JXL_ASSIGN_OR_RETURN(ImageBundle ib, frame.Copy()); const ImageBundle* to_color_transform = &ib; ImageMetadata metadata = io.metadata.m; - ImageBundle store(&metadata); + ImageBundle store(memory_manager, &metadata); const ImageBundle* transformed; // TODO(firsching): handle the transform here. JXL_RETURN_IF_ERROR(TransformIfNeeded(*to_color_transform, c_desired, @@ -329,7 +349,7 @@ Status ConvertCodecInOutToPackedPixelFile(const CodecInOut& io, // TODO(firsching): Convert the extra channels, beside one potential alpha // channel. FIXME! - JXL_CHECK(frame.extra_channels().size() <= has_alpha); + JXL_ENSURE(frame.extra_channels().size() <= (has_alpha ? 1 : 0)); ppf->frames.push_back(std::move(packed_frame)); } diff --git a/third_party/jpeg-xl/lib/extras/packed_image_convert.h b/third_party/jpeg-xl/lib/extras/packed_image_convert.h index b14eed174e617..20ed330b84719 100644 --- a/third_party/jpeg-xl/lib/extras/packed_image_convert.h +++ b/third_party/jpeg-xl/lib/extras/packed_image_convert.h @@ -31,10 +31,9 @@ Status ConvertCodecInOutToPackedPixelFile(const CodecInOut& io, ThreadPool* pool, PackedPixelFile* ppf); -PackedPixelFile ConvertImage3FToPackedPixelFile(const Image3F& image, - const ColorEncoding& c_enc, - JxlPixelFormat format, - ThreadPool* pool); +StatusOr ConvertImage3FToPackedPixelFile( + const Image3F& image, const ColorEncoding& c_enc, JxlPixelFormat format, + ThreadPool* pool); } // namespace extras } // namespace jxl diff --git a/third_party/jpeg-xl/lib/extras/time.cc b/third_party/jpeg-xl/lib/extras/time.cc index d4f41754dadd7..344994f78da7a 100644 --- a/third_party/jpeg-xl/lib/extras/time.cc +++ b/third_party/jpeg-xl/lib/extras/time.cc @@ -46,7 +46,7 @@ double Now() { if (timebase.denom == 0) { (void)mach_timebase_info(&timebase); } - return double(t) * timebase.numer / timebase.denom * 1E-9; + return double(t) * timebase.numer / timebase.denom * 1E-9; // notypo #elif JXL_OS_HAIKU return double(system_time_nsecs()) * 1E-9; #else diff --git a/third_party/jpeg-xl/lib/extras/tone_mapping.cc b/third_party/jpeg-xl/lib/extras/tone_mapping.cc index 3d0269524bff9..9a700c48a32f0 100644 --- a/third_party/jpeg-xl/lib/extras/tone_mapping.cc +++ b/third_party/jpeg-xl/lib/extras/tone_mapping.cc @@ -19,7 +19,7 @@ HWY_BEFORE_NAMESPACE(); namespace jxl { namespace HWY_NAMESPACE { -static constexpr float rec2020_luminances[3] = {0.2627f, 0.6780f, 0.0593f}; +static constexpr Vector3 rec2020_luminances{0.2627f, 0.6780f, 0.0593f}; Status ToneMapFrame(const std::pair display_nits, ImageBundle* const ib, ThreadPool* const pool) { @@ -44,23 +44,25 @@ Status ToneMapFrame(const std::pair display_nits, ib->metadata()->IntensityTarget()}, display_nits, rec2020_luminances); - return RunOnPool( - pool, 0, ib->ysize(), ThreadPool::NoInit, - [&](const uint32_t y, size_t /* thread */) { - float* const JXL_RESTRICT row_r = ib->color()->PlaneRow(0, y); - float* const JXL_RESTRICT row_g = ib->color()->PlaneRow(1, y); - float* const JXL_RESTRICT row_b = ib->color()->PlaneRow(2, y); - for (size_t x = 0; x < ib->xsize(); x += Lanes(df)) { - V red = Load(df, row_r + x); - V green = Load(df, row_g + x); - V blue = Load(df, row_b + x); - tone_mapper.ToneMap(&red, &green, &blue); - Store(red, df, row_r + x); - Store(green, df, row_g + x); - Store(blue, df, row_b + x); - } - }, - "ToneMap"); + const auto process_row = [&](const uint32_t y, + size_t /* thread */) -> Status { + float* const JXL_RESTRICT row_r = ib->color()->PlaneRow(0, y); + float* const JXL_RESTRICT row_g = ib->color()->PlaneRow(1, y); + float* const JXL_RESTRICT row_b = ib->color()->PlaneRow(2, y); + for (size_t x = 0; x < ib->xsize(); x += Lanes(df)) { + V red = Load(df, row_r + x); + V green = Load(df, row_g + x); + V blue = Load(df, row_b + x); + tone_mapper.ToneMap(&red, &green, &blue); + Store(red, df, row_r + x); + Store(green, df, row_g + x); + Store(blue, df, row_b + x); + } + return true; + }; + JXL_RETURN_IF_ERROR(RunOnPool(pool, 0, ib->ysize(), ThreadPool::NoInit, + process_row, "ToneMap")); + return true; } Status GamutMapFrame(ImageBundle* const ib, float preserve_saturation, @@ -77,24 +79,24 @@ Status GamutMapFrame(ImageBundle* const ib, float preserve_saturation, JXL_RETURN_IF_ERROR( ib->TransformTo(linear_rec2020, *JxlGetDefaultCms(), pool)); - JXL_RETURN_IF_ERROR(RunOnPool( - pool, 0, ib->ysize(), ThreadPool::NoInit, - [&](const uint32_t y, size_t /* thread*/) { - float* const JXL_RESTRICT row_r = ib->color()->PlaneRow(0, y); - float* const JXL_RESTRICT row_g = ib->color()->PlaneRow(1, y); - float* const JXL_RESTRICT row_b = ib->color()->PlaneRow(2, y); - for (size_t x = 0; x < ib->xsize(); x += Lanes(df)) { - V red = Load(df, row_r + x); - V green = Load(df, row_g + x); - V blue = Load(df, row_b + x); - GamutMap(&red, &green, &blue, rec2020_luminances, - preserve_saturation); - Store(red, df, row_r + x); - Store(green, df, row_g + x); - Store(blue, df, row_b + x); - } - }, - "GamutMap")); + const auto process_row = [&](const uint32_t y, size_t /* thread*/) -> Status { + float* const JXL_RESTRICT row_r = ib->color()->PlaneRow(0, y); + float* const JXL_RESTRICT row_g = ib->color()->PlaneRow(1, y); + float* const JXL_RESTRICT row_b = ib->color()->PlaneRow(2, y); + for (size_t x = 0; x < ib->xsize(); x += Lanes(df)) { + V red = Load(df, row_r + x); + V green = Load(df, row_g + x); + V blue = Load(df, row_b + x); + GamutMap(&red, &green, &blue, rec2020_luminances, preserve_saturation); + Store(red, df, row_r + x); + Store(green, df, row_g + x); + Store(blue, df, row_b + x); + } + return true; + }; + + JXL_RETURN_IF_ERROR(RunOnPool(pool, 0, ib->ysize(), ThreadPool::NoInit, + process_row, "GamutMap")); return true; } diff --git a/third_party/jpeg-xl/lib/extras/tone_mapping_gbench.cc b/third_party/jpeg-xl/lib/extras/tone_mapping_gbench.cc index 8fc928a4fd0d7..30b4e6e7e0930 100644 --- a/third_party/jpeg-xl/lib/extras/tone_mapping_gbench.cc +++ b/third_party/jpeg-xl/lib/extras/tone_mapping_gbench.cc @@ -3,37 +3,55 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include + #include "benchmark/benchmark.h" -#include "lib/extras/codec.h" #include "lib/extras/tone_mapping.h" +#include "lib/jxl/base/status.h" #include "lib/jxl/image.h" +#include "tools/no_memory_manager.h" namespace jxl { +#define QUIT(M) \ + state.SkipWithError(M); \ + return; + +#define BM_CHECK(C) \ + if (!(C)) { \ + QUIT(#C) \ + } + static void BM_ToneMapping(benchmark::State& state) { - JXL_ASSIGN_OR_DIE(Image3F color, Image3F::Create(2268, 1512)); + JxlMemoryManager* memory_manager = jpegxl::tools::NoMemoryManager(); + JXL_ASSIGN_OR_QUIT(Image3F color, Image3F::Create(memory_manager, 2268, 1512), + "Failed to allocate color plane"); FillImage(0.5f, &color); // Use linear Rec. 2020 so that `ToneMapTo` doesn't have to convert to it and // we mainly measure the tone mapping itself. ColorEncoding linear_rec2020; linear_rec2020.SetColorSpace(ColorSpace::kRGB); - JXL_CHECK(linear_rec2020.SetPrimariesType(Primaries::k2100)); - JXL_CHECK(linear_rec2020.SetWhitePointType(WhitePoint::kD65)); + BM_CHECK(linear_rec2020.SetPrimariesType(Primaries::k2100)); + BM_CHECK(linear_rec2020.SetWhitePointType(WhitePoint::kD65)); linear_rec2020.Tf().SetTransferFunction(TransferFunction::kLinear); - JXL_CHECK(linear_rec2020.CreateICC()); + BM_CHECK(linear_rec2020.CreateICC()); for (auto _ : state) { + (void)_; state.PauseTiming(); - CodecInOut tone_mapping_input; - JXL_ASSIGN_OR_DIE(Image3F color2, - Image3F::Create(color.xsize(), color.ysize())); - CopyImageTo(color, &color2); - tone_mapping_input.SetFromImage(std::move(color2), linear_rec2020); + CodecInOut tone_mapping_input{memory_manager}; + JXL_ASSIGN_OR_QUIT( + Image3F color2, + Image3F::Create(memory_manager, color.xsize(), color.ysize()), + "Failed to allocate color plane"); + BM_CHECK(CopyImageTo(color, &color2)); + BM_CHECK( + tone_mapping_input.SetFromImage(std::move(color2), linear_rec2020)); tone_mapping_input.metadata.m.SetIntensityTarget(255); state.ResumeTiming(); - JXL_CHECK(ToneMapTo({0.1, 100}, &tone_mapping_input)); + BM_CHECK(ToneMapTo({0.1, 100}, &tone_mapping_input)); } state.SetItemsProcessed(state.iterations() * color.xsize() * color.ysize()); diff --git a/third_party/jpeg-xl/lib/include/jxl/cms_interface.h b/third_party/jpeg-xl/lib/include/jxl/cms_interface.h index 25c700867ac5c..137fb42d8ca9e 100644 --- a/third_party/jpeg-xl/lib/include/jxl/cms_interface.h +++ b/third_party/jpeg-xl/lib/include/jxl/cms_interface.h @@ -23,7 +23,7 @@ #include #include -#if defined(__cplusplus) || defined(c_plusplus) +#ifdef __cplusplus extern "C" { #endif @@ -246,7 +246,7 @@ typedef struct { jpegxl_cms_destroy_func destroy; } JxlCmsInterface; -#if defined(__cplusplus) || defined(c_plusplus) +#ifdef __cplusplus } #endif diff --git a/third_party/jpeg-xl/lib/include/jxl/codestream_header.h b/third_party/jpeg-xl/lib/include/jxl/codestream_header.h index e60eb03355417..513c92f1dda2d 100644 --- a/third_party/jpeg-xl/lib/include/jxl/codestream_header.h +++ b/third_party/jpeg-xl/lib/include/jxl/codestream_header.h @@ -19,7 +19,7 @@ #include #include -#if defined(__cplusplus) || defined(c_plusplus) +#ifdef __cplusplus extern "C" { #endif @@ -424,7 +424,7 @@ typedef struct { JxlLayerInfo layer_info; } JxlFrameHeader; -#if defined(__cplusplus) || defined(c_plusplus) +#ifdef __cplusplus } #endif diff --git a/third_party/jpeg-xl/lib/include/jxl/color_encoding.h b/third_party/jpeg-xl/lib/include/jxl/color_encoding.h index e6325dcb30299..14dcdeb0a2123 100644 --- a/third_party/jpeg-xl/lib/include/jxl/color_encoding.h +++ b/third_party/jpeg-xl/lib/include/jxl/color_encoding.h @@ -14,9 +14,7 @@ #ifndef JXL_COLOR_ENCODING_H_ #define JXL_COLOR_ENCODING_H_ -#include - -#if defined(__cplusplus) || defined(c_plusplus) +#ifdef __cplusplus extern "C" { #endif @@ -34,9 +32,9 @@ typedef enum { JXL_COLOR_SPACE_UNKNOWN, } JxlColorSpace; -/** Built-in whitepoints for color encoding. When decoding, the numerical xy - * whitepoint value can be read from the @ref JxlColorEncoding white_point field - * regardless of the enum value. When encoding, enum values except +/** Built-in white points for color encoding. When decoding, the numerical xy + * white point value can be read from the @ref JxlColorEncoding white_point + * field regardless of the enum value. When encoding, enum values except * ::JXL_WHITE_POINT_CUSTOM override the numerical fields. Some enum values * match a subset of CICP (Rec. ITU-T H.273 | ISO/IEC 23091-2:2019(E)), however * the white point and RGB primaries are separate enums here. @@ -80,7 +78,7 @@ typedef enum { * of CICP (Rec. ITU-T H.273 | ISO/IEC 23091-2:2019(E)) unless specified * otherwise. */ typedef enum { - /** As specified in SMPTE RP 431-2 */ + /** As specified in ITU-R BT.709-6 */ JXL_TRANSFER_FUNCTION_709 = 1, /** None of the other table entries describe the transfer function. */ JXL_TRANSFER_FUNCTION_UNKNOWN = 2, @@ -99,7 +97,7 @@ typedef enum { JXL_TRANSFER_FUNCTION_GAMMA = 65535, } JxlTransferFunction; -/** Renderig intent for color encoding, as specified in ISO 15076-1:2010 */ +/** Rendering intent for color encoding, as specified in ISO 15076-1:2010 */ typedef enum { /** vendor-specific */ JXL_RENDERING_INTENT_PERCEPTUAL = 0, @@ -119,7 +117,7 @@ typedef struct { JxlColorSpace color_space; /** Built-in white point. If this value is ::JXL_WHITE_POINT_CUSTOM, must - * use the numerical whitepoint values from white_point_xy. + * use the numerical white point values from white_point_xy. */ JxlWhitePoint white_point; @@ -154,7 +152,7 @@ typedef struct { JxlRenderingIntent rendering_intent; } JxlColorEncoding; -#if defined(__cplusplus) || defined(c_plusplus) +#ifdef __cplusplus } #endif diff --git a/third_party/jpeg-xl/lib/include/jxl/compressed_icc.h b/third_party/jpeg-xl/lib/include/jxl/compressed_icc.h new file mode 100644 index 0000000000000..10232794b69d3 --- /dev/null +++ b/third_party/jpeg-xl/lib/include/jxl/compressed_icc.h @@ -0,0 +1,75 @@ +/* Copyright (c) the JPEG XL Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + */ + +/** @addtogroup libjxl_metadata + * @{ + * @file compressed_icc.h + * @brief Utility functions to compress and decompress ICC streams. + */ + +#ifndef JXL_COMPRESSED_ICC_H_ +#define JXL_COMPRESSED_ICC_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Allocates a buffer using the memory manager, fills it with a compressed + * representation of an ICC profile, returns the result through @c output_buffer + * and indicates its size through @c output_size. + * + * The result must be freed using the memory manager once it is not of any more + * use. + * + * @param[in] memory_manager Pointer to a JxlMemoryManager. + * @param[in] icc Pointer to a buffer containing the uncompressed ICC profile. + * @param[in] icc_size Size of the buffer containing the ICC profile. + * @param[out] compressed_icc Will be set to a pointer to the buffer containing + * the result. + * @param[out] compressed_icc_size Will be set to the size of the buffer + * containing the result. + * @return Whether compressing the profile was successful. + */ +JXL_EXPORT JXL_BOOL JxlICCProfileEncode(const JxlMemoryManager* memory_manager, + const uint8_t* icc, size_t icc_size, + uint8_t** compressed_icc, + size_t* compressed_icc_size); + +/** + * Allocates a buffer using the memory manager, fills it with the decompressed + * version of the ICC profile in @c compressed_icc, returns the result through + * @c output_buffer and indicates its size through @c output_size. + * + * The result must be freed using the memory manager once it is not of any more + * use. + * + * @param[in] memory_manager Pointer to a JxlMemoryManager. + * @param[in] compressed_icc Pointer to a buffer containing the compressed ICC + * profile. + * @param[in] compressed_icc_size Size of the buffer containing the compressed + * ICC profile. + * @param[out] icc Will be set to a pointer to the buffer containing the result. + * @param[out] icc_size Will be set to the size of the buffer containing the + * result. + * @return Whether decompressing the profile was successful. + */ +JXL_EXPORT JXL_BOOL JxlICCProfileDecode(const JxlMemoryManager* memory_manager, + const uint8_t* compressed_icc, + size_t compressed_icc_size, + uint8_t** icc, size_t* icc_size); + +#ifdef __cplusplus +} +#endif + +#endif /* JXL_COMPRESSED_ICC_H_ */ + +/** @} */ diff --git a/third_party/jpeg-xl/lib/include/jxl/decode.h b/third_party/jpeg-xl/lib/include/jxl/decode.h index 599b8336f3fc2..69c00243d6633 100644 --- a/third_party/jpeg-xl/lib/include/jxl/decode.h +++ b/third_party/jpeg-xl/lib/include/jxl/decode.h @@ -24,7 +24,7 @@ #include #include -#if defined(__cplusplus) || defined(c_plusplus) +#ifdef __cplusplus extern "C" { #endif @@ -290,12 +290,13 @@ typedef enum { * * The buffer set with @ref JxlDecoderSetBoxBuffer must be set again for each * next box to be obtained, or can be left unset to skip outputting this box. - * The output buffer contains the full box data when the next ::JXL_DEC_BOX - * event or ::JXL_DEC_SUCCESS occurs. ::JXL_DEC_BOX occurs for all - * boxes, including non-metadata boxes such as the signature box or codestream - * boxes. To check whether the box is a metadata type for respectively EXIF, - * XMP or JUMBF, use @ref JxlDecoderGetBoxType and check for types "Exif", - * "xml " and "jumb" respectively. + * The output buffer contains the full box data when the + * ::JXL_DEC_BOX_COMPLETE (if subscribed to) or subsequent ::JXL_DEC_SUCCESS + * or ::JXL_DEC_BOX event occurs. ::JXL_DEC_BOX occurs for all boxes, + * including non-metadata boxes such as the signature box or codestream boxes. + * To check whether the box is a metadata type for respectively EXIF, XMP or + * JUMBF, use @ref JxlDecoderGetBoxType and check for types "Exif", "xml " and + * "jumb" respectively. * * In this case, @ref JxlDecoderReleaseInput will return all bytes from the * start of the box header as unprocessed. @@ -318,6 +319,11 @@ typedef enum { * unprocessed. */ JXL_DEC_FRAME_PROGRESSION = 0x8000, + + /** The box being decoded is now complete. This is only emitted if a buffer + * was set for the box. + */ + JXL_DEC_BOX_COMPLETE = 0x10000, } JxlDecoderStatus; /** Types of progressive detail. @@ -721,7 +727,7 @@ typedef enum { * It is often possible to use @ref JxlDecoderGetColorAsICCProfile as an * alternative anyway. The following scenarios are possible: * - The JPEG XL image has an attached ICC Profile, in that case, the encoded - * structured data is not available, this function will return an error + * structured data is not available and this function will return an error * status. @ref JxlDecoderGetColorAsICCProfile should be called instead. * - The JPEG XL image has an encoded structured color profile, and it * represents an RGB or grayscale color space. This function will return it. @@ -800,8 +806,8 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderGetICCProfileSize( * or the color profile of the decoded pixels. * @param icc_profile buffer to copy the ICC profile into * @param size size of the icc_profile buffer in bytes - * @return ::JXL_DEC_SUCCESS if the profile was successfully returned is - * available, ::JXL_DEC_NEED_MORE_INPUT if not yet available, @ref + * @return ::JXL_DEC_SUCCESS if the profile was successfully returned, + * ::JXL_DEC_NEED_MORE_INPUT if not yet available, @ref * JXL_DEC_ERROR if the profile doesn't exist or the output size is not * large enough. */ @@ -869,7 +875,7 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderSetDesiredIntensityTarget( * * This function must not be called before @ref JxlDecoderSetCms. * - * @param dec decoder orbject + * @param dec decoder object * @param color_encoding the output color encoding * @param icc_data bytes of the icc profile * @param icc_size size of the icc profile in bytes @@ -913,7 +919,7 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderPreviewOutBufferSize( const JxlDecoder* dec, const JxlPixelFormat* format, size_t* size); /** - * Sets the buffer to write the small resolution preview image + * Sets the buffer to write the low-resolution preview image * to. The size of the buffer must be at least as large as given by @ref * JxlDecoderPreviewOutBufferSize. The buffer follows the format described * by @ref JxlPixelFormat. The preview image dimensions are given by the @@ -962,10 +968,10 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderGetFrameName(const JxlDecoder* dec, /** * Outputs the blend information for the current frame for a specific extra - * channel. This function can be called when ::JXL_DEC_FRAME occurred for the - * current frame, even when have_animation in the @ref JxlBasicInfo is @ref - * JXL_FALSE. This information is only useful if coalescing is disabled; - * otherwise the decoder will have performed blending already. + * channel. This function can be called once the ::JXL_DEC_FRAME event occurred + * for the current frame, even if the `have_animation` field in the @ref + * JxlBasicInfo is @ref JXL_FALSE. This information is only useful if coalescing + * is disabled; otherwise the decoder will have performed blending already. * * @param dec decoder object * @param index the index of the extra channel @@ -1344,7 +1350,7 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderSetDecompressBoxes(JxlDecoder* dec, * animation allowing the decoder to jump to individual frames more * efficiently. * - "jbrd": JPEG reconstruction box, contains the information required to - * byte-for-byte losslessly recontruct a JPEG-1 image. The JPEG DCT + * byte-for-byte losslessly reconstruct a JPEG-1 image. The JPEG DCT * coefficients (pixel content) themselves as well as the ICC profile are * encoded in the JXL codestream (jxlc or jxlp) itself. EXIF, XMP and JUMBF * metadata is encoded in the corresponding boxes. The jbrd box itself @@ -1366,7 +1372,7 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderSetDecompressBoxes(JxlDecoder* dec, * @param decompressed which box type to get: JXL_FALSE to get the raw box type, * which can be "brob", JXL_TRUE, get the underlying box type. * @return ::JXL_DEC_SUCCESS if the value is available, ::JXL_DEC_ERROR if - * not, for example the JXL file does not use the container format. + * not, for example the JPEG XL file does not use the container format. */ JXL_EXPORT JxlDecoderStatus JxlDecoderGetBoxType(JxlDecoder* dec, JxlBoxType type, @@ -1457,7 +1463,7 @@ JXL_EXPORT JxlDecoderStatus JxlDecoderFlushImage(JxlDecoder* dec); JXL_EXPORT JxlDecoderStatus JxlDecoderSetImageOutBitDepth(JxlDecoder* dec, const JxlBitDepth* bit_depth); -#if defined(__cplusplus) || defined(c_plusplus) +#ifdef __cplusplus } #endif diff --git a/third_party/jpeg-xl/lib/include/jxl/decode_cxx.h b/third_party/jpeg-xl/lib/include/jxl/decode_cxx.h index 94d2fad83d85a..6089538dbe76c 100644 --- a/third_party/jpeg-xl/lib/include/jxl/decode_cxx.h +++ b/third_party/jpeg-xl/lib/include/jxl/decode_cxx.h @@ -20,7 +20,7 @@ #include -#if !(defined(__cplusplus) || defined(c_plusplus)) +#ifndef __cplusplus #error "This a C++ only header. Use jxl/decode.h from C sources." #endif diff --git a/third_party/jpeg-xl/lib/include/jxl/encode.h b/third_party/jpeg-xl/lib/include/jxl/encode.h index bb11dd7572874..633a98e41754e 100644 --- a/third_party/jpeg-xl/lib/include/jxl/encode.h +++ b/third_party/jpeg-xl/lib/include/jxl/encode.h @@ -25,7 +25,7 @@ #include #include -#if defined(__cplusplus) || defined(c_plusplus) +#ifdef __cplusplus extern "C" { #endif @@ -388,6 +388,11 @@ typedef enum { */ JXL_ENC_FRAME_SETTING_USE_FULL_IMAGE_HEURISTICS = 38, + /** Disable perceptual optimizations. 0 = optimizations enabled (default), 1 = + * optimizations disabled. + */ + JXL_ENC_FRAME_SETTING_DISABLE_PERCEPTUAL_HEURISTICS = 39, + /** Enum value not to be used as an option. This value is added to force the * C compiler to have the enum to take a known size. */ @@ -1588,7 +1593,7 @@ JXL_EXPORT void JxlEncoderSetDebugImageCallback( JXL_EXPORT void JxlEncoderCollectStats(JxlEncoderFrameSettings* frame_settings, JxlEncoderStats* stats); -#if defined(__cplusplus) || defined(c_plusplus) +#ifdef __cplusplus } #endif diff --git a/third_party/jpeg-xl/lib/include/jxl/encode_cxx.h b/third_party/jpeg-xl/lib/include/jxl/encode_cxx.h index 13adb8683ce7f..8e552357ac1c5 100644 --- a/third_party/jpeg-xl/lib/include/jxl/encode_cxx.h +++ b/third_party/jpeg-xl/lib/include/jxl/encode_cxx.h @@ -20,7 +20,7 @@ #include -#if !(defined(__cplusplus) || defined(c_plusplus)) +#ifndef __cplusplus #error "This a C++ only header. Use jxl/encode.h from C sources." #endif diff --git a/third_party/jpeg-xl/lib/include/jxl/gain_map.h b/third_party/jpeg-xl/lib/include/jxl/gain_map.h new file mode 100644 index 0000000000000..e1b314b56cbd9 --- /dev/null +++ b/third_party/jpeg-xl/lib/include/jxl/gain_map.h @@ -0,0 +1,129 @@ +/* Copyright (c) the JPEG XL Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + */ + +/** @addtogroup libjxl_metadata + * @{ + * @file gain_map.h + * @brief Utility functions to manipulate jhgm (gain map) boxes. + */ + +#ifndef JXL_GAIN_MAP_H_ +#define JXL_GAIN_MAP_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Gain map bundle + * + * This structure is used to serialize gain map data to and from an input + * buffer. It holds pointers to sections within the buffer, and different parts + * of the gain map data such as metadata, ICC profile data, and the gain map + * itself. + * + * The pointers in this structure do not take ownership of the memory they point + * to. Instead, they reference specific locations within the provided buffer. It + * is the caller's responsibility to ensure that the buffer remains valid and is + * not deallocated as long as these pointers are in use. The structure should be + * considered as providing a view into the buffer, not as an owner of the data. + */ +typedef struct { + /** Version number of the gain map bundle. */ + uint8_t jhgm_version; + /** Size of the gain map metadata in bytes. */ + uint16_t gain_map_metadata_size; + /** Pointer to the gain map metadata, which is a binary + * blob following ISO 21496-1. This pointer references data within the input + * buffer. */ + const uint8_t* gain_map_metadata; + /** Indicates whether a color encoding is present. */ + JXL_BOOL has_color_encoding; + /** If has_color_encoding is true, this field contains the + * uncompressed color encoding data. */ + JxlColorEncoding color_encoding; + /** Size of the alternative ICC profile in bytes (compressed + * size). */ + uint32_t alt_icc_size; + /** Pointer to the compressed ICC profile. This pointer references + * data within the input buffer. */ + const uint8_t* alt_icc; + /** Size of the gain map in bytes. */ + uint32_t gain_map_size; + /** Pointer to the gain map data, which is a JPEG XL naked + * codestream. This pointer references data within the input buffer.*/ + const uint8_t* gain_map; +} JxlGainMapBundle; + +/** + * Calculates the total size required to serialize the gain map bundle into a + * binary buffer. This function accounts for all the necessary space to + * serialize fields such as gain map metadata, color encoding, compressed ICC + * profile data, and the gain map itself. + * + * @param[in] map_bundle Pointer to the JxlGainMapBundle containing all + * necessary data to compute the size. + * @param[out] bundle_size The size in bytes required to serialize the bundle. + * @return Whether setting the size was successful. + */ +JXL_EXPORT JXL_BOOL JxlGainMapGetBundleSize(const JxlGainMapBundle* map_bundle, + size_t* bundle_size); + +/** + * Serializes the gain map bundle into a preallocated buffer. The function + * ensures that all parts of the bundle such as metadata, color encoding, + * compressed ICC profile, and the gain map are correctly encoded into the + * buffer. First call `JxlGainMapGetBundleSize` to get the size needed for + * the buffer. + * + * @param[in] map_bundle Pointer to the `JxlGainMapBundle` to serialize. + * @param[out] output_buffer Pointer to the buffer where the serialized data + * will be written. + * @param[in] output_buffer_size The size of the output buffer in bytes. Must be + * large enough to hold the entire serialized data. + * @param[out] bytes_written The number of bytes written to the output buffer. + * @return Whether writing the bundle was successful. + */ +JXL_EXPORT JXL_BOOL JxlGainMapWriteBundle(const JxlGainMapBundle* map_bundle, + uint8_t* output_buffer, + size_t output_buffer_size, + size_t* bytes_written); + +/** + * Deserializes a gain map bundle from a provided buffer and populates a + * `JxlGainMapBundle` structure with the data extracted. This function assumes + * the buffer contains a valid serialized gain map bundle. After successful + * execution, the `JxlGainMapBundle` structure will reference three different + * sections within the buffer: + * - gain_map_metadata + * - alt_icc + * - gain_map + * These sections will be accompanied by their respective sizes. Users must + * ensure that the buffer remains valid as long as these pointers are in use. + * @param[in,out] map_bundle Pointer to a preallocated `JxlGainMapBundle` where + * the deserialized data will be stored. + * @param[in] input_buffer Pointer to the buffer containing the serialized gain + * map bundle data. + * @param[in] input_buffer_size The size of the input buffer in bytes. + * @param[out] bytes_read The number of bytes read from the input buffer. + * @return Whether reading the bundle was successful. + */ +JXL_EXPORT JXL_BOOL JxlGainMapReadBundle(JxlGainMapBundle* map_bundle, + const uint8_t* input_buffer, + size_t input_buffer_size, + size_t* bytes_read); + +#ifdef __cplusplus +} +#endif + +#endif /* JXL_GAIN_MAP_H_ */ + +/** @} */ diff --git a/third_party/jpeg-xl/lib/include/jxl/memory_manager.h b/third_party/jpeg-xl/lib/include/jxl/memory_manager.h index 52640a8beba56..05b4abe90b520 100644 --- a/third_party/jpeg-xl/lib/include/jxl/memory_manager.h +++ b/third_party/jpeg-xl/lib/include/jxl/memory_manager.h @@ -15,7 +15,7 @@ #include -#if defined(__cplusplus) || defined(c_plusplus) +#ifdef __cplusplus extern "C" { #endif @@ -55,7 +55,8 @@ typedef struct JxlMemoryManagerStruct { /** Memory allocation function. This can be NULL if and only if also the * free() member in this class is NULL. All dynamic memory will be allocated - * and freed with these functions if they are not NULL. */ + * and freed with these functions if they are not NULL, otherwise with the + * standard malloc/free. */ jpegxl_alloc_func alloc; /** Free function matching the alloc() member. */ jpegxl_free_func free; @@ -63,7 +64,7 @@ typedef struct JxlMemoryManagerStruct { /* TODO(deymo): Add cache-aligned alloc/free functions here. */ } JxlMemoryManager; -#if defined(__cplusplus) || defined(c_plusplus) +#ifdef __cplusplus } #endif diff --git a/third_party/jpeg-xl/lib/include/jxl/parallel_runner.h b/third_party/jpeg-xl/lib/include/jxl/parallel_runner.h index ea66685dbc0e7..742f9598e90a5 100644 --- a/third_party/jpeg-xl/lib/include/jxl/parallel_runner.h +++ b/third_party/jpeg-xl/lib/include/jxl/parallel_runner.h @@ -40,20 +40,25 @@ #include #include -#if defined(__cplusplus) || defined(c_plusplus) +#ifdef __cplusplus extern "C" { #endif /** Return code used in the JxlParallel* functions as return value. A value - * of 0 means success and any other value means error. The special value - * ::JXL_PARALLEL_RET_RUNNER_ERROR can be used by the runner to indicate any - * other error. + * of ::JXL_PARALLEL_RET_SUCCESS means success and any other value means error. + * The special value ::JXL_PARALLEL_RET_RUNNER_ERROR can be used by the runner + * to indicate any other error. */ typedef int JxlParallelRetCode; /** - * General error returned by the @ref JxlParallelRunInit function to indicate - * an error. + * Code returned by the @ref JxlParallelRunInit function to indicate success. + */ +#define JXL_PARALLEL_RET_SUCCESS (0) + +/** + * Code returned by the @ref JxlParallelRunInit function to indicate a general + * error. */ #define JXL_PARALLEL_RET_RUNNER_ERROR (-1) @@ -146,11 +151,11 @@ typedef JxlParallelRetCode (*JxlParallelRunner)( // order. (*func)(jpegxl_opaque, i, 0); } - return 0; + return JXL_PARALLEL_RET_SUCCESS; } */ -#if defined(__cplusplus) || defined(c_plusplus) +#ifdef __cplusplus } #endif diff --git a/third_party/jpeg-xl/lib/include/jxl/resizable_parallel_runner.h b/third_party/jpeg-xl/lib/include/jxl/resizable_parallel_runner.h index c82b0bc23b81d..b0bf68091ea21 100644 --- a/third_party/jpeg-xl/lib/include/jxl/resizable_parallel_runner.h +++ b/third_party/jpeg-xl/lib/include/jxl/resizable_parallel_runner.h @@ -37,7 +37,7 @@ #include #include -#if defined(__cplusplus) || defined(c_plusplus) +#ifdef __cplusplus extern "C" { #endif @@ -68,7 +68,7 @@ JxlResizableParallelRunnerSuggestThreads(uint64_t xsize, uint64_t ysize); */ JXL_THREADS_EXPORT void JxlResizableParallelRunnerDestroy(void* runner_opaque); -#if defined(__cplusplus) || defined(c_plusplus) +#ifdef __cplusplus } #endif diff --git a/third_party/jpeg-xl/lib/include/jxl/resizable_parallel_runner_cxx.h b/third_party/jpeg-xl/lib/include/jxl/resizable_parallel_runner_cxx.h index 84ba82772a82e..344c96cc9ebf9 100644 --- a/third_party/jpeg-xl/lib/include/jxl/resizable_parallel_runner_cxx.h +++ b/third_party/jpeg-xl/lib/include/jxl/resizable_parallel_runner_cxx.h @@ -21,7 +21,7 @@ #include -#if !(defined(__cplusplus) || defined(c_plusplus)) +#ifndef __cplusplus #error \ "This a C++ only header. Use jxl/jxl_resizable_parallel_runner.h from C" \ "sources." diff --git a/third_party/jpeg-xl/lib/include/jxl/stats.h b/third_party/jpeg-xl/lib/include/jxl/stats.h index 5ed440636f355..35930b4da1547 100644 --- a/third_party/jpeg-xl/lib/include/jxl/stats.h +++ b/third_party/jpeg-xl/lib/include/jxl/stats.h @@ -16,7 +16,7 @@ #include #include -#if defined(__cplusplus) || defined(c_plusplus) +#ifdef __cplusplus extern "C" { #endif @@ -94,7 +94,7 @@ JXL_EXPORT size_t JxlEncoderStatsGet(const JxlEncoderStats* stats, JXL_EXPORT void JxlEncoderStatsMerge(JxlEncoderStats* stats, const JxlEncoderStats* other); -#if defined(__cplusplus) || defined(c_plusplus) +#ifdef __cplusplus } #endif diff --git a/third_party/jpeg-xl/lib/include/jxl/thread_parallel_runner.h b/third_party/jpeg-xl/lib/include/jxl/thread_parallel_runner.h index 933f373ce960c..fbfe9e20749aa 100644 --- a/third_party/jpeg-xl/lib/include/jxl/thread_parallel_runner.h +++ b/third_party/jpeg-xl/lib/include/jxl/thread_parallel_runner.h @@ -37,7 +37,7 @@ #include #include -#if defined(__cplusplus) || defined(c_plusplus) +#ifdef __cplusplus extern "C" { #endif @@ -62,7 +62,7 @@ JXL_THREADS_EXPORT void JxlThreadParallelRunnerDestroy(void* runner_opaque); */ JXL_THREADS_EXPORT size_t JxlThreadParallelRunnerDefaultNumWorkerThreads(void); -#if defined(__cplusplus) || defined(c_plusplus) +#ifdef __cplusplus } #endif diff --git a/third_party/jpeg-xl/lib/include/jxl/thread_parallel_runner_cxx.h b/third_party/jpeg-xl/lib/include/jxl/thread_parallel_runner_cxx.h index 6c0bd4b302859..7f35ca00e2898 100644 --- a/third_party/jpeg-xl/lib/include/jxl/thread_parallel_runner_cxx.h +++ b/third_party/jpeg-xl/lib/include/jxl/thread_parallel_runner_cxx.h @@ -21,7 +21,7 @@ #include #include -#if !(defined(__cplusplus) || defined(c_plusplus)) +#ifndef __cplusplus #error \ "This a C++ only header. Use jxl/jxl_thread_parallel_runner.h from C" \ "sources." diff --git a/third_party/jpeg-xl/lib/include/jxl/types.h b/third_party/jpeg-xl/lib/include/jxl/types.h index 2538dbaa82e3b..1844375f68dac 100644 --- a/third_party/jpeg-xl/lib/include/jxl/types.h +++ b/third_party/jpeg-xl/lib/include/jxl/types.h @@ -16,7 +16,7 @@ #include #include -#if defined(__cplusplus) || defined(c_plusplus) +#ifdef __cplusplus extern "C" { #endif @@ -145,7 +145,7 @@ typedef struct { */ typedef char JxlBoxType[4]; -#if defined(__cplusplus) || defined(c_plusplus) +#ifdef __cplusplus } #endif diff --git a/third_party/jpeg-xl/lib/jpegli.cmake b/third_party/jpeg-xl/lib/jpegli.cmake index f06912f4387ad..a471c8b2abd8c 100644 --- a/third_party/jpeg-xl/lib/jpegli.cmake +++ b/third_party/jpeg-xl/lib/jpegli.cmake @@ -88,7 +88,6 @@ foreach (TESTFILE IN LISTS JPEGXL_INTERNAL_JPEGLI_TESTS) target_link_libraries(${TESTNAME} hwy jpegli-static - gmock GTest::GTest GTest::Main ${JPEG_LIBRARIES} diff --git a/third_party/jpeg-xl/lib/jpegli/README.md b/third_party/jpeg-xl/lib/jpegli/README.md index 72f13afd2265b..7241d1eaabfd9 100644 --- a/third_party/jpeg-xl/lib/jpegli/README.md +++ b/third_party/jpeg-xl/lib/jpegli/README.md @@ -1,3 +1,6 @@ +:warning: **Important Update:** Development continues at https://github.com/google/jpegli + + # Improved JPEG encoder and decoder implementation This subdirectory contains a JPEG encoder and decoder implementation that is diff --git a/third_party/jpeg-xl/lib/jpegli/adaptive_quantization.cc b/third_party/jpeg-xl/lib/jpegli/adaptive_quantization.cc index 2039326cbd4a7..11367ee66083f 100644 --- a/third_party/jpeg-xl/lib/jpegli/adaptive_quantization.cc +++ b/third_party/jpeg-xl/lib/jpegli/adaptive_quantization.cc @@ -279,8 +279,8 @@ V GammaModulation(const D d, const size_t x, const size_t y, // ideally -1.0, but likely optimal correction adds some entropy, so slightly // less than that. // ln(2) constant folded in because we want std::log but have FastLog2f. - const auto kGam = Set(d, -0.15526878023684174f * 0.693147180559945f); - return MulAdd(kGam, FastLog2f(d, overall_ratio), out_val); + const auto kGamma = Set(d, -0.15526878023684174f * 0.693147180559945f); + return MulAdd(kGamma, FastLog2f(d, overall_ratio), out_val); } // Change precision in 8x8 blocks that have high frequency content. @@ -478,11 +478,11 @@ void ComputePreErosion(const RowBuffer& input, const size_t xsize, } if (iy % 4 == 3) { size_t y_out = y0_out + iy / 4; - float* row_dout = pre_erosion->Row(y_out); + float* row_d_out = pre_erosion->Row(y_out); for (size_t x = 0; x < xsize_out; x++) { - row_dout[x] = (row_out[x * 4] + row_out[x * 4 + 1] + - row_out[x * 4 + 2] + row_out[x * 4 + 3]) * - 0.25f; + row_d_out[x] = (row_out[x * 4] + row_out[x * 4 + 1] + + row_out[x * 4 + 2] + row_out[x * 4 + 3]) * + 0.25f; } pre_erosion->PadRow(y_out, xsize_out, border); } diff --git a/third_party/jpeg-xl/lib/jpegli/color_quantize.cc b/third_party/jpeg-xl/lib/jpegli/color_quantize.cc index c4f32bf439c43..d5b0097f3d066 100644 --- a/third_party/jpeg-xl/lib/jpegli/color_quantize.cc +++ b/third_party/jpeg-xl/lib/jpegli/color_quantize.cc @@ -11,7 +11,6 @@ #include "lib/jpegli/decode_internal.h" #include "lib/jpegli/error.h" -#include "lib/jxl/base/status.h" namespace jpegli { @@ -438,8 +437,8 @@ void FindCandidatesForCell(j_decompress_ptr cinfo, int ncomp, const int cell[], void CreateInverseColorMap(j_decompress_ptr cinfo) { jpeg_decomp_master* m = cinfo->master; int ncomp = cinfo->out_color_components; - JXL_ASSERT(ncomp > 0); - JXL_ASSERT(ncomp <= kMaxComponents); + JPEGLI_CHECK(ncomp > 0); + JPEGLI_CHECK(ncomp <= kMaxComponents); int num_cells = 1; for (int c = 0; c < ncomp; ++c) { num_cells *= (1 << kNumColorCellBits[c]); @@ -474,7 +473,7 @@ int LookupColorIndex(j_decompress_ptr cinfo, const JSAMPLE* pixel) { cell_idx += (pixel[c] >> (8 - kNumColorCellBits[c])) * stride; stride <<= kNumColorCellBits[c]; } - JXL_ASSERT(cell_idx < m->candidate_lists_.size()); + JPEGLI_CHECK(cell_idx < m->candidate_lists_.size()); int mindist = std::numeric_limits::max(); const auto& candidates = m->candidate_lists_[cell_idx]; for (uint8_t i : candidates) { @@ -489,7 +488,7 @@ int LookupColorIndex(j_decompress_ptr cinfo, const JSAMPLE* pixel) { } } } - JXL_ASSERT(index < cinfo->actual_number_of_colors); + JPEGLI_CHECK(index < cinfo->actual_number_of_colors); return index; } diff --git a/third_party/jpeg-xl/lib/jpegli/color_transform.cc b/third_party/jpeg-xl/lib/jpegli/color_transform.cc index 020a6fd80c8db..ec906bedce414 100644 --- a/third_party/jpeg-xl/lib/jpegli/color_transform.cc +++ b/third_party/jpeg-xl/lib/jpegli/color_transform.cc @@ -26,11 +26,16 @@ using hwy::HWY_NAMESPACE::Mul; using hwy::HWY_NAMESPACE::MulAdd; using hwy::HWY_NAMESPACE::Sub; -void YCbCrToRGB(float* row[kMaxComponents], size_t xsize) { +template +void YCbCrToExtRGB(float* row[kMaxComponents], size_t xsize) { const HWY_CAPPED(float, 8) df; - float* JXL_RESTRICT row0 = row[0]; - float* JXL_RESTRICT row1 = row[1]; - float* JXL_RESTRICT row2 = row[2]; + const float* row_y = row[0]; + const float* row_cb = row[1]; + const float* row_cr = row[2]; + float* row_r = row[kRed]; + float* row_g = row[kGreen]; + float* row_b = row[kBlue]; + float* row_a = row[kAlpha]; // Full-range BT.601 as defined by JFIF Clause 7: // https://www.itu.int/rec/T-REC-T.871-201105-I/en @@ -38,20 +43,48 @@ void YCbCrToRGB(float* row[kMaxComponents], size_t xsize) { const auto cgcb = Set(df, -0.114f * 1.772f / 0.587f); const auto cgcr = Set(df, -0.299f * 1.402f / 0.587f); const auto cbcb = Set(df, 1.772f); + const auto alpha_opaque = Set(df, 127.0f / 255.0f); for (size_t x = 0; x < xsize; x += Lanes(df)) { - const auto y_vec = Load(df, row0 + x); - const auto cb_vec = Load(df, row1 + x); - const auto cr_vec = Load(df, row2 + x); + const auto y_vec = Load(df, row_y + x); + const auto cb_vec = Load(df, row_cb + x); + const auto cr_vec = Load(df, row_cr + x); const auto r_vec = MulAdd(crcr, cr_vec, y_vec); const auto g_vec = MulAdd(cgcr, cr_vec, MulAdd(cgcb, cb_vec, y_vec)); const auto b_vec = MulAdd(cbcb, cb_vec, y_vec); - Store(r_vec, df, row0 + x); - Store(g_vec, df, row1 + x); - Store(b_vec, df, row2 + x); + Store(r_vec, df, row_r + x); + Store(g_vec, df, row_g + x); + Store(b_vec, df, row_b + x); + if (kAlpha >= 0) { + Store(alpha_opaque, df, row_a + x); + } } } +void YCbCrToRGB(float* row[kMaxComponents], size_t xsize) { + YCbCrToExtRGB<0, 1, 2, -1>(row, xsize); +} + +void YCbCrToBGR(float* row[kMaxComponents], size_t xsize) { + YCbCrToExtRGB<2, 1, 0, -1>(row, xsize); +} + +void YCbCrToRGBA(float* row[kMaxComponents], size_t xsize) { + YCbCrToExtRGB<0, 1, 2, 3>(row, xsize); +} + +void YCbCrToBGRA(float* row[kMaxComponents], size_t xsize) { + YCbCrToExtRGB<2, 1, 0, 3>(row, xsize); +} + +void YCbCrToARGB(float* row[kMaxComponents], size_t xsize) { + YCbCrToExtRGB<1, 2, 3, 0>(row, xsize); +} + +void YCbCrToABGR(float* row[kMaxComponents], size_t xsize) { + YCbCrToExtRGB<3, 2, 1, 0>(row, xsize); +} + void YCCKToCMYK(float* row[kMaxComponents], size_t xsize) { const HWY_CAPPED(float, 8) df; float* JXL_RESTRICT row0 = row[0]; @@ -66,11 +99,15 @@ void YCCKToCMYK(float* row[kMaxComponents], size_t xsize) { } } -void RGBToYCbCr(float* row[kMaxComponents], size_t xsize) { +template +void ExtRGBToYCbCr(float* row[kMaxComponents], size_t xsize) { const HWY_CAPPED(float, 8) df; - float* JXL_RESTRICT row0 = row[0]; - float* JXL_RESTRICT row1 = row[1]; - float* JXL_RESTRICT row2 = row[2]; + const float* row_r = row[kRed]; + const float* row_g = row[kGreen]; + const float* row_b = row[kBlue]; + float* row_y = row[0]; + float* row_cb = row[1]; + float* row_cr = row[2]; // Full-range BT.601 as defined by JFIF Clause 7: // https://www.itu.int/rec/T-REC-T.871-201105-I/en const auto c128 = Set(df, 128.0f); @@ -85,9 +122,9 @@ void RGBToYCbCr(float* row[kMaxComponents], size_t xsize) { const auto kNormB = Div(Set(df, 1.0f), (Add(kR, Add(kG, kAmpB)))); for (size_t x = 0; x < xsize; x += Lanes(df)) { - const auto r = Load(df, row0 + x); - const auto g = Load(df, row1 + x); - const auto b = Load(df, row2 + x); + const auto r = Load(df, row_r + x); + const auto g = Load(df, row_g + x); + const auto b = Load(df, row_b + x); const auto r_base = Mul(r, kR); const auto r_diff = Mul(r, kDiffR); const auto g_base = Mul(g, kG); @@ -96,12 +133,28 @@ void RGBToYCbCr(float* row[kMaxComponents], size_t xsize) { const auto y_base = Add(r_base, Add(g_base, b_base)); const auto cb_vec = MulAdd(Sub(b_diff, y_base), kNormB, c128); const auto cr_vec = MulAdd(Sub(r_diff, y_base), kNormR, c128); - Store(y_base, df, row0 + x); - Store(cb_vec, df, row1 + x); - Store(cr_vec, df, row2 + x); + Store(y_base, df, row_y + x); + Store(cb_vec, df, row_cb + x); + Store(cr_vec, df, row_cr + x); } } +void RGBToYCbCr(float* row[kMaxComponents], size_t xsize) { + ExtRGBToYCbCr<0, 1, 2>(row, xsize); +} + +void BGRToYCbCr(float* row[kMaxComponents], size_t xsize) { + ExtRGBToYCbCr<2, 1, 0>(row, xsize); +} + +void ARGBToYCbCr(float* row[kMaxComponents], size_t xsize) { + ExtRGBToYCbCr<1, 2, 3>(row, xsize); +} + +void ABGRToYCbCr(float* row[kMaxComponents], size_t xsize) { + ExtRGBToYCbCr<3, 2, 1>(row, xsize); +} + void CMYKToYCCK(float* row[kMaxComponents], size_t xsize) { const HWY_CAPPED(float, 8) df; float* JXL_RESTRICT row0 = row[0]; @@ -127,7 +180,15 @@ namespace jpegli { HWY_EXPORT(CMYKToYCCK); HWY_EXPORT(YCCKToCMYK); HWY_EXPORT(YCbCrToRGB); +HWY_EXPORT(YCbCrToBGR); +HWY_EXPORT(YCbCrToRGBA); +HWY_EXPORT(YCbCrToBGRA); +HWY_EXPORT(YCbCrToARGB); +HWY_EXPORT(YCbCrToABGR); HWY_EXPORT(RGBToYCbCr); +HWY_EXPORT(BGRToYCbCr); +HWY_EXPORT(ARGBToYCbCr); +HWY_EXPORT(ABGRToYCbCr); bool CheckColorSpaceComponents(int num_components, J_COLOR_SPACE colorspace) { switch (colorspace) { @@ -135,19 +196,25 @@ bool CheckColorSpaceComponents(int num_components, J_COLOR_SPACE colorspace) { return num_components == 1; case JCS_RGB: case JCS_YCbCr: +#ifdef JCS_EXTENSIONS case JCS_EXT_RGB: case JCS_EXT_BGR: +#endif return num_components == 3; case JCS_CMYK: case JCS_YCCK: +#ifdef JCS_EXTENSIONS case JCS_EXT_RGBX: case JCS_EXT_BGRX: case JCS_EXT_XBGR: case JCS_EXT_XRGB: +#endif +#ifdef JCS_ALPHA_EXTENSIONS case JCS_EXT_RGBA: case JCS_EXT_BGRA: case JCS_EXT_ABGR: case JCS_EXT_ARGB: +#endif return num_components == 4; default: // Unrecognized colorspaces can have any number of channels, since no @@ -158,16 +225,73 @@ bool CheckColorSpaceComponents(int num_components, J_COLOR_SPACE colorspace) { void NullTransform(float* row[kMaxComponents], size_t len) {} +void FillAlpha(float* row, size_t len) { + static const float kAlpha = 127.0f / 255.0f; + for (size_t i = 0; i < len; ++i) { + row[i] = kAlpha; + } +} + +// Works for BGR as well. void GrayscaleToRGB(float* row[kMaxComponents], size_t len) { memcpy(row[1], row[0], len * sizeof(row[1][0])); memcpy(row[2], row[0], len * sizeof(row[2][0])); } +// Works for BGRA as well. +void GrayscaleToRGBA(float* row[kMaxComponents], size_t len) { + memcpy(row[1], row[0], len * sizeof(row[1][0])); + memcpy(row[2], row[0], len * sizeof(row[2][0])); + FillAlpha(row[3], len); +} + +// Works for ABGR as well. +void GrayscaleToARGB(float* row[kMaxComponents], size_t len) { + memcpy(row[1], row[0], len * sizeof(row[1][0])); + memcpy(row[2], row[0], len * sizeof(row[2][0])); + memcpy(row[3], row[0], len * sizeof(row[1][0])); + FillAlpha(row[0], len); +} + void GrayscaleToYCbCr(float* row[kMaxComponents], size_t len) { memset(row[1], 0, len * sizeof(row[1][0])); memset(row[2], 0, len * sizeof(row[2][0])); } +void RGBToBGR(float* row[kMaxComponents], size_t len) { + for (size_t i = 0; i < len; ++i) { + std::swap(row[0][i], row[2][i]); + } +} + +void RGBToRGBA(float* row[kMaxComponents], size_t len) { + FillAlpha(row[3], len); +} + +void RGBToBGRA(float* row[kMaxComponents], size_t len) { + static const float kAlpha = 127.0f / 255.0f; + for (size_t i = 0; i < len; ++i) { + std::swap(row[0][i], row[2][i]); + row[3][i] = kAlpha; + } +} + +void RGBToARGB(float* row[kMaxComponents], size_t len) { + memcpy(row[3], row[2], len * sizeof(row[1][0])); + memcpy(row[2], row[1], len * sizeof(row[2][0])); + memcpy(row[1], row[0], len * sizeof(row[1][0])); + FillAlpha(row[0], len); +} + +void RGBToABGR(float* row[kMaxComponents], size_t len) { + static const float kAlpha = 127.0f / 255.0f; + for (size_t i = 0; i < len; ++i) { + std::swap(row[1][i], row[2][i]); + row[3][i] = row[0][i]; + row[0][i] = kAlpha; + } +} + void ChooseColorTransform(j_compress_ptr cinfo) { jpeg_comp_master* m = cinfo->master; if (!CheckColorSpaceComponents(cinfo->input_components, @@ -220,6 +344,43 @@ void ChooseColorTransform(j_compress_ptr cinfo) { } } + if (cinfo->jpeg_color_space == JCS_GRAYSCALE || + cinfo->jpeg_color_space == JCS_YCbCr) { + switch (cinfo->in_color_space) { +#ifdef JCS_EXTENSIONS + case JCS_EXT_RGB: + case JCS_EXT_RGBX: + m->color_transform = HWY_DYNAMIC_DISPATCH(RGBToYCbCr); + break; + case JCS_EXT_BGR: + case JCS_EXT_BGRX: + m->color_transform = HWY_DYNAMIC_DISPATCH(BGRToYCbCr); + break; + case JCS_EXT_XRGB: + m->color_transform = HWY_DYNAMIC_DISPATCH(ARGBToYCbCr); + break; + case JCS_EXT_XBGR: + m->color_transform = HWY_DYNAMIC_DISPATCH(ABGRToYCbCr); + break; +#endif +#ifdef JCS_ALPHA_EXTENSIONS + case JCS_EXT_RGBA: + m->color_transform = HWY_DYNAMIC_DISPATCH(RGBToYCbCr); + break; + case JCS_EXT_BGRA: + m->color_transform = HWY_DYNAMIC_DISPATCH(BGRToYCbCr); + break; + case JCS_EXT_ARGB: + m->color_transform = HWY_DYNAMIC_DISPATCH(ARGBToYCbCr); + break; + case JCS_EXT_ABGR: + m->color_transform = HWY_DYNAMIC_DISPATCH(ABGRToYCbCr); + break; +#endif + default:; // Nothing to do. + } + } + if (m->color_transform == nullptr) { // TODO(szabadka) Support more color transforms. JPEGLI_ERROR("Unsupported color transform %d -> %d", cinfo->in_color_space, @@ -251,18 +412,123 @@ void ChooseColorTransform(j_decompress_ptr cinfo) { m->color_transform = nullptr; if (cinfo->jpeg_color_space == JCS_GRAYSCALE) { - if (cinfo->out_color_space == JCS_RGB) { - m->color_transform = GrayscaleToRGB; + switch (cinfo->out_color_space) { + case JCS_RGB: + m->color_transform = GrayscaleToRGB; + break; +#ifdef JCS_EXTENSIONS + case JCS_EXT_RGB: + case JCS_EXT_BGR: + m->color_transform = GrayscaleToRGB; + break; + case JCS_EXT_RGBX: + case JCS_EXT_BGRX: + m->color_transform = GrayscaleToRGBA; + break; + case JCS_EXT_XRGB: + case JCS_EXT_XBGR: + m->color_transform = GrayscaleToARGB; + break; +#endif +#ifdef JCS_ALPHA_EXTENSIONS + case JCS_EXT_RGBA: + case JCS_EXT_BGRA: + m->color_transform = GrayscaleToRGBA; + break; + case JCS_EXT_ARGB: + case JCS_EXT_ABGR: + m->color_transform = GrayscaleToARGB; + break; +#endif + default: + m->color_transform = nullptr; } } else if (cinfo->jpeg_color_space == JCS_RGB) { - if (cinfo->out_color_space == JCS_GRAYSCALE) { - m->color_transform = HWY_DYNAMIC_DISPATCH(RGBToYCbCr); + switch (cinfo->out_color_space) { + case JCS_GRAYSCALE: + m->color_transform = HWY_DYNAMIC_DISPATCH(RGBToYCbCr); + break; +#ifdef JCS_EXTENSIONS + case JCS_EXT_RGB: + m->color_transform = NullTransform; + break; + case JCS_EXT_BGR: + m->color_transform = RGBToBGR; + break; + case JCS_EXT_RGBX: + m->color_transform = RGBToRGBA; + break; + case JCS_EXT_BGRX: + m->color_transform = RGBToBGRA; + break; + case JCS_EXT_XRGB: + m->color_transform = RGBToARGB; + break; + case JCS_EXT_XBGR: + m->color_transform = RGBToABGR; + break; +#endif +#ifdef JCS_ALPHA_EXTENSIONS + case JCS_EXT_RGBA: + m->color_transform = RGBToRGBA; + break; + case JCS_EXT_BGRA: + m->color_transform = RGBToBGRA; + break; + case JCS_EXT_ARGB: + m->color_transform = RGBToARGB; + break; + case JCS_EXT_ABGR: + m->color_transform = RGBToABGR; + break; +#endif + default: + m->color_transform = nullptr; } } else if (cinfo->jpeg_color_space == JCS_YCbCr) { - if (cinfo->out_color_space == JCS_RGB) { - m->color_transform = HWY_DYNAMIC_DISPATCH(YCbCrToRGB); - } else if (cinfo->out_color_space == JCS_GRAYSCALE) { - m->color_transform = NullTransform; + switch (cinfo->out_color_space) { + case JCS_GRAYSCALE: + m->color_transform = NullTransform; + break; + case JCS_RGB: + m->color_transform = HWY_DYNAMIC_DISPATCH(YCbCrToRGB); + break; +#ifdef JCS_EXTENSIONS + case JCS_EXT_RGB: + m->color_transform = HWY_DYNAMIC_DISPATCH(YCbCrToRGB); + break; + case JCS_EXT_BGR: + m->color_transform = HWY_DYNAMIC_DISPATCH(YCbCrToBGR); + break; + case JCS_EXT_RGBX: + m->color_transform = HWY_DYNAMIC_DISPATCH(YCbCrToRGBA); + break; + case JCS_EXT_BGRX: + m->color_transform = HWY_DYNAMIC_DISPATCH(YCbCrToBGRA); + break; + case JCS_EXT_XRGB: + m->color_transform = HWY_DYNAMIC_DISPATCH(YCbCrToARGB); + break; + case JCS_EXT_XBGR: + m->color_transform = HWY_DYNAMIC_DISPATCH(YCbCrToABGR); + break; +#endif +#ifdef JCS_ALPHA_EXTENSIONS + case JCS_EXT_RGBA: + m->color_transform = HWY_DYNAMIC_DISPATCH(YCbCrToRGBA); + break; + case JCS_EXT_BGRA: + m->color_transform = HWY_DYNAMIC_DISPATCH(YCbCrToBGRA); + break; + case JCS_EXT_ARGB: + m->color_transform = HWY_DYNAMIC_DISPATCH(YCbCrToARGB); + break; + case JCS_EXT_ABGR: + m->color_transform = HWY_DYNAMIC_DISPATCH(YCbCrToABGR); + break; +#endif + default: + m->color_transform = nullptr; } } else if (cinfo->jpeg_color_space == JCS_YCCK) { if (cinfo->out_color_space == JCS_CMYK) { diff --git a/third_party/jpeg-xl/lib/jpegli/common.h b/third_party/jpeg-xl/lib/jpegli/common.h index 42487f2b89469..731a2e9d3f361 100644 --- a/third_party/jpeg-xl/lib/jpegli/common.h +++ b/third_party/jpeg-xl/lib/jpegli/common.h @@ -20,14 +20,9 @@ #ifndef LIB_JPEGLI_COMMON_H_ #define LIB_JPEGLI_COMMON_H_ -/* clang-format off */ -#include -#include -/* clang-format on */ +#include "lib/jxl/base/include_jpeglib.h" // NOLINT -#include "lib/jpegli/types.h" - -#if defined(__cplusplus) || defined(c_plusplus) +#ifdef __cplusplus extern "C" { #endif @@ -41,7 +36,7 @@ JQUANT_TBL* jpegli_alloc_quant_table(j_common_ptr cinfo); JHUFF_TBL* jpegli_alloc_huff_table(j_common_ptr cinfo); -#if defined(__cplusplus) || defined(c_plusplus) +#ifdef __cplusplus } // extern "C" #endif diff --git a/third_party/jpeg-xl/lib/jpegli/common_internal.h b/third_party/jpeg-xl/lib/jpegli/common_internal.h index 248d3154e10ee..bd0a86d3b0864 100644 --- a/third_party/jpeg-xl/lib/jpegli/common_internal.h +++ b/third_party/jpeg-xl/lib/jpegli/common_internal.h @@ -6,17 +6,33 @@ #ifndef LIB_JPEGLI_COMMON_INTERNAL_H_ #define LIB_JPEGLI_COMMON_INTERNAL_H_ -#include -#include -#include +#include +#include +#include + +// Suppress any -Wdeprecated-declarations warning that might be emitted by +// GCC or Clang by std::stable_sort in C++17 or later mode +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#elif defined(__GNUC__) +#pragma GCC push_options +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif #include + +#ifdef __clang__ +#pragma clang diagnostic pop +#elif defined(__GNUC__) +#pragma GCC pop_options +#endif + #include #include "lib/jpegli/memory_manager.h" #include "lib/jpegli/simd.h" #include "lib/jxl/base/compiler_specific.h" // for ssize_t -#include "lib/jxl/base/status.h" // for JXL_CHECK namespace jpegli { @@ -94,8 +110,8 @@ class RowBuffer { public: template void Allocate(CInfoType cinfo, size_t num_rows, size_t rowsize) { + static_assert(sizeof(T) == 4); size_t vec_size = std::max(VectorSize(), sizeof(T)); - JXL_CHECK(vec_size % sizeof(T) == 0); size_t alignment = std::max(HWY_ALIGNMENT, vec_size); size_t min_memstride = alignment + rowsize * sizeof(T) + vec_size; size_t memstride = RoundUpTo(min_memstride, alignment); diff --git a/third_party/jpeg-xl/lib/jpegli/dct-inl.h b/third_party/jpeg-xl/lib/jpegli/dct-inl.h index 66cc3b6b53b76..fb54a152d59c3 100644 --- a/third_party/jpeg-xl/lib/jpegli/dct-inl.h +++ b/third_party/jpeg-xl/lib/jpegli/dct-inl.h @@ -35,24 +35,24 @@ using D = HWY_FULL(float); using DI = HWY_FULL(int32_t); template -void AddReverse(const float* JXL_RESTRICT ain1, const float* JXL_RESTRICT ain2, - float* JXL_RESTRICT aout) { +void AddReverse(const float* JXL_RESTRICT a_in1, + const float* JXL_RESTRICT a_in2, float* JXL_RESTRICT a_out) { HWY_CAPPED(float, 8) d8; for (size_t i = 0; i < N; i++) { - auto in1 = Load(d8, ain1 + i * 8); - auto in2 = Load(d8, ain2 + (N - i - 1) * 8); - Store(Add(in1, in2), d8, aout + i * 8); + auto in1 = Load(d8, a_in1 + i * 8); + auto in2 = Load(d8, a_in2 + (N - i - 1) * 8); + Store(Add(in1, in2), d8, a_out + i * 8); } } template -void SubReverse(const float* JXL_RESTRICT ain1, const float* JXL_RESTRICT ain2, - float* JXL_RESTRICT aout) { +void SubReverse(const float* JXL_RESTRICT a_in1, + const float* JXL_RESTRICT a_in2, float* JXL_RESTRICT a_out) { HWY_CAPPED(float, 8) d8; for (size_t i = 0; i < N; i++) { - auto in1 = Load(d8, ain1 + i * 8); - auto in2 = Load(d8, ain2 + (N - i - 1) * 8); - Store(Sub(in1, in2), d8, aout + i * 8); + auto in1 = Load(d8, a_in1 + i * 8); + auto in2 = Load(d8, a_in2 + (N - i - 1) * 8); + Store(Sub(in1, in2), d8, a_out + i * 8); } } @@ -73,15 +73,15 @@ void B(float* JXL_RESTRICT coeff) { // Ideally optimized away by compiler (except the multiply). template -void InverseEvenOdd(const float* JXL_RESTRICT ain, float* JXL_RESTRICT aout) { +void InverseEvenOdd(const float* JXL_RESTRICT a_in, float* JXL_RESTRICT a_out) { HWY_CAPPED(float, 8) d8; for (size_t i = 0; i < N / 2; i++) { - auto in1 = Load(d8, ain + i * 8); - Store(in1, d8, aout + 2 * i * 8); + auto in1 = Load(d8, a_in + i * 8); + Store(in1, d8, a_out + 2 * i * 8); } for (size_t i = N / 2; i < N; i++) { - auto in1 = Load(d8, ain + i * 8); - Store(in1, d8, aout + (2 * (i - N / 2) + 1) * 8); + auto in1 = Load(d8, a_in + i * 8); + Store(in1, d8, a_out + (2 * (i - N / 2) + 1) * 8); } } @@ -109,8 +109,10 @@ struct WcMultipliers<8> { }; }; +#if JXL_CXX_LANG < JXL_CXX_17 constexpr float WcMultipliers<4>::kMultipliers[]; constexpr float WcMultipliers<8>::kMultipliers[]; +#endif // Invoked on full vector. template diff --git a/third_party/jpeg-xl/lib/jpegli/decode.cc b/third_party/jpeg-xl/lib/jpegli/decode.cc index bf57115ad6a52..d967b787d34c1 100644 --- a/third_party/jpeg-xl/lib/jpegli/decode.cc +++ b/third_party/jpeg-xl/lib/jpegli/decode.cc @@ -54,6 +54,7 @@ void InitializeImage(j_decompress_ptr cinfo) { m->found_soi_ = false; m->found_dri_ = false; m->found_sof_ = false; + m->found_sos_ = false; m->found_eoi_ = false; m->icc_index_ = 0; m->icc_total_ = 0; @@ -177,7 +178,7 @@ void BuildHuffmanLookupTable(j_decompress_ptr cinfo, JHUFF_TBL* table, for (int i = 0; i < total_count; ++i) { int value = table->huffval[i]; if (values_seen[value]) { - return JPEGLI_ERROR("Duplicate Huffman code value %d", value); + JPEGLI_ERROR("Duplicate Huffman code value %d", value); } values_seen[value] = 1; values[i] = value; @@ -225,7 +226,7 @@ void PrepareForScan(j_decompress_ptr cinfo) { HuffmanTableEntry* huff_lut = &m->dc_huff_lut_[dc_tbl_idx * kJpegHuffmanLutSize]; if (!table) { - return JPEGLI_ERROR("DC Huffman table %d not found", dc_tbl_idx); + JPEGLI_ERROR("DC Huffman table %d not found", dc_tbl_idx); } BuildHuffmanLookupTable(cinfo, table, huff_lut); } @@ -235,7 +236,7 @@ void PrepareForScan(j_decompress_ptr cinfo) { HuffmanTableEntry* huff_lut = &m->ac_huff_lut_[ac_tbl_idx * kJpegHuffmanLutSize]; if (!table) { - return JPEGLI_ERROR("AC Huffman table %d not found", ac_tbl_idx); + JPEGLI_ERROR("AC Huffman table %d not found", ac_tbl_idx); } BuildHuffmanLookupTable(cinfo, table, huff_lut); } @@ -243,10 +244,14 @@ void PrepareForScan(j_decompress_ptr cinfo) { // Copy quantization tables into comp_info. for (int i = 0; i < cinfo->comps_in_scan; ++i) { jpeg_component_info* comp = cinfo->cur_comp_info[i]; + int quant_tbl_idx = comp->quant_tbl_no; + JQUANT_TBL* quant_table = cinfo->quant_tbl_ptrs[quant_tbl_idx]; + if (!quant_table) { + JPEGLI_ERROR("Quantization table with index %d not found", quant_tbl_idx); + } if (comp->quant_table == nullptr) { comp->quant_table = Allocate(cinfo, 1, JPOOL_IMAGE); - memcpy(comp->quant_table, cinfo->quant_tbl_ptrs[comp->quant_tbl_no], - sizeof(JQUANT_TBL)); + memcpy(comp->quant_table, quant_table, sizeof(JQUANT_TBL)); } } if (cinfo->comps_in_scan == 1) { @@ -723,16 +728,36 @@ void jpegli_calc_output_dimensions(j_decompress_ptr cinfo) { } } } - if (cinfo->out_color_space == JCS_GRAYSCALE) { - cinfo->out_color_components = 1; - } else if (cinfo->out_color_space == JCS_RGB || - cinfo->out_color_space == JCS_YCbCr) { - cinfo->out_color_components = 3; - } else if (cinfo->out_color_space == JCS_CMYK || - cinfo->out_color_space == JCS_YCCK) { - cinfo->out_color_components = 4; - } else { - cinfo->out_color_components = cinfo->num_components; + switch (cinfo->out_color_space) { + case JCS_GRAYSCALE: + cinfo->out_color_components = 1; + break; + case JCS_RGB: + case JCS_YCbCr: +#ifdef JCS_EXTENSIONS + case JCS_EXT_RGB: + case JCS_EXT_BGR: +#endif + cinfo->out_color_components = 3; + break; + case JCS_CMYK: + case JCS_YCCK: +#ifdef JCS_EXTENSIONS + case JCS_EXT_RGBX: + case JCS_EXT_BGRX: + case JCS_EXT_XBGR: + case JCS_EXT_XRGB: +#endif +#ifdef JCS_ALPHA_EXTENSIONS + case JCS_EXT_RGBA: + case JCS_EXT_BGRA: + case JCS_EXT_ABGR: + case JCS_EXT_ARGB: +#endif + cinfo->out_color_components = 4; + break; + default: + cinfo->out_color_components = cinfo->num_components; } cinfo->output_components = cinfo->quantize_colors ? 1 : cinfo->out_color_components; @@ -740,8 +765,11 @@ void jpegli_calc_output_dimensions(j_decompress_ptr cinfo) { } boolean jpegli_has_multiple_scans(j_decompress_ptr cinfo) { - if (cinfo->input_scan_number == 0) { - JPEGLI_ERROR("No SOS marker found."); + if (cinfo->global_state != jpegli::kDecHeaderDone && + cinfo->global_state != jpegli::kDecProcessScan && + cinfo->global_state != jpegli::kDecProcessMarkers) { + JPEGLI_ERROR("jpegli_has_multiple_scans: unexpected state %d", + cinfo->global_state); } return TO_JXL_BOOL(cinfo->master->is_multiscan_); } diff --git a/third_party/jpeg-xl/lib/jpegli/decode.h b/third_party/jpeg-xl/lib/jpegli/decode.h index 9800ebf67a210..78c39b409cd16 100644 --- a/third_party/jpeg-xl/lib/jpegli/decode.h +++ b/third_party/jpeg-xl/lib/jpegli/decode.h @@ -21,8 +21,9 @@ #define LIB_JPEGLI_DECODE_H_ #include "lib/jpegli/common.h" +#include "lib/jpegli/types.h" -#if defined(__cplusplus) || defined(c_plusplus) +#ifdef __cplusplus extern "C" { #endif @@ -36,7 +37,7 @@ void jpegli_CreateDecompress(j_decompress_ptr cinfo, int version, void jpegli_stdio_src(j_decompress_ptr cinfo, FILE *infile); void jpegli_mem_src(j_decompress_ptr cinfo, const unsigned char *inbuffer, - unsigned long insize); + unsigned long insize /* NOLINT */); int jpegli_read_header(j_decompress_ptr cinfo, boolean require_image); @@ -99,7 +100,7 @@ void jpegli_new_colormap(j_decompress_ptr cinfo); void jpegli_set_output_format(j_decompress_ptr cinfo, JpegliDataType data_type, JpegliEndianness endianness); -#if defined(__cplusplus) || defined(c_plusplus) +#ifdef __cplusplus } // extern "C" #endif diff --git a/third_party/jpeg-xl/lib/jpegli/decode_api_test.cc b/third_party/jpeg-xl/lib/jpegli/decode_api_test.cc index bc903c2bbfad0..a3caa5106d96b 100644 --- a/third_party/jpeg-xl/lib/jpegli/decode_api_test.cc +++ b/third_party/jpeg-xl/lib/jpegli/decode_api_test.cc @@ -3,17 +3,27 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include +#include + +#include #include +#include +#include +#include +#include +#include +#include +#include #include #include "lib/jpegli/decode.h" #include "lib/jpegli/encode.h" +#include "lib/jpegli/libjpeg_test_util.h" +#include "lib/jpegli/test_params.h" #include "lib/jpegli/test_utils.h" #include "lib/jpegli/testing.h" -#include "lib/jxl/base/byte_order.h" +#include "lib/jpegli/types.h" #include "lib/jxl/base/status.h" -#include "lib/jxl/sanitizers.h" namespace jpegli { namespace { @@ -78,7 +88,8 @@ class SourceManager { return TRUE; } - static void skip_input_data(j_decompress_ptr cinfo, long num_bytes) { + static void skip_input_data(j_decompress_ptr cinfo, + long num_bytes /* NOLINT */) { auto* src = reinterpret_cast(cinfo->src); if (num_bytes <= 0) { return; @@ -219,13 +230,14 @@ struct TestConfig { float max_diff = 35.0f; }; -std::vector GetTestJpegData(TestConfig& config) { +jxl::StatusOr> GetTestJpegData(TestConfig& config) { std::vector compressed; if (!config.fn.empty()) { - compressed = ReadTestData(config.fn); + JXL_ASSIGN_OR_RETURN(compressed, ReadTestData(config.fn)); } else { GeneratePixels(&config.input); - JXL_CHECK(EncodeWithJpegli(config.input, config.jparams, &compressed)); + JXL_RETURN_IF_ERROR( + EncodeWithJpegli(config.input, config.jparams, &compressed)); } if (config.dparams.size_factor < 1.0f) { compressed.resize(compressed.size() * config.dparams.size_factor); @@ -256,8 +268,8 @@ void TestAPINonBuffered(const CompressParams& jparams, if (!jparams.icc.empty()) { uint8_t* icc_data = nullptr; unsigned int icc_len; - JXL_CHECK(jpegli_read_icc_profile(cinfo, &icc_data, &icc_len)); - JXL_CHECK(icc_data); + ASSERT_TRUE(jpegli_read_icc_profile(cinfo, &icc_data, &icc_len)); + ASSERT_TRUE(icc_data); EXPECT_EQ(0, memcmp(jparams.icc.data(), icc_data, icc_len)); free(icc_data); } @@ -278,7 +290,7 @@ void TestAPINonBuffered(const CompressParams& jparams, } if (dparams.output_mode == COEFFICIENTS) { jvirt_barray_ptr* coef_arrays = jpegli_read_coefficients(cinfo); - JXL_CHECK(coef_arrays != nullptr); + ASSERT_TRUE(coef_arrays != nullptr); CopyCoefficients(cinfo, coef_arrays, output); } else { jpegli_start_decompress(cinfo); @@ -297,10 +309,10 @@ void TestAPIBuffered(const CompressParams& jparams, SetDecompressParams(dparams, cinfo); jpegli_set_output_format(cinfo, dparams.data_type, dparams.endianness); VerifyHeader(jparams, cinfo); + bool has_multiple_scans = FROM_JXL_BOOL(jpegli_has_multiple_scans(cinfo)); EXPECT_TRUE(jpegli_start_decompress(cinfo)); // start decompress should not read the whole input in buffered image mode EXPECT_FALSE(jpegli_input_complete(cinfo)); - bool has_multiple_scans = FROM_JXL_BOOL(jpegli_has_multiple_scans(cinfo)); EXPECT_EQ(0, cinfo->output_scan_number); int sos_marker_cnt = 1; // read_header reads the first SOS marker while (!jpegli_input_complete(cinfo)) { @@ -330,7 +342,7 @@ void TestAPIBuffered(const CompressParams& jparams, ++sos_marker_cnt; // finish output reads the next SOS marker or EOI if (dparams.output_mode == COEFFICIENTS) { jvirt_barray_ptr* coef_arrays = jpegli_read_coefficients(cinfo); - JXL_CHECK(coef_arrays != nullptr); + ASSERT_TRUE(coef_arrays != nullptr); CopyCoefficients(cinfo, coef_arrays, &output_progression->back()); } } @@ -366,7 +378,8 @@ TEST(DecodeAPITest, ReuseCinfo) { "Generating input with %dx%d chroma subsampling " "progressive level %d\n", h_samp, v_samp, progr); - JXL_CHECK(EncodeWithJpegli(input, jparams, &compressed)); + JPEGLI_TEST_ENSURE_TRUE( + EncodeWithJpegli(input, jparams, &compressed)); for (JpegIOMode output_mode : {PIXELS, RAW_DATA, COEFFICIENTS}) { for (bool crop : {true, false}) { if (crop && output_mode != PIXELS) continue; @@ -408,8 +421,8 @@ TEST(DecodeAPITest, ReuseCinfo) { output_progression.clear(); src.Reset(); TestAPIBuffered(jparams, dparams, &cinfo, &output_progression); - JXL_CHECK(output_progression.size() == - expected_output_progression.size()); + JPEGLI_TEST_ENSURE_TRUE(output_progression.size() == + expected_output_progression.size()); for (size_t i = 0; i < output_progression.size(); ++i) { const TestImage& output = output_progression[i]; const TestImage& expected = expected_output_progression[i]; @@ -447,7 +460,7 @@ std::vector GenerateBasicConfigs() { TEST(DecodeAPITest, ReuseCinfoSameMemSource) { std::vector all_configs = GenerateBasicConfigs(); uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT { jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { @@ -487,7 +500,7 @@ TEST(DecodeAPITest, ReuseCinfoSameMemSource) { TEST(DecodeAPITest, ReuseCinfoSameStdSource) { std::vector all_configs = GenerateBasicConfigs(); FILE* tmpf = tmpfile(); - JXL_CHECK(tmpf); + ASSERT_TRUE(tmpf); { jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { @@ -502,7 +515,7 @@ TEST(DecodeAPITest, ReuseCinfoSameStdSource) { EXPECT_TRUE(try_catch_block()); jpegli_destroy_compress(&cinfo); } - rewind(tmpf); + fseek(tmpf, 0, SEEK_SET); std::vector all_outputs(all_configs.size()); { jpeg_decompress_struct cinfo; @@ -527,9 +540,9 @@ TEST(DecodeAPITest, ReuseCinfoSameStdSource) { TEST(DecodeAPITest, AbbreviatedStreams) { uint8_t* table_stream = nullptr; - unsigned long table_stream_size = 0; + unsigned long table_stream_size = 0; // NOLINT uint8_t* data_stream = nullptr; - unsigned long data_stream_size = 0; + unsigned long data_stream_size = 0; // NOLINT { jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { @@ -591,7 +604,8 @@ TEST_P(DecodeAPITestParam, TestAPI) { TestConfig config = GetParam(); const DecompressParams& dparams = config.dparams; if (dparams.skip_scans) return; - const std::vector compressed = GetTestJpegData(config); + JXL_ASSIGN_OR_QUIT(std::vector compressed, GetTestJpegData(config), + "Failed to create test data"); SourceManager src(compressed.data(), compressed.size(), dparams.chunk_size); TestImage output1; @@ -625,7 +639,8 @@ class DecodeAPITestParamBuffered : public ::testing::TestWithParam { TEST_P(DecodeAPITestParamBuffered, TestAPI) { TestConfig config = GetParam(); const DecompressParams& dparams = config.dparams; - const std::vector compressed = GetTestJpegData(config); + JXL_ASSIGN_OR_QUIT(std::vector compressed, GetTestJpegData(config), + "Failed to create test data."); SourceManager src(compressed.data(), compressed.size(), dparams.chunk_size); std::vector output_progression1; @@ -893,7 +908,9 @@ std::vector GenerateTests(bool buffered) { all_tests.push_back(config); } // Tests for color transforms. - for (J_COLOR_SPACE out_color_space : {JCS_RGB, JCS_GRAYSCALE}) { + for (J_COLOR_SPACE out_color_space : + {JCS_RGB, JCS_GRAYSCALE, JCS_EXT_RGB, JCS_EXT_BGR, JCS_EXT_RGBA, + JCS_EXT_BGRA, JCS_EXT_ARGB, JCS_EXT_ABGR}) { TestConfig config; config.input.xsize = config.input.ysize = 256; config.input.color_space = JCS_GRAYSCALE; @@ -902,7 +919,9 @@ std::vector GenerateTests(bool buffered) { all_tests.push_back(config); } for (J_COLOR_SPACE jpeg_color_space : {JCS_RGB, JCS_YCbCr}) { - for (J_COLOR_SPACE out_color_space : {JCS_RGB, JCS_YCbCr, JCS_GRAYSCALE}) { + for (J_COLOR_SPACE out_color_space : + {JCS_RGB, JCS_YCbCr, JCS_GRAYSCALE, JCS_EXT_RGB, JCS_EXT_BGR, + JCS_EXT_RGBA, JCS_EXT_BGRA, JCS_EXT_ARGB, JCS_EXT_ABGR}) { if (jpeg_color_space == JCS_RGB && out_color_space == JCS_YCbCr) continue; TestConfig config; config.input.xsize = config.input.ysize = 256; @@ -1107,6 +1126,8 @@ std::vector GenerateTests(bool buffered) { TestConfig config; config.input.xsize = xsize; config.input.ysize = ysize; + config.jparams.h_sampling = {1, 1, 1}; + config.jparams.v_sampling = {1, 1, 1}; all_tests.push_back(config); } } diff --git a/third_party/jpeg-xl/lib/jpegli/decode_internal.h b/third_party/jpeg-xl/lib/jpegli/decode_internal.h index ed7baa39e9867..c36f6774b9ca6 100644 --- a/third_party/jpeg-xl/lib/jpegli/decode_internal.h +++ b/third_party/jpeg-xl/lib/jpegli/decode_internal.h @@ -6,14 +6,15 @@ #ifndef LIB_JPEGLI_DECODE_INTERNAL_H_ #define LIB_JPEGLI_DECODE_INTERNAL_H_ -#include #include +#include #include #include "lib/jpegli/common.h" #include "lib/jpegli/common_internal.h" #include "lib/jpegli/huffman.h" +#include "lib/jpegli/types.h" namespace jpegli { @@ -45,19 +46,26 @@ struct jpeg_decomp_master { size_t input_buffer_pos_; // Number of bits after codestream_pos_ that were already processed. size_t codestream_bits_ahead_; - bool streaming_mode_; // Coefficient buffers jvirt_barray_ptr* coef_arrays; JBLOCKARRAY coeff_rows[jpegli::kMaxComponents]; + bool streaming_mode_; + // // Marker data processing state. // bool found_soi_; bool found_dri_; bool found_sof_; + bool found_sos_; bool found_eoi_; + + // Whether this jpeg has multiple scans (progressive or non-interleaved + // sequential). + bool is_multiscan_; + size_t icc_index_; size_t icc_total_; std::vector icc_profile_; @@ -66,16 +74,13 @@ struct jpeg_decomp_master { uint8_t markers_to_save_[32]; jpeg_marker_parser_method app_marker_parsers[16]; jpeg_marker_parser_method com_marker_parser; - // Whether this jpeg has multiple scans (progressive or non-interleaved - // sequential). - bool is_multiscan_; // Fields defined by SOF marker. size_t iMCU_cols_; int h_factor[jpegli::kMaxComponents]; int v_factor[jpegli::kMaxComponents]; - // Initialized at strat of frame. + // Initialized at start of frame. uint16_t scan_progression_[jpegli::kMaxComponents][DCTSIZE2]; // @@ -96,9 +101,11 @@ struct jpeg_decomp_master { // int output_passes_done_; JpegliDataType output_data_type_ = JPEGLI_TYPE_UINT8; - bool swap_endianness_ = false; size_t xoffset_; + bool swap_endianness_ = false; bool need_context_rows_; + bool regenerate_inverse_colormap_; + bool apply_smoothing; int min_scaled_dct_size; int scaled_dct_size[jpegli::kMaxComponents]; @@ -127,7 +134,6 @@ struct jpeg_decomp_master { uint8_t* pixels_; JSAMPARRAY scanlines_; std::vector> candidate_lists_; - bool regenerate_inverse_colormap_; float* dither_[jpegli::kMaxComponents]; float* error_row_[2 * jpegli::kMaxComponents]; size_t dither_size_; @@ -145,7 +151,6 @@ struct jpeg_decomp_master { // i.e. the bottom half when rendering incomplete scans. int (*coef_bits_latch)[SAVED_COEFS]; int (*prev_coef_bits_latch)[SAVED_COEFS]; - bool apply_smoothing; }; #endif // LIB_JPEGLI_DECODE_INTERNAL_H_ diff --git a/third_party/jpeg-xl/lib/jpegli/decode_marker.cc b/third_party/jpeg-xl/lib/jpegli/decode_marker.cc index 6ef2dd4d7eec7..2621ed08670cc 100644 --- a/third_party/jpeg-xl/lib/jpegli/decode_marker.cc +++ b/third_party/jpeg-xl/lib/jpegli/decode_marker.cc @@ -23,23 +23,22 @@ constexpr uint8_t kIccProfileTag[12] = "ICC_PROFILE"; // Macros for commonly used error conditions. -#define JPEG_VERIFY_LEN(n) \ - if (pos + (n) > len) { \ - return JPEGLI_ERROR("Unexpected end of marker: pos=%" PRIuS \ - " need=%d len=%" PRIuS, \ - pos, static_cast(n), len); \ +#define JPEG_VERIFY_LEN(n) \ + if (pos + (n) > len) { \ + JPEGLI_ERROR("Unexpected end of marker: pos=%" PRIuS \ + " need=%d len=%" PRIuS, \ + pos, static_cast(n), len); \ } -#define JPEG_VERIFY_INPUT(var, low, high) \ - if ((var) < (low) || (var) > (high)) { \ - return JPEGLI_ERROR("Invalid " #var ": %d", static_cast(var)); \ +#define JPEG_VERIFY_INPUT(var, low, high) \ + if ((var) < (low) || (var) > (high)) { \ + JPEGLI_ERROR("Invalid " #var ": %d", static_cast(var)); \ } -#define JPEG_VERIFY_MARKER_END() \ - if (pos != len) { \ - return JPEGLI_ERROR("Invalid marker length: declared=%" PRIuS \ - " actual=%" PRIuS, \ - len, pos); \ +#define JPEG_VERIFY_MARKER_END() \ + if (pos != len) { \ + JPEGLI_ERROR("Invalid marker length: declared=%" PRIuS " actual=%" PRIuS, \ + len, pos); \ } inline int ReadUint8(const uint8_t* data, size_t* pos) { @@ -104,9 +103,6 @@ void ProcessSOF(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { int quant_tbl_idx = ReadUint8(data, &pos); JPEG_VERIFY_INPUT(quant_tbl_idx, 0, NUM_QUANT_TBLS - 1); comp->quant_tbl_no = quant_tbl_idx; - if (cinfo->quant_tbl_ptrs[quant_tbl_idx] == nullptr) { - JPEGLI_ERROR("Quantization table with index %u not found", quant_tbl_idx); - } comp->quant_table = nullptr; // will be allocated after SOS marker } JPEG_VERIFY_MARKER_END(); @@ -169,6 +165,7 @@ void ProcessSOS(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { if (!m->found_sof_) { JPEGLI_ERROR("Unexpected SOS marker."); } + m->found_sos_ = true; size_t pos = 2; JPEG_VERIFY_LEN(1); cinfo->comps_in_scan = ReadUint8(data, &pos); @@ -182,7 +179,7 @@ void ProcessSOS(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { for (int i = 0; i < cinfo->comps_in_scan; ++i) { int id = ReadUint8(data, &pos); if (ids_seen[id]) { // (cf. section B.2.3, regarding CSj) - return JPEGLI_ERROR("Duplicate ID %d in SOS.", id); + JPEGLI_ERROR("Duplicate ID %d in SOS.", id); } ids_seen[id] = 1; jpeg_component_info* comp = nullptr; @@ -193,8 +190,7 @@ void ProcessSOS(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { } } if (!comp) { - return JPEGLI_ERROR("SOS marker: Could not find component with id %d", - id); + JPEGLI_ERROR("SOS marker: Could not find component with id %d", id); } int c = ReadUint8(data, &pos); comp->dc_tbl_no = c >> 4; @@ -262,12 +258,12 @@ void ProcessSOS(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { int comp_idx = cinfo->cur_comp_info[i]->component_index; for (int k = cinfo->Ss; k <= cinfo->Se; ++k) { if (m->scan_progression_[comp_idx][k] & scan_bitmask) { - return JPEGLI_ERROR( + JPEGLI_ERROR( "Overlapping scans: component=%d k=%d prev_mask: %u cur_mask %u", comp_idx, k, m->scan_progression_[i][k], scan_bitmask); } if (m->scan_progression_[comp_idx][k] & refinement_bitmask) { - return JPEGLI_ERROR( + JPEGLI_ERROR( "Invalid scan order, a more refined scan was already done: " "component=%d k=%d prev_mask=%u cur_mask=%u", comp_idx, k, m->scan_progression_[i][k], scan_bitmask); @@ -276,7 +272,7 @@ void ProcessSOS(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { } } if (cinfo->Al > 10) { - return JPEGLI_ERROR("Scan parameter Al=%d is not supported.", cinfo->Al); + JPEGLI_ERROR("Scan parameter Al=%d is not supported.", cinfo->Al); } } @@ -286,7 +282,7 @@ void ProcessSOS(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { void ProcessDHT(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { size_t pos = 2; if (pos == len) { - return JPEGLI_ERROR("DHT marker: no Huffman table found"); + JPEGLI_ERROR("DHT marker: no Huffman table found"); } while (pos < len) { JPEG_VERIFY_LEN(1 + kJpegHuffmanMaxBitLength); @@ -339,12 +335,12 @@ void ProcessDHT(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { void ProcessDQT(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { jpeg_decomp_master* m = cinfo->master; - if (m->found_sof_) { + if (m->found_sos_) { JPEGLI_ERROR("Updating quant tables between scans is not supported."); } size_t pos = 2; if (pos == len) { - return JPEGLI_ERROR("DQT marker: no quantization table found"); + JPEGLI_ERROR("DQT marker: no quantization table found"); } while (pos < len) { JPEG_VERIFY_LEN(1); @@ -378,7 +374,7 @@ void ProcessDNL(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { void ProcessDRI(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { jpeg_decomp_master* m = cinfo->master; if (m->found_dri_) { - return JPEGLI_ERROR("Duplicate DRI marker."); + JPEGLI_ERROR("Duplicate DRI marker."); } m->found_dri_ = true; size_t pos = 2; @@ -412,24 +408,24 @@ void ProcessAPP(j_decompress_ptr cinfo, const uint8_t* data, size_t len) { payload += sizeof(kIccProfileTag); payload_size -= sizeof(kIccProfileTag); if (payload_size < 2) { - return JPEGLI_ERROR("ICC chunk is too small."); + JPEGLI_ERROR("ICC chunk is too small."); } uint8_t index = payload[0]; uint8_t total = payload[1]; ++m->icc_index_; if (m->icc_index_ != index) { - return JPEGLI_ERROR("Invalid ICC chunk order."); + JPEGLI_ERROR("Invalid ICC chunk order."); } if (total == 0) { - return JPEGLI_ERROR("Invalid ICC chunk total."); + JPEGLI_ERROR("Invalid ICC chunk total."); } if (m->icc_total_ == 0) { m->icc_total_ = total; } else if (m->icc_total_ != total) { - return JPEGLI_ERROR("Invalid ICC chunk total."); + JPEGLI_ERROR("Invalid ICC chunk total."); } if (m->icc_index_ > m->icc_total_) { - return JPEGLI_ERROR("Invalid ICC chunk index."); + JPEGLI_ERROR("Invalid ICC chunk index."); } m->icc_profile_.insert(m->icc_profile_.end(), payload + 2, payload + payload_size); diff --git a/third_party/jpeg-xl/lib/jpegli/decode_scan.cc b/third_party/jpeg-xl/lib/jpegli/decode_scan.cc index 1b50792f0af4c..6c4e5ac5f77e5 100644 --- a/third_party/jpeg-xl/lib/jpegli/decode_scan.cc +++ b/third_party/jpeg-xl/lib/jpegli/decode_scan.cc @@ -7,7 +7,7 @@ #include -#include +#include // HWY_ALIGN_MAX #include "lib/jpegli/decode_internal.h" #include "lib/jpegli/error.h" @@ -159,7 +159,7 @@ int ReadSymbol(const HuffmanTableEntry* table, BitReaderState* br) { * The lower half represents the negative DIFFs with an offset. */ int HuffExtend(int x, int s) { - JXL_DASSERT(s >= 1); + JXL_DASSERT(s > 0); int half = 1 << (s - 1); if (x >= half) { JXL_DASSERT(x < (1 << s)); diff --git a/third_party/jpeg-xl/lib/jpegli/destination_manager.cc b/third_party/jpeg-xl/lib/jpegli/destination_manager.cc index 6548130866c30..05d35797b87cb 100644 --- a/third_party/jpeg-xl/lib/jpegli/destination_manager.cc +++ b/third_party/jpeg-xl/lib/jpegli/destination_manager.cc @@ -52,7 +52,7 @@ struct MemoryDestinationManager { jpeg_destination_mgr pub; // Output buffer supplied by the application uint8_t** output; - unsigned long* output_size; + unsigned long* output_size; // NOLINT // Output buffer allocated by us. uint8_t* temp_buffer; // Current output buffer (either application supplied or allocated by us). @@ -113,7 +113,7 @@ void jpegli_stdio_dest(j_compress_ptr cinfo, FILE* outfile) { } void jpegli_mem_dest(j_compress_ptr cinfo, unsigned char** outbuffer, - unsigned long* outsize) { + unsigned long* outsize /* NOLINT */) { if (outbuffer == nullptr || outsize == nullptr) { JPEGLI_ERROR("jpegli_mem_dest: Invalid destination."); } diff --git a/third_party/jpeg-xl/lib/jpegli/downsample.cc b/third_party/jpeg-xl/lib/jpegli/downsample.cc index f1e945d509392..1e5bb1563b190 100644 --- a/third_party/jpeg-xl/lib/jpegli/downsample.cc +++ b/third_party/jpeg-xl/lib/jpegli/downsample.cc @@ -295,13 +295,14 @@ void DownsampleInputBuffer(j_compress_ptr cinfo) { } auto& input = *m->smooth_input[c]; auto& output = *m->raw_data[c]; - const size_t yout0 = y0 / v_factor; + const size_t y_out0 = y0 / v_factor; float* rows_in[MAX_SAMP_FACTOR]; - for (size_t yin = y0, yout = yout0; yin < y1; yin += v_factor, ++yout) { + for (size_t y_in = y0, y_out = y_out0; y_in < y1; + y_in += v_factor, ++y_out) { for (int iy = 0; iy < v_factor; ++iy) { - rows_in[iy] = input.Row(yin + iy); + rows_in[iy] = input.Row(y_in + iy); } - float* row_out = output.Row(yout); + float* row_out = output.Row(y_out); (*m->downsample_method[c])(rows_in, xsize_padded, row_out); } } diff --git a/third_party/jpeg-xl/lib/jpegli/encode.cc b/third_party/jpeg-xl/lib/jpegli/encode.cc index 15a961283904c..410eeed8083ec 100644 --- a/third_party/jpeg-xl/lib/jpegli/encode.cc +++ b/third_party/jpeg-xl/lib/jpegli/encode.cc @@ -146,7 +146,7 @@ void SetDefaultScanScript(j_compress_ptr cinfo) { ++next_scan; } } - JXL_ASSERT(next_scan - cinfo->script_space == cinfo->script_space_size); + JPEGLI_CHECK(next_scan - cinfo->script_space == cinfo->script_space_size); cinfo->scan_info = cinfo->script_space; cinfo->num_scans = cinfo->script_space_size; } @@ -283,15 +283,15 @@ void ProcessCompressionParams(j_compress_ptr cinfo) { JPEGLI_ERROR("Invalid sampling factor %d x %d", comp->h_samp_factor, comp->v_samp_factor); } + if (cinfo->num_components == 1) { + // Force samp factors to 1x1 for single-component images. + comp->h_samp_factor = comp->v_samp_factor = 1; + } cinfo->max_h_samp_factor = std::max(comp->h_samp_factor, cinfo->max_h_samp_factor); cinfo->max_v_samp_factor = std::max(comp->v_samp_factor, cinfo->max_v_samp_factor); } - if (cinfo->num_components == 1 && - (cinfo->max_h_samp_factor != 1 || cinfo->max_v_samp_factor != 1)) { - JPEGLI_ERROR("Sampling is not supported for simgle component image."); - } size_t iMCU_width = DCTSIZE * cinfo->max_h_samp_factor; size_t iMCU_height = DCTSIZE * cinfo->max_v_samp_factor; size_t total_iMCU_cols = DivCeil(cinfo->image_width, iMCU_width); @@ -587,7 +587,7 @@ void PadInputBuffer(j_compress_ptr cinfo, float* row[kMaxComponents]) { } void ProcessiMCURow(j_compress_ptr cinfo) { - JXL_ASSERT(cinfo->master->next_iMCU_row < cinfo->total_iMCU_rows); + JPEGLI_CHECK(cinfo->master->next_iMCU_row < cinfo->total_iMCU_rows); if (!cinfo->raw_data_in) { ApplyInputSmoothing(cinfo); DownsampleInputBuffer(cinfo); @@ -628,9 +628,9 @@ void ZigZagShuffleBlocks(j_compress_ptr cinfo) { for (int c = 0; c < cinfo->num_components; ++c) { jpeg_component_info* comp = &cinfo->comp_info[c]; for (JDIMENSION by = 0; by < comp->height_in_blocks; ++by) { - JBLOCKARRAY ba = GetBlockRow(cinfo, c, by); + JBLOCKARRAY blocks = GetBlockRow(cinfo, c, by); for (JDIMENSION bx = 0; bx < comp->width_in_blocks; ++bx) { - JCOEF* block = &ba[0][bx][0]; + JCOEF* block = &blocks[0][bx][0]; for (int k = 0; k < DCTSIZE2; ++k) { tmp[k] = block[kJPEGNaturalOrder[k]]; } @@ -713,18 +713,31 @@ void jpegli_set_defaults(j_compress_ptr cinfo) { void jpegli_default_colorspace(j_compress_ptr cinfo) { CheckState(cinfo, jpegli::kEncStart); + if (cinfo->in_color_space == JCS_RGB && cinfo->master->xyb_mode) { + jpegli_set_colorspace(cinfo, JCS_RGB); + return; + } switch (cinfo->in_color_space) { case JCS_GRAYSCALE: jpegli_set_colorspace(cinfo, JCS_GRAYSCALE); break; - case JCS_RGB: { - if (cinfo->master->xyb_mode) { - jpegli_set_colorspace(cinfo, JCS_RGB); - } else { - jpegli_set_colorspace(cinfo, JCS_YCbCr); - } + case JCS_RGB: +#ifdef JCS_EXTENSIONS + case JCS_EXT_RGB: + case JCS_EXT_BGR: + case JCS_EXT_RGBX: + case JCS_EXT_BGRX: + case JCS_EXT_XRGB: + case JCS_EXT_XBGR: +#endif +#if JCS_ALPHA_EXTENSIONS + case JCS_EXT_RGBA: + case JCS_EXT_BGRA: + case JCS_EXT_ARGB: + case JCS_EXT_ABGR: +#endif + jpegli_set_colorspace(cinfo, JCS_YCbCr); break; - } case JCS_YCbCr: jpegli_set_colorspace(cinfo, JCS_YCbCr); break; @@ -806,6 +819,11 @@ void jpegli_set_colorspace(j_compress_ptr cinfo, J_COLOR_SPACE colorspace) { cinfo->comp_info[2].quant_tbl_no = 1; cinfo->comp_info[1].dc_tbl_no = cinfo->comp_info[1].ac_tbl_no = 1; cinfo->comp_info[2].dc_tbl_no = cinfo->comp_info[2].ac_tbl_no = 1; + // Use chroma subsampling by default + cinfo->comp_info[0].h_samp_factor = cinfo->comp_info[0].v_samp_factor = 2; + if (colorspace == JCS_YCCK) { + cinfo->comp_info[3].h_samp_factor = cinfo->comp_info[3].v_samp_factor = 2; + } } } @@ -957,7 +975,7 @@ void jpegli_copy_critical_parameters(j_decompress_ptr srcinfo, jpegli_set_colorspace(dstinfo, srcinfo->jpeg_color_space); if (dstinfo->num_components != srcinfo->num_components) { const auto& cinfo = dstinfo; - return JPEGLI_ERROR("Mismatch between src colorspace and components"); + JPEGLI_ERROR("Mismatch between src colorspace and components"); } dstinfo->data_precision = srcinfo->data_precision; dstinfo->CCIR601_sampling = srcinfo->CCIR601_sampling; @@ -1156,7 +1174,7 @@ JDIMENSION jpegli_write_raw_data(j_compress_ptr cinfo, JSAMPIMAGE data, JPEGLI_ERROR("Missing input lines, minimum is %u", iMCU_height); } if (cinfo->next_scanline < m->next_input_row) { - JXL_ASSERT(m->next_input_row - cinfo->next_scanline == iMCU_height); + JPEGLI_CHECK(m->next_input_row - cinfo->next_scanline == iMCU_height); if (!jpegli::EmptyBitWriterBuffer(&m->bw)) { return 0; } diff --git a/third_party/jpeg-xl/lib/jpegli/encode.h b/third_party/jpeg-xl/lib/jpegli/encode.h index 320dfaaf8d1b8..54ff9d1f9eec6 100644 --- a/third_party/jpeg-xl/lib/jpegli/encode.h +++ b/third_party/jpeg-xl/lib/jpegli/encode.h @@ -21,8 +21,9 @@ #define LIB_JPEGLI_ENCODE_H_ #include "lib/jpegli/common.h" +#include "lib/jpegli/types.h" -#if defined(__cplusplus) || defined(c_plusplus) +#ifdef __cplusplus extern "C" { #endif @@ -35,7 +36,7 @@ void jpegli_CreateCompress(j_compress_ptr cinfo, int version, void jpegli_stdio_dest(j_compress_ptr cinfo, FILE* outfile); void jpegli_mem_dest(j_compress_ptr cinfo, unsigned char** outbuffer, - unsigned long* outsize); + unsigned long* outsize /* NOLINT */); void jpegli_set_defaults(j_compress_ptr cinfo); @@ -151,7 +152,7 @@ void jpegli_set_progressive_level(j_compress_ptr cinfo, int level); // AC coefficients. Must be called before jpegli_set_defaults(). void jpegli_use_standard_quant_tables(j_compress_ptr cinfo); -#if defined(__cplusplus) || defined(c_plusplus) +#ifdef __cplusplus } // extern "C" #endif diff --git a/third_party/jpeg-xl/lib/jpegli/encode_api_test.cc b/third_party/jpeg-xl/lib/jpegli/encode_api_test.cc index 1afdcf610d22a..c8a8e21f677aa 100644 --- a/third_party/jpeg-xl/lib/jpegli/encode_api_test.cc +++ b/third_party/jpeg-xl/lib/jpegli/encode_api_test.cc @@ -4,14 +4,22 @@ // license that can be found in the LICENSE file. #include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include "lib/jpegli/encode.h" -#include "lib/jpegli/error.h" +#include "lib/jpegli/libjpeg_test_util.h" +#include "lib/jpegli/test_params.h" #include "lib/jpegli/test_utils.h" #include "lib/jpegli/testing.h" -#include "lib/jxl/sanitizers.h" +#include "lib/jpegli/types.h" namespace jpegli { namespace { @@ -69,7 +77,7 @@ TEST(EncodeAPITest, ReuseCinfoSameImageTwice) { CompressParams jparams; GenerateInput(PIXELS, jparams, &input); uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT std::vector compressed0; std::vector compressed1; jpeg_compress_struct cinfo; @@ -117,7 +125,7 @@ std::vector GenerateBasicConfigs() { TEST(EncodeAPITest, ReuseCinfoSameMemOutput) { std::vector all_configs = GenerateBasicConfigs(); uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT { jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { @@ -145,7 +153,7 @@ TEST(EncodeAPITest, ReuseCinfoSameMemOutput) { TEST(EncodeAPITest, ReuseCinfoSameStdOutput) { std::vector all_configs = GenerateBasicConfigs(); FILE* tmpf = tmpfile(); - JXL_CHECK(tmpf); + ASSERT_TRUE(tmpf); { jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { @@ -161,9 +169,9 @@ TEST(EncodeAPITest, ReuseCinfoSameStdOutput) { jpegli_destroy_compress(&cinfo); } size_t total_size = ftell(tmpf); - rewind(tmpf); + fseek(tmpf, 0, SEEK_SET); std::vector compressed(total_size); - JXL_CHECK(total_size == fread(compressed.data(), 1, total_size, tmpf)); + ASSERT_TRUE(total_size == fread(compressed.data(), 1, total_size, tmpf)); fclose(tmpf); size_t pos = 0; for (auto& config : all_configs) { @@ -181,7 +189,7 @@ TEST(EncodeAPITest, ReuseCinfoChangeParams) { CompressParams jparams; DecompressParams dparams; uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT std::vector compressed; jpeg_compress_struct cinfo; const auto max_rms = [](int q, int hs, int vs) { @@ -246,9 +254,9 @@ TEST(EncodeAPITest, ReuseCinfoChangeParams) { TEST(EncodeAPITest, AbbreviatedStreams) { uint8_t* table_stream = nullptr; - unsigned long table_stream_size = 0; + unsigned long table_stream_size = 0; // NOLINT uint8_t* data_stream = nullptr; - unsigned long data_stream_size = 0; + unsigned long data_stream_size = 0; // NOLINT { jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { @@ -372,6 +380,8 @@ std::vector GenerateTests() { { TestConfig config; config.jparams.quality = 100; + config.jparams.h_sampling = {1, 1, 1}; + config.jparams.v_sampling = {1, 1, 1}; config.max_bpp = 6.6; config.max_dist = 0.6; all_tests.push_back(config); @@ -510,17 +520,23 @@ std::vector GenerateTests() { config.jparams.libjpeg_mode = true; config.max_bpp = 2.1; config.max_dist = 1.7; + config.jparams.h_sampling = {1, 1, 1}; + config.jparams.v_sampling = {1, 1, 1}; all_tests.push_back(config); } - for (J_COLOR_SPACE in_color_space : {JCS_RGB, JCS_YCbCr, JCS_GRAYSCALE}) { + for (J_COLOR_SPACE in_color_space : + {JCS_RGB, JCS_YCbCr, JCS_GRAYSCALE, JCS_EXT_RGB, JCS_EXT_BGR, + JCS_EXT_RGBA, JCS_EXT_BGRA, JCS_EXT_ARGB, JCS_EXT_ABGR}) { for (J_COLOR_SPACE jpeg_color_space : {JCS_RGB, JCS_YCbCr, JCS_GRAYSCALE}) { - if (jpeg_color_space == JCS_RGB && in_color_space == JCS_YCbCr) continue; + if (jpeg_color_space == JCS_RGB && in_color_space >= JCS_YCbCr) continue; TestConfig config; config.input.xsize = config.input.ysize = 256; config.input.color_space = in_color_space; config.jparams.set_jpeg_colorspace = true; config.jparams.jpeg_color_space = jpeg_color_space; + config.jparams.h_sampling = {1, 1, 1}; + config.jparams.v_sampling = {1, 1, 1}; config.max_bpp = jpeg_color_space == JCS_RGB ? 4.5 : 1.85; config.max_dist = jpeg_color_space == JCS_RGB ? 1.4 : 2.05; all_tests.push_back(config); @@ -536,6 +552,8 @@ std::vector GenerateTests() { config.jparams.set_jpeg_colorspace = true; config.jparams.jpeg_color_space = jpeg_color_space; } + config.jparams.h_sampling = {1, 1, 1, 1}; + config.jparams.v_sampling = {1, 1, 1, 1}; config.max_bpp = jpeg_color_space == JCS_CMYK ? 4.0 : 3.6; config.max_dist = jpeg_color_space == JCS_CMYK ? 1.2 : 1.5; all_tests.push_back(config); @@ -546,6 +564,8 @@ std::vector GenerateTests() { config.input.color_space = JCS_YCbCr; config.max_bpp = 1.6; config.max_dist = 1.35; + config.jparams.h_sampling = {1, 1, 1}; + config.jparams.v_sampling = {1, 1, 1}; all_tests.push_back(config); } for (bool xyb : {false, true}) { @@ -596,6 +616,8 @@ std::vector GenerateTests() { table.add_raw = add_raw; table.Generate(); config.jparams.optimize_coding = 1; + config.jparams.h_sampling = {1, 1, 1}; + config.jparams.v_sampling = {1, 1, 1}; config.jparams.quant_tables.push_back(table); config.jparams.quant_indexes = {0, 0, 0}; float q = (type == 0 ? 16 : type) * scale * 0.01f; @@ -614,6 +636,8 @@ std::vector GenerateTests() { config.input.ysize = 256; config.jparams.quant_indexes = {(qidx >> 2) & 1, (qidx >> 1) & 1, (qidx >> 0) & 1}; + config.jparams.h_sampling = {1, 1, 1}; + config.jparams.v_sampling = {1, 1, 1}; config.max_bpp = 2.25; config.max_dist = 2.8; all_tests.push_back(config); @@ -626,6 +650,8 @@ std::vector GenerateTests() { config.input.ysize = 256; config.jparams.quant_indexes = {(qidx >> 2) & 1, (qidx >> 1) & 1, (qidx >> 0) & 1}; + config.jparams.h_sampling = {1, 1, 1}; + config.jparams.v_sampling = {1, 1, 1}; CustomQuantTable table; table.slot_idx = slot_idx; table.Generate(); @@ -643,6 +669,10 @@ std::vector GenerateTests() { config.jparams.xyb_mode = xyb; config.jparams.quant_indexes = {(qidx >> 2) & 1, (qidx >> 1) & 1, (qidx >> 0) & 1}; + if (!xyb) { + config.jparams.h_sampling = {1, 1, 1}; + config.jparams.v_sampling = {1, 1, 1}; + } { CustomQuantTable table; table.slot_idx = 0; @@ -667,6 +697,10 @@ std::vector GenerateTests() { config.input.ysize = 256; config.jparams.xyb_mode = xyb; config.jparams.quant_indexes = {0, 1, 2}; + if (!xyb) { + config.jparams.h_sampling = {1, 1, 1}; + config.jparams.v_sampling = {1, 1, 1}; + } { CustomQuantTable table; table.slot_idx = 0; @@ -738,6 +772,8 @@ std::vector GenerateTests() { } config.jparams.progressive_mode = 0; config.jparams.optimize_coding = 0; + config.jparams.h_sampling = {1, 1, 1}; + config.jparams.v_sampling = {1, 1, 1}; config.max_bpp = 1.85; config.max_dist = 2.05; if (input_mode == COEFFICIENTS) { diff --git a/third_party/jpeg-xl/lib/jpegli/encode_finish.cc b/third_party/jpeg-xl/lib/jpegli/encode_finish.cc index 767a6532c5891..8cc3b8d27503b 100644 --- a/third_party/jpeg-xl/lib/jpegli/encode_finish.cc +++ b/third_party/jpeg-xl/lib/jpegli/encode_finish.cc @@ -99,10 +99,10 @@ float ComputePSNR(j_compress_ptr cinfo, int sampling) { HWY_ALIGN float iqmc[64]; ComputeInverseWeights(qmc, iqmc); for (JDIMENSION by = 0; by < comp->height_in_blocks; by += sampling) { - JBLOCKARRAY ba = GetBlockRow(cinfo, c, by); + JBLOCKARRAY blocks = GetBlockRow(cinfo, c, by); const float* qf = m->quant_field.Row(by * v_factor); for (JDIMENSION bx = 0; bx < comp->width_in_blocks; bx += sampling) { - error += BlockError(&ba[0][bx][0], qmc, iqmc, qf[bx * h_factor], + error += BlockError(&blocks[0][bx][0], qmc, iqmc, qf[bx * h_factor], zero_bias_offset, zero_bias_mul); num += DCTSIZE2; } @@ -122,11 +122,11 @@ void ReQuantizeCoeffs(j_compress_ptr cinfo) { const float* zero_bias_offset = m->zero_bias_offset[c]; const float* zero_bias_mul = m->zero_bias_mul[c]; for (JDIMENSION by = 0; by < comp->height_in_blocks; ++by) { - JBLOCKARRAY ba = GetBlockRow(cinfo, c, by); + JBLOCKARRAY block = GetBlockRow(cinfo, c, by); const float* qf = m->quant_field.Row(by * v_factor); for (JDIMENSION bx = 0; bx < comp->width_in_blocks; ++bx) { - ReQuantizeBlock(&ba[0][bx][0], qmc, qf[bx * h_factor], zero_bias_offset, - zero_bias_mul); + ReQuantizeBlock(&block[0][bx][0], qmc, qf[bx * h_factor], + zero_bias_offset, zero_bias_mul); } } } diff --git a/third_party/jpeg-xl/lib/jpegli/encode_streaming.cc b/third_party/jpeg-xl/lib/jpegli/encode_streaming.cc index 89dbd813f8534..ff43864a47bae 100644 --- a/third_party/jpeg-xl/lib/jpegli/encode_streaming.cc +++ b/third_party/jpeg-xl/lib/jpegli/encode_streaming.cc @@ -114,14 +114,14 @@ void ProcessiMCURow(j_compress_ptr cinfo) { int32_t* nonzero_idx = m->block_tmp + 3 * DCTSIZE2; coeff_t* JXL_RESTRICT last_dc_coeff = m->last_dc_coeff; bool adaptive_quant = m->use_adaptive_quantization && m->psnr_target == 0; - JBLOCKARRAY ba[kMaxComponents]; + JBLOCKARRAY blocks[kMaxComponents]; if (kMode == kStreamingModeCoefficients) { for (int c = 0; c < cinfo->num_components; ++c) { jpeg_component_info* comp = &cinfo->comp_info[c]; int by0 = mcu_y * comp->v_samp_factor; int block_rows_left = comp->height_in_blocks - by0; int max_block_rows = std::min(comp->v_samp_factor, block_rows_left); - ba[c] = (*cinfo->mem->access_virt_barray)( + blocks[c] = (*cinfo->mem->access_virt_barray)( reinterpret_cast(cinfo), m->coeff_buffers[c], by0, max_block_rows, true); } @@ -189,7 +189,7 @@ void ProcessiMCURow(j_compress_ptr cinfo) { aq_strength, zero_bias_offset, zero_bias_mul, m->dct_buffer, block); if (kMode == kStreamingModeCoefficients) { - JCOEF* cblock = &ba[c][iy][bx][0]; + JCOEF* cblock = &blocks[c][iy][bx][0]; for (int k = 0; k < DCTSIZE2; ++k) { cblock[k] = block[kJPEGNaturalOrder[k]]; } diff --git a/third_party/jpeg-xl/lib/jpegli/entropy_coding.cc b/third_party/jpeg-xl/lib/jpegli/entropy_coding.cc index 515996a43d7f2..d7d928099b1c2 100644 --- a/third_party/jpeg-xl/lib/jpegli/entropy_coding.cc +++ b/third_party/jpeg-xl/lib/jpegli/entropy_coding.cc @@ -106,7 +106,7 @@ void TokenizeACProgressiveScan(j_compress_ptr cinfo, int scan_index, eob_run = 0; }; for (JDIMENSION by = 0; by < comp->height_in_blocks; ++by) { - JBLOCKARRAY ba = (*cinfo->mem->access_virt_barray)( + JBLOCKARRAY blocks = (*cinfo->mem->access_virt_barray)( reinterpret_cast(cinfo), m->coeff_buffers[comp_idx], by, 1, FALSE); // Each coefficient can appear in at most one token, but we have to reserve @@ -132,7 +132,7 @@ void TokenizeACProgressiveScan(j_compress_ptr cinfo, int scan_index, sti->restarts[restart_idx++] = m->total_num_tokens + ta->num_tokens; restarts_to_go = restart_interval; } - const coeff_t* block = &ba[0][bx][0]; + const coeff_t* block = &blocks[0][bx][0]; coeff_t temp2; coeff_t temp; int r = 0; @@ -213,7 +213,7 @@ void TokenizeACRefinementScan(j_compress_ptr cinfo, int scan_index, uint16_t* next_eobrun = sti->eobruns; size_t restart_idx = 0; for (JDIMENSION by = 0; by < comp->height_in_blocks; ++by) { - JBLOCKARRAY ba = (*cinfo->mem->access_virt_barray)( + JBLOCKARRAY blocks = (*cinfo->mem->access_virt_barray)( reinterpret_cast(cinfo), m->coeff_buffers[comp_idx], by, 1, FALSE); for (JDIMENSION bx = 0; bx < comp->width_in_blocks; ++bx) { @@ -223,7 +223,7 @@ void TokenizeACRefinementScan(j_compress_ptr cinfo, int scan_index, next_eob_token = next_token; eob_run = eob_refbits = 0; } - const coeff_t* block = &ba[0][bx][0]; + const coeff_t* block = &blocks[0][bx][0]; int num_eob_refinement_bits = 0; int num_refinement_bits = 0; int num_nzeros = 0; @@ -347,7 +347,7 @@ void TokenizeScan(j_compress_ptr cinfo, size_t scan_index, int ac_ctx_offset, } } - JBLOCKARRAY ba[MAX_COMPS_IN_SCAN]; + JBLOCKARRAY blocks[MAX_COMPS_IN_SCAN]; size_t block_idx = 0; for (size_t mcu_y = 0; mcu_y < sti->MCU_rows_in_scan; ++mcu_y) { for (int i = 0; i < scan_info->comps_in_scan; ++i) { @@ -357,7 +357,7 @@ void TokenizeScan(j_compress_ptr cinfo, size_t scan_index, int ac_ctx_offset, int by0 = mcu_y * n_blocks_y; int block_rows_left = comp->height_in_blocks - by0; int max_block_rows = std::min(n_blocks_y, block_rows_left); - ba[i] = (*cinfo->mem->access_virt_barray)( + blocks[i] = (*cinfo->mem->access_virt_barray)( reinterpret_cast(cinfo), m->coeff_buffers[comp_idx], by0, max_block_rows, FALSE); } @@ -400,7 +400,7 @@ void TokenizeScan(j_compress_ptr cinfo, size_t scan_index, int ac_ctx_offset, block_y >= comp->height_in_blocks) { block = kSinkBlock; } else { - block = &ba[i][iy][block_x][0]; + block = &blocks[i][iy][block_x][0]; } if (!is_progressive) { HWY_DYNAMIC_DISPATCH(ComputeTokensSequential) @@ -441,18 +441,19 @@ void TokenizeJpeg(j_compress_ptr cinfo) { std::vector processed(cinfo->num_scans); size_t max_refinement_tokens = 0; size_t num_refinement_bits = 0; - int num_refinement_scans[DCTSIZE2] = {}; + int num_refinement_scans[kMaxComponents][DCTSIZE2] = {}; int max_num_refinement_scans = 0; for (int i = 0; i < cinfo->num_scans; ++i) { const jpeg_scan_info* si = &cinfo->scan_info[i]; ScanTokenInfo* sti = &m->scan_token_info[i]; if (si->Ss > 0 && si->Ah == 0 && si->Al > 0) { int offset = m->ac_ctx_offset[i]; + int comp_idx = si->component_index[0]; TokenizeScan(cinfo, i, offset, sti); processed[i] = 1; max_refinement_tokens += sti->num_future_nonzeros; for (int k = si->Ss; k <= si->Se; ++k) { - num_refinement_scans[k] = si->Al; + num_refinement_scans[comp_idx][k] = si->Al; } max_num_refinement_scans = std::max(max_num_refinement_scans, si->Al); num_refinement_bits += sti->num_nonzeros; @@ -475,16 +476,17 @@ void TokenizeJpeg(j_compress_ptr cinfo) { size_t new_refinement_bits = 0; for (int i = 0; i < cinfo->num_scans; ++i) { const jpeg_scan_info* si = &cinfo->scan_info[i]; + int comp_idx = si->component_index[0]; ScanTokenInfo* sti = &m->scan_token_info[i]; if (si->Ss > 0 && si->Ah > 0 && - si->Ah == num_refinement_scans[si->Ss] - j) { + si->Ah == num_refinement_scans[comp_idx][si->Ss] - j) { int offset = m->ac_ctx_offset[i]; TokenizeScan(cinfo, i, offset, sti); processed[i] = 1; new_refinement_bits += sti->num_nonzeros; } } - JXL_DASSERT(m->next_refinement_bit == + JXL_DASSERT(m->next_refinement_bit <= refinement_bits + num_refinement_bits); num_refinement_bits += new_refinement_bits; } @@ -568,8 +570,8 @@ bool IsEmptyHistogram(const Histogram& histo) { return true; } -void ClusterJpegHistograms(const Histogram* histograms, size_t num, - JpegClusteredHistograms* clusters) { +void ClusterJpegHistograms(j_compress_ptr cinfo, const Histogram* histograms, + size_t num, JpegClusteredHistograms* clusters) { clusters->histogram_indexes.resize(num); std::vector slot_histograms; std::vector slot_costs; @@ -614,7 +616,7 @@ void ClusterJpegHistograms(const Histogram* histograms, size_t num, const Histogram& prev = clusters->histograms[histogram_index]; AddHistograms(prev, cur, &clusters->histograms[histogram_index]); clusters->histogram_indexes[i] = histogram_index; - JXL_ASSERT(clusters->slot_ids[histogram_index] == best_slot); + JPEGLI_CHECK(clusters->slot_ids[histogram_index] == best_slot); slot_costs[best_slot] += best_cost; } } @@ -716,11 +718,12 @@ void OptimizeHuffmanCodes(j_compress_ptr cinfo) { // Cluster DC histograms. JpegClusteredHistograms dc_clusters; - ClusterJpegHistograms(histograms.data(), cinfo->num_components, &dc_clusters); + ClusterJpegHistograms(cinfo, histograms.data(), cinfo->num_components, + &dc_clusters); // Cluster AC histograms. JpegClusteredHistograms ac_clusters; - ClusterJpegHistograms(histograms.data() + 4, m->num_contexts - 4, + ClusterJpegHistograms(cinfo, histograms.data() + 4, m->num_contexts - 4, &ac_clusters); // Create Huffman tables and slot ids clusters. diff --git a/third_party/jpeg-xl/lib/jpegli/error.cc b/third_party/jpeg-xl/lib/jpegli/error.cc index 289261672de19..b3ccab0452e74 100644 --- a/third_party/jpeg-xl/lib/jpegli/error.cc +++ b/third_party/jpeg-xl/lib/jpegli/error.cc @@ -22,7 +22,7 @@ const char* const kErrorMessageTable[] = { bool FormatString(char* buffer, const char* format, ...) { va_list args; va_start(args, format); - vsnprintf(buffer, JMSG_STR_PARM_MAX, format, args); + vsnprintf(buffer, JMSG_STR_PARM_MAX, format, args); // notypo va_end(args); return false; } diff --git a/third_party/jpeg-xl/lib/jpegli/error.h b/third_party/jpeg-xl/lib/jpegli/error.h index 4451abd416e8f..fb5dc411a8b6d 100644 --- a/third_party/jpeg-xl/lib/jpegli/error.h +++ b/third_party/jpeg-xl/lib/jpegli/error.h @@ -10,6 +10,7 @@ #include #include "lib/jpegli/common.h" +#include "lib/jxl/base/compiler_specific.h" namespace jpegli { @@ -17,10 +18,12 @@ bool FormatString(char* buffer, const char* format, ...); } // namespace jpegli +// `error_exit` should be no-return; but let's add some guarantees on our side. #define JPEGLI_ERROR(format, ...) \ jpegli::FormatString(cinfo->err->msg_parm.s, ("%s:%d: " format), __FILE__, \ __LINE__, ##__VA_ARGS__), \ - (*cinfo->err->error_exit)(reinterpret_cast(cinfo)) + (*cinfo->err->error_exit)(reinterpret_cast(cinfo)), \ + JXL_CRASH() #define JPEGLI_WARN(format, ...) \ jpegli::FormatString(cinfo->err->msg_parm.s, ("%s:%d: " format), __FILE__, \ @@ -34,4 +37,11 @@ bool FormatString(char* buffer, const char* format, ...); (*cinfo->err->emit_message)(reinterpret_cast(cinfo), \ (level)) +#define JPEGLI_CHECK(condition) \ + do { \ + if (!(condition)) { \ + JPEGLI_ERROR("JPEGLI_CHECK: %s", #condition); \ + } \ + } while (0) + #endif // LIB_JPEGLI_ERROR_H_ diff --git a/third_party/jpeg-xl/lib/jpegli/error_handling_test.cc b/third_party/jpeg-xl/lib/jpegli/error_handling_test.cc index 3eaf6a313b6fb..da85dbcb0b3db 100644 --- a/third_party/jpeg-xl/lib/jpegli/error_handling_test.cc +++ b/third_party/jpeg-xl/lib/jpegli/error_handling_test.cc @@ -3,19 +3,26 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include +#include +#include +#include +#include + +#include "lib/jpegli/common.h" #include "lib/jpegli/decode.h" #include "lib/jpegli/encode.h" -#include "lib/jpegli/error.h" +#include "lib/jpegli/libjpeg_test_util.h" +#include "lib/jpegli/test_params.h" #include "lib/jpegli/test_utils.h" #include "lib/jpegli/testing.h" -#include "lib/jxl/sanitizers.h" namespace jpegli { namespace { TEST(EncoderErrorHandlingTest, MinimalSuccess) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT { jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { @@ -64,7 +71,7 @@ TEST(EncoderErrorHandlingTest, NoDestination) { TEST(EncoderErrorHandlingTest, NoImageDimensions) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -82,7 +89,7 @@ TEST(EncoderErrorHandlingTest, NoImageDimensions) { TEST(EncoderErrorHandlingTest, ImageTooBig) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -102,7 +109,7 @@ TEST(EncoderErrorHandlingTest, ImageTooBig) { TEST(EncoderErrorHandlingTest, NoInputComponents) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -121,7 +128,7 @@ TEST(EncoderErrorHandlingTest, NoInputComponents) { TEST(EncoderErrorHandlingTest, TooManyInputComponents) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -141,7 +148,7 @@ TEST(EncoderErrorHandlingTest, TooManyInputComponents) { TEST(EncoderErrorHandlingTest, NoSetDefaults) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -164,7 +171,7 @@ TEST(EncoderErrorHandlingTest, NoSetDefaults) { TEST(EncoderErrorHandlingTest, NoStartCompress) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -186,7 +193,7 @@ TEST(EncoderErrorHandlingTest, NoStartCompress) { TEST(EncoderErrorHandlingTest, NoWriteScanlines) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -207,7 +214,7 @@ TEST(EncoderErrorHandlingTest, NoWriteScanlines) { TEST(EncoderErrorHandlingTest, NoWriteAllScanlines) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -231,7 +238,7 @@ TEST(EncoderErrorHandlingTest, NoWriteAllScanlines) { TEST(EncoderErrorHandlingTest, InvalidQuantValue) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -260,7 +267,7 @@ TEST(EncoderErrorHandlingTest, InvalidQuantValue) { TEST(EncoderErrorHandlingTest, InvalidQuantTableIndex) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -285,7 +292,7 @@ TEST(EncoderErrorHandlingTest, InvalidQuantTableIndex) { TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch1) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -306,7 +313,7 @@ TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch1) { TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch2) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -327,7 +334,7 @@ TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch2) { TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch3) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -353,7 +360,7 @@ TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch3) { TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch4) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -378,7 +385,7 @@ TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch4) { TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch5) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -403,7 +410,7 @@ TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch5) { TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch6) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -429,7 +436,7 @@ TEST(EncoderErrorHandlingTest, NumberOfComponentsMismatch6) { TEST(EncoderErrorHandlingTest, InvalidColorTransform) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -455,7 +462,7 @@ TEST(EncoderErrorHandlingTest, InvalidColorTransform) { TEST(EncoderErrorHandlingTest, DuplicateComponentIds) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -477,7 +484,7 @@ TEST(EncoderErrorHandlingTest, DuplicateComponentIds) { TEST(EncoderErrorHandlingTest, InvalidComponentIndex) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -498,7 +505,7 @@ TEST(EncoderErrorHandlingTest, InvalidComponentIndex) { TEST(EncoderErrorHandlingTest, ArithmeticCoding) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -519,7 +526,7 @@ TEST(EncoderErrorHandlingTest, ArithmeticCoding) { TEST(EncoderErrorHandlingTest, CCIR601Sampling) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -540,7 +547,7 @@ TEST(EncoderErrorHandlingTest, CCIR601Sampling) { TEST(EncoderErrorHandlingTest, InvalidScanScript1) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -563,7 +570,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript1) { TEST(EncoderErrorHandlingTest, InvalidScanScript2) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -586,7 +593,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript2) { TEST(EncoderErrorHandlingTest, InvalidScanScript3) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -609,7 +616,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript3) { TEST(EncoderErrorHandlingTest, InvalidScanScript4) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -632,7 +639,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript4) { TEST(EncoderErrorHandlingTest, InvalidScanScript5) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -655,7 +662,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript5) { TEST(EncoderErrorHandlingTest, InvalidScanScript6) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -678,7 +685,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript6) { TEST(EncoderErrorHandlingTest, InvalidScanScript7) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -701,7 +708,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript7) { TEST(EncoderErrorHandlingTest, InvalidScanScript8) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -726,7 +733,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript8) { TEST(EncoderErrorHandlingTest, InvalidScanScript9) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -751,7 +758,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript9) { TEST(EncoderErrorHandlingTest, InvalidScanScript10) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -776,7 +783,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript10) { TEST(EncoderErrorHandlingTest, InvalidScanScript11) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -801,7 +808,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript11) { TEST(EncoderErrorHandlingTest, InvalidScanScript12) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -826,7 +833,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript12) { TEST(EncoderErrorHandlingTest, InvalidScanScript13) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -854,7 +861,7 @@ TEST(EncoderErrorHandlingTest, InvalidScanScript13) { TEST(EncoderErrorHandlingTest, MCUSizeTooBig) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -877,7 +884,7 @@ TEST(EncoderErrorHandlingTest, MCUSizeTooBig) { TEST(EncoderErrorHandlingTest, RestartIntervalTooBig) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -898,7 +905,7 @@ TEST(EncoderErrorHandlingTest, RestartIntervalTooBig) { TEST(EncoderErrorHandlingTest, SamplingFactorTooBig) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -919,7 +926,7 @@ TEST(EncoderErrorHandlingTest, SamplingFactorTooBig) { TEST(EncoderErrorHandlingTest, NonIntegralSamplingRatio) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -996,6 +1003,9 @@ TEST(EncoderErrorHandlingTest, AddOnTableNoStringParam) { const uint8_t kCompressed0[] = { // SOI 0xff, 0xd8, // + // SOF + 0xff, 0xc0, 0x00, 0x0b, 0x08, 0x00, 0x01, 0x00, 0x01, 0x01, // + 0x01, 0x11, 0x00, // // DQT 0xff, 0xdb, 0x00, 0x43, 0x00, 0x03, 0x02, 0x02, 0x03, 0x02, // 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x03, 0x03, 0x04, 0x05, // @@ -1004,9 +1014,6 @@ const uint8_t kCompressed0[] = { 0x0e, 0x12, 0x10, 0x0d, 0x0e, 0x11, 0x0e, 0x0b, 0x0b, 0x10, // 0x16, 0x10, 0x11, 0x13, 0x14, 0x15, 0x15, 0x15, 0x0c, 0x0f, // 0x17, 0x18, 0x16, 0x14, 0x18, 0x12, 0x14, 0x15, 0x14, // - // SOF - 0xff, 0xc0, 0x00, 0x0b, 0x08, 0x00, 0x01, 0x00, 0x01, 0x01, // - 0x01, 0x11, 0x00, // // DHT 0xff, 0xc4, 0x00, 0xd2, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, // 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // @@ -1039,16 +1046,16 @@ const uint8_t kCompressed0[] = { }; const size_t kLen0 = sizeof(kCompressed0); -const size_t kDQTOffset = 2; -const size_t kSOFOffset = 71; +const size_t kSOFOffset = 2; +const size_t kDQTOffset = 15; const size_t kDHTOffset = 84; const size_t kSOSOffset = 296; TEST(DecoderErrorHandlingTest, MinimalSuccess) { - JXL_CHECK(kCompressed0[kDQTOffset] == 0xff); - JXL_CHECK(kCompressed0[kSOFOffset] == 0xff); - JXL_CHECK(kCompressed0[kDHTOffset] == 0xff); - JXL_CHECK(kCompressed0[kSOSOffset] == 0xff); + ASSERT_TRUE(kCompressed0[kDQTOffset] == 0xff); + ASSERT_TRUE(kCompressed0[kSOFOffset] == 0xff); + ASSERT_TRUE(kCompressed0[kDHTOffset] == 0xff); + ASSERT_TRUE(kCompressed0[kSOSOffset] == 0xff); jpeg_decompress_struct cinfo = {}; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -1169,7 +1176,7 @@ TEST(DecoderErrorHandlingTest, InvalidDQT) { compressed[kDQTOffset + 3] += diff; EXPECT_FALSE(ParseCompressed(compressed)); } - // inavlid table index / precision + // invalid table index / precision for (int val : {0x20, 0x05}) { std::vector compressed(kCompressed0, kCompressed0 + kLen0); compressed[kDQTOffset + 4] = val; @@ -1234,7 +1241,7 @@ TEST(DecoderErrorHandlingTest, InvalidDHT) { compressed[kDHTOffset + 2] += 17; EXPECT_FALSE(ParseCompressed(compressed)); } - // inavlid table slot_id + // invalid table slot_id for (int val : {0x05, 0x15, 0x20}) { std::vector compressed(kCompressed0, kCompressed0 + kLen0); compressed[kDHTOffset + 4] = val; diff --git a/third_party/jpeg-xl/lib/jpegli/fuzztest.h b/third_party/jpeg-xl/lib/jpegli/fuzztest.h new file mode 100644 index 0000000000000..d5cde97713e67 --- /dev/null +++ b/third_party/jpeg-xl/lib/jpegli/fuzztest.h @@ -0,0 +1,22 @@ +// Copyright (c) the JPEG XL Project Authors. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#ifndef LIB_JPEGLI_FUZZTEST_H_ +#define LIB_JPEGLI_FUZZTEST_H_ + +#include "lib/jxl/base/compiler_specific.h" + +#if !defined(FUZZ_TEST) +struct FuzzTestSink { + template + FuzzTestSink WithSeeds(F /*f*/) { + return *this; + } +}; +#define FUZZ_TEST(A, B) \ + const JXL_MAYBE_UNUSED FuzzTestSink unused##A##B = FuzzTestSink() +#endif + +#endif // LIB_JPEGLI_FUZZTEST_H_ diff --git a/third_party/jpeg-xl/lib/jpegli/huffman.cc b/third_party/jpeg-xl/lib/jpegli/huffman.cc index 5391030213379..6b068ab64f6ad 100644 --- a/third_party/jpeg-xl/lib/jpegli/huffman.cc +++ b/third_party/jpeg-xl/lib/jpegli/huffman.cc @@ -10,6 +10,7 @@ #include "lib/jpegli/common.h" #include "lib/jpegli/error.h" +#include "lib/jxl/base/status.h" namespace jpegli { diff --git a/third_party/jpeg-xl/lib/jpegli/idct.cc b/third_party/jpeg-xl/lib/jpegli/idct.cc index 9859e8ef85bfc..665a00d826de0 100644 --- a/third_party/jpeg-xl/lib/jpegli/idct.cc +++ b/third_party/jpeg-xl/lib/jpegli/idct.cc @@ -8,6 +8,7 @@ #include #include "lib/jpegli/decode_internal.h" +#include "lib/jxl/base/compiler_specific.h" #include "lib/jxl/base/status.h" #undef HWY_TARGET_INCLUDE @@ -62,15 +63,15 @@ void DequantBlock(const int16_t* JXL_RESTRICT qblock, } template -void ForwardEvenOdd(const float* JXL_RESTRICT ain, size_t ain_stride, - float* JXL_RESTRICT aout) { +void ForwardEvenOdd(const float* JXL_RESTRICT a_in, size_t a_in_stride, + float* JXL_RESTRICT a_out) { for (size_t i = 0; i < N / 2; i++) { - auto in1 = LoadU(d8, ain + 2 * i * ain_stride); - Store(in1, d8, aout + i * 8); + auto in1 = LoadU(d8, a_in + 2 * i * a_in_stride); + Store(in1, d8, a_out + i * 8); } for (size_t i = N / 2; i < N; i++) { - auto in1 = LoadU(d8, ain + (2 * (i - N / 2) + 1) * ain_stride); - Store(in1, d8, aout + i * 8); + auto in1 = LoadU(d8, a_in + (2 * (i - N / 2) + 1) * a_in_stride); + Store(in1, d8, a_out + i * 8); } } @@ -111,8 +112,10 @@ struct WcMultipliers<8> { }; }; +#if JXL_CXX_LANG < JXL_CXX_17 constexpr float WcMultipliers<4>::kMultipliers[]; constexpr float WcMultipliers<8>::kMultipliers[]; +#endif template void MultiplyAndAdd(const float* JXL_RESTRICT coeff, float* JXL_RESTRICT out, @@ -609,7 +612,7 @@ void Compute1dIDCT(const float* in, float* out, size_t N) { break; } default: - JXL_ABORT("Compute1dIDCT does not support N=%d", static_cast(N)); + JXL_DEBUG_ABORT("Unreachable"); break; } } @@ -679,16 +682,21 @@ namespace jpegli { HWY_EXPORT(InverseTransformBlock8x8); HWY_EXPORT(InverseTransformBlockGeneric); -void ChooseInverseTransform(j_decompress_ptr cinfo) { +jxl::Status ChooseInverseTransform(j_decompress_ptr cinfo) { jpeg_decomp_master* m = cinfo->master; for (int c = 0; c < cinfo->num_components; ++c) { - if (m->scaled_dct_size[c] == DCTSIZE) { + int dct_size = m->scaled_dct_size[c]; + if (dct_size < 1 || dct_size > 16) { + return JXL_FAILURE("Compute1dIDCT does not support N=%d", dct_size); + } + if (dct_size == DCTSIZE) { m->inverse_transform[c] = HWY_DYNAMIC_DISPATCH(InverseTransformBlock8x8); } else { m->inverse_transform[c] = HWY_DYNAMIC_DISPATCH(InverseTransformBlockGeneric); } } + return true; } } // namespace jpegli diff --git a/third_party/jpeg-xl/lib/jpegli/idct.h b/third_party/jpeg-xl/lib/jpegli/idct.h index c2ec6d18dc859..746b1562c1524 100644 --- a/third_party/jpeg-xl/lib/jpegli/idct.h +++ b/third_party/jpeg-xl/lib/jpegli/idct.h @@ -7,11 +7,11 @@ #define LIB_JPEGLI_IDCT_H_ #include "lib/jpegli/common.h" -#include "lib/jxl/base/compiler_specific.h" +#include "lib/jxl/base/status.h" namespace jpegli { -void ChooseInverseTransform(j_decompress_ptr cinfo); +jxl::Status ChooseInverseTransform(j_decompress_ptr cinfo); } // namespace jpegli diff --git a/third_party/jpeg-xl/lib/jpegli/input_suspension_test.cc b/third_party/jpeg-xl/lib/jpegli/input_suspension_test.cc index eb8b7ebc26da7..6fa1416213ce6 100644 --- a/third_party/jpeg-xl/lib/jpegli/input_suspension_test.cc +++ b/third_party/jpeg-xl/lib/jpegli/input_suspension_test.cc @@ -3,16 +3,24 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include +#include + +#include +#include #include +#include +#include +#include +#include +#include #include #include "lib/jpegli/decode.h" +#include "lib/jpegli/libjpeg_test_util.h" +#include "lib/jpegli/test_params.h" #include "lib/jpegli/test_utils.h" #include "lib/jpegli/testing.h" -#include "lib/jxl/base/byte_order.h" #include "lib/jxl/base/status.h" -#include "lib/jxl/sanitizers.h" namespace jpegli { namespace { @@ -80,7 +88,8 @@ struct SourceManager { static boolean fill_input_buffer(j_decompress_ptr cinfo) { return FALSE; } - static void skip_input_data(j_decompress_ptr cinfo, long num_bytes) { + static void skip_input_data(j_decompress_ptr cinfo, + long num_bytes /* NOLINT*/) { auto* src = reinterpret_cast(cinfo->src); if (num_bytes <= 0) { return; @@ -119,8 +128,9 @@ boolean test_marker_processor(j_decompress_ptr cinfo) { return TRUE; } -void ReadOutputImage(const DecompressParams& dparams, j_decompress_ptr cinfo, - SourceManager* src, TestImage* output) { +jxl::Status ReadOutputImage(const DecompressParams& dparams, + j_decompress_ptr cinfo, SourceManager* src, + TestImage* output) { output->ysize = cinfo->output_height; output->xsize = cinfo->output_width; output->components = cinfo->num_components; @@ -160,7 +170,7 @@ void ReadOutputImage(const DecompressParams& dparams, j_decompress_ptr cinfo, } while ((num_output_lines = jpegli_read_raw_data(cinfo, data.data(), max_lines)) == 0) { - JXL_CHECK(src && src->LoadNextChunk()); + JXL_ENSURE(src && src->LoadNextChunk()); } } else { size_t max_output_lines = dparams.max_output_lines; @@ -175,15 +185,16 @@ void ReadOutputImage(const DecompressParams& dparams, j_decompress_ptr cinfo, } while ((num_output_lines = jpegli_read_scanlines(cinfo, scanlines.data(), max_lines)) == 0) { - JXL_CHECK(src && src->LoadNextChunk()); + JXL_ENSURE(src && src->LoadNextChunk()); } } total_output_lines += num_output_lines; EXPECT_EQ(total_output_lines, cinfo->output_scanline); if (num_output_lines < max_lines) { - JXL_CHECK(src && src->LoadNextChunk()); + JXL_ENSURE(src && src->LoadNextChunk()); } } + return true; } struct TestConfig { @@ -195,13 +206,15 @@ struct TestConfig { float max_rms_dist = 1.0f; }; -std::vector GetTestJpegData(TestConfig& config) { +jxl::StatusOr> GetTestJpegData(TestConfig& config) { + std::vector compressed; if (!config.fn.empty()) { - return ReadTestData(config.fn); + JXL_ASSIGN_OR_RETURN(compressed, ReadTestData(config.fn)); + } else { + GeneratePixels(&config.input); + JXL_RETURN_IF_ERROR( + EncodeWithJpegli(config.input, config.jparams, &compressed)); } - GeneratePixels(&config.input); - std::vector compressed; - JXL_CHECK(EncodeWithJpegli(config.input, config.jparams, &compressed)); return compressed; } @@ -217,7 +230,8 @@ class InputSuspensionTestParam : public ::testing::TestWithParam {}; TEST_P(InputSuspensionTestParam, InputOutputLockStepNonBuffered) { TestConfig config = GetParam(); const DecompressParams& dparams = config.dparams; - std::vector compressed = GetTestJpegData(config); + JXL_ASSIGN_OR_QUIT(std::vector compressed, GetTestJpegData(config), + "Failed to create test data."); bool is_partial = config.dparams.size_factor < 1.0f; if (is_partial) { compressed.resize(compressed.size() * config.dparams.size_factor); @@ -240,7 +254,7 @@ TEST_P(InputSuspensionTestParam, InputOutputLockStepNonBuffered) { jpegli_set_marker_processor(&cinfo, 0xe8, test_marker_processor); } while (jpegli_read_header(&cinfo, TRUE) == JPEG_SUSPENDED) { - JXL_CHECK(src.LoadNextChunk()); + JPEGLI_TEST_ENSURE_TRUE(src.LoadNextChunk()); } SetDecompressParams(dparams, &cinfo); jpegli_set_output_format(&cinfo, dparams.data_type, dparams.endianness); @@ -254,18 +268,18 @@ TEST_P(InputSuspensionTestParam, InputOutputLockStepNonBuffered) { if (dparams.output_mode == COEFFICIENTS) { jvirt_barray_ptr* coef_arrays; while ((coef_arrays = jpegli_read_coefficients(&cinfo)) == nullptr) { - JXL_CHECK(src.LoadNextChunk()); + JPEGLI_TEST_ENSURE_TRUE(src.LoadNextChunk()); } CopyCoefficients(&cinfo, coef_arrays, &output0); } else { while (!jpegli_start_decompress(&cinfo)) { - JXL_CHECK(src.LoadNextChunk()); + JPEGLI_TEST_ENSURE_TRUE(src.LoadNextChunk()); } - ReadOutputImage(dparams, &cinfo, &src, &output0); + JPEGLI_TEST_ENSURE_TRUE(ReadOutputImage(dparams, &cinfo, &src, &output0)); } while (!jpegli_finish_decompress(&cinfo)) { - JXL_CHECK(src.LoadNextChunk()); + JPEGLI_TEST_ENSURE_TRUE(src.LoadNextChunk()); } return true; }; @@ -281,7 +295,8 @@ TEST_P(InputSuspensionTestParam, InputOutputLockStepBuffered) { TestConfig config = GetParam(); if (config.jparams.add_marker) return; const DecompressParams& dparams = config.dparams; - std::vector compressed = GetTestJpegData(config); + JXL_ASSIGN_OR_QUIT(std::vector compressed, GetTestJpegData(config), + "Failed to create test data."); bool is_partial = config.dparams.size_factor < 1.0f; if (is_partial) { compressed.resize(compressed.size() * config.dparams.size_factor); @@ -297,7 +312,7 @@ TEST_P(InputSuspensionTestParam, InputOutputLockStepBuffered) { cinfo.src = reinterpret_cast(&src); while (jpegli_read_header(&cinfo, TRUE) == JPEG_SUSPENDED) { - JXL_CHECK(src.LoadNextChunk()); + JPEGLI_TEST_ENSURE_TRUE(src.LoadNextChunk()); } SetDecompressParams(dparams, &cinfo); jpegli_set_output_format(&cinfo, dparams.data_type, dparams.endianness); @@ -318,18 +333,18 @@ TEST_P(InputSuspensionTestParam, InputOutputLockStepBuffered) { EXPECT_EQ(cinfo.output_scan_number, cinfo.input_scan_number); EXPECT_EQ(cinfo.input_scan_number, sos_marker_cnt); TestImage output; - ReadOutputImage(dparams, &cinfo, &src, &output); + JPEGLI_TEST_ENSURE_TRUE(ReadOutputImage(dparams, &cinfo, &src, &output)); output_progression0.emplace_back(std::move(output)); // read scanlines/read raw data does not change input/output scan number EXPECT_EQ(cinfo.input_scan_number, sos_marker_cnt); EXPECT_EQ(cinfo.output_scan_number, cinfo.input_scan_number); while (!jpegli_finish_output(&cinfo)) { - JXL_CHECK(src.LoadNextChunk()); + JPEGLI_TEST_ENSURE_TRUE(src.LoadNextChunk()); } ++sos_marker_cnt; // finish output reads the next SOS marker or EOI if (dparams.output_mode == COEFFICIENTS) { jvirt_barray_ptr* coef_arrays = jpegli_read_coefficients(&cinfo); - JXL_CHECK(coef_arrays != nullptr); + JPEGLI_TEST_ENSURE_TRUE(coef_arrays != nullptr); CopyCoefficients(&cinfo, coef_arrays, &output_progression0.back()); } } @@ -355,7 +370,8 @@ TEST_P(InputSuspensionTestParam, PreConsumeInputBuffered) { TestConfig config = GetParam(); if (config.jparams.add_marker) return; const DecompressParams& dparams = config.dparams; - std::vector compressed = GetTestJpegData(config); + JXL_ASSIGN_OR_QUIT(std::vector compressed, GetTestJpegData(config), + "Failed to create test data."); bool is_partial = config.dparams.size_factor < 1.0f; if (is_partial) { compressed.resize(compressed.size() * config.dparams.size_factor); @@ -375,7 +391,7 @@ TEST_P(InputSuspensionTestParam, PreConsumeInputBuffered) { int status; while ((status = jpegli_consume_input(&cinfo)) != JPEG_REACHED_SOS) { if (status == JPEG_SUSPENDED) { - JXL_CHECK(src.LoadNextChunk()); + JPEGLI_TEST_ENSURE_TRUE(src.LoadNextChunk()); } } EXPECT_EQ(JPEG_REACHED_SOS, jpegli_consume_input(&cinfo)); @@ -390,7 +406,7 @@ TEST_P(InputSuspensionTestParam, PreConsumeInputBuffered) { while ((status = jpegli_consume_input(&cinfo)) != JPEG_REACHED_EOI) { if (status == JPEG_SUSPENDED) { - JXL_CHECK(src.LoadNextChunk()); + JPEGLI_TEST_ENSURE_TRUE(src.LoadNextChunk()); } } @@ -402,14 +418,15 @@ TEST_P(InputSuspensionTestParam, PreConsumeInputBuffered) { EXPECT_EQ(output_progression1.size(), cinfo.input_scan_number); EXPECT_EQ(cinfo.output_scan_number, cinfo.input_scan_number); - ReadOutputImage(dparams, &cinfo, nullptr, &output0); + JPEGLI_TEST_ENSURE_TRUE( + ReadOutputImage(dparams, &cinfo, nullptr, &output0)); EXPECT_EQ(output_progression1.size(), cinfo.input_scan_number); EXPECT_EQ(cinfo.output_scan_number, cinfo.input_scan_number); EXPECT_TRUE(jpegli_finish_output(&cinfo)); if (dparams.output_mode == COEFFICIENTS) { jvirt_barray_ptr* coef_arrays = jpegli_read_coefficients(&cinfo); - JXL_CHECK(coef_arrays != nullptr); + JPEGLI_TEST_ENSURE_TRUE(coef_arrays != nullptr); CopyCoefficients(&cinfo, coef_arrays, &output0); } EXPECT_TRUE(jpegli_finish_decompress(&cinfo)); @@ -425,7 +442,8 @@ TEST_P(InputSuspensionTestParam, PreConsumeInputNonBuffered) { TestConfig config = GetParam(); if (config.jparams.add_marker || IsSequential(config)) return; const DecompressParams& dparams = config.dparams; - std::vector compressed = GetTestJpegData(config); + JXL_ASSIGN_OR_QUIT(std::vector compressed, GetTestJpegData(config), + "Failed to create test data."); bool is_partial = config.dparams.size_factor < 1.0f; if (is_partial) { compressed.resize(compressed.size() * config.dparams.size_factor); @@ -442,7 +460,7 @@ TEST_P(InputSuspensionTestParam, PreConsumeInputNonBuffered) { int status; while ((status = jpegli_consume_input(&cinfo)) != JPEG_REACHED_SOS) { if (status == JPEG_SUSPENDED) { - JXL_CHECK(src.LoadNextChunk()); + JPEGLI_TEST_ENSURE_TRUE(src.LoadNextChunk()); } } EXPECT_EQ(JPEG_REACHED_SOS, jpegli_consume_input(&cinfo)); @@ -453,22 +471,23 @@ TEST_P(InputSuspensionTestParam, PreConsumeInputNonBuffered) { jpegli_read_coefficients(&cinfo); } else { while (!jpegli_start_decompress(&cinfo)) { - JXL_CHECK(src.LoadNextChunk()); + JPEGLI_TEST_ENSURE_TRUE(src.LoadNextChunk()); } } while ((status = jpegli_consume_input(&cinfo)) != JPEG_REACHED_EOI) { if (status == JPEG_SUSPENDED) { - JXL_CHECK(src.LoadNextChunk()); + JPEGLI_TEST_ENSURE_TRUE(src.LoadNextChunk()); } } if (dparams.output_mode == COEFFICIENTS) { jvirt_barray_ptr* coef_arrays = jpegli_read_coefficients(&cinfo); - JXL_CHECK(coef_arrays != nullptr); + JPEGLI_TEST_ENSURE_TRUE(coef_arrays != nullptr); CopyCoefficients(&cinfo, coef_arrays, &output0); } else { - ReadOutputImage(dparams, &cinfo, nullptr, &output0); + JPEGLI_TEST_ENSURE_TRUE( + ReadOutputImage(dparams, &cinfo, nullptr, &output0)); } EXPECT_TRUE(jpegli_finish_decompress(&cinfo)); diff --git a/third_party/jpeg-xl/lib/jpegli/libjpeg_test_util.cc b/third_party/jpeg-xl/lib/jpegli/libjpeg_test_util.cc index 020adf5e9e9ee..22088b3d214b2 100644 --- a/third_party/jpeg-xl/lib/jpegli/libjpeg_test_util.cc +++ b/third_party/jpeg-xl/lib/jpegli/libjpeg_test_util.cc @@ -5,18 +5,22 @@ #include "lib/jpegli/libjpeg_test_util.h" -/* clang-format off */ -#include -#include -#include -/* clang-format on */ +#include -#include "lib/jxl/sanitizers.h" +#include "lib/jxl/base/compiler_specific.h" +#include "lib/jxl/base/include_jpeglib.h" // NOLINT +#include "lib/jxl/base/sanitizers.h" namespace jpegli { namespace { +void Check(bool ok) { + if (!ok) { + JXL_CRASH(); + } +} + #define JPEG_API_FN(name) jpeg_##name #include "lib/jpegli/test_utils-inl.h" #undef JPEG_API_FN @@ -31,7 +35,7 @@ void ReadOutputPass(j_decompress_ptr cinfo, const DecompressParams& dparams, xoffset = xsize_cropped = cinfo->output_width / 3; yoffset = ysize_cropped = cinfo->output_height / 3; jpeg_crop_scanline(cinfo, &xoffset, &xsize_cropped); - JXL_CHECK(xsize_cropped == cinfo->output_width); + Check(xsize_cropped == cinfo->output_width); } output->xsize = xsize_cropped; output->ysize = ysize_cropped; @@ -56,7 +60,7 @@ void ReadOutputPass(j_decompress_ptr cinfo, const DecompressParams& dparams, for (size_t y = 0; y < output->ysize; ++y) { JSAMPROW rows[] = { reinterpret_cast(&output->pixels[y * stride])}; - JXL_CHECK(1 == jpeg_read_scanlines(cinfo, rows, 1)); + Check(1 == jpeg_read_scanlines(cinfo, rows, 1)); jxl::msan::UnpoisonMemory( rows[0], sizeof(JSAMPLE) * cinfo->output_components * output->xsize); if (cinfo->quantize_colors) { @@ -77,7 +81,7 @@ void ReadOutputPass(j_decompress_ptr cinfo, const DecompressParams& dparams, } while (cinfo->output_scanline < cinfo->output_height) { size_t iMCU_height = cinfo->max_v_samp_factor * DCTSIZE; - JXL_CHECK(cinfo->output_scanline == cinfo->output_iMCU_row * iMCU_height); + Check(cinfo->output_scanline == cinfo->output_iMCU_row * iMCU_height); std::vector> rowdata(cinfo->num_components); std::vector data(cinfo->num_components); for (int c = 0; c < cinfo->num_components; ++c) { @@ -92,12 +96,11 @@ void ReadOutputPass(j_decompress_ptr cinfo, const DecompressParams& dparams, } data[c] = rowdata[c].data(); } - JXL_CHECK(iMCU_height == - jpeg_read_raw_data(cinfo, data.data(), iMCU_height)); + Check(iMCU_height == jpeg_read_raw_data(cinfo, data.data(), iMCU_height)); } } - JXL_CHECK(cinfo->total_iMCU_rows == - DivCeil(cinfo->image_height, cinfo->max_v_samp_factor * DCTSIZE)); + Check(cinfo->total_iMCU_rows == + DivCeil(cinfo->image_height, cinfo->max_v_samp_factor * DCTSIZE)); } void DecodeWithLibjpeg(const CompressParams& jparams, @@ -110,29 +113,30 @@ void DecodeWithLibjpeg(const CompressParams& jparams, if (!jparams.icc.empty()) { jpeg_save_markers(cinfo, JPEG_APP0 + 2, 0xffff); } - JXL_CHECK(JPEG_REACHED_SOS == - jpeg_read_header(cinfo, /*require_image=*/TRUE)); + Check(JPEG_REACHED_SOS == jpeg_read_header(cinfo, /*require_image=*/TRUE)); if (!jparams.icc.empty()) { uint8_t* icc_data = nullptr; unsigned int icc_len = 0; // "unpoison" via initialization - JXL_CHECK(jpeg_read_icc_profile(cinfo, &icc_data, &icc_len)); - JXL_CHECK(icc_data); + Check(jpeg_read_icc_profile(cinfo, &icc_data, &icc_len)); + Check(icc_data); jxl::msan::UnpoisonMemory(icc_data, icc_len); - JXL_CHECK(0 == memcmp(jparams.icc.data(), icc_data, icc_len)); + Check(0 == memcmp(jparams.icc.data(), icc_data, icc_len)); free(icc_data); } SetDecompressParams(dparams, cinfo); VerifyHeader(jparams, cinfo); if (dparams.output_mode == COEFFICIENTS) { jvirt_barray_ptr* coef_arrays = jpeg_read_coefficients(cinfo); - JXL_CHECK(coef_arrays != nullptr); + Check(coef_arrays != nullptr); + jxl::msan::UnpoisonMemory(coef_arrays, + cinfo->num_components * sizeof(jvirt_barray_ptr)); CopyCoefficients(cinfo, coef_arrays, output); } else { - JXL_CHECK(jpeg_start_decompress(cinfo)); + Check(jpeg_start_decompress(cinfo)); VerifyScanHeader(jparams, cinfo); ReadOutputPass(cinfo, dparams, output); } - JXL_CHECK(jpeg_finish_decompress(cinfo)); + Check(jpeg_finish_decompress(cinfo)); } } // namespace @@ -164,18 +168,17 @@ void DecodeAllScansWithLibjpeg(const CompressParams& jparams, jpeg_save_markers(&cinfo, kSpecialMarker0, 0xffff); jpeg_save_markers(&cinfo, kSpecialMarker1, 0xffff); } - JXL_CHECK(JPEG_REACHED_SOS == - jpeg_read_header(&cinfo, /*require_image=*/TRUE)); + Check(JPEG_REACHED_SOS == jpeg_read_header(&cinfo, /*require_image=*/TRUE)); cinfo.buffered_image = TRUE; SetDecompressParams(dparams, &cinfo); VerifyHeader(jparams, &cinfo); - JXL_CHECK(jpeg_start_decompress(&cinfo)); + Check(jpeg_start_decompress(&cinfo)); // start decompress should not read the whole input in buffered image mode - JXL_CHECK(!jpeg_input_complete(&cinfo)); - JXL_CHECK(cinfo.output_scan_number == 0); + Check(!jpeg_input_complete(&cinfo)); + Check(cinfo.output_scan_number == 0); int sos_marker_cnt = 1; // read header reads the first SOS marker while (!jpeg_input_complete(&cinfo)) { - JXL_CHECK(cinfo.input_scan_number == sos_marker_cnt); + Check(cinfo.input_scan_number == sos_marker_cnt); if (dparams.skip_scans && (cinfo.input_scan_number % 2) != 1) { int result = JPEG_SUSPENDED; while (result != JPEG_REACHED_SOS && result != JPEG_REACHED_EOI) { @@ -185,32 +188,34 @@ void DecodeAllScansWithLibjpeg(const CompressParams& jparams, continue; } SetScanDecompressParams(dparams, &cinfo, cinfo.input_scan_number); - JXL_CHECK(jpeg_start_output(&cinfo, cinfo.input_scan_number)); + Check(jpeg_start_output(&cinfo, cinfo.input_scan_number)); // start output sets output_scan_number, but does not change // input_scan_number - JXL_CHECK(cinfo.output_scan_number == cinfo.input_scan_number); - JXL_CHECK(cinfo.input_scan_number == sos_marker_cnt); + Check(cinfo.output_scan_number == cinfo.input_scan_number); + Check(cinfo.input_scan_number == sos_marker_cnt); VerifyScanHeader(jparams, &cinfo); TestImage output; ReadOutputPass(&cinfo, dparams, &output); output_progression->emplace_back(std::move(output)); // read scanlines/read raw data does not change input/output scan number if (!cinfo.progressive_mode) { - JXL_CHECK(cinfo.input_scan_number == sos_marker_cnt); - JXL_CHECK(cinfo.output_scan_number == cinfo.input_scan_number); + Check(cinfo.input_scan_number == sos_marker_cnt); + Check(cinfo.output_scan_number == cinfo.input_scan_number); } - JXL_CHECK(jpeg_finish_output(&cinfo)); + Check(jpeg_finish_output(&cinfo)); ++sos_marker_cnt; // finish output reads the next SOS marker or EOI if (dparams.output_mode == COEFFICIENTS) { jvirt_barray_ptr* coef_arrays = jpeg_read_coefficients(&cinfo); - JXL_CHECK(coef_arrays != nullptr); + Check(coef_arrays != nullptr); + jxl::msan::UnpoisonMemory( + coef_arrays, cinfo.num_components * sizeof(jvirt_barray_ptr)); CopyCoefficients(&cinfo, coef_arrays, &output_progression->back()); } } - JXL_CHECK(jpeg_finish_decompress(&cinfo)); + Check(jpeg_finish_decompress(&cinfo)); return true; }; - JXL_CHECK(try_catch_block()); + Check(try_catch_block()); jpeg_destroy_decompress(&cinfo); } @@ -243,10 +248,11 @@ size_t DecodeWithLibjpeg(const CompressParams& jparams, } jpeg_mem_src(&cinfo, compressed, len); DecodeWithLibjpeg(jparams, dparams, &cinfo, output); + jxl::msan::UnpoisonMemory(cinfo.src, sizeof(jpeg_source_mgr)); bytes_read = len - cinfo.src->bytes_in_buffer; return true; }; - JXL_CHECK(try_catch_block()); + Check(try_catch_block()); jpeg_destroy_decompress(&cinfo); return bytes_read; } diff --git a/third_party/jpeg-xl/lib/jpegli/libjpeg_wrapper.cc b/third_party/jpeg-xl/lib/jpegli/libjpeg_wrapper.cc index 471b7c7192362..a2b333afef2c7 100644 --- a/third_party/jpeg-xl/lib/jpegli/libjpeg_wrapper.cc +++ b/third_party/jpeg-xl/lib/jpegli/libjpeg_wrapper.cc @@ -38,7 +38,7 @@ void jpeg_stdio_src(j_decompress_ptr cinfo, FILE *infile) { } void jpeg_mem_src(j_decompress_ptr cinfo, const unsigned char *inbuffer, - unsigned long insize) { + unsigned long insize /* NOLINT */) { jpegli_mem_src(cinfo, inbuffer, insize); } @@ -138,7 +138,7 @@ void jpeg_stdio_dest(j_compress_ptr cinfo, FILE *outfile) { } void jpeg_mem_dest(j_compress_ptr cinfo, unsigned char **outbuffer, - unsigned long *outsize) { + unsigned long *outsize /* NOLINT */) { jpegli_mem_dest(cinfo, outbuffer, outsize); } diff --git a/third_party/jpeg-xl/lib/jpegli/output_suspension_test.cc b/third_party/jpeg-xl/lib/jpegli/output_suspension_test.cc index 3cb2fd3ee49a2..44d63fdcbb4d0 100644 --- a/third_party/jpeg-xl/lib/jpegli/output_suspension_test.cc +++ b/third_party/jpeg-xl/lib/jpegli/output_suspension_test.cc @@ -3,7 +3,18 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include +#include +#include +#include +#include +#include +#include +#include + #include "lib/jpegli/encode.h" +#include "lib/jpegli/libjpeg_test_util.h" +#include "lib/jpegli/test_params.h" #include "lib/jpegli/test_utils.h" #include "lib/jpegli/testing.h" @@ -130,6 +141,7 @@ TEST_P(OutputSuspensionTestParam, RawData) { cinfo.input_components = input.components; cinfo.in_color_space = JCS_YCbCr; jpegli_set_defaults(&cinfo); + cinfo.comp_info[0].h_samp_factor = config.jparams.h_sampling[0]; cinfo.comp_info[0].v_samp_factor = config.jparams.v_sampling[0]; jpegli_set_progressive_level(&cinfo, 0); cinfo.optimize_coding = FALSE; diff --git a/third_party/jpeg-xl/lib/jpegli/render.cc b/third_party/jpeg-xl/lib/jpegli/render.cc index c550f9a575ddd..1510401fa70e6 100644 --- a/third_party/jpeg-xl/lib/jpegli/render.cc +++ b/third_party/jpeg-xl/lib/jpegli/render.cc @@ -5,13 +5,11 @@ #include "lib/jpegli/render.h" -#include - #include #include #include #include -#include +#include #include #include "lib/jpegli/color_quantize.h" @@ -22,7 +20,6 @@ #include "lib/jpegli/upsample.h" #include "lib/jxl/base/byte_order.h" #include "lib/jxl/base/compiler_specific.h" -#include "lib/jxl/base/status.h" #ifdef MEMORY_SANITIZER #define JXL_MEMORY_SANITIZER 1 @@ -431,7 +428,7 @@ void PredictSmooth(j_decompress_ptr cinfo, JBLOCKARRAY blocks, int component, } } // Get the correct coef_bits: In case of an incomplete scan, we use the - // prev coeficients. + // prev coefficients. if (cinfo->output_iMCU_row + 1 > cinfo->input_iMCU_row) { coef_bits = cinfo->master->prev_coef_bits_latch[component]; } else { @@ -466,8 +463,8 @@ void PredictSmooth(j_decompress_ptr cinfo, JBLOCKARRAY blocks, int component, auto dc = [&](int i, int j) { return swap_indices ? dc_values[j][i] : dc_values[i][j]; }; + JPEGLI_CHECK(coef_index >= 0 && coef_index < 10); Al = coef_bits[coef_index]; - JXL_ASSERT(coef_index >= 0 && coef_index < 10); switch (coef_index) { case 0: // set the DC @@ -569,21 +566,21 @@ void PrepareForOutput(j_decompress_ptr cinfo) { m->dequant_[c * DCTSIZE2 + k] = table->quantval[k] * kDequantScale; } } - ChooseInverseTransform(cinfo); + JPEGLI_CHECK(ChooseInverseTransform(cinfo)); ChooseColorTransform(cinfo); } void DecodeCurrentiMCURow(j_decompress_ptr cinfo) { jpeg_decomp_master* m = cinfo->master; const size_t imcu_row = cinfo->output_iMCU_row; - JBLOCKARRAY ba[kMaxComponents]; + JBLOCKARRAY blocks[kMaxComponents]; for (int c = 0; c < cinfo->num_components; ++c) { const jpeg_component_info* comp = &cinfo->comp_info[c]; int by0 = imcu_row * comp->v_samp_factor; int block_rows_left = comp->height_in_blocks - by0; int max_block_rows = std::min(comp->v_samp_factor, block_rows_left); int offset = m->streaming_mode_ ? 0 : by0; - ba[c] = (*cinfo->mem->access_virt_barray)( + blocks[c] = (*cinfo->mem->access_virt_barray)( reinterpret_cast(cinfo), m->coef_arrays[c], offset, max_block_rows, FALSE); } @@ -598,7 +595,7 @@ void DecodeCurrentiMCURow(j_decompress_ptr cinfo) { if (by >= compinfo.height_in_blocks) { continue; } - int16_t* JXL_RESTRICT coeffs = &ba[c][iy][0][0]; + int16_t* JXL_RESTRICT coeffs = &blocks[c][iy][0][0]; size_t num = compinfo.width_in_blocks * DCTSIZE2; GatherBlockStats(coeffs, num, &m->nonzeros_[k0], &m->sumabs_[k0]); m->num_processed_blocks_[c] += compinfo.width_in_blocks; @@ -617,11 +614,11 @@ void DecodeCurrentiMCURow(j_decompress_ptr cinfo) { continue; } size_t dctsize = m->scaled_dct_size[c]; - int16_t* JXL_RESTRICT row_in = &ba[c][iy][0][0]; + int16_t* JXL_RESTRICT row_in = &blocks[c][iy][0][0]; float* JXL_RESTRICT row_out = raw_out->Row(by * dctsize); for (size_t bx = 0; bx < compinfo.width_in_blocks; ++bx) { if (m->apply_smoothing) { - PredictSmooth(cinfo, ba[c], c, bx, iy); + PredictSmooth(cinfo, blocks[c], c, bx, iy); (*m->inverse_transform[c])(m->smoothing_scratch_, &m->dequant_[k0], &m->biases_[k0], m->idct_scratch_, &row_out[bx * dctsize], raw_out->stride(), @@ -746,7 +743,7 @@ void ProcessOutput(j_decompress_ptr cinfo, size_t* num_output_rows, WriteToOutput(cinfo, rows, m->xoffset_, cinfo->output_width, cinfo->out_color_components, output); } - JXL_ASSERT(cinfo->output_scanline == y + yix); + JPEGLI_CHECK(cinfo->output_scanline == y + yix); ++cinfo->output_scanline; ++(*num_output_rows); if (cinfo->output_scanline == cinfo->output_height) { diff --git a/third_party/jpeg-xl/lib/jpegli/source_manager.cc b/third_party/jpeg-xl/lib/jpegli/source_manager.cc index 58adf803b1f0f..e0f0b4c275a12 100644 --- a/third_party/jpeg-xl/lib/jpegli/source_manager.cc +++ b/third_party/jpeg-xl/lib/jpegli/source_manager.cc @@ -12,9 +12,10 @@ namespace jpegli { void init_mem_source(j_decompress_ptr cinfo) {} void init_stdio_source(j_decompress_ptr cinfo) {} -void skip_input_data(j_decompress_ptr cinfo, long num_bytes) { +void skip_input_data(j_decompress_ptr cinfo, long num_bytes /* NOLINT */) { if (num_bytes <= 0) return; - while (num_bytes > static_cast(cinfo->src->bytes_in_buffer)) { + while (num_bytes > + static_cast(cinfo->src->bytes_in_buffer)) { // NOLINT num_bytes -= cinfo->src->bytes_in_buffer; (*cinfo->src->fill_input_buffer)(cinfo); } @@ -53,7 +54,7 @@ struct StdioSourceManager { } // namespace jpegli void jpegli_mem_src(j_decompress_ptr cinfo, const unsigned char* inbuffer, - unsigned long insize) { + unsigned long insize /* NOLINT */) { if (cinfo->src && cinfo->src->init_source != jpegli::init_mem_source) { JPEGLI_ERROR("jpegli_mem_src: a different source manager was already set"); } diff --git a/third_party/jpeg-xl/lib/jpegli/source_manager_test.cc b/third_party/jpeg-xl/lib/jpegli/source_manager_test.cc index 59d12b001b0d9..b70b43d8dbef3 100644 --- a/third_party/jpeg-xl/lib/jpegli/source_manager_test.cc +++ b/third_party/jpeg-xl/lib/jpegli/source_manager_test.cc @@ -3,11 +3,18 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include +#include #include +#include +#include +#include +#include +#include #include #include "lib/jpegli/decode.h" +#include "lib/jpegli/libjpeg_test_util.h" +#include "lib/jpegli/test_params.h" #include "lib/jpegli/test_utils.h" #include "lib/jpegli/testing.h" #include "lib/jxl/base/status.h" @@ -43,14 +50,15 @@ FILE* MemOpen(const std::vector& data) { FILE* src = tmpfile(); if (!src) return nullptr; fwrite(data.data(), 1, data.size(), src); - rewind(src); + fseek(src, 0, SEEK_SET); return src; } } // namespace TEST_P(SourceManagerTestParam, TestStdioSourceManager) { TestConfig config = GetParam(); - std::vector compressed = ReadTestData(config.fn); + JXL_ASSIGN_OR_QUIT(std::vector compressed, ReadTestData(config.fn), + "Failed to read test data."); if (config.dparams.size_factor < 1.0) { compressed.resize(compressed.size() * config.dparams.size_factor); } @@ -77,7 +85,8 @@ TEST_P(SourceManagerTestParam, TestStdioSourceManager) { TEST_P(SourceManagerTestParam, TestMemSourceManager) { TestConfig config = GetParam(); - std::vector compressed = ReadTestData(config.fn); + JXL_ASSIGN_OR_QUIT(std::vector compressed, ReadTestData(config.fn), + "Failed to read test data."); if (config.dparams.size_factor < 1.0f) { compressed.resize(compressed.size() * config.dparams.size_factor); } diff --git a/third_party/jpeg-xl/lib/jpegli/streaming_test.cc b/third_party/jpeg-xl/lib/jpegli/streaming_test.cc index 2e6f7029b0d85..ae85fd2451a18 100644 --- a/third_party/jpeg-xl/lib/jpegli/streaming_test.cc +++ b/third_party/jpeg-xl/lib/jpegli/streaming_test.cc @@ -3,8 +3,18 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include +#include +#include +#include +#include +#include +#include +#include + #include "lib/jpegli/decode.h" #include "lib/jpegli/encode.h" +#include "lib/jpegli/test_params.h" #include "lib/jpegli/test_utils.h" #include "lib/jpegli/testing.h" @@ -28,7 +38,8 @@ struct SourceManager { static void init_source(j_decompress_ptr cinfo) {} static boolean fill_input_buffer(j_decompress_ptr cinfo) { return FALSE; } - static void skip_input_data(j_decompress_ptr cinfo, long num_bytes) {} + static void skip_input_data(j_decompress_ptr cinfo, + long num_bytes /* NOLINT */) {} static void term_source(j_decompress_ptr cinfo) {} }; @@ -117,26 +128,26 @@ TEST_P(StreamingTestParam, TestStreaming) { size_t stride = cinfo.image_width * cinfo.input_components; size_t iMCU_height = 8 * cinfo.max_v_samp_factor; std::vector row_bytes(iMCU_height * stride); - size_t yin = 0; - size_t yout = 0; - while (yin < cinfo.image_height) { + size_t y_in = 0; + size_t y_out = 0; + while (y_in < cinfo.image_height) { // Feed one iMCU row at a time to the compressor. - size_t lines_in = std::min(iMCU_height, cinfo.image_height - yin); - memcpy(row_bytes.data(), &input.pixels[yin * stride], lines_in * stride); + size_t lines_in = std::min(iMCU_height, cinfo.image_height - y_in); + memcpy(row_bytes.data(), &input.pixels[y_in * stride], lines_in * stride); std::vector rows_in(lines_in); for (size_t i = 0; i < lines_in; ++i) { rows_in[i] = &row_bytes[i * stride]; } EXPECT_EQ(lines_in, jpegli_write_scanlines(&cinfo, rows_in.data(), lines_in)); - yin += lines_in; - if (yin == cinfo.image_height) { + y_in += lines_in; + if (y_in == cinfo.image_height) { jpegli_finish_compress(&cinfo); } // Atfer the first iMCU row, we don't yet expect any output because the // compressor delays processing to have context rows after the iMCU row. - if (yin < std::min(2 * iMCU_height, cinfo.image_height)) { + if (y_in < std::min(2 * iMCU_height, cinfo.image_height)) { continue; } @@ -144,7 +155,7 @@ TEST_P(StreamingTestParam, TestStreaming) { // data. We check here that at least the scan header was output, because // we expect that the compressor's output buffer was filled at least once // while emitting the first compressed iMCU row. - if (yin == std::min(2 * iMCU_height, cinfo.image_height)) { + if (y_in == std::min(2 * iMCU_height, cinfo.image_height)) { EXPECT_EQ(JPEG_REACHED_SOS, jpegli_read_header(&dinfo, /*require_image=*/TRUE)); output.xsize = dinfo.image_width; @@ -155,7 +166,7 @@ TEST_P(StreamingTestParam, TestStreaming) { EXPECT_EQ(output.components, input.components); EXPECT_TRUE(jpegli_start_decompress(&dinfo)); output.pixels.resize(output.ysize * stride); - if (yin < cinfo.image_height) { + if (y_in < cinfo.image_height) { continue; } } @@ -165,7 +176,7 @@ TEST_P(StreamingTestParam, TestStreaming) { // data to be in the decoder's input buffer, but since the decoder also // needs context rows for upsampling and smoothing, we don't expect any // output to be ready yet. - if (yin < 7 * iMCU_height && yin < cinfo.image_height) { + if (y_in < 7 * iMCU_height && y_in < cinfo.image_height) { continue; } @@ -173,18 +184,19 @@ TEST_P(StreamingTestParam, TestStreaming) { // with four iMCU rows of delay. // TODO(szabadka) Reduce the processing delay in the decoder if possible. size_t lines_out = - (yin == cinfo.image_height ? cinfo.image_height - yout : iMCU_height); + (y_in == cinfo.image_height ? cinfo.image_height - y_out + : iMCU_height); std::vector rows_out(lines_out); for (size_t i = 0; i < lines_out; ++i) { rows_out[i] = - reinterpret_cast(&output.pixels[(yout + i) * stride]); + reinterpret_cast(&output.pixels[(y_out + i) * stride]); } EXPECT_EQ(lines_out, jpegli_read_scanlines(&dinfo, rows_out.data(), lines_out)); - VerifyOutputImage(input, output, yout, lines_out, 3.8f); - yout += lines_out; + VerifyOutputImage(input, output, y_out, lines_out, 3.8f); + y_out += lines_out; - if (yout == cinfo.image_height) { + if (y_out == cinfo.image_height) { EXPECT_TRUE(jpegli_finish_decompress(&dinfo)); } } diff --git a/third_party/jpeg-xl/lib/jpegli/test_utils-inl.h b/third_party/jpeg-xl/lib/jpegli/test_utils-inl.h index 4fbcb721e4c61..da1a924e21f85 100644 --- a/third_party/jpeg-xl/lib/jpegli/test_utils-inl.h +++ b/third_party/jpeg-xl/lib/jpegli/test_utils-inl.h @@ -183,11 +183,11 @@ void SetScanDecompressParams(const DecompressParams& dparams, cinfo->two_pass_quantize = FALSE; cinfo->colormap = nullptr; } else if (sparams->color_quant_mode == CQUANT_2PASS) { - JXL_CHECK(cinfo->out_color_space == JCS_RGB); + Check(cinfo->out_color_space == JCS_RGB); cinfo->two_pass_quantize = TRUE; cinfo->colormap = nullptr; } else if (sparams->color_quant_mode == CQUANT_EXTERNAL) { - JXL_CHECK(cinfo->out_color_space == JCS_RGB); + Check(cinfo->out_color_space == JCS_RGB); cinfo->two_pass_quantize = FALSE; bool have_colormap = cinfo->colormap != nullptr; cinfo->actual_number_of_colors = kTestColorMapNumColors; @@ -205,8 +205,8 @@ void SetScanDecompressParams(const DecompressParams& dparams, JPEG_API_FN(new_colormap)(cinfo); } } else if (sparams->color_quant_mode == CQUANT_REUSE) { - JXL_CHECK(cinfo->out_color_space == JCS_RGB); - JXL_CHECK(cinfo->colormap); + Check(cinfo->out_color_space == JCS_RGB); + Check(cinfo->colormap); } } } @@ -259,18 +259,18 @@ void CheckMarkerPresent(j_decompress_ptr cinfo, uint8_t marker_type) { marker_found = true; } } - JXL_CHECK(marker_found); + Check(marker_found); } void VerifyHeader(const CompressParams& jparams, j_decompress_ptr cinfo) { if (jparams.set_jpeg_colorspace) { - JXL_CHECK(cinfo->jpeg_color_space == jparams.jpeg_color_space); + Check(cinfo->jpeg_color_space == jparams.jpeg_color_space); } if (jparams.override_JFIF >= 0) { - JXL_CHECK(cinfo->saw_JFIF_marker == jparams.override_JFIF); + Check(cinfo->saw_JFIF_marker == jparams.override_JFIF); } if (jparams.override_Adobe >= 0) { - JXL_CHECK(cinfo->saw_Adobe_marker == jparams.override_Adobe); + Check(cinfo->saw_Adobe_marker == jparams.override_Adobe); } if (jparams.add_marker) { CheckMarkerPresent(cinfo, kSpecialMarker0); @@ -283,114 +283,114 @@ void VerifyHeader(const CompressParams& jparams, j_decompress_ptr cinfo) { for (int i = 0; i < cinfo->num_components; ++i) { jpeg_component_info* comp = &cinfo->comp_info[i]; if (!jparams.comp_ids.empty()) { - JXL_CHECK(comp->component_id == jparams.comp_ids[i]); + Check(comp->component_id == jparams.comp_ids[i]); } if (!jparams.h_sampling.empty()) { - JXL_CHECK(comp->h_samp_factor == jparams.h_sampling[i]); + Check(comp->h_samp_factor == jparams.h_sampling[i]); } if (!jparams.v_sampling.empty()) { - JXL_CHECK(comp->v_samp_factor == jparams.v_sampling[i]); + Check(comp->v_samp_factor == jparams.v_sampling[i]); } if (!jparams.quant_indexes.empty()) { - JXL_CHECK(comp->quant_tbl_no == jparams.quant_indexes[i]); + Check(comp->quant_tbl_no == jparams.quant_indexes[i]); } max_h_samp_factor = std::max(max_h_samp_factor, comp->h_samp_factor); max_v_samp_factor = std::max(max_v_samp_factor, comp->v_samp_factor); } - JXL_CHECK(max_h_samp_factor == cinfo->max_h_samp_factor); - JXL_CHECK(max_v_samp_factor == cinfo->max_v_samp_factor); + Check(max_h_samp_factor == cinfo->max_h_samp_factor); + Check(max_v_samp_factor == cinfo->max_v_samp_factor); int referenced_tables[NUM_QUANT_TBLS] = {}; for (int i = 0; i < cinfo->num_components; ++i) { jpeg_component_info* comp = &cinfo->comp_info[i]; - JXL_CHECK(comp->width_in_blocks == - DivCeil(cinfo->image_width * comp->h_samp_factor, - max_h_samp_factor * DCTSIZE)); - JXL_CHECK(comp->height_in_blocks == - DivCeil(cinfo->image_height * comp->v_samp_factor, - max_v_samp_factor * DCTSIZE)); + Check(comp->width_in_blocks == + DivCeil(cinfo->image_width * comp->h_samp_factor, + max_h_samp_factor * DCTSIZE)); + Check(comp->height_in_blocks == + DivCeil(cinfo->image_height * comp->v_samp_factor, + max_v_samp_factor * DCTSIZE)); referenced_tables[comp->quant_tbl_no] = 1; } for (const auto& table : jparams.quant_tables) { JQUANT_TBL* quant_table = cinfo->quant_tbl_ptrs[table.slot_idx]; if (!referenced_tables[table.slot_idx]) { - JXL_CHECK(quant_table == nullptr); + Check(quant_table == nullptr); continue; } - JXL_CHECK(quant_table != nullptr); + Check(quant_table != nullptr); jxl::msan::UnpoisonMemory(quant_table, sizeof(*quant_table)); for (int k = 0; k < DCTSIZE2; ++k) { - JXL_CHECK(quant_table->quantval[k] == table.quantval[k]); + Check(quant_table->quantval[k] == table.quantval[k]); } } } void VerifyScanHeader(const CompressParams& jparams, j_decompress_ptr cinfo) { - JXL_CHECK(cinfo->input_scan_number > 0); + Check(cinfo->input_scan_number > 0); if (cinfo->progressive_mode) { - JXL_CHECK(cinfo->Ss != 0 || cinfo->Se != 63); + Check(cinfo->Ss != 0 || cinfo->Se != 63); } else { - JXL_CHECK(cinfo->Ss == 0 && cinfo->Se == 63); + Check(cinfo->Ss == 0 && cinfo->Se == 63); } if (jparams.progressive_mode > 2) { - JXL_CHECK(jparams.progressive_mode < 3 + kNumTestScripts); + Check(jparams.progressive_mode < 3 + kNumTestScripts); const ScanScript& script = kTestScript[jparams.progressive_mode - 3]; - JXL_CHECK(cinfo->input_scan_number <= script.num_scans); + Check(cinfo->input_scan_number <= script.num_scans); const jpeg_scan_info& scan = script.scans[cinfo->input_scan_number - 1]; - JXL_CHECK(cinfo->comps_in_scan == scan.comps_in_scan); + Check(cinfo->comps_in_scan == scan.comps_in_scan); for (int i = 0; i < cinfo->comps_in_scan; ++i) { - JXL_CHECK(cinfo->cur_comp_info[i]->component_index == - scan.component_index[i]); + Check(cinfo->cur_comp_info[i]->component_index == + scan.component_index[i]); } - JXL_CHECK(cinfo->Ss == scan.Ss); - JXL_CHECK(cinfo->Se == scan.Se); - JXL_CHECK(cinfo->Ah == scan.Ah); - JXL_CHECK(cinfo->Al == scan.Al); + Check(cinfo->Ss == scan.Ss); + Check(cinfo->Se == scan.Se); + Check(cinfo->Ah == scan.Ah); + Check(cinfo->Al == scan.Al); } if (jparams.restart_interval > 0) { - JXL_CHECK(cinfo->restart_interval == jparams.restart_interval); + Check(cinfo->restart_interval == jparams.restart_interval); } else if (jparams.restart_in_rows > 0) { - JXL_CHECK(cinfo->restart_interval == - jparams.restart_in_rows * cinfo->MCUs_per_row); + Check(cinfo->restart_interval == + jparams.restart_in_rows * cinfo->MCUs_per_row); } if (jparams.progressive_mode == 0 && jparams.optimize_coding == 0) { if (cinfo->jpeg_color_space == JCS_RGB) { - JXL_CHECK(cinfo->comp_info[0].dc_tbl_no == 0); - JXL_CHECK(cinfo->comp_info[1].dc_tbl_no == 0); - JXL_CHECK(cinfo->comp_info[2].dc_tbl_no == 0); - JXL_CHECK(cinfo->comp_info[0].ac_tbl_no == 0); - JXL_CHECK(cinfo->comp_info[1].ac_tbl_no == 0); - JXL_CHECK(cinfo->comp_info[2].ac_tbl_no == 0); + Check(cinfo->comp_info[0].dc_tbl_no == 0); + Check(cinfo->comp_info[1].dc_tbl_no == 0); + Check(cinfo->comp_info[2].dc_tbl_no == 0); + Check(cinfo->comp_info[0].ac_tbl_no == 0); + Check(cinfo->comp_info[1].ac_tbl_no == 0); + Check(cinfo->comp_info[2].ac_tbl_no == 0); } else if (cinfo->jpeg_color_space == JCS_YCbCr) { - JXL_CHECK(cinfo->comp_info[0].dc_tbl_no == 0); - JXL_CHECK(cinfo->comp_info[1].dc_tbl_no == 1); - JXL_CHECK(cinfo->comp_info[2].dc_tbl_no == 1); - JXL_CHECK(cinfo->comp_info[0].ac_tbl_no == 0); - JXL_CHECK(cinfo->comp_info[1].ac_tbl_no == 1); - JXL_CHECK(cinfo->comp_info[2].ac_tbl_no == 1); + Check(cinfo->comp_info[0].dc_tbl_no == 0); + Check(cinfo->comp_info[1].dc_tbl_no == 1); + Check(cinfo->comp_info[2].dc_tbl_no == 1); + Check(cinfo->comp_info[0].ac_tbl_no == 0); + Check(cinfo->comp_info[1].ac_tbl_no == 1); + Check(cinfo->comp_info[2].ac_tbl_no == 1); } else if (cinfo->jpeg_color_space == JCS_CMYK) { - JXL_CHECK(cinfo->comp_info[0].dc_tbl_no == 0); - JXL_CHECK(cinfo->comp_info[1].dc_tbl_no == 0); - JXL_CHECK(cinfo->comp_info[2].dc_tbl_no == 0); - JXL_CHECK(cinfo->comp_info[3].dc_tbl_no == 0); - JXL_CHECK(cinfo->comp_info[0].ac_tbl_no == 0); - JXL_CHECK(cinfo->comp_info[1].ac_tbl_no == 0); - JXL_CHECK(cinfo->comp_info[2].ac_tbl_no == 0); - JXL_CHECK(cinfo->comp_info[3].ac_tbl_no == 0); + Check(cinfo->comp_info[0].dc_tbl_no == 0); + Check(cinfo->comp_info[1].dc_tbl_no == 0); + Check(cinfo->comp_info[2].dc_tbl_no == 0); + Check(cinfo->comp_info[3].dc_tbl_no == 0); + Check(cinfo->comp_info[0].ac_tbl_no == 0); + Check(cinfo->comp_info[1].ac_tbl_no == 0); + Check(cinfo->comp_info[2].ac_tbl_no == 0); + Check(cinfo->comp_info[3].ac_tbl_no == 0); } else if (cinfo->jpeg_color_space == JCS_YCCK) { - JXL_CHECK(cinfo->comp_info[0].dc_tbl_no == 0); - JXL_CHECK(cinfo->comp_info[1].dc_tbl_no == 1); - JXL_CHECK(cinfo->comp_info[2].dc_tbl_no == 1); - JXL_CHECK(cinfo->comp_info[3].dc_tbl_no == 0); - JXL_CHECK(cinfo->comp_info[0].ac_tbl_no == 0); - JXL_CHECK(cinfo->comp_info[1].ac_tbl_no == 1); - JXL_CHECK(cinfo->comp_info[2].ac_tbl_no == 1); - JXL_CHECK(cinfo->comp_info[3].ac_tbl_no == 0); + Check(cinfo->comp_info[0].dc_tbl_no == 0); + Check(cinfo->comp_info[1].dc_tbl_no == 1); + Check(cinfo->comp_info[2].dc_tbl_no == 1); + Check(cinfo->comp_info[3].dc_tbl_no == 0); + Check(cinfo->comp_info[0].ac_tbl_no == 0); + Check(cinfo->comp_info[1].ac_tbl_no == 1); + Check(cinfo->comp_info[2].ac_tbl_no == 1); + Check(cinfo->comp_info[3].ac_tbl_no == 0); } if (jparams.use_flat_dc_luma_code) { JHUFF_TBL* tbl = cinfo->dc_huff_tbl_ptrs[0]; jxl::msan::UnpoisonMemory(tbl, sizeof(*tbl)); for (int i = 0; i < 15; ++i) { - JXL_CHECK(tbl->huffval[i] == i); + Check(tbl->huffval[i] == i); } } } @@ -398,10 +398,10 @@ void VerifyScanHeader(const CompressParams& jparams, j_decompress_ptr cinfo) { void UnmapColors(uint8_t* row, size_t xsize, int components, JSAMPARRAY colormap, size_t num_colors) { - JXL_CHECK(colormap != nullptr); + Check(colormap != nullptr); std::vector tmp(xsize * components); for (size_t x = 0; x < xsize; ++x) { - JXL_CHECK(row[x] < num_colors); + Check(row[x] < num_colors); for (int c = 0; c < components; ++c) { tmp[x * components + c] = colormap[c][row[x]]; } @@ -421,11 +421,11 @@ void CopyCoefficients(j_decompress_ptr cinfo, jvirt_barray_ptr* coef_arrays, std::vector coeffs(comp->width_in_blocks * comp->height_in_blocks * DCTSIZE2); for (size_t by = 0; by < comp->height_in_blocks; ++by) { - JBLOCKARRAY ba = (*cinfo->mem->access_virt_barray)(comptr, coef_arrays[c], - by, 1, TRUE); + JBLOCKARRAY blocks = (*cinfo->mem->access_virt_barray)( + comptr, coef_arrays[c], by, 1, TRUE); size_t stride = comp->width_in_blocks * sizeof(JBLOCK); size_t offset = by * comp->width_in_blocks * DCTSIZE2; - memcpy(&coeffs[offset], ba[0], stride); + memcpy(&coeffs[offset], blocks[0], stride); } output->coeffs.emplace_back(std::move(coeffs)); } diff --git a/third_party/jpeg-xl/lib/jpegli/test_utils.cc b/third_party/jpeg-xl/lib/jpegli/test_utils.cc index 4e675070cf717..2b903fa0c022f 100644 --- a/third_party/jpeg-xl/lib/jpegli/test_utils.cc +++ b/third_party/jpeg-xl/lib/jpegli/test_utils.cc @@ -7,14 +7,17 @@ #include #include +#include #include +#include #include "lib/jpegli/decode.h" #include "lib/jpegli/encode.h" #include "lib/jxl/base/byte_order.h" +#include "lib/jxl/base/compiler_specific.h" #include "lib/jxl/base/printf_macros.h" +#include "lib/jxl/base/sanitizers.h" #include "lib/jxl/base/status.h" -#include "lib/jxl/sanitizers.h" #if !defined(TEST_DATA_PATH) #include "tools/cpp/runfiles/runfiles.h" @@ -22,6 +25,15 @@ namespace jpegli { +namespace { +void Check(bool ok) { + if (!ok) { + JXL_CRASH(); + } +} +#define QUIT(M) Check(false); +} // namespace + #define JPEG_API_FN(name) jpegli_##name #include "lib/jpegli/test_utils-inl.h" #undef JPEG_API_FN @@ -31,7 +43,7 @@ std::string GetTestDataPath(const std::string& filename) { return std::string(TEST_DATA_PATH "/") + filename; } #else -using bazel::tools::cpp::runfiles::Runfiles; +using ::bazel::tools::cpp::runfiles::Runfiles; const std::unique_ptr kRunfiles(Runfiles::Create("")); std::string GetTestDataPath(const std::string& filename) { std::string root(JPEGXL_ROOT_PACKAGE "/testdata/"); @@ -39,15 +51,16 @@ std::string GetTestDataPath(const std::string& filename) { } #endif -std::vector ReadTestData(const std::string& filename) { +jxl::StatusOr> ReadTestData(const std::string& filename) { + std::vector data; std::string full_path = GetTestDataPath(filename); fprintf(stderr, "ReadTestData %s\n", full_path.c_str()); std::ifstream file(full_path, std::ios::binary); std::vector str((std::istreambuf_iterator(file)), std::istreambuf_iterator()); - JXL_CHECK(file.good()); + JXL_ENSURE(file.good()); const uint8_t* raw = reinterpret_cast(str.data()); - std::vector data(raw, raw + str.size()); + data = std::vector(raw, raw + str.size()); printf("Test data %s is %d bytes long.\n", filename.c_str(), static_cast(data.size())); return data; @@ -171,6 +184,18 @@ std::string ColorSpaceName(J_COLOR_SPACE colorspace) { return "CMYK"; case JCS_YCCK: return "YCCK"; + case JCS_EXT_RGB: + return "EXT_RGB"; + case JCS_EXT_BGR: + return "EXT_BGR"; + case JCS_EXT_RGBA: + return "EXT_RGBA"; + case JCS_EXT_BGRA: + return "EXT_BGRA"; + case JCS_EXT_ARGB: + return "EXT_ARGB"; + case JCS_EXT_ABGR: + return "EXT_ABGR"; default: return ""; } @@ -196,7 +221,7 @@ std::string IOMethodName(JpegliDataType data_type, std::string SamplingId(const CompressParams& jparams) { std::stringstream os; - JXL_CHECK(jparams.h_sampling.size() == jparams.v_sampling.size()); + Check(jparams.h_sampling.size() == jparams.v_sampling.size()); if (!jparams.h_sampling.empty()) { size_t len = jparams.h_sampling.size(); while (len > 1 && jparams.h_sampling[len - 1] == 1 && @@ -298,18 +323,23 @@ std::ostream& operator<<(std::ostream& os, const CompressParams& jparams) { return os; } -void SetNumChannels(J_COLOR_SPACE colorspace, size_t* channels) { +jxl::Status SetNumChannels(J_COLOR_SPACE colorspace, size_t* channels) { if (colorspace == JCS_GRAYSCALE) { *channels = 1; - } else if (colorspace == JCS_RGB || colorspace == JCS_YCbCr) { + } else if (colorspace == JCS_RGB || colorspace == JCS_YCbCr || + colorspace == JCS_EXT_RGB || colorspace == JCS_EXT_BGR) { *channels = 3; - } else if (colorspace == JCS_CMYK || colorspace == JCS_YCCK) { + } else if (colorspace == JCS_CMYK || colorspace == JCS_YCCK || + colorspace == JCS_EXT_RGBA || colorspace == JCS_EXT_BGRA || + colorspace == JCS_EXT_ARGB || colorspace == JCS_EXT_ABGR) { *channels = 4; } else if (colorspace == JCS_UNKNOWN) { - JXL_CHECK(*channels <= 4); + JXL_ENSURE(*channels <= 4); } else { - JXL_ABORT(); + return JXL_FAILURE("Unsupported colorspace: %d", + static_cast(colorspace)); } + return true; } void RGBToYCbCr(float r, float g, float b, float* y, float* cb, float* cr) { @@ -330,7 +360,28 @@ void ConvertPixel(const uint8_t* input_rgb, uint8_t* out, if (colorspace == JCS_GRAYSCALE) { const float Y = 0.299f * r + 0.587f * g + 0.114f * b; out8[0] = static_cast(std::round(Y * kMul)); - } else if (colorspace == JCS_RGB || colorspace == JCS_UNKNOWN) { + } else if (colorspace == JCS_RGB || colorspace == JCS_EXT_RGB || + colorspace == JCS_EXT_RGBA) { + out8[0] = input_rgb[0]; + out8[1] = input_rgb[1]; + out8[2] = input_rgb[2]; + if (colorspace == JCS_EXT_RGBA) out8[3] = 255; + } else if (colorspace == JCS_EXT_BGR || colorspace == JCS_EXT_BGRA) { + out8[2] = input_rgb[0]; + out8[1] = input_rgb[1]; + out8[0] = input_rgb[2]; + if (colorspace == JCS_EXT_BGRA) out8[3] = 255; + } else if (colorspace == JCS_EXT_ABGR) { + out8[0] = 255; + out8[3] = input_rgb[0]; + out8[2] = input_rgb[1]; + out8[1] = input_rgb[2]; + } else if (colorspace == JCS_EXT_ARGB) { + out8[0] = 255; + out8[1] = input_rgb[0]; + out8[2] = input_rgb[1]; + out8[3] = input_rgb[2]; + } else if (colorspace == JCS_UNKNOWN) { for (size_t c = 0; c < num_channels; ++c) { out8[c] = input_rgb[std::min(2, c)]; } @@ -363,7 +414,7 @@ void ConvertPixel(const uint8_t* input_rgb, uint8_t* out, } out8[3] = static_cast(std::round(K * kMul)); } else { - JXL_ABORT("Colorspace %d not supported", colorspace); + Check(false); } if (data_type == JPEGLI_TYPE_UINT8) { memcpy(out, out8, num_channels); @@ -389,10 +440,24 @@ void ConvertPixel(const uint8_t* input_rgb, uint8_t* out, void ConvertToGrayscale(TestImage* img) { if (img->color_space == JCS_GRAYSCALE) return; - JXL_CHECK(img->data_type == JPEGLI_TYPE_UINT8); - for (size_t i = 0; i < img->pixels.size(); i += 3) { - if (img->color_space == JCS_RGB) { - ConvertPixel(&img->pixels[i], &img->pixels[i / 3], JCS_GRAYSCALE, 1); + Check(img->data_type == JPEGLI_TYPE_UINT8); + bool rgb_pre_alpha = + img->color_space == JCS_EXT_ARGB || img->color_space == JCS_EXT_ABGR; + bool rgb_post_alpha = + img->color_space == JCS_EXT_RGBA || img->color_space == JCS_EXT_BGRA; + bool rgb_alpha = rgb_pre_alpha || rgb_post_alpha; + bool is_rgb = img->color_space == JCS_RGB || + img->color_space == JCS_EXT_RGB || + img->color_space == JCS_EXT_BGR || rgb_alpha; + bool switch_br = img->color_space == JCS_EXT_BGR || + img->color_space == JCS_EXT_ABGR || + img->color_space == JCS_EXT_BGRA; + size_t stride = rgb_alpha ? 4 : 3; + size_t offset = rgb_pre_alpha ? 1 : 0; + for (size_t i = offset; i < img->pixels.size(); i += stride) { + if (is_rgb) { + if (switch_br) std::swap(img->pixels[i], img->pixels[i + 2]); + ConvertPixel(&img->pixels[i], &img->pixels[i / stride], JCS_GRAYSCALE, 1); } else if (img->color_space == JCS_YCbCr) { img->pixels[i / 3] = img->pixels[i]; } @@ -403,25 +468,27 @@ void ConvertToGrayscale(TestImage* img) { } void GeneratePixels(TestImage* img) { - const std::vector imgdata = ReadTestData("jxl/flower/flower.pnm"); + JXL_ASSIGN_OR_QUIT(std::vector imgdata, + ReadTestData("jxl/flower/flower.pnm"), + "Failed to read test data"); size_t xsize; size_t ysize; size_t channels; size_t bitdepth; std::vector pixels; - JXL_CHECK(ReadPNM(imgdata, &xsize, &ysize, &channels, &bitdepth, &pixels)); + Check(ReadPNM(imgdata, &xsize, &ysize, &channels, &bitdepth, &pixels)); if (img->xsize == 0) img->xsize = xsize; if (img->ysize == 0) img->ysize = ysize; - JXL_CHECK(img->xsize <= xsize); - JXL_CHECK(img->ysize <= ysize); - JXL_CHECK(3 == channels); - JXL_CHECK(8 == bitdepth); + Check(img->xsize <= xsize); + Check(img->ysize <= ysize); + Check(3 == channels); + Check(8 == bitdepth); size_t in_bytes_per_pixel = channels; size_t in_stride = xsize * in_bytes_per_pixel; size_t x0 = (xsize - img->xsize) / 2; size_t y0 = (ysize - img->ysize) / 2; - SetNumChannels(static_cast(img->color_space), - &img->components); + Check(SetNumChannels(static_cast(img->color_space), + &img->components)); size_t out_bytes_per_pixel = jpegli_bytes_per_sample(img->data_type) * img->components; size_t out_stride = img->xsize * out_bytes_per_pixel; @@ -548,7 +615,7 @@ void EncodeWithJpegli(const TestImage& input, const CompressParams& jparams, } if (jparams.simple_progression) { jpegli_simple_progression(cinfo); - JXL_CHECK(jparams.progressive_mode == -1); + Check(jparams.progressive_mode == -1); } if (jparams.progressive_mode > 2) { const ScanScript& script = kTestScript[jparams.progressive_mode - 3]; @@ -624,7 +691,7 @@ void EncodeWithJpegli(const TestImage& input, const CompressParams& jparams, } } size_t num_lines = jpegli_write_raw_data(cinfo, data.data(), max_lines); - JXL_CHECK(num_lines == max_lines); + Check(num_lines == max_lines); } } else if (!input.coeffs.empty()) { j_common_ptr comptr = reinterpret_cast(cinfo); @@ -650,11 +717,11 @@ void EncodeWithJpegli(const TestImage& input, const CompressParams& jparams, for (int c = 0; c < cinfo->num_components; ++c) { jpeg_component_info* comp = &cinfo->comp_info[c]; for (size_t by = 0; by < comp->height_in_blocks; ++by) { - JBLOCKARRAY ba = (*cinfo->mem->access_virt_barray)( + JBLOCKARRAY blocks = (*cinfo->mem->access_virt_barray)( comptr, coef_arrays[c], by, 1, TRUE); size_t stride = comp->width_in_blocks * sizeof(JBLOCK); size_t offset = by * comp->width_in_blocks * DCTSIZE2; - memcpy(ba[0], &input.coeffs[c][offset], stride); + memcpy(blocks[0], &input.coeffs[c][offset], stride); } } } else { @@ -673,7 +740,7 @@ void EncodeWithJpegli(const TestImage& input, const CompressParams& jparams, bool EncodeWithJpegli(const TestImage& input, const CompressParams& jparams, std::vector* compressed) { uint8_t* buffer = nullptr; - unsigned long buffer_size = 0; + unsigned long buffer_size = 0; // NOLINT jpeg_compress_struct cinfo; const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); @@ -695,7 +762,7 @@ bool EncodeWithJpegli(const TestImage& input, const CompressParams& jparams, int NumTestScanScripts() { return kNumTestScripts; } void DumpImage(const TestImage& image, const std::string& fn) { - JXL_CHECK(image.components == 1 || image.components == 3); + Check(image.components == 1 || image.components == 3); size_t bytes_per_sample = jpegli_bytes_per_sample(image.data_type); uint32_t maxval = (1u << (8 * bytes_per_sample)) - 1; char type = image.components == 1 ? '5' : '6'; @@ -719,7 +786,7 @@ double DistanceRms(const TestImage& input, const TestImage& output, (im.endianness == JPEGLI_LITTLE_ENDIAN || (im.endianness == JPEGLI_NATIVE_ENDIAN && IsLittleEndian())); size_t offset = start_offset + idx * bytes_per_sample; - JXL_CHECK(offset < data.size()); + Check(offset < data.size()); const uint8_t* p = &data[offset]; if (im.data_type == JPEGLI_TYPE_UINT8) { static const double mul8 = 1.0 / 255.0; @@ -745,10 +812,10 @@ double DistanceRms(const TestImage& input, const TestImage& output, diff2 += diff * diff; } } else { - JXL_CHECK(!input.raw_data.empty()); - JXL_CHECK(!output.raw_data.empty()); + Check(!input.raw_data.empty()); + Check(!output.raw_data.empty()); for (size_t c = 0; c < input.raw_data.size(); ++c) { - JXL_CHECK(c < output.raw_data.size()); + Check(c < output.raw_data.size()); num_samples += input.raw_data[c].size(); for (size_t i = 0; i < input.raw_data[c].size(); ++i) { double sample_orig = get_sample(input, input.raw_data[c], i); @@ -774,23 +841,23 @@ void VerifyOutputImage(const TestImage& input, const TestImage& output, double rms = DistanceRms(input, output, start_line, num_lines, &max_d); printf("rms: %f, max_rms: %f, max_d: %f, max_diff: %f\n", rms, max_rms, max_d, max_diff); - JXL_CHECK(rms <= max_rms); - JXL_CHECK(max_d <= max_diff); + Check(rms <= max_rms); + Check(max_d <= max_diff); } void VerifyOutputImage(const TestImage& input, const TestImage& output, double max_rms, double max_diff) { - JXL_CHECK(output.xsize == input.xsize); - JXL_CHECK(output.ysize == input.ysize); - JXL_CHECK(output.components == input.components); - JXL_CHECK(output.color_space == input.color_space); + Check(output.xsize == input.xsize); + Check(output.ysize == input.ysize); + Check(output.components == input.components); + Check(output.color_space == input.color_space); if (!input.coeffs.empty()) { - JXL_CHECK(input.coeffs.size() == input.components); - JXL_CHECK(output.coeffs.size() == input.components); + Check(input.coeffs.size() == input.components); + Check(output.coeffs.size() == input.components); for (size_t c = 0; c < input.components; ++c) { - JXL_CHECK(output.coeffs[c].size() == input.coeffs[c].size()); - JXL_CHECK(0 == memcmp(input.coeffs[c].data(), output.coeffs[c].data(), - input.coeffs[c].size())); + Check(output.coeffs[c].size() == input.coeffs[c].size()); + Check(0 == memcmp(input.coeffs[c].data(), output.coeffs[c].data(), + input.coeffs[c].size())); } } else { VerifyOutputImage(input, output, 0, output.ysize, max_rms, max_diff); diff --git a/third_party/jpeg-xl/lib/jpegli/test_utils.h b/third_party/jpeg-xl/lib/jpegli/test_utils.h index 132cfd042ad03..0ebd7ffbc8224 100644 --- a/third_party/jpeg-xl/lib/jpegli/test_utils.h +++ b/third_party/jpeg-xl/lib/jpegli/test_utils.h @@ -6,22 +6,15 @@ #ifndef LIB_JPEGLI_TEST_UTILS_H_ #define LIB_JPEGLI_TEST_UTILS_H_ -#include -#include - -#include +#include +#include #include #include -/* clang-format off */ -#include -#include -#include -/* clang-format on */ - -#include "lib/jpegli/common.h" -#include "lib/jpegli/libjpeg_test_util.h" #include "lib/jpegli/test_params.h" +#include "lib/jpegli/types.h" +#include "lib/jxl/base/include_jpeglib.h" // NOLINT +#include "lib/jxl/base/status.h" namespace jpegli { @@ -66,7 +59,7 @@ void UnmapColors(uint8_t* row, size_t xsize, int components, JSAMPARRAY colormap, size_t num_colors); std::string GetTestDataPath(const std::string& filename); -std::vector ReadTestData(const std::string& filename); +jxl::StatusOr> ReadTestData(const std::string& filename); class PNMParser { public: @@ -95,7 +88,7 @@ bool ReadPNM(const std::vector& data, size_t* xsize, size_t* ysize, size_t* num_channels, size_t* bitdepth, std::vector* pixels); -void SetNumChannels(J_COLOR_SPACE colorspace, size_t* channels); +jxl::Status SetNumChannels(J_COLOR_SPACE colorspace, size_t* channels); void ConvertToGrayscale(TestImage* img); diff --git a/third_party/jpeg-xl/lib/jpegli/testing.h b/third_party/jpeg-xl/lib/jpegli/testing.h index 873a0171e7ada..58df563f06644 100644 --- a/third_party/jpeg-xl/lib/jpegli/testing.h +++ b/third_party/jpeg-xl/lib/jpegli/testing.h @@ -6,15 +6,7 @@ #ifndef LIB_JPEGLI_TESTING_H_ #define LIB_JPEGLI_TESTING_H_ -// GTest/GMock specific macros / wrappers. - -// gmock unconditionally redefines those macros (to wrong values). -// Lets include it only here and mitigate the problem. -#pragma push_macro("PRIdS") -#pragma push_macro("PRIuS") -#include "gmock/gmock.h" -#pragma pop_macro("PRIuS") -#pragma pop_macro("PRIdS") +// GTest specific macros / wrappers. #include "gtest/gtest.h" @@ -26,10 +18,20 @@ #define JPEGLI_INSTANTIATE_TEST_SUITE_P INSTANTIATE_TEST_CASE_P #endif +// Replacement for ASSERT_TRUE inside try-catch blocks. +#define JPEGLI_TEST_ENSURE_TRUE(C) \ + if (!(C)) return false; + +#define QUIT(M) FAIL() << M + // Ensures that we don't make our test bounds too lax, effectively disabling the // tests. -MATCHER_P(IsSlightlyBelow, max, "") { - return max * 0.75 <= arg && arg <= max * 1.0; -} +#define EXPECT_SLIGHTLY_BELOW(A, E) \ + { \ + double _actual = (A); \ + double _expected = (E); \ + EXPECT_LE(_actual, _expected); \ + EXPECT_GE(_actual, 0.75 * _expected); \ + } #endif // LIB_JPEGLI_TESTING_H_ diff --git a/third_party/jpeg-xl/lib/jpegli/transcode_api_test.cc b/third_party/jpeg-xl/lib/jpegli/transcode_api_test.cc index 1d99ce37fa288..42d7e4f7fe324 100644 --- a/third_party/jpeg-xl/lib/jpegli/transcode_api_test.cc +++ b/third_party/jpeg-xl/lib/jpegli/transcode_api_test.cc @@ -3,13 +3,21 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include +#include +#include +#include +#include +#include +#include #include #include "lib/jpegli/decode.h" #include "lib/jpegli/encode.h" +#include "lib/jpegli/libjpeg_test_util.h" +#include "lib/jpegli/test_params.h" #include "lib/jpegli/test_utils.h" #include "lib/jpegli/testing.h" -#include "lib/jxl/base/status.h" namespace jpegli { namespace { @@ -20,7 +28,7 @@ void TranscodeWithJpegli(const std::vector& jpeg_input, jpeg_decompress_struct dinfo = {}; jpeg_compress_struct cinfo = {}; uint8_t* transcoded_data = nullptr; - unsigned long transcoded_size; + unsigned long transcoded_size; // NOLINT const auto try_catch_block = [&]() -> bool { ERROR_HANDLER_SETUP(jpegli); dinfo.err = cinfo.err; @@ -30,7 +38,7 @@ void TranscodeWithJpegli(const std::vector& jpeg_input, EXPECT_EQ(JPEG_REACHED_SOS, jpegli_read_header(&dinfo, /*require_image=*/TRUE)); jvirt_barray_ptr* coef_arrays = jpegli_read_coefficients(&dinfo); - JXL_CHECK(coef_arrays != nullptr); + JPEGLI_TEST_ENSURE_TRUE(coef_arrays != nullptr); jpegli_create_compress(&cinfo); jpegli_mem_dest(&cinfo, &transcoded_data, &transcoded_size); jpegli_copy_critical_parameters(&dinfo, &cinfo); diff --git a/third_party/jpeg-xl/lib/jpegli/types.h b/third_party/jpeg-xl/lib/jpegli/types.h index 2f446b7fff2af..c0c0450c1865d 100644 --- a/third_party/jpeg-xl/lib/jpegli/types.h +++ b/third_party/jpeg-xl/lib/jpegli/types.h @@ -6,7 +6,7 @@ #ifndef LIB_JPEGLI_TYPES_H_ #define LIB_JPEGLI_TYPES_H_ -#if defined(__cplusplus) || defined(c_plusplus) +#ifdef __cplusplus extern "C" { #endif @@ -31,7 +31,7 @@ typedef enum { int jpegli_bytes_per_sample(JpegliDataType data_type); -#if defined(__cplusplus) || defined(c_plusplus) +#ifdef __cplusplus } // extern "C" #endif diff --git a/third_party/jpeg-xl/lib/jxl.cmake b/third_party/jpeg-xl/lib/jxl.cmake index 86fa37151d0b8..59b2cca4265ab 100644 --- a/third_party/jpeg-xl/lib/jxl.cmake +++ b/third_party/jpeg-xl/lib/jxl.cmake @@ -13,7 +13,9 @@ if (JPEGXL_ENABLE_TRANSCODE_JPEG OR JPEGXL_ENABLE_TOOLS OR JPEGXL_ENABLE_DEVTOOL list(APPEND JPEGXL_INTERNAL_DEC_SOURCES ${JPEGXL_INTERNAL_DEC_JPEG_SOURCES}) endif() -set_source_files_properties(jxl/enc_fast_lossless.cc PROPERTIES COMPILE_FLAGS -O3) +set(FJXL_COMPILE_FLAGS "-O3") + +set_source_files_properties(jxl/enc_fast_lossless.cc PROPERTIES COMPILE_FLAGS "${FJXL_COMPILE_FLAGS}") set(JPEGXL_DEC_INTERNAL_LIBS hwy @@ -80,10 +82,10 @@ foreach(path ${JPEGXL_INTERNAL_PUBLIC_HEADERS}) endforeach() add_library(jxl_base INTERFACE) -target_include_directories(jxl_base SYSTEM INTERFACE +target_include_directories(jxl_base SYSTEM BEFORE INTERFACE "$" ) -target_include_directories(jxl_base INTERFACE +target_include_directories(jxl_base BEFORE INTERFACE ${PROJECT_SOURCE_DIR} ${JXL_HWY_INCLUDE_DIRS} ) @@ -104,7 +106,7 @@ add_library(jxl_dec-obj OBJECT ${JPEGXL_INTERNAL_DEC_SOURCES}) target_compile_options(jxl_dec-obj PRIVATE ${JPEGXL_INTERNAL_FLAGS}) target_compile_options(jxl_dec-obj PUBLIC ${JPEGXL_COVERAGE_FLAGS}) set_property(TARGET jxl_dec-obj PROPERTY POSITION_INDEPENDENT_CODE ON) -target_include_directories(jxl_dec-obj PUBLIC +target_include_directories(jxl_dec-obj BEFORE PUBLIC "$" "${JXL_HWY_INCLUDE_DIRS}" "$>" @@ -119,7 +121,7 @@ add_library(jxl_enc-obj OBJECT ${JPEGXL_INTERNAL_ENC_SOURCES}) target_compile_options(jxl_enc-obj PRIVATE ${JPEGXL_INTERNAL_FLAGS}) target_compile_options(jxl_enc-obj PUBLIC ${JPEGXL_COVERAGE_FLAGS}) set_property(TARGET jxl_enc-obj PROPERTY POSITION_INDEPENDENT_CODE ON) -target_include_directories(jxl_enc-obj PUBLIC +target_include_directories(jxl_enc-obj BEFORE PUBLIC ${PROJECT_SOURCE_DIR} ${JXL_HWY_INCLUDE_DIRS} $ @@ -172,7 +174,7 @@ target_link_libraries(jxl-internal PUBLIC jxl_cms jxl_base ) -target_include_directories(jxl-internal PUBLIC +target_include_directories(jxl-internal BEFORE PUBLIC "$") target_compile_definitions(jxl-internal INTERFACE -DJXL_STATIC_DEFINE) diff --git a/third_party/jpeg-xl/lib/jxl/ac_context.h b/third_party/jpeg-xl/lib/jxl/ac_context.h index a2b9e046d1188..6529a9bb88bcb 100644 --- a/third_party/jpeg-xl/lib/jxl/ac_context.h +++ b/third_party/jpeg-xl/lib/jxl/ac_context.h @@ -62,7 +62,8 @@ static JXL_INLINE size_t ZeroDensityContext(size_t nonzeros_left, size_t k, size_t covered_blocks, size_t log2_covered_blocks, size_t prev) { - JXL_DASSERT((1u << log2_covered_blocks) == covered_blocks); + JXL_DASSERT((static_cast(1) << log2_covered_blocks) == + covered_blocks); nonzeros_left = (nonzeros_left + covered_blocks - 1) >> log2_covered_blocks; k >>= log2_covered_blocks; JXL_DASSERT(k > 0); @@ -109,7 +110,8 @@ struct BlockCtxMap { // Non-zero context is based on number of non-zeros and block context. // For better clustering, contexts with same number of non-zeros are grouped. constexpr uint32_t ZeroDensityContextsOffset(uint32_t block_ctx) const { - return num_ctxs * kNonZeroBuckets + kZeroDensityContextCount * block_ctx; + return static_cast(num_ctxs * kNonZeroBuckets + + kZeroDensityContextCount * block_ctx); } // Context map for AC coefficients consists of 2 blocks: @@ -121,7 +123,8 @@ struct BlockCtxMap { // number of non-zeros left and // index in scan order constexpr uint32_t NumACContexts() const { - return num_ctxs * (kNonZeroBuckets + kZeroDensityContextCount); + return static_cast(num_ctxs * + (kNonZeroBuckets + kZeroDensityContextCount)); } // Non-zero context is based on number of non-zeros and block context. @@ -134,7 +137,7 @@ struct BlockCtxMap { } else { ctx = 4 + non_zeros / 2; } - return ctx * num_ctxs + block_ctx; + return static_cast(ctx * num_ctxs + block_ctx); } BlockCtxMap() { diff --git a/third_party/jpeg-xl/lib/jxl/ac_strategy.cc b/third_party/jpeg-xl/lib/jxl/ac_strategy.cc index e7a72f5a33243..69e8ae6f470c1 100644 --- a/third_party/jpeg-xl/lib/jxl/ac_strategy.cc +++ b/third_party/jpeg-xl/lib/jxl/ac_strategy.cc @@ -5,12 +5,14 @@ #include "lib/jxl/ac_strategy.h" -#include +#include #include +#include #include #include "lib/jxl/base/bits.h" +#include "lib/jxl/base/compiler_specific.h" namespace jxl { @@ -78,20 +80,23 @@ void AcStrategy::ComputeNaturalCoeffOrderLut(coeff_order_t* lut) const { CoeffOrderAndLut(*this, lut); } -// These definitions are needed before C++17. +#if JXL_CXX_LANG < JXL_CXX_17 constexpr size_t AcStrategy::kMaxCoeffBlocks; constexpr size_t AcStrategy::kMaxBlockDim; constexpr size_t AcStrategy::kMaxCoeffArea; +#endif -StatusOr AcStrategyImage::Create(size_t xsize, size_t ysize) { +StatusOr AcStrategyImage::Create( + JxlMemoryManager* memory_manager, size_t xsize, size_t ysize) { AcStrategyImage img; - JXL_ASSIGN_OR_RETURN(img.layers_, ImageB::Create(xsize, ysize)); + JXL_ASSIGN_OR_RETURN(img.layers_, + ImageB::Create(memory_manager, xsize, ysize)); img.row_ = img.layers_.Row(0); img.stride_ = img.layers_.PixelsPerRow(); return img; } -size_t AcStrategyImage::CountBlocks(AcStrategy::Type type) const { +size_t AcStrategyImage::CountBlocks(AcStrategyType type) const { size_t ret = 0; for (size_t y = 0; y < layers_.ysize(); y++) { const uint8_t* JXL_RESTRICT row = layers_.ConstRow(y); diff --git a/third_party/jpeg-xl/lib/jxl/ac_strategy.h b/third_party/jpeg-xl/lib/jxl/ac_strategy.h index 9e5917ff1b84a..8c3191c791a90 100644 --- a/third_party/jpeg-xl/lib/jxl/ac_strategy.h +++ b/third_party/jpeg-xl/lib/jxl/ac_strategy.h @@ -6,14 +6,18 @@ #ifndef LIB_JXL_AC_STRATEGY_H_ #define LIB_JXL_AC_STRATEGY_H_ -#include -#include +#include +#include +#include #include // kMaxVectorSize +#include "lib/jxl/base/compiler_specific.h" +#include "lib/jxl/base/rect.h" #include "lib/jxl/base/status.h" #include "lib/jxl/coeff_order_fwd.h" #include "lib/jxl/frame_dimensions.h" +#include "lib/jxl/image.h" #include "lib/jxl/image_ops.h" // Defines the different kinds of transforms, and heuristics to choose between @@ -27,6 +31,53 @@ namespace jxl { +// Raw strategy types. +enum class AcStrategyType : uint32_t { + // Regular block size DCT + DCT = 0, + // Encode pixels without transforming + IDENTITY = 1, + // Use 2-by-2 DCT + DCT2X2 = 2, + // Use 4-by-4 DCT + DCT4X4 = 3, + // Use 16-by-16 DCT + DCT16X16 = 4, + // Use 32-by-32 DCT + DCT32X32 = 5, + // Use 16-by-8 DCT + DCT16X8 = 6, + // Use 8-by-16 DCT + DCT8X16 = 7, + // Use 32-by-8 DCT + DCT32X8 = 8, + // Use 8-by-32 DCT + DCT8X32 = 9, + // Use 32-by-16 DCT + DCT32X16 = 10, + // Use 16-by-32 DCT + DCT16X32 = 11, + // 4x8 and 8x4 DCT + DCT4X8 = 12, + DCT8X4 = 13, + // Corner-DCT. + AFV0 = 14, + AFV1 = 15, + AFV2 = 16, + AFV3 = 17, + // Larger DCTs + DCT64X64 = 18, + DCT64X32 = 19, + DCT32X64 = 20, + // No transforms smaller than 64x64 are allowed below. + DCT128X128 = 21, + DCT128X64 = 22, + DCT64X128 = 23, + DCT256X256 = 24, + DCT256X128 = 25, + DCT128X256 = 26 +}; + class AcStrategy { public: // Extremal values for the number of blocks/coefficients of a single strategy. @@ -38,55 +89,10 @@ class AcStrategy { static_assert((kMaxCoeffArea * sizeof(float)) % hwy::kMaxVectorSize == 0, "Coefficient area is not a multiple of vector size"); - // Raw strategy types. - enum Type : uint32_t { - // Regular block size DCT - DCT = 0, - // Encode pixels without transforming - IDENTITY = 1, - // Use 2-by-2 DCT - DCT2X2 = 2, - // Use 4-by-4 DCT - DCT4X4 = 3, - // Use 16-by-16 DCT - DCT16X16 = 4, - // Use 32-by-32 DCT - DCT32X32 = 5, - // Use 16-by-8 DCT - DCT16X8 = 6, - // Use 8-by-16 DCT - DCT8X16 = 7, - // Use 32-by-8 DCT - DCT32X8 = 8, - // Use 8-by-32 DCT - DCT8X32 = 9, - // Use 32-by-16 DCT - DCT32X16 = 10, - // Use 16-by-32 DCT - DCT16X32 = 11, - // 4x8 and 8x4 DCT - DCT4X8 = 12, - DCT8X4 = 13, - // Corner-DCT. - AFV0 = 14, - AFV1 = 15, - AFV2 = 16, - AFV3 = 17, - // Larger DCTs - DCT64X64 = 18, - DCT64X32 = 19, - DCT32X64 = 20, - DCT128X128 = 21, - DCT128X64 = 22, - DCT64X128 = 23, - DCT256X256 = 24, - DCT256X128 = 25, - DCT128X256 = 26, - // Marker for num of valid strategies. - kNumValidStrategies - }; - - static constexpr uint32_t TypeBit(const Type type) { + static constexpr uint8_t kNumValidStrategies = + static_cast(AcStrategyType::DCT128X256) + 1; + + static constexpr uint32_t TypeBit(const AcStrategyType type) { return 1u << static_cast(type); } @@ -96,15 +102,17 @@ class AcStrategy { JXL_INLINE bool IsMultiblock() const { constexpr uint32_t bits = - TypeBit(Type::DCT16X16) | TypeBit(Type::DCT32X32) | - TypeBit(Type::DCT16X8) | TypeBit(Type::DCT8X16) | - TypeBit(Type::DCT32X8) | TypeBit(Type::DCT8X32) | - TypeBit(Type::DCT16X32) | TypeBit(Type::DCT32X16) | - TypeBit(Type::DCT32X64) | TypeBit(Type::DCT64X32) | - TypeBit(Type::DCT64X64) | TypeBit(DCT64X128) | TypeBit(DCT128X64) | - TypeBit(DCT128X128) | TypeBit(DCT128X256) | TypeBit(DCT256X128) | - TypeBit(DCT256X256); - JXL_DASSERT(Strategy() < kNumValidStrategies); + TypeBit(AcStrategyType::DCT16X16) | TypeBit(AcStrategyType::DCT32X32) | + TypeBit(AcStrategyType::DCT16X8) | TypeBit(AcStrategyType::DCT8X16) | + TypeBit(AcStrategyType::DCT32X8) | TypeBit(AcStrategyType::DCT8X32) | + TypeBit(AcStrategyType::DCT16X32) | TypeBit(AcStrategyType::DCT32X16) | + TypeBit(AcStrategyType::DCT32X64) | TypeBit(AcStrategyType::DCT64X32) | + TypeBit(AcStrategyType::DCT64X64) | TypeBit(AcStrategyType::DCT64X128) | + TypeBit(AcStrategyType::DCT128X64) | + TypeBit(AcStrategyType::DCT128X128) | + TypeBit(AcStrategyType::DCT128X256) | + TypeBit(AcStrategyType::DCT256X128) | + TypeBit(AcStrategyType::DCT256X256); return ((1u << static_cast(Strategy())) & bits) != 0; } @@ -113,17 +121,16 @@ class AcStrategy { return static_cast(strategy_); } - JXL_INLINE Type Strategy() const { return strategy_; } + JXL_INLINE AcStrategyType Strategy() const { return strategy_; } // Inverse check static JXL_INLINE constexpr bool IsRawStrategyValid(int raw_strategy) { - return raw_strategy < static_cast(kNumValidStrategies) && - raw_strategy >= 0; + return raw_strategy < kNumValidStrategies && raw_strategy >= 0; } static JXL_INLINE AcStrategy FromRawStrategy(uint8_t raw_strategy) { - return FromRawStrategy(static_cast(raw_strategy)); + return FromRawStrategy(static_cast(raw_strategy)); } - static JXL_INLINE AcStrategy FromRawStrategy(Type raw_strategy) { + static JXL_INLINE AcStrategy FromRawStrategy(AcStrategyType raw_strategy) { JXL_DASSERT(IsRawStrategyValid(static_cast(raw_strategy))); return AcStrategy(raw_strategy, /*is_first=*/true); } @@ -167,12 +174,12 @@ class AcStrategy { private: friend class AcStrategyRow; - JXL_INLINE AcStrategy(Type strategy, bool is_first) + JXL_INLINE AcStrategy(AcStrategyType strategy, bool is_first) : strategy_(strategy), is_first_(is_first) { JXL_DASSERT(IsMultiblock() || is_first == true); } - Type strategy_; + AcStrategyType strategy_; bool is_first_; }; @@ -181,7 +188,7 @@ class AcStrategyRow { public: explicit AcStrategyRow(const uint8_t* row) : row_(row) {} AcStrategy operator[](size_t x) const { - AcStrategy::Type strategy = static_cast(row_[x] >> 1); + AcStrategyType strategy = static_cast(row_[x] >> 1); bool is_first = static_cast(row_[x] & 1); return AcStrategy(strategy, is_first); } @@ -193,29 +200,31 @@ class AcStrategyRow { class AcStrategyImage { public: AcStrategyImage() = default; - static StatusOr Create(size_t xsize, size_t ysize); + static StatusOr Create(JxlMemoryManager* memory_manager, + size_t xsize, size_t ysize); AcStrategyImage(AcStrategyImage&&) = default; AcStrategyImage& operator=(AcStrategyImage&&) = default; void FillDCT8(const Rect& rect) { - FillPlane((static_cast(AcStrategy::Type::DCT) << 1) | 1, + FillPlane((static_cast(AcStrategyType::DCT) << 1) | 1, &layers_, rect); } void FillDCT8() { FillDCT8(Rect(layers_)); } void FillInvalid() { FillImage(INVALID, &layers_); } - void Set(size_t x, size_t y, AcStrategy::Type type) { -#if JXL_ENABLE_ASSERT + Status Set(size_t x, size_t y, AcStrategyType type) { +#if (JXL_IS_DEBUG_BUILD) AcStrategy acs = AcStrategy::FromRawStrategy(type); -#endif // JXL_ENABLE_ASSERT - JXL_ASSERT(y + acs.covered_blocks_y() <= layers_.ysize()); - JXL_ASSERT(x + acs.covered_blocks_x() <= layers_.xsize()); - JXL_CHECK(SetNoBoundsCheck(x, y, type, /*check=*/false)); + JXL_DASSERT(y + acs.covered_blocks_y() <= layers_.ysize()); + JXL_DASSERT(x + acs.covered_blocks_x() <= layers_.xsize()); +#endif + JXL_RETURN_IF_ERROR(SetNoBoundsCheck(x, y, type, /*check=*/false)); + return true; } - Status SetNoBoundsCheck(size_t x, size_t y, AcStrategy::Type type, + Status SetNoBoundsCheck(size_t x, size_t y, AcStrategyType type, bool check = true) { AcStrategy acs = AcStrategy::FromRawStrategy(type); for (size_t iy = 0; iy < acs.covered_blocks_y(); iy++) { @@ -247,7 +256,9 @@ class AcStrategyImage { size_t ysize() const { return layers_.ysize(); } // Count the number of blocks of a given type. - size_t CountBlocks(AcStrategy::Type type) const; + size_t CountBlocks(AcStrategyType type) const; + + JxlMemoryManager* memory_manager() const { return layers_.memory_manager(); } private: ImageB layers_; diff --git a/third_party/jpeg-xl/lib/jxl/ac_strategy_test.cc b/third_party/jpeg-xl/lib/jxl/ac_strategy_test.cc index b1d9103466ad8..e6405fc86b25a 100644 --- a/third_party/jpeg-xl/lib/jxl/ac_strategy_test.cc +++ b/third_party/jpeg-xl/lib/jxl/ac_strategy_test.cc @@ -5,19 +5,21 @@ #include "lib/jxl/ac_strategy.h" -#include +#include -#include -#include +#include +#include #include // HWY_ALIGN_MAX #include -#include #include "lib/jxl/base/random.h" -#include "lib/jxl/dct_scales.h" +#include "lib/jxl/coeff_order_fwd.h" #include "lib/jxl/dec_transforms_testonly.h" #include "lib/jxl/enc_transforms.h" +#include "lib/jxl/memory_manager_internal.h" #include "lib/jxl/simd_util.h" +#include "lib/jxl/test_memory_manager.h" +#include "lib/jxl/test_utils.h" #include "lib/jxl/testing.h" namespace jxl { @@ -27,19 +29,22 @@ namespace { class AcStrategyRoundtrip : public ::hwy::TestWithParamTargetAndT { protected: void Run() { - const AcStrategy::Type type = static_cast(GetParam()); + JxlMemoryManager* memory_manager = test::MemoryManager(); + const AcStrategyType type = static_cast(GetParam()); const AcStrategy acs = AcStrategy::FromRawStrategy(type); const size_t dct_scratch_size = 3 * (MaxVectorSize() / sizeof(float)) * AcStrategy::kMaxBlockDim; - auto mem = hwy::AllocateAligned(4 * AcStrategy::kMaxCoeffArea + - dct_scratch_size); - float* coeffs = mem.get(); + size_t mem_bytes = + (4 * AcStrategy::kMaxCoeffArea + dct_scratch_size) * sizeof(float); + JXL_TEST_ASSIGN_OR_DIE(AlignedMemory mem, + AlignedMemory::Create(memory_manager, mem_bytes)); + float* coeffs = mem.address(); float* idct = coeffs + AcStrategy::kMaxCoeffArea; float* input = idct + AcStrategy::kMaxCoeffArea; float* scratch_space = input + AcStrategy::kMaxCoeffArea; - Rng rng(type * 65537 + 13); + Rng rng(static_cast(type) * 65537 + 13); for (size_t j = 0; j < 64; j++) { size_t i = (acs.log2_covered_blocks() @@ -55,7 +60,7 @@ class AcStrategyRoundtrip : public ::hwy::TestWithParamTargetAndT { scratch_space); for (size_t j = 0; j < 64u << acs.log2_covered_blocks(); j++) { ASSERT_NEAR(idct[j], j == i ? 0.2f : 0, 2e-6) - << "j = " << j << " i = " << i << " acs " << type; + << "j = " << j << " i = " << i << " acs " << static_cast(type); } } // Test DC. @@ -72,7 +77,8 @@ class AcStrategyRoundtrip : public ::hwy::TestWithParamTargetAndT { dc[y * acs.covered_blocks_x() * 8 + x] = 0.2; for (size_t j = 0; j < 64u << acs.log2_covered_blocks(); j++) { ASSERT_NEAR(idct[j], dc[j], 1e-6) - << "j = " << j << " x = " << x << " y = " << y << " acs " << type; + << "j = " << j << " x = " << x << " y = " << y << " acs " + << static_cast(type); } } } @@ -81,8 +87,7 @@ class AcStrategyRoundtrip : public ::hwy::TestWithParamTargetAndT { HWY_TARGET_INSTANTIATE_TEST_SUITE_P_T( AcStrategyRoundtrip, - ::testing::Range(0, - static_cast(AcStrategy::Type::kNumValidStrategies))); + ::testing::Range(0, static_cast(AcStrategy::kNumValidStrategies))); TEST_P(AcStrategyRoundtrip, Test) { Run(); } @@ -91,20 +96,23 @@ class AcStrategyRoundtripDownsample : public ::hwy::TestWithParamTargetAndT { protected: void Run() { - const AcStrategy::Type type = static_cast(GetParam()); + JxlMemoryManager* memory_manager = test::MemoryManager(); + const AcStrategyType type = static_cast(GetParam()); const AcStrategy acs = AcStrategy::FromRawStrategy(type); const size_t dct_scratch_size = 3 * (MaxVectorSize() / sizeof(float)) * AcStrategy::kMaxBlockDim; - auto mem = hwy::AllocateAligned(4 * AcStrategy::kMaxCoeffArea + - dct_scratch_size); - float* coeffs = mem.get(); + size_t mem_bytes = + (4 * AcStrategy::kMaxCoeffArea + dct_scratch_size) * sizeof(float); + JXL_TEST_ASSIGN_OR_DIE(AlignedMemory mem, + AlignedMemory::Create(memory_manager, mem_bytes)); + float* coeffs = mem.address(); float* idct = coeffs + AcStrategy::kMaxCoeffArea; float* dc = idct + AcStrategy::kMaxCoeffArea; float* scratch_space = dc + AcStrategy::kMaxCoeffArea; std::fill_n(coeffs, AcStrategy::kMaxCoeffArea, 0.0f); - Rng rng(type * 65537 + 13); + Rng rng(static_cast(type) * 65537 + 13); for (size_t y = 0; y < acs.covered_blocks_y(); y++) { for (size_t x = 0; x < acs.covered_blocks_x(); x++) { @@ -132,7 +140,7 @@ class AcStrategyRoundtripDownsample } sum /= 64.0f; ASSERT_NEAR(sum, dc[dy * 8 * acs.covered_blocks_x() + dx], 1e-6) - << "acs " << type; + << "acs " << static_cast(type); } } } @@ -142,8 +150,7 @@ class AcStrategyRoundtripDownsample HWY_TARGET_INSTANTIATE_TEST_SUITE_P_T( AcStrategyRoundtripDownsample, - ::testing::Range(0, - static_cast(AcStrategy::Type::kNumValidStrategies))); + ::testing::Range(0, static_cast(AcStrategy::kNumValidStrategies))); TEST_P(AcStrategyRoundtripDownsample, Test) { Run(); } @@ -152,7 +159,8 @@ TEST_P(AcStrategyRoundtripDownsample, Test) { Run(); } class AcStrategyDownsample : public ::hwy::TestWithParamTargetAndT { protected: void Run() { - const AcStrategy::Type type = static_cast(GetParam()); + JxlMemoryManager* memory_manager = test::MemoryManager(); + const AcStrategyType type = static_cast(GetParam()); const AcStrategy acs = AcStrategy::FromRawStrategy(type); const size_t dct_scratch_size = 3 * (MaxVectorSize() / sizeof(float)) * AcStrategy::kMaxBlockDim; @@ -160,14 +168,16 @@ class AcStrategyDownsample : public ::hwy::TestWithParamTargetAndT { size_t cy = acs.covered_blocks_x(); CoefficientLayout(&cy, &cx); - auto mem = hwy::AllocateAligned(4 * AcStrategy::kMaxCoeffArea + - dct_scratch_size); - float* idct = mem.get(); + size_t mem_bytes = + (4 * AcStrategy::kMaxCoeffArea + dct_scratch_size) * sizeof(float); + JXL_TEST_ASSIGN_OR_DIE(AlignedMemory mem, + AlignedMemory::Create(memory_manager, mem_bytes)); + float* idct = mem.address(); float* idct_acs_downsampled = idct + AcStrategy::kMaxCoeffArea; float* coeffs = idct + AcStrategy::kMaxCoeffArea; float* scratch_space = coeffs + AcStrategy::kMaxCoeffArea; - Rng rng(type * 65537 + 13); + Rng rng(static_cast(type) * 65537 + 13); for (size_t y = 0; y < cy; y++) { for (size_t x = 0; x < cx; x++) { @@ -197,7 +207,7 @@ class AcStrategyDownsample : public ::hwy::TestWithParamTargetAndT { ASSERT_NEAR( sum, idct_acs_downsampled[dy * 8 * acs.covered_blocks_x() + dx], 1e-6) - << " acs " << type; + << " acs " << static_cast(type); } } } @@ -207,8 +217,7 @@ class AcStrategyDownsample : public ::hwy::TestWithParamTargetAndT { HWY_TARGET_INSTANTIATE_TEST_SUITE_P_T( AcStrategyDownsample, - ::testing::Range(0, - static_cast(AcStrategy::Type::kNumValidStrategies))); + ::testing::Range(0, static_cast(AcStrategy::kNumValidStrategies))); TEST_P(AcStrategyDownsample, Test) { Run(); } @@ -231,13 +240,16 @@ TEST_P(AcStrategyTargetTest, RoundtripAFVDCT) { } TEST_P(AcStrategyTargetTest, BenchmarkAFV) { - const AcStrategy::Type type = AcStrategy::Type::AFV0; + JxlMemoryManager* memory_manager = test::MemoryManager(); + const AcStrategyType type = AcStrategyType::AFV0; HWY_ALIGN_MAX float pixels[64] = {1}; HWY_ALIGN_MAX float coeffs[64] = {}; const size_t dct_scratch_size = 3 * (MaxVectorSize() / sizeof(float)) * AcStrategy::kMaxBlockDim; - auto mem = hwy::AllocateAligned(64 + dct_scratch_size); - float* scratch_space = mem.get(); + size_t mem_bytes = (64 + dct_scratch_size) * sizeof(float); + JXL_TEST_ASSIGN_OR_DIE(AlignedMemory mem, + AlignedMemory::Create(memory_manager, mem_bytes)); + float* scratch_space = mem.address(); for (size_t i = 0; i < 1 << 14; i++) { TransformToPixels(type, coeffs, pixels, 8, scratch_space); TransformFromPixels(type, pixels, 8, coeffs, scratch_space); diff --git a/third_party/jpeg-xl/lib/jxl/alpha_test.cc b/third_party/jpeg-xl/lib/jxl/alpha_test.cc index ddafd829ecf11..6e26e77be6a7c 100644 --- a/third_party/jpeg-xl/lib/jxl/alpha_test.cc +++ b/third_party/jpeg-xl/lib/jxl/alpha_test.cc @@ -5,69 +5,69 @@ #include "lib/jxl/alpha.h" -#include "lib/jxl/test_utils.h" +#include + +#include "lib/jxl/base/common.h" #include "lib/jxl/testing.h" namespace jxl { namespace { -using ::testing::_; -using ::testing::ElementsAre; -using ::testing::FloatNear; +AlphaBlendingInputLayer makeAbil(const Color& rgb, const float& a) { + const float* data = rgb.data(); + return {data, data + 1, data + 2, &a}; +} + +AlphaBlendingOutput makeAbo(Color& rgb, float& a) { + float* data = rgb.data(); + return {data, data + 1, data + 2, &a}; +} TEST(AlphaTest, BlendingWithNonPremultiplied) { - const float bg_rgb[3] = {100, 110, 120}; + const Color bg_rgb{100, 110, 120}; const float bg_a = 180.f / 255; - const float fg_rgb[3] = {25, 21, 23}; + const Color fg_rgb{25, 21, 23}; const float fg_a = 15420.f / 65535; const float fg_a2 = 2.0f; - float out_rgb[3]; + Color out_rgb; float out_a; PerformAlphaBlending( - /*bg=*/{&bg_rgb[0], &bg_rgb[1], &bg_rgb[2], &bg_a}, - /*fg=*/{&fg_rgb[0], &fg_rgb[1], &fg_rgb[2], &fg_a}, - /*out=*/{&out_rgb[0], &out_rgb[1], &out_rgb[2], &out_a}, 1, + /*bg=*/makeAbil(bg_rgb, bg_a), + /*fg=*/makeAbil(fg_rgb, fg_a), + /*out=*/makeAbo(out_rgb, out_a), 1, /*alpha_is_premultiplied=*/false, /*clamp=*/false); - EXPECT_THAT(out_rgb, - ElementsAre(FloatNear(77.2f, .05f), FloatNear(83.0f, .05f), - FloatNear(90.6f, .05f))); + EXPECT_ARRAY_NEAR(out_rgb, (Color{77.2f, 83.0f, 90.6f}), 0.05f); EXPECT_NEAR(out_a, 3174.f / 4095, 1e-5); PerformAlphaBlending( - /*bg=*/{&bg_rgb[0], &bg_rgb[1], &bg_rgb[2], &bg_a}, - /*fg=*/{&fg_rgb[0], &fg_rgb[1], &fg_rgb[2], &fg_a2}, - /*out=*/{&out_rgb[0], &out_rgb[1], &out_rgb[2], &out_a}, 1, + /*bg=*/makeAbil(bg_rgb, bg_a), + /*fg=*/makeAbil(fg_rgb, fg_a2), + /*out=*/makeAbo(out_rgb, out_a), 1, /*alpha_is_premultiplied=*/false, /*clamp=*/true); - EXPECT_THAT(out_rgb, ElementsAre(FloatNear(fg_rgb[0], .05f), - FloatNear(fg_rgb[1], .05f), - FloatNear(fg_rgb[2], .05f))); + EXPECT_ARRAY_NEAR(out_rgb, fg_rgb, 0.05f); EXPECT_NEAR(out_a, 1.0f, 1e-5); } TEST(AlphaTest, BlendingWithPremultiplied) { - const float bg_rgb[3] = {100, 110, 120}; + const Color bg_rgb{100, 110, 120}; const float bg_a = 180.f / 255; - const float fg_rgb[3] = {25, 21, 23}; + const Color fg_rgb{25, 21, 23}; const float fg_a = 15420.f / 65535; const float fg_a2 = 2.0f; - float out_rgb[3]; + Color out_rgb; float out_a; PerformAlphaBlending( - /*bg=*/{&bg_rgb[0], &bg_rgb[1], &bg_rgb[2], &bg_a}, - /*fg=*/{&fg_rgb[0], &fg_rgb[1], &fg_rgb[2], &fg_a}, - /*out=*/{&out_rgb[0], &out_rgb[1], &out_rgb[2], &out_a}, 1, + /*bg=*/makeAbil(bg_rgb, bg_a), + /*fg=*/makeAbil(fg_rgb, fg_a), + /*out=*/makeAbo(out_rgb, out_a), 1, /*alpha_is_premultiplied=*/true, /*clamp=*/false); - EXPECT_THAT(out_rgb, - ElementsAre(FloatNear(101.5f, .05f), FloatNear(105.1f, .05f), - FloatNear(114.8f, .05f))); + EXPECT_ARRAY_NEAR(out_rgb, (Color{101.5f, 105.1f, 114.8f}), 0.05f); EXPECT_NEAR(out_a, 3174.f / 4095, 1e-5); PerformAlphaBlending( - /*bg=*/{&bg_rgb[0], &bg_rgb[1], &bg_rgb[2], &bg_a}, - /*fg=*/{&fg_rgb[0], &fg_rgb[1], &fg_rgb[2], &fg_a2}, - /*out=*/{&out_rgb[0], &out_rgb[1], &out_rgb[2], &out_a}, 1, + /*bg=*/makeAbil(bg_rgb, bg_a), + /*fg=*/makeAbil(fg_rgb, fg_a2), + /*out=*/makeAbo(out_rgb, out_a), 1, /*alpha_is_premultiplied=*/true, /*clamp=*/true); - EXPECT_THAT(out_rgb, ElementsAre(FloatNear(fg_rgb[0], .05f), - FloatNear(fg_rgb[1], .05f), - FloatNear(fg_rgb[2], .05f))); + EXPECT_ARRAY_NEAR(out_rgb, fg_rgb, 0.05f); EXPECT_NEAR(out_a, 1.0f, 1e-5); } @@ -76,58 +76,51 @@ TEST(AlphaTest, Mul) { const float fg = 25; float out; PerformMulBlending(&bg, &fg, &out, 1, /*clamp=*/false); - EXPECT_THAT(out, FloatNear(fg * bg, .05f)); + EXPECT_NEAR(out, fg * bg, .05f); PerformMulBlending(&bg, &fg, &out, 1, /*clamp=*/true); - EXPECT_THAT(out, FloatNear(bg, .05f)); + EXPECT_NEAR(out, bg, .05f); } TEST(AlphaTest, PremultiplyAndUnpremultiply) { - const float alpha[] = {0.f, 63.f / 255, 127.f / 255, 1.f}; - float r[] = {120, 130, 140, 150}; - float g[] = {124, 134, 144, 154}; - float b[] = {127, 137, 147, 157}; - - PremultiplyAlpha(r, g, b, alpha, 4); - EXPECT_THAT( - r, ElementsAre(FloatNear(0.f, 1e-5f), FloatNear(130 * 63.f / 255, 1e-5f), - FloatNear(140 * 127.f / 255, 1e-5f), 150)); - EXPECT_THAT( - g, ElementsAre(FloatNear(0.f, 1e-5f), FloatNear(134 * 63.f / 255, 1e-5f), - FloatNear(144 * 127.f / 255, 1e-5f), 154)); - EXPECT_THAT( - b, ElementsAre(FloatNear(0.f, 1e-5f), FloatNear(137 * 63.f / 255, 1e-5f), - FloatNear(147 * 127.f / 255, 1e-5f), 157)); - - UnpremultiplyAlpha(r, g, b, alpha, 4); - EXPECT_THAT(r, ElementsAre(FloatNear(120, 1e-4f), FloatNear(130, 1e-4f), - FloatNear(140, 1e-4f), FloatNear(150, 1e-4f))); - EXPECT_THAT(g, ElementsAre(FloatNear(124, 1e-4f), FloatNear(134, 1e-4f), - FloatNear(144, 1e-4f), FloatNear(154, 1e-4f))); - EXPECT_THAT(b, ElementsAre(FloatNear(127, 1e-4f), FloatNear(137, 1e-4f), - FloatNear(147, 1e-4f), FloatNear(157, 1e-4f))); + using F4 = std::array; + const F4 alpha{0.f, 63.f / 255, 127.f / 255, 1.f}; + F4 r{120, 130, 140, 150}; + F4 g{124, 134, 144, 154}; + F4 b{127, 137, 147, 157}; + + PremultiplyAlpha(r.data(), g.data(), b.data(), alpha.data(), alpha.size()); + EXPECT_ARRAY_NEAR(r, (F4{0.0f, 130 * 63.f / 255, 140 * 127.f / 255, 150}), + 1e-5f); + EXPECT_ARRAY_NEAR(g, (F4{0.0f, 134 * 63.f / 255, 144 * 127.f / 255, 154}), + 1e-5f); + EXPECT_ARRAY_NEAR(b, (F4{0.0f, 137 * 63.f / 255, 147 * 127.f / 255, 157}), + 1e-5f); + + UnpremultiplyAlpha(r.data(), g.data(), b.data(), alpha.data(), alpha.size()); + EXPECT_ARRAY_NEAR(r, (F4{120, 130, 140, 150}), 1e-4f); + EXPECT_ARRAY_NEAR(g, (F4{124, 134, 144, 154}), 1e-4f); + EXPECT_ARRAY_NEAR(b, (F4{127, 137, 147, 157}), 1e-4f); } TEST(AlphaTest, UnpremultiplyAndPremultiply) { - const float alpha[] = {0.f, 63.f / 255, 127.f / 255, 1.f}; - float r[] = {50, 60, 70, 80}; - float g[] = {54, 64, 74, 84}; - float b[] = {57, 67, 77, 87}; - - UnpremultiplyAlpha(r, g, b, alpha, 4); - EXPECT_THAT(r, ElementsAre(_, FloatNear(60 * 255.f / 63, 1e-4f), - FloatNear(70 * 255.f / 127, 1e-4f), 80)); - EXPECT_THAT(g, ElementsAre(_, FloatNear(64 * 255.f / 63, 1e-4f), - FloatNear(74 * 255.f / 127, 1e-4f), 84)); - EXPECT_THAT(b, ElementsAre(_, FloatNear(67 * 255.f / 63, 1e-4f), - FloatNear(77 * 255.f / 127, 1e-4f), 87)); - - PremultiplyAlpha(r, g, b, alpha, 4); - EXPECT_THAT(r, ElementsAre(FloatNear(50, 1e-4f), FloatNear(60, 1e-4f), - FloatNear(70, 1e-4f), FloatNear(80, 1e-4f))); - EXPECT_THAT(g, ElementsAre(FloatNear(54, 1e-4f), FloatNear(64, 1e-4f), - FloatNear(74, 1e-4f), FloatNear(84, 1e-4f))); - EXPECT_THAT(b, ElementsAre(FloatNear(57, 1e-4f), FloatNear(67, 1e-4f), - FloatNear(77, 1e-4f), FloatNear(87, 1e-4f))); + using F4 = std::array; + const F4 alpha{0.f, 63.f / 255, 127.f / 255, 1.f}; + F4 r{50, 60, 70, 80}; + F4 g{54, 64, 74, 84}; + F4 b{57, 67, 77, 87}; + + UnpremultiplyAlpha(r.data(), g.data(), b.data(), alpha.data(), alpha.size()); + EXPECT_ARRAY_NEAR( + r, (F4{50.0f * (1 << 26), 60 * 255.f / 63, 70 * 255.f / 127, 80}), 1e-4f); + EXPECT_ARRAY_NEAR( + g, (F4{54.0f * (1 << 26), 64 * 255.f / 63, 74 * 255.f / 127, 84}), 1e-4f); + EXPECT_ARRAY_NEAR( + b, (F4{57.0f * (1 << 26), 67 * 255.f / 63, 77 * 255.f / 127, 87}), 1e-4f); + + PremultiplyAlpha(r.data(), g.data(), b.data(), alpha.data(), alpha.size()); + EXPECT_ARRAY_NEAR(r, (F4{50, 60, 70, 80}), 1e-4); + EXPECT_ARRAY_NEAR(g, (F4{54, 64, 74, 84}), 1e-4); + EXPECT_ARRAY_NEAR(b, (F4{57, 67, 77, 87}), 1e-4); } } // namespace diff --git a/third_party/jpeg-xl/lib/jxl/ans_common.cc b/third_party/jpeg-xl/lib/jxl/ans_common.cc index 8e52cad0e8bf9..306ecb7276782 100644 --- a/third_party/jpeg-xl/lib/jxl/ans_common.cc +++ b/third_party/jpeg-xl/lib/jxl/ans_common.cc @@ -5,7 +5,10 @@ #include "lib/jxl/ans_common.h" +#include +#include #include +#include #include "lib/jxl/ans_params.h" #include "lib/jxl/base/status.h" @@ -13,8 +16,8 @@ namespace jxl { std::vector CreateFlatHistogram(int length, int total_count) { - JXL_ASSERT(length > 0); - JXL_ASSERT(length <= total_count); + JXL_DASSERT(length > 0); + JXL_DASSERT(length <= total_count); const int count = total_count / length; std::vector result(length, count); const int rem_counts = total_count % length; @@ -48,8 +51,12 @@ std::vector CreateFlatHistogram(int length, int total_count) { // underfull nor overfull, and represents exactly two symbols. The overfull // entry might be either overfull or underfull, and is pushed into the // corresponding stack. -void InitAliasTable(std::vector distribution, uint32_t range, - size_t log_alpha_size, AliasTable::Entry* JXL_RESTRICT a) { +Status InitAliasTable(std::vector distribution, uint32_t log_range, + size_t log_alpha_size, + AliasTable::Entry* JXL_RESTRICT a) { + const uint32_t range = 1 << log_range; + const size_t table_size = 1 << log_alpha_size; + JXL_ENSURE(table_size <= range); while (!distribution.empty() && distribution.back() == 0) { distribution.pop_back(); } @@ -59,32 +66,36 @@ void InitAliasTable(std::vector distribution, uint32_t range, if (distribution.empty()) { distribution.emplace_back(range); } - const size_t table_size = 1 << log_alpha_size; -#if JXL_ENABLE_ASSERT - int sum = std::accumulate(distribution.begin(), distribution.end(), 0); -#endif // JXL_ENABLE_ASSERT - JXL_ASSERT(static_cast(sum) == range); - // range must be a power of two - JXL_ASSERT((range & (range - 1)) == 0); - JXL_ASSERT(distribution.size() <= table_size); - JXL_ASSERT(table_size <= range); + JXL_ENSURE(distribution.size() <= table_size); const uint32_t entry_size = range >> log_alpha_size; // this is exact + int single_symbol = -1; + int sum = 0; // Special case for single-symbol distributions, that ensures that the state // does not change when decoding from such a distribution. Note that, since we // hardcode offset0 == 0, it is not straightforward (if at all possible) to // fix the general case to produce this result. for (size_t sym = 0; sym < distribution.size(); sym++) { - if (distribution[sym] == ANS_TAB_SIZE) { - for (size_t i = 0; i < table_size; i++) { - a[i].right_value = sym; - a[i].cutoff = 0; - a[i].offsets1 = entry_size * i; - a[i].freq0 = 0; - a[i].freq1_xor_freq0 = ANS_TAB_SIZE; - } - return; + int32_t v = distribution[sym]; + sum += v; + if (v == ANS_TAB_SIZE) { + JXL_ENSURE(single_symbol == -1); + single_symbol = sym; + } + } + JXL_ENSURE(static_cast(sum) == range); + if (single_symbol != -1) { + uint8_t sym = single_symbol; + JXL_ENSURE(single_symbol == sym); + for (size_t i = 0; i < table_size; i++) { + a[i].right_value = sym; + a[i].cutoff = 0; + a[i].offsets1 = entry_size * i; + a[i].freq0 = 0; + a[i].freq1_xor_freq0 = ANS_TAB_SIZE; } + return true; } + std::vector underfull_posn; std::vector overfull_posn; std::vector cutoffs(1 << log_alpha_size); @@ -105,7 +116,7 @@ void InitAliasTable(std::vector distribution, uint32_t range, while (!overfull_posn.empty()) { uint32_t overfull_i = overfull_posn.back(); overfull_posn.pop_back(); - JXL_ASSERT(!underfull_posn.empty()); + JXL_ENSURE(!underfull_posn.empty()); uint32_t underfull_i = underfull_posn.back(); underfull_posn.pop_back(); uint32_t underfull_by = entry_size - cutoffs[underfull_i]; @@ -143,6 +154,7 @@ void InitAliasTable(std::vector distribution, uint32_t range, a[i].freq0 = static_cast(freq0); a[i].freq1_xor_freq0 = static_cast(freq1 ^ freq0); } + return true; } } // namespace jxl diff --git a/third_party/jpeg-xl/lib/jxl/ans_common.h b/third_party/jpeg-xl/lib/jxl/ans_common.h index 44b8e3fba13eb..20897028f026a 100644 --- a/third_party/jpeg-xl/lib/jxl/ans_common.h +++ b/third_party/jpeg-xl/lib/jxl/ans_common.h @@ -6,9 +6,11 @@ #ifndef LIB_JXL_ANS_COMMON_H_ #define LIB_JXL_ANS_COMMON_H_ -#include - #include +#include +#include +#include +#include #include // Prefetch #include @@ -21,8 +23,8 @@ namespace jxl { // Returns the precision (number of bits) that should be used to store // a histogram count such that Log2Floor(count) == logcount. -static JXL_INLINE uint32_t GetPopulationCountPrecision(uint32_t logcount, - uint32_t shift) { +static JXL_MAYBE_UNUSED JXL_INLINE uint32_t +GetPopulationCountPrecision(uint32_t logcount, uint32_t shift) { int32_t r = std::min( logcount, static_cast(shift) - static_cast((ANS_LOG_TAB_SIZE - logcount) >> 1)); @@ -136,8 +138,8 @@ struct AliasTable { }; // Computes an alias table for a given distribution. -void InitAliasTable(std::vector distribution, uint32_t range, - size_t log_alpha_size, AliasTable::Entry* JXL_RESTRICT a); +Status InitAliasTable(std::vector distribution, uint32_t log_range, + size_t log_alpha_size, AliasTable::Entry* JXL_RESTRICT a); } // namespace jxl diff --git a/third_party/jpeg-xl/lib/jxl/ans_common_test.cc b/third_party/jpeg-xl/lib/jxl/ans_common_test.cc index 487b6cf5bdb44..b97f5186f9fae 100644 --- a/third_party/jpeg-xl/lib/jxl/ans_common_test.cc +++ b/third_party/jpeg-xl/lib/jxl/ans_common_test.cc @@ -14,10 +14,11 @@ namespace jxl { namespace { void VerifyAliasDistribution(const std::vector& distribution, - uint32_t range) { + uint32_t log_range) { constexpr size_t log_alpha_size = 8; AliasTable::Entry table[1 << log_alpha_size]; - InitAliasTable(distribution, range, log_alpha_size, table); + ASSERT_TRUE(InitAliasTable(distribution, log_range, log_alpha_size, table)); + uint32_t range = 1 << log_range; std::vector> offsets(distribution.size()); for (uint32_t i = 0; i < range; i++) { AliasTable::Symbol s = AliasTable::Lookup( @@ -34,9 +35,10 @@ void VerifyAliasDistribution(const std::vector& distribution, } TEST(ANSCommonTest, AliasDistributionSmoke) { - VerifyAliasDistribution({ANS_TAB_SIZE / 2, ANS_TAB_SIZE / 2}, ANS_TAB_SIZE); - VerifyAliasDistribution({ANS_TAB_SIZE}, ANS_TAB_SIZE); - VerifyAliasDistribution({0, 0, 0, ANS_TAB_SIZE, 0}, ANS_TAB_SIZE); + VerifyAliasDistribution({ANS_TAB_SIZE / 2, ANS_TAB_SIZE / 2}, + ANS_LOG_TAB_SIZE); + VerifyAliasDistribution({ANS_TAB_SIZE}, ANS_LOG_TAB_SIZE); + VerifyAliasDistribution({0, 0, 0, ANS_TAB_SIZE, 0}, ANS_LOG_TAB_SIZE); } } // namespace diff --git a/third_party/jpeg-xl/lib/jxl/ans_test.cc b/third_party/jpeg-xl/lib/jxl/ans_test.cc index 5d6a5ef0906a8..8bed98895f4c1 100644 --- a/third_party/jpeg-xl/lib/jxl/ans_test.cc +++ b/third_party/jpeg-xl/lib/jxl/ans_test.cc @@ -3,19 +3,22 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include -#include +#include +#include +#include #include #include "lib/jxl/ans_params.h" #include "lib/jxl/base/random.h" -#include "lib/jxl/base/span.h" +#include "lib/jxl/base/status.h" #include "lib/jxl/dec_ans.h" #include "lib/jxl/dec_bit_reader.h" #include "lib/jxl/enc_ans.h" #include "lib/jxl/enc_aux_out.h" #include "lib/jxl/enc_bit_writer.h" +#include "lib/jxl/test_memory_manager.h" +#include "lib/jxl/test_utils.h" #include "lib/jxl/testing.h" namespace jxl { @@ -23,29 +26,37 @@ namespace { void RoundtripTestcase(int n_histograms, int alphabet_size, const std::vector& input_values) { + JxlMemoryManager* memory_manager = jxl::test::MemoryManager(); constexpr uint16_t kMagic1 = 0x9e33; constexpr uint16_t kMagic2 = 0x8b04; - BitWriter writer; + BitWriter writer{memory_manager}; // Space for magic bytes. - BitWriter::Allotment allotment_magic1(&writer, 16); - writer.Write(16, kMagic1); - allotment_magic1.ReclaimAndCharge(&writer, 0, nullptr); + ASSERT_TRUE(writer.WithMaxBits(16, LayerType::Header, nullptr, [&] { + writer.Write(16, kMagic1); + return true; + })); std::vector context_map; EntropyEncodingData codes; std::vector> input_values_vec; input_values_vec.push_back(input_values); - BuildAndEncodeHistograms(HistogramParams(), n_histograms, input_values_vec, - &codes, &context_map, &writer, 0, nullptr); - WriteTokens(input_values_vec[0], codes, context_map, 0, &writer, 0, nullptr); + JXL_TEST_ASSIGN_OR_DIE( + size_t cost, + BuildAndEncodeHistograms(memory_manager, HistogramParams(), n_histograms, + input_values_vec, &codes, &context_map, &writer, + LayerType::Header, nullptr)); + (void)cost; + ASSERT_TRUE(WriteTokens(input_values_vec[0], codes, context_map, 0, &writer, + LayerType::Header, nullptr)); // Magic bytes + padding - BitWriter::Allotment allotment_magic2(&writer, 24); - writer.Write(16, kMagic2); - writer.ZeroPadToByte(); - allotment_magic2.ReclaimAndCharge(&writer, 0, nullptr); + ASSERT_TRUE(writer.WithMaxBits(24, LayerType::Header, nullptr, [&] { + writer.Write(16, kMagic2); + writer.ZeroPadToByte(); + return true; + })); // We do not truncate the output. Reading past the end reads out zeroes // anyway. @@ -55,10 +66,11 @@ void RoundtripTestcase(int n_histograms, int alphabet_size, std::vector dec_context_map; ANSCode decoded_codes; - ASSERT_TRUE( - DecodeHistograms(&br, n_histograms, &decoded_codes, &dec_context_map)); + ASSERT_TRUE(DecodeHistograms(memory_manager, &br, n_histograms, + &decoded_codes, &dec_context_map)); ASSERT_EQ(dec_context_map, context_map); - ANSSymbolReader reader(&decoded_codes, &br); + JXL_TEST_ASSIGN_OR_DIE(ANSSymbolReader reader, + ANSSymbolReader::Create(&decoded_codes, &br)); for (const Token& symbol : input_values) { uint32_t read_symbol = @@ -157,6 +169,7 @@ TEST(ANSTest, RandomUnbalancedStreamRoundtripBig) { } TEST(ANSTest, UintConfigRoundtrip) { + JxlMemoryManager* memory_manager = jxl::test::MemoryManager(); for (size_t log_alpha_size = 5; log_alpha_size <= 8; log_alpha_size++) { std::vector uint_config; std::vector uint_config_dec; @@ -169,10 +182,12 @@ TEST(ANSTest, UintConfigRoundtrip) { } uint_config.emplace_back(log_alpha_size, 0, 0); uint_config_dec.resize(uint_config.size()); - BitWriter writer; - BitWriter::Allotment allotment(&writer, 10 * uint_config.size()); - EncodeUintConfigs(uint_config, &writer, log_alpha_size); - allotment.ReclaimAndCharge(&writer, 0, nullptr); + BitWriter writer{memory_manager}; + ASSERT_TRUE(writer.WithMaxBits( + 10 * uint_config.size(), LayerType::Header, nullptr, [&] { + EncodeUintConfigs(uint_config, &writer, log_alpha_size); + return true; + })); writer.ZeroPadToByte(); BitReader br(writer.GetSpan()); EXPECT_TRUE(DecodeUintConfigs(log_alpha_size, &uint_config_dec, &br)); @@ -186,6 +201,7 @@ TEST(ANSTest, UintConfigRoundtrip) { } void TestCheckpointing(bool ans, bool lz77) { + JxlMemoryManager* memory_manager = jxl::test::MemoryManager(); std::vector> input_values(1); for (size_t i = 0; i < 1024; i++) { input_values[0].emplace_back(0, i % 4); @@ -207,13 +223,16 @@ void TestCheckpointing(bool ans, bool lz77) { : HistogramParams::LZ77Method::kNone; params.force_huffman = !ans; - BitWriter writer; + BitWriter writer{memory_manager}; { auto input_values_copy = input_values; - BuildAndEncodeHistograms(params, 1, input_values_copy, &codes, &context_map, - &writer, 0, nullptr); - WriteTokens(input_values_copy[0], codes, context_map, 0, &writer, 0, - nullptr); + JXL_TEST_ASSIGN_OR_DIE( + size_t cost, BuildAndEncodeHistograms( + memory_manager, params, 1, input_values_copy, &codes, + &context_map, &writer, LayerType::Header, nullptr)); + (void)cost; + ASSERT_TRUE(WriteTokens(input_values_copy[0], codes, context_map, 0, + &writer, LayerType::Header, nullptr)); writer.ZeroPadToByte(); } @@ -222,13 +241,15 @@ void TestCheckpointing(bool ans, bool lz77) { BitReader br(writer.GetSpan()); Status status = true; { - BitReaderScopedCloser bc(&br, &status); + BitReaderScopedCloser bc(br, status); std::vector dec_context_map; ANSCode decoded_codes; - ASSERT_TRUE(DecodeHistograms(&br, 1, &decoded_codes, &dec_context_map)); + ASSERT_TRUE(DecodeHistograms(memory_manager, &br, 1, &decoded_codes, + &dec_context_map)); ASSERT_EQ(dec_context_map, context_map); - ANSSymbolReader reader(&decoded_codes, &br); + JXL_TEST_ASSIGN_OR_DIE(ANSSymbolReader reader, + ANSSymbolReader::Create(&decoded_codes, &br)); ANSSymbolReader::Checkpoint checkpoint; size_t br_pos = 0; diff --git a/third_party/jpeg-xl/lib/jxl/base/common.h b/third_party/jpeg-xl/lib/jxl/base/common.h index d57328050ecaf..0893ef26b5a5a 100644 --- a/third_party/jpeg-xl/lib/jxl/base/common.h +++ b/third_party/jpeg-xl/lib/jxl/base/common.h @@ -70,6 +70,8 @@ std::unique_ptr make_unique(Args&&... args) { using std::make_unique; #endif +typedef std::array Color; + // Backported std::experimental::to_array template diff --git a/third_party/jpeg-xl/lib/jxl/base/compiler_specific.h b/third_party/jpeg-xl/lib/jxl/base/compiler_specific.h index 702ff8e058179..cb1a8a038641f 100644 --- a/third_party/jpeg-xl/lib/jxl/base/compiler_specific.h +++ b/third_party/jpeg-xl/lib/jxl/base/compiler_specific.h @@ -8,11 +8,14 @@ // Macros for compiler version + nonstandard keywords, e.g. __builtin_expect. -#include #include #include "lib/jxl/base/sanitizer_definitions.h" +#if JXL_ADDRESS_SANITIZER || JXL_MEMORY_SANITIZER || JXL_THREAD_SANITIZER +#include "sanitizer/common_interface_defs.h" // __sanitizer_print_stack_trace +#endif // defined(*_SANITIZER) + // #if is shorter and safer than #ifdef. *_VERSION are zero if not detected, // otherwise 100 * major + minor version. Note that other packages check for // #ifdef COMPILER_MSVC, so we cannot use that same name. @@ -62,14 +65,6 @@ #define JXL_NORETURN #endif -#if JXL_COMPILER_MSVC -#define JXL_UNREACHABLE_BUILTIN __assume(false) -#elif JXL_COMPILER_CLANG || JXL_COMPILER_GCC >= 405 -#define JXL_UNREACHABLE_BUILTIN __builtin_unreachable() -#else -#define JXL_UNREACHABLE_BUILTIN -#endif - #if JXL_COMPILER_MSVC #define JXL_MAYBE_UNUSED #else @@ -97,6 +92,11 @@ #define JXL_UNLIKELY(expr) __builtin_expect(!!(expr), 0) #endif +#if JXL_COMPILER_MSVC +#include +using ssize_t = intptr_t; +#endif + // Returns a void* pointer which the compiler then assumes is N-byte aligned. // Example: float* JXL_RESTRICT aligned = (float*)JXL_ASSUME_ALIGNED(in, 32); // @@ -150,8 +150,71 @@ #define JXL_FORMAT(idx_fmt, idx_arg) #endif +// C++ standard. +#if defined(_MSC_VER) && !defined(__clang__) && defined(_MSVC_LANG) && \ + _MSVC_LANG > __cplusplus +#define JXL_CXX_LANG _MSVC_LANG +#else +#define JXL_CXX_LANG __cplusplus +#endif + +// Known / distinguished C++ standards. +#define JXL_CXX_17 201703 + +// In most cases we consider build as "debug". Use `NDEBUG` for release build. +#if defined(JXL_IS_DEBUG_BUILD) +#undef JXL_IS_DEBUG_BUILD +#define JXL_IS_DEBUG_BUILD 1 +#elif defined(NDEBUG) +#define JXL_IS_DEBUG_BUILD 0 +#else +#define JXL_IS_DEBUG_BUILD 1 +#endif + +#if defined(JXL_CRASH_ON_ERROR) +#undef JXL_CRASH_ON_ERROR +#define JXL_CRASH_ON_ERROR 1 +#else +#define JXL_CRASH_ON_ERROR 0 +#endif + +#if JXL_CRASH_ON_ERROR && !JXL_IS_DEBUG_BUILD +#error "JXL_CRASH_ON_ERROR requires JXL_IS_DEBUG_BUILD" +#endif + +// Pass -DJXL_DEBUG_ON_ALL_ERROR at compile time to print debug messages on +// all error (fatal and non-fatal) status. +#if defined(JXL_DEBUG_ON_ALL_ERROR) +#undef JXL_DEBUG_ON_ALL_ERROR +#define JXL_DEBUG_ON_ALL_ERROR 1 +#else +#define JXL_DEBUG_ON_ALL_ERROR 0 +#endif + +#if JXL_DEBUG_ON_ALL_ERROR && !JXL_IS_DEBUG_BUILD +#error "JXL_DEBUG_ON_ALL_ERROR requires JXL_IS_DEBUG_BUILD" +#endif + +// Pass -DJXL_DEBUG_ON_ABORT={0} to disable the debug messages on +// (debug) JXL_ENSURE and JXL_DASSERT. +#if !defined(JXL_DEBUG_ON_ABORT) +#define JXL_DEBUG_ON_ABORT JXL_IS_DEBUG_BUILD +#endif // JXL_DEBUG_ON_ABORT + +#if JXL_DEBUG_ON_ABORT && !JXL_IS_DEBUG_BUILD +#error "JXL_DEBUG_ON_ABORT requires JXL_IS_DEBUG_BUILD" +#endif + +#if JXL_ADDRESS_SANITIZER || JXL_MEMORY_SANITIZER || JXL_THREAD_SANITIZER +#define JXL_PRINT_STACK_TRACE() __sanitizer_print_stack_trace(); +#else +#define JXL_PRINT_STACK_TRACE() +#endif + #if JXL_COMPILER_MSVC -using ssize_t = intptr_t; +#define JXL_CRASH() __debugbreak(), (void)abort() +#else +#define JXL_CRASH() (void)__builtin_trap() #endif #endif // LIB_JXL_BASE_COMPILER_SPECIFIC_H_ diff --git a/third_party/jpeg-xl/lib/jxl/base/data_parallel.h b/third_party/jpeg-xl/lib/jxl/base/data_parallel.h index a7f977b7ce9be..e39f46c75b929 100644 --- a/third_party/jpeg-xl/lib/jxl/base/data_parallel.h +++ b/third_party/jpeg-xl/lib/jxl/base/data_parallel.h @@ -10,8 +10,10 @@ // data-parallel computations. #include -#include -#include + +#include +#include +#include #include "lib/jxl/base/compiler_specific.h" #include "lib/jxl/base/status.h" @@ -44,25 +46,34 @@ class ThreadPool { // Precondition: begin <= end. template Status Run(uint32_t begin, uint32_t end, const InitFunc& init_func, - const DataFunc& data_func, const char* caller = "") { - JXL_ASSERT(begin <= end); + const DataFunc& data_func, const char* caller) { + JXL_ENSURE(begin <= end); if (begin == end) return true; RunCallState call_state(init_func, data_func); // The runner_ uses the C convention and returns 0 in case of error, so we // convert it to a Status. if (!runner_) { void* jpegxl_opaque = static_cast(&call_state); - if (call_state.CallInitFunc(jpegxl_opaque, 1) != 0) { + if (call_state.CallInitFunc(jpegxl_opaque, 1) != + JXL_PARALLEL_RET_SUCCESS) { return JXL_FAILURE("Failed to initialize thread"); } for (uint32_t i = begin; i < end; i++) { call_state.CallDataFunc(jpegxl_opaque, i, 0); } + if (call_state.HasError()) { + return JXL_FAILURE("[%s] failed", caller); + } return true; } - return (*runner_)(runner_opaque_, static_cast(&call_state), - &call_state.CallInitFunc, &call_state.CallDataFunc, begin, - end) == 0; + JxlParallelRetCode ret = (*runner_)( + runner_opaque_, static_cast(&call_state), + &call_state.CallInitFunc, &call_state.CallDataFunc, begin, end); + + if (ret != JXL_PARALLEL_RET_SUCCESS || call_state.HasError()) { + return JXL_FAILURE("[%s] failed", caller); + } + return true; } // Use this as init_func when no initialization is needed. @@ -79,24 +90,34 @@ class ThreadPool { // JxlParallelRunInit interface. static int CallInitFunc(void* jpegxl_opaque, size_t num_threads) { - const auto* self = + auto* self = static_cast*>(jpegxl_opaque); // Returns -1 when the internal init function returns false Status to // indicate an error. - return self->init_func_(num_threads) ? 0 : -1; + if (!self->init_func_(num_threads)) { + self->has_error_ = true; + return JXL_PARALLEL_RET_RUNNER_ERROR; + } + return JXL_PARALLEL_RET_SUCCESS; } // JxlParallelRunFunction interface. static void CallDataFunc(void* jpegxl_opaque, uint32_t value, size_t thread_id) { - const auto* self = + auto* self = static_cast*>(jpegxl_opaque); - return self->data_func_(value, thread_id); + if (self->has_error_) return; + if (!self->data_func_(value, thread_id)) { + self->has_error_ = true; + } } + bool HasError() const { return has_error_; } + private: const InitFunc& init_func_; const DataFunc& data_func_; + std::atomic has_error_{false}; }; // The caller supplied runner function and its opaque void*. diff --git a/third_party/jpeg-xl/lib/jxl/base/exif.h b/third_party/jpeg-xl/lib/jxl/base/exif.h index a3574a16ffda7..acaa1a1ce4361 100644 --- a/third_party/jpeg-xl/lib/jxl/base/exif.h +++ b/third_party/jpeg-xl/lib/jxl/base/exif.h @@ -3,8 +3,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#ifndef LIB_JXL_EXIF_H_ -#define LIB_JXL_EXIF_H_ +#ifndef LIB_JXL_BASE_EXIF_H_ +#define LIB_JXL_BASE_EXIF_H_ // Basic parsing of Exif (just enough for the render-impacting things // like orientation) @@ -87,4 +87,4 @@ JXL_INLINE void InterpretExif(const std::vector& exif, } // namespace jxl -#endif // LIB_JXL_EXIF_H_ +#endif // LIB_JXL_BASE_EXIF_H_ diff --git a/third_party/jpeg-xl/lib/jxl/base/float.h b/third_party/jpeg-xl/lib/jxl/base/float.h index 0f5b3b1f3a413..50af582b6f54a 100644 --- a/third_party/jpeg-xl/lib/jxl/base/float.h +++ b/third_party/jpeg-xl/lib/jxl/base/float.h @@ -62,9 +62,7 @@ static Status JXL_INLINE LoadFloatRow(const uint8_t* src, size_t count, case JXL_TYPE_UINT8: for (size_t i = 0; i < count; ++i) { - // Integer multiply uint8 value before scaling so that the UINT8 value - // and the corresponding UINT16 value convert to the same float - callback(i, (src[stride * i] * 257) * scale); + callback(i, src[stride * i] * scale); } return true; diff --git a/third_party/jpeg-xl/lib/jxl/base/include_jpeglib.h b/third_party/jpeg-xl/lib/jxl/base/include_jpeglib.h new file mode 100644 index 0000000000000..f72d13d04bad0 --- /dev/null +++ b/third_party/jpeg-xl/lib/jxl/base/include_jpeglib.h @@ -0,0 +1,20 @@ +// Copyright (c) the JPEG XL Project Authors. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#ifndef LIB_JXL_BASE_INCLUDE_JPEGLIB_H_ +#define LIB_JXL_BASE_INCLUDE_JPEGLIB_H_ + +// Using this header ensures that includes go in the right order, +// not alphabetically sorted. + +// NOLINTBEGIN +/* clang-format off */ +#include // IWYU pragma: keep +#include // IWYU pragma: keep +#include // IWYU pragma: keep +/* clang-format on */ +// NOLINTEND + +#endif // LIB_JXL_BASE_INCLUDE_JPEGLIB_H_ diff --git a/third_party/jpeg-xl/lib/jxl/base/matrix_ops.h b/third_party/jpeg-xl/lib/jxl/base/matrix_ops.h index 1a969bd4f0a0c..e1f8753932581 100644 --- a/third_party/jpeg-xl/lib/jxl/base/matrix_ops.h +++ b/third_party/jpeg-xl/lib/jxl/base/matrix_ops.h @@ -3,11 +3,12 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#ifndef LIB_JXL_MATRIX_OPS_H_ -#define LIB_JXL_MATRIX_OPS_H_ +#ifndef LIB_JXL_BASE_MATRIX_OPS_H_ +#define LIB_JXL_BASE_MATRIX_OPS_H_ // 3x3 matrix operations. +#include #include // abs #include @@ -15,70 +16,71 @@ namespace jxl { +typedef std::array Vector3; +typedef std::array Vector3d; +typedef std::array Matrix3x3; +typedef std::array Matrix3x3d; + // Computes C = A * B, where A, B, C are 3x3 matrices. -template -void Mul3x3Matrix(const T* a, const T* b, T* c) { - alignas(16) T temp[3]; // For transposed column +template +void Mul3x3Matrix(const Matrix& a, const Matrix& b, Matrix& c) { for (size_t x = 0; x < 3; x++) { - for (size_t z = 0; z < 3; z++) { - temp[z] = b[z * 3 + x]; - } + alignas(16) Vector3d temp{b[0][x], b[1][x], b[2][x]}; // transpose for (size_t y = 0; y < 3; y++) { - double e = 0; - for (size_t z = 0; z < 3; z++) { - e += a[y * 3 + z] * temp[z]; - } - c[y * 3 + x] = e; + c[y][x] = a[y][0] * temp[0] + a[y][1] * temp[1] + a[y][2] * temp[2]; } } } // Computes C = A * B, where A is 3x3 matrix and B is vector. -template -void Mul3x3Vector(const T* a, const T* b, T* c) { +template +void Mul3x3Vector(const Matrix& a, const Vector& b, Vector& c) { for (size_t y = 0; y < 3; y++) { double e = 0; for (size_t x = 0; x < 3; x++) { - e += a[y * 3 + x] * b[x]; + e += a[y][x] * b[x]; } c[y] = e; } } // Inverts a 3x3 matrix in place. -template -Status Inv3x3Matrix(T* matrix) { +template +Status Inv3x3Matrix(Matrix& matrix) { // Intermediate computation is done in double precision. - double temp[9]; - temp[0] = static_cast(matrix[4]) * matrix[8] - - static_cast(matrix[5]) * matrix[7]; - temp[1] = static_cast(matrix[2]) * matrix[7] - - static_cast(matrix[1]) * matrix[8]; - temp[2] = static_cast(matrix[1]) * matrix[5] - - static_cast(matrix[2]) * matrix[4]; - temp[3] = static_cast(matrix[5]) * matrix[6] - - static_cast(matrix[3]) * matrix[8]; - temp[4] = static_cast(matrix[0]) * matrix[8] - - static_cast(matrix[2]) * matrix[6]; - temp[5] = static_cast(matrix[2]) * matrix[3] - - static_cast(matrix[0]) * matrix[5]; - temp[6] = static_cast(matrix[3]) * matrix[7] - - static_cast(matrix[4]) * matrix[6]; - temp[7] = static_cast(matrix[1]) * matrix[6] - - static_cast(matrix[0]) * matrix[7]; - temp[8] = static_cast(matrix[0]) * matrix[4] - - static_cast(matrix[1]) * matrix[3]; - double det = matrix[0] * temp[0] + matrix[1] * temp[3] + matrix[2] * temp[6]; + Matrix3x3d temp; + temp[0][0] = static_cast(matrix[1][1]) * matrix[2][2] - + static_cast(matrix[1][2]) * matrix[2][1]; + temp[0][1] = static_cast(matrix[0][2]) * matrix[2][1] - + static_cast(matrix[0][1]) * matrix[2][2]; + temp[0][2] = static_cast(matrix[0][1]) * matrix[1][2] - + static_cast(matrix[0][2]) * matrix[1][1]; + temp[1][0] = static_cast(matrix[1][2]) * matrix[2][0] - + static_cast(matrix[1][0]) * matrix[2][2]; + temp[1][1] = static_cast(matrix[0][0]) * matrix[2][2] - + static_cast(matrix[0][2]) * matrix[2][0]; + temp[1][2] = static_cast(matrix[0][2]) * matrix[1][0] - + static_cast(matrix[0][0]) * matrix[1][2]; + temp[2][0] = static_cast(matrix[1][0]) * matrix[2][1] - + static_cast(matrix[1][1]) * matrix[2][0]; + temp[2][1] = static_cast(matrix[0][1]) * matrix[2][0] - + static_cast(matrix[0][0]) * matrix[2][1]; + temp[2][2] = static_cast(matrix[0][0]) * matrix[1][1] - + static_cast(matrix[0][1]) * matrix[1][0]; + double det = matrix[0][0] * temp[0][0] + matrix[0][1] * temp[1][0] + + matrix[0][2] * temp[2][0]; if (std::abs(det) < 1e-10) { return JXL_FAILURE("Matrix determinant is too close to 0"); } double idet = 1.0 / det; - for (size_t i = 0; i < 9; i++) { - matrix[i] = temp[i] * idet; + for (size_t j = 0; j < 3; j++) { + for (size_t i = 0; i < 3; i++) { + matrix[j][i] = temp[j][i] * idet; + } } return true; } } // namespace jxl -#endif // LIB_JXL_MATRIX_OPS_H_ +#endif // LIB_JXL_BASE_MATRIX_OPS_H_ diff --git a/third_party/jpeg-xl/lib/jxl/base/random.h b/third_party/jpeg-xl/lib/jxl/base/random.h index b27815bf0031b..6922e282e83bc 100644 --- a/third_party/jpeg-xl/lib/jxl/base/random.h +++ b/third_party/jpeg-xl/lib/jxl/base/random.h @@ -20,7 +20,7 @@ namespace jxl { struct Rng { - explicit Rng(size_t seed) + explicit Rng(uint64_t seed) : s{static_cast(0x94D049BB133111EBull), static_cast(0xBF58476D1CE4E5B9ull) + seed} {} diff --git a/third_party/jpeg-xl/lib/jxl/base/rect.h b/third_party/jpeg-xl/lib/jxl/base/rect.h new file mode 100644 index 0000000000000..31fe12dfb9529 --- /dev/null +++ b/third_party/jpeg-xl/lib/jxl/base/rect.h @@ -0,0 +1,186 @@ +// Copyright (c) the JPEG XL Project Authors. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#ifndef LIB_JXL_BASE_RECT_H_ +#define LIB_JXL_BASE_RECT_H_ + +#include +#include +#include +#include +#include +#include +#include // std::move + +#include "lib/jxl/base/compiler_specific.h" +#include "lib/jxl/base/status.h" + +namespace jxl { + +// Rectangular region in image(s). Factoring this out of Image instead of +// shifting the pointer by x0/y0 allows this to apply to multiple images with +// different resolutions (e.g. color transform and quantization field). +// Can compare using SameSize(rect1, rect2). +template +class RectT { + public: + // Most windows are xsize_max * ysize_max, except those on the borders where + // begin + size_max > end. + constexpr RectT(T xbegin, T ybegin, size_t xsize_max, size_t ysize_max, + T xend, T yend) + : x0_(xbegin), + y0_(ybegin), + xsize_(ClampedSize(xbegin, xsize_max, xend)), + ysize_(ClampedSize(ybegin, ysize_max, yend)) {} + + // Construct with origin and known size (typically from another Rect). + constexpr RectT(T xbegin, T ybegin, size_t xsize, size_t ysize) + : x0_(xbegin), y0_(ybegin), xsize_(xsize), ysize_(ysize) {} + + // Construct a rect that covers a whole image/plane/ImageBundle etc. + template + explicit RectT(const ImageT& image) + : RectT(0, 0, image.xsize(), image.ysize()) {} + + RectT() : RectT(0, 0, 0, 0) {} + + RectT(const RectT&) = default; + RectT& operator=(const RectT&) = default; + + // Construct a subrect that resides in an image/plane/ImageBundle etc. + template + RectT Crop(const ImageT& image) const { + return Intersection(RectT(image)); + } + + // Construct a subrect that resides in the [0, ysize) x [0, xsize) region of + // the current rect. + RectT Crop(size_t area_xsize, size_t area_ysize) const { + return Intersection(RectT(0, 0, area_xsize, area_ysize)); + } + + JXL_MUST_USE_RESULT RectT Intersection(const RectT& other) const { + return RectT(std::max(x0_, other.x0_), std::max(y0_, other.y0_), xsize_, + ysize_, std::min(x1(), other.x1()), + std::min(y1(), other.y1())); + } + + JXL_MUST_USE_RESULT RectT Translate(int64_t x_offset, + int64_t y_offset) const { + return RectT(x0_ + x_offset, y0_ + y_offset, xsize_, ysize_); + } + + template