[PDF Ink Signatures] Avoid flashing after stroke completion
Painting in PdfViewWebPlugin uses a current image snapshot to draw onto the canvas. This gets updated after PaintManager finishes doing a flush of paint requests. After a stroke has been added to a PDF page, PdfInkModule makes an invalidate call which kicks off the request to redraw the area where the stroke occurred. However, there can be a call for PdfViewWebPlugin to paint before the snapshot has been updated. This presents a period where the snapshot does not include the newly drawn Ink stroke, and there are no longer any in-progress Ink inputs held by PdfInkModule. This can result in a flash, where the paint uses only the now-stale snapshot. Avoid the flash effect where a newly drawn Ink stroke temporarily disappears by retaining the snapshot rendering of the in-progress Ink stroke. Reuse this in PdfViewWebPlugin::Paint() until the current image snapshot gets updated. Fixed: 380057101 Change-Id: Icda9260a6d022f3458f0ae1e28dfa5d492daa8c8 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6363095 Reviewed-by: Andy Phan <andyphan@chromium.org> Reviewed-by: Lei Zhang <thestig@chromium.org> Commit-Queue: Alan Screen <awscreen@chromium.org> Cr-Commit-Position: refs/heads/main@{#1433897}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
7821e3373a
commit
b9182a2d47
@@ -605,7 +605,11 @@ void PdfViewWebPlugin::Paint(cc::PaintCanvas* canvas, const gfx::Rect& rect) {
|
|||||||
canvas->drawImage(snapshot_, 0, 0);
|
canvas->drawImage(snapshot_, 0, 0);
|
||||||
|
|
||||||
#if BUILDFLAG(ENABLE_PDF_INK2)
|
#if BUILDFLAG(ENABLE_PDF_INK2)
|
||||||
if (ink_module_ && ink_module_->HasInputsToDraw()) {
|
if (!ink_module_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ink_module_->HasInputsToDraw()) {
|
||||||
SkBitmap sk_bitmap;
|
SkBitmap sk_bitmap;
|
||||||
sk_bitmap.allocPixels(
|
sk_bitmap.allocPixels(
|
||||||
SkImageInfo::MakeN32Premul(rect.width(), rect.height()));
|
SkImageInfo::MakeN32Premul(rect.width(), rect.height()));
|
||||||
@@ -615,13 +619,18 @@ void PdfViewWebPlugin::Paint(cc::PaintCanvas* canvas, const gfx::Rect& rect) {
|
|||||||
|
|
||||||
sk_sp<SkImage> snapshot = sk_bitmap.asImage();
|
sk_sp<SkImage> snapshot = sk_bitmap.asImage();
|
||||||
CHECK(snapshot);
|
CHECK(snapshot);
|
||||||
cc::PaintImage cc_snapshot =
|
snapshot_ink_inputs_ =
|
||||||
cc::PaintImageBuilder::WithDefault()
|
cc::PaintImageBuilder::WithDefault()
|
||||||
.set_image(std::move(snapshot), cc::PaintImage::GetNextContentId())
|
.set_image(std::move(snapshot), cc::PaintImage::GetNextContentId())
|
||||||
.set_id(cc::PaintImage::GetNextId())
|
.set_id(cc::PaintImage::GetNextId())
|
||||||
.set_no_cache(true)
|
.set_no_cache(true)
|
||||||
.TakePaintImage();
|
.TakePaintImage();
|
||||||
canvas->drawImage(cc_snapshot, 0, 0);
|
canvas->drawImage(snapshot_ink_inputs_.value(), 0, 0);
|
||||||
|
} else if (snapshot_ink_inputs_.has_value()) {
|
||||||
|
// Waiting on `snapshot_` to get refreshed to reflect the change for an
|
||||||
|
// added stroke, so reapply the last Ink inputs snapshot to avoid a flash
|
||||||
|
// of a recently added stroke temporarily disappearing.
|
||||||
|
canvas->drawImage(snapshot_ink_inputs_.value(), 0, 0);
|
||||||
}
|
}
|
||||||
#endif // BUILDFLAG(ENABLE_PDF_INK2)
|
#endif // BUILDFLAG(ENABLE_PDF_INK2)
|
||||||
}
|
}
|
||||||
@@ -2264,6 +2273,14 @@ void PdfViewWebPlugin::UpdateSnapshot(sk_sp<SkImage> snapshot) {
|
|||||||
.set_no_cache(true)
|
.set_no_cache(true)
|
||||||
.TakePaintImage();
|
.TakePaintImage();
|
||||||
|
|
||||||
|
#if BUILDFLAG(ENABLE_PDF_INK2)
|
||||||
|
// `paint_manager_` updates the snapshot after it has completed painting,
|
||||||
|
// which uses `engine_` in `DoPaint()`. Any newly added Ink stroke will now
|
||||||
|
// be applied in the snapshot, so there is no need to retain any prior
|
||||||
|
// `snapshot_ink_inputs_`.
|
||||||
|
snapshot_ink_inputs_.reset();
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!plugin_rect_.IsEmpty())
|
if (!plugin_rect_.IsEmpty())
|
||||||
InvalidatePluginContainer();
|
InvalidatePluginContainer();
|
||||||
}
|
}
|
||||||
|
@@ -481,6 +481,10 @@ class PdfViewWebPlugin final : public PDFiumEngineClient,
|
|||||||
const std::vector<gfx::Rect>& deferred_invalidates_for_testing() const {
|
const std::vector<gfx::Rect>& deferred_invalidates_for_testing() const {
|
||||||
return deferred_invalidates_;
|
return deferred_invalidates_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HasInkInputsSnapshotForTesting() const {
|
||||||
|
return snapshot_ink_inputs_.has_value();
|
||||||
|
}
|
||||||
#endif // BUILDFLAG(ENABLE_PDF_INK2)
|
#endif // BUILDFLAG(ENABLE_PDF_INK2)
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -768,6 +772,11 @@ class PdfViewWebPlugin final : public PDFiumEngineClient,
|
|||||||
// The current image snapshot.
|
// The current image snapshot.
|
||||||
cc::PaintImage snapshot_;
|
cc::PaintImage snapshot_;
|
||||||
|
|
||||||
|
#if BUILDFLAG(ENABLE_PDF_INK2)
|
||||||
|
// The last saved image snapshot for rendering of Ink inputs.
|
||||||
|
std::optional<cc::PaintImage> snapshot_ink_inputs_;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Translate from snapshot to device pixels.
|
// Translate from snapshot to device pixels.
|
||||||
gfx::Vector2dF snapshot_translate_;
|
gfx::Vector2dF snapshot_translate_;
|
||||||
|
|
||||||
|
@@ -3004,9 +3004,10 @@ TEST_F(PdfViewWebPluginInkTest, DrawInProgressStroke) {
|
|||||||
|
|
||||||
// Draw the canvas for the in-progress stroke.
|
// Draw the canvas for the in-progress stroke.
|
||||||
plugin_->Paint(canvas_.sk_canvas(), kScreenRect);
|
plugin_->Paint(canvas_.sk_canvas(), kScreenRect);
|
||||||
EXPECT_TRUE(MatchesPngFile(
|
const base::FilePath stroked_image_png_file =
|
||||||
canvas_.GetBitmap().asImage().get(),
|
GetInkTestDataFilePath(FILE_PATH_LITERAL("diagonal_stroke.png"));
|
||||||
GetInkTestDataFilePath(FILE_PATH_LITERAL("diagonal_stroke.png"))));
|
EXPECT_TRUE(MatchesPngFile(canvas_.GetBitmap().asImage().get(),
|
||||||
|
stroked_image_png_file));
|
||||||
|
|
||||||
// Finish the stroke. After a stroke is finished there is nothing more to
|
// Finish the stroke. After a stroke is finished there is nothing more to
|
||||||
// be drawn by PdfInkModule, as the completed stroke is provided by a
|
// be drawn by PdfInkModule, as the completed stroke is provided by a
|
||||||
@@ -3017,6 +3018,27 @@ TEST_F(PdfViewWebPluginInkTest, DrawInProgressStroke) {
|
|||||||
.CreateLeftMouseUpAtPosition(kStrokeEndingPosition)
|
.CreateLeftMouseUpAtPosition(kStrokeEndingPosition)
|
||||||
.Build(),
|
.Build(),
|
||||||
blink::WebInputEventResult::kHandledApplication);
|
blink::WebInputEventResult::kHandledApplication);
|
||||||
|
|
||||||
|
// Updating of `PdfViewWebPlugin::snapshot_` does not happen automatically
|
||||||
|
// on the invalidate call, but later after the tasks PaintManager posted have
|
||||||
|
// a chance to run. This means painting uses the last snapshot, which does
|
||||||
|
// not include the last Ink stroke. This results in the most recent stroke
|
||||||
|
// disappearing, causing a flash for the user unless the snapshot from the
|
||||||
|
// most recent stroke is reused.
|
||||||
|
EXPECT_TRUE(plugin_->HasInkInputsSnapshotForTesting());
|
||||||
|
plugin_->Paint(canvas_.sk_canvas(), kScreenRect);
|
||||||
|
EXPECT_TRUE(MatchesPngFile(canvas_.GetBitmap().asImage().get(),
|
||||||
|
stroked_image_png_file));
|
||||||
|
|
||||||
|
// Simulate how the snapshot eventually gets updated, after all necessary
|
||||||
|
// tasks that normally happen from the PaintManager finally complete. That
|
||||||
|
// results in a blank canvas here for this test, as PdfViewWebPlugin no
|
||||||
|
// longer uses the last Ink rendering snapshot for painting, and
|
||||||
|
// ApplyStroke() was mocked out so there is nothing to draw from the PDF
|
||||||
|
// engine.
|
||||||
|
plugin_->UpdateSnapshot(CreateSkiaImageForTesting(
|
||||||
|
plugin_->GetPluginRectForTesting().size(), SK_ColorWHITE));
|
||||||
|
EXPECT_FALSE(plugin_->HasInkInputsSnapshotForTesting());
|
||||||
plugin_->Paint(canvas_.sk_canvas(), kScreenRect);
|
plugin_->Paint(canvas_.sk_canvas(), kScreenRect);
|
||||||
EXPECT_TRUE(cc::MatchesBitmap(canvas_.GetBitmap(), blank_bitmap,
|
EXPECT_TRUE(cc::MatchesBitmap(canvas_.GetBitmap(), blank_bitmap,
|
||||||
cc::ExactPixelComparator()));
|
cc::ExactPixelComparator()));
|
||||||
|
Reference in New Issue
Block a user