-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor Canvas noise injection logic and improve support for gradients in post-processed ImageData #13199
Conversation
EWS run on previous version of this PR (hash c424770)
|
EWS run on previous version of this PR (hash 0d9701f) |
EWS run on previous version of this PR (hash 32396d9)
|
EWS run on previous version of this PR (hash 9747080)
|
Source/WebCore/html/CanvasBase.cpp
Outdated
@@ -373,6 +374,203 @@ bool CanvasBase::shouldInjectNoiseBeforeReadback() const | |||
return scriptExecutionContext() && scriptExecutionContext()->noiseInjectionHashSalt(); | |||
} | |||
|
|||
struct RGBAColor { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd be hesitant to add yet-another color type. Mostly this seems to be usable as uint32_t?
E.g ordering seems to be uint32_t ordering.
Alternatively you could perhaps try to use existing ColorComponents<> or something?
Source/WebCore/html/CanvasBase.cpp
Outdated
} | ||
return tweak; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This noise algorithm now adds significant noise to already complex CanvasBase, doubling its size, and still it's a bit peripheral to the Canvas functionality.
Could we encapsulate the noise injection into a new file, such as CanvasNoiseInjection.h/cpp?
Source/WebCore/html/CanvasBase.h
Outdated
@@ -90,6 +90,8 @@ class CanvasBase { | |||
void setOriginTainted() { m_originClean = false; } | |||
bool originClean() const { return m_originClean; } | |||
|
|||
void setHadGradientFill() { m_hadGradientFill = true; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding custom ad-hoc state to the CanvasBase will result in hard to maintain Canvas implementation down the line.
Adding ad-hoc state to the algorithm creates a problem where you need to run security analysis on each possible state.
Would it be possible to implement one, stateless algorithm that would be good?
If the gradient algorithm is good enough for injecting noise for the gradient case, could it be used also in non-gradient case? This would fix the corner-cases where a gradient would be drawn to a canvas a, canvas a to canvas b, and canvas b would be read back, injecting the noise in b read.
Source/WebCore/html/CanvasBase.cpp
Outdated
bool isInLeftColumn = !(pixelIndex % size.width()); | ||
bool isInRightColumn = (pixelIndex % size.width()) == static_cast<unsigned>(size.width()) - 1; | ||
bool isInTopLeftCorner = isInTopRow && isInLeftColumn; | ||
bool isInBotomLeftCorner = isInBottomRow && isInLeftColumn; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo here
Source/WebCore/html/CanvasBase.cpp
Outdated
return { componentAt(offset), componentAt(offset + greenOffsetFromIndex), componentAt(offset + blueOffsetFromIndex), componentAt(offset + alphaOffsetFromIndex) }; | ||
} | ||
|
||
static std::optional<std::pair<size_t, size_t>> getGradientNeighbors(size_t index, const Ref<PixelBuffer>&& pixelBuffer) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const Ref&& doesn't make much sense.
I think this means PixelBuffer&
Source/WebCore/html/CanvasBase.cpp
Outdated
@@ -411,6 +609,8 @@ bool CanvasBase::postProcessPixelBufferResults(Ref<PixelBuffer>&& pixelBuffer, c | |||
HashMap<uint32_t, uint32_t> pixelColorMap; | |||
bool wasPixelBufferModified { false }; | |||
|
|||
HashMap<size_t, std::pair<size_t, size_t>> gradientIndiceMap; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't quite understand this map.
If I have 2000x2000 canvas with a full-screen gradient, does this map get 4 million entries? Sounds that it doesn't work in general case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm sure a fast algorithm to add visually non-distracting noise to a picture has been a solved research question for a while now. Maybe we could just look up a proper scientific noise kernel from some research paper and implement that?
EWS run on previous version of this PR (hash 6c7d857) |
EWS run on previous version of this PR (hash a3b1808)
|
} | ||
} | ||
|
||
bool CanvasNoiseInjection::postProcessPixelBufferResults(Ref<PixelBuffer>&& pixelBuffer, NoiseInjectionHashSalt salt) const |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here we're saying "this method may take ownership of the reference to the pixel buffer."
The method actually never takes the ownership of the reference.
So the signature should just be PixelBuffer&
which means "this method uses the pixel buffer".
Source/WebCore/html/CanvasBase.h
Outdated
mutable Lock m_imageBufferAssignmentLock; | ||
mutable RefPtr<ImageBuffer> m_imageBuffer; | ||
mutable size_t m_imageBufferCost { 0 }; | ||
mutable std::unique_ptr<GraphicsContextStateSaver> m_contextStateSaver; | ||
mutable CanvasNoiseInjection m_canvasNoiseInjection; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems the CanvasNoiseInjection doesn't need to be mutable, as postprocessdirty is only used in mutable scope.
EWS run on current version of this PR (hash 60e7230)
|
EWS run on previous version of this PR (hash 60e7230)
|
EWS run on current version of this PR (hash 59fa2ec)
|
Now I'm confident enough that the gtk/wpe failures are flakey. |
…ts in post-processed ImageData https://bugs.webkit.org/show_bug.cgi?id=255993 rdar://107371244 Reviewed by Kimmo Kinnunen. Gradients present an interesting problem when post-processing canvas ImageData because tweaking colors result in significant visual anomalies. This change introduces some naive gradient detection by looking at all of the immediate neighbors of a pixel. We decide that a pixel is within a gradient if the current color is between its opposing adjacent colors (e.g., above and below, left and right, etc). If a color is decided to be within a gradient, then we set those adjacent colors as bounds within which we can tweak the current color. In addition, within this change, we move the noise injection logic into its own class, it removes the dependency on supplied colors for post-processing, and it reduces the magnitude of noise from ~5% to ~1%. * Source/WebCore/Headers.cmake: * Source/WebCore/Sources.txt: * Source/WebCore/WebCore.xcodeproj/project.pbxproj: * Source/WebCore/html/CanvasBase.cpp: (WebCore::CanvasBase::makeRenderingResultsAvailable): (WebCore::CanvasBase::didDraw): We clip the rect before passing it into CanvasNoiseInjection, and if the rect is std::nullopt then we pass in the entire canvas. (WebCore::CanvasBase::postProcessPixelBufferResults const): (WebCore::CanvasBase::postProcessDirtyCanvasBuffer const): Deleted. * Source/WebCore/html/CanvasBase.h: * Source/WebCore/html/CanvasNoiseInjection.cpp: Added. (WebCore::CanvasNoiseInjection::updateDirtyRect): (WebCore::isIndexInBounds): (WebCore::setTightnessBounds): (WebCore::getGradientNeighbors): (WebCore::CanvasNoiseInjection::postProcessDirtyCanvasBuffer): (WebCore::CanvasNoiseInjection::postProcessPixelBufferResults const): * Source/WebCore/html/CanvasNoiseInjection.h: Added. * Source/WebCore/html/HTMLCanvasElement.cpp: (WebCore::HTMLCanvasElement::getImageData): Canonical link: https://commits.webkit.org/263979@main
59fa2ec
to
eabcb3e
Compare
Committed 263979@main (eabcb3e): https://commits.webkit.org/263979@main Reviewed commits have been landed. Closing PR #13199 and removing active labels. |
709720d