Skip to content

Commit

Permalink
[UnifiedPDF] Determine what kind of repaint a given annotation change…
Browse files Browse the repository at this point in the history
… requires

https://bugs.webkit.org/show_bug.cgi?id=269623
rdar://123120061

Reviewed by Sammy Gill.

Some annotation changes, like the blue textfield hover, only require us to repaint
the hover overlay. Others, like checkboxes and radio buttons, require a regeneration
of the cached tiles.

To distinguish between these, change `ShouldRepaint` into `RepaintRequirement`
which is used in an OptionSet<>. Pass this to `setNeedsRepaintInDocumentRect()`
and have it invalidate the tiles only when necessary.

Implement `repaintRequirementsForAnnotation()` so we know what kinds of repaint
a given annotation requires.

* Source/WebKit/WebProcess/Plugins/PDF/UnifiedPDF/UnifiedPDFPlugin.h:
* Source/WebKit/WebProcess/Plugins/PDF/UnifiedPDF/UnifiedPDFPlugin.mm:
(WebKit::UnifiedPDFPlugin::setNeedsRepaintInDocumentRect):
(WebKit::UnifiedPDFPlugin::handleMouseEvent):
(WebKit::UnifiedPDFPlugin::repaintRequirementsForAnnotation):
(WebKit::UnifiedPDFPlugin::startTrackingAnnotation):
(WebKit::UnifiedPDFPlugin::finishTrackingAnnotation):
(WebKit::UnifiedPDFPlugin::setActiveAnnotation):
(WebKit::AnnotationTrackingState::startAnnotationTracking):
(WebKit::AnnotationTrackingState::finishAnnotationTracking):
(WebKit::UnifiedPDFPlugin::setPDFChangedInDocumentRect): Deleted.
(WebKit::AnnotationTrackingState::handleMouseDraggedOffTrackedAnnotation): Deleted. It was just a one-liner.

Canonical link: https://commits.webkit.org/274911@main
  • Loading branch information
smfr committed Feb 17, 2024
1 parent 5f1ac64 commit 40fc435
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 52 deletions.
17 changes: 11 additions & 6 deletions Source/WebKit/WebProcess/Plugins/PDF/UnifiedPDF/UnifiedPDFPlugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,18 +58,21 @@ enum class WebEventType : uint8_t;
enum class WebMouseEventButton : int8_t;
enum class WebEventModifier : uint8_t;

enum class ShouldRepaint : bool { No, Yes };
enum class RepaintRequirement : uint8_t {
PDFContent = 1 << 0,
Selection = 1 << 1,
HoverOverlay = 1 << 2
};

class AnnotationTrackingState {
public:
ShouldRepaint startAnnotationTracking(RetainPtr<PDFAnnotation>&&, WebEventType, WebMouseEventButton);
ShouldRepaint finishAnnotationTracking(WebEventType, WebMouseEventButton);
OptionSet<RepaintRequirement> startAnnotationTracking(RetainPtr<PDFAnnotation>&&, WebEventType, WebMouseEventButton);
OptionSet<RepaintRequirement> finishAnnotationTracking(WebEventType, WebMouseEventButton);

PDFAnnotation *trackedAnnotation() const { return m_trackedAnnotation.get(); }
bool isBeingHovered() const;

private:
void handleMouseDraggedOffTrackedAnnotation();
void resetAnnotationTrackingState();

RetainPtr<PDFAnnotation> m_trackedAnnotation;
Expand Down Expand Up @@ -107,6 +110,8 @@ class UnifiedPDFPlugin final : public PDFPluginBase, public WebCore::GraphicsLay
RetainPtr<PDFAnnotation> nextTextAnnotation(AnnotationSearchDirection) const;
void handlePDFActionForAnnotation(PDFAnnotation *, unsigned currentPageIndex);
#endif
enum class IsAnnotationCommit : bool { No, Yes };
static OptionSet<RepaintRequirement> repaintRequirementsForAnnotation(PDFAnnotation *, IsAnnotationCommit = IsAnnotationCommit::No);

void attemptToUnlockPDF(const String& password) final;
void windowActivityDidChange() final;
Expand Down Expand Up @@ -363,11 +368,11 @@ class UnifiedPDFPlugin final : public PDFPluginBase, public WebCore::GraphicsLay
void followLinkAnnotation(PDFAnnotation *);

void startTrackingAnnotation(RetainPtr<PDFAnnotation>&&, WebEventType, WebMouseEventButton);
void finishTrackingAnnotation(WebEventType, WebMouseEventButton);
void finishTrackingAnnotation(WebEventType, WebMouseEventButton, OptionSet<RepaintRequirement> = { });

RefPtr<WebCore::GraphicsLayer> createGraphicsLayer(const String& name, WebCore::GraphicsLayer::Type);

void setPDFChangedInDocumentRect(const WebCore::FloatRect&);
void setNeedsRepaintInDocumentRect(OptionSet<RepaintRequirement>, const WebCore::FloatRect&);

WebCore::IntPoint convertFromRootViewToDocument(const WebCore::IntPoint&) const;
WebCore::IntPoint convertFromPluginToDocument(const WebCore::IntPoint&) const;
Expand Down
106 changes: 60 additions & 46 deletions Source/WebKit/WebProcess/Plugins/PDF/UnifiedPDF/UnifiedPDFPlugin.mm
Original file line number Diff line number Diff line change
Expand Up @@ -278,16 +278,21 @@ static String mutationObserverNotificationString()
return graphicsLayer;
}

void UnifiedPDFPlugin::setPDFChangedInDocumentRect(const FloatRect& rectInDocumentCoordinates)
void UnifiedPDFPlugin::setNeedsRepaintInDocumentRect(OptionSet<RepaintRequirement> repaintRequirements, const FloatRect& rectInDocumentCoordinates)
{
auto paintintRect = rectInDocumentCoordinates;
if (!repaintRequirements)
return;

auto paintingRect = rectInDocumentCoordinates;
// FIXME: Use some flavor of convertFromDocumentToContents() once we untangle the coordinate systems.
paintintRect.scale(m_documentLayout.scale());
paintingRect.scale(m_documentLayout.scale());

if (RefPtr asyncRenderer = asyncRendererIfExists())
asyncRenderer->invalidateTilesForPaintingRect(m_scaleFactor, paintintRect);
if (repaintRequirements.contains(RepaintRequirement::PDFContent)) {
if (RefPtr asyncRenderer = asyncRendererIfExists())
asyncRenderer->invalidateTilesForPaintingRect(m_scaleFactor, paintingRect);
}

RefPtr { m_contentsLayer }->setNeedsDisplayInRect(paintintRect);
RefPtr { m_contentsLayer }->setNeedsDisplayInRect(paintingRect);
}

void UnifiedPDFPlugin::scheduleRenderingUpdate()
Expand Down Expand Up @@ -1692,7 +1697,7 @@ static bool isContextMenuEvent(const WebMouseEvent& event)

RetainPtr annotationUnderMouse = annotationForRootViewPoint(event.position());
if (auto* currentTrackedAnnotation = m_annotationTrackingState.trackedAnnotation(); (currentTrackedAnnotation && currentTrackedAnnotation != annotationUnderMouse) || (currentTrackedAnnotation && !m_annotationTrackingState.isBeingHovered()))
finishTrackingAnnotation(mouseEventType, mouseEventButton);
finishTrackingAnnotation(mouseEventType, mouseEventButton, RepaintRequirement::HoverOverlay);

if (!m_annotationTrackingState.trackedAnnotation() && annotationUnderMouse && [annotationUnderMouse isKindOfClass:getPDFAnnotationTextWidgetClass()])
startTrackingAnnotation(WTFMove(annotationUnderMouse), mouseEventType, mouseEventButton);
Expand All @@ -1702,7 +1707,7 @@ static bool isContextMenuEvent(const WebMouseEvent& event)
case WebMouseEventButton::Left: {
if (RetainPtr trackedAnnotation = m_annotationTrackingState.trackedAnnotation(); trackedAnnotation && trackedAnnotation != annotationForRootViewPoint(event.position())) {
notifyCursorChanged(toWebCoreCursorType({ }));
finishTrackingAnnotation(mouseEventType, mouseEventButton);
finishTrackingAnnotation(mouseEventType, mouseEventButton, RepaintRequirement::HoverOverlay);
return true;
}

Expand Down Expand Up @@ -1820,6 +1825,25 @@ static bool isContextMenuEvent(const WebMouseEvent& event)
scrollToPDFDestination(destination);
}

OptionSet<RepaintRequirement> UnifiedPDFPlugin::repaintRequirementsForAnnotation(PDFAnnotation *annotation, IsAnnotationCommit isAnnotationCommit)
{
if ([annotation isKindOfClass:getPDFAnnotationButtonWidgetClass()])
return RepaintRequirement::PDFContent;

if ([annotation isKindOfClass:getPDFAnnotationPopupClass()])
return RepaintRequirement::PDFContent;

if ([annotation isKindOfClass:getPDFAnnotationTextClass()])
return RepaintRequirement::PDFContent;

if ([annotation isKindOfClass:getPDFAnnotationTextWidgetClass()])
return isAnnotationCommit == IsAnnotationCommit::Yes ? RepaintRequirement::PDFContent : RepaintRequirement::HoverOverlay;

// No visual feedback for getPDFAnnotationLinkClass at this time.

return { };
}

WebCore::FloatRect UnifiedPDFPlugin::documentRectForAnnotation(PDFAnnotation *annotation) const
{
if (!annotation)
Expand All @@ -1835,21 +1859,18 @@ static bool isContextMenuEvent(const WebMouseEvent& event)

void UnifiedPDFPlugin::startTrackingAnnotation(RetainPtr<PDFAnnotation>&& annotation, WebEventType mouseEventType, WebMouseEventButton mouseEventButton)
{
// FIXME: We need to distinguish betwene annoation changes that affect PDF tiles, and those that are just painted overlays.
auto repaint = m_annotationTrackingState.startAnnotationTracking(WTFMove(annotation), mouseEventType, mouseEventButton);
if (repaint == ShouldRepaint::Yes) {
auto repaintRequirements = m_annotationTrackingState.startAnnotationTracking(WTFMove(annotation), mouseEventType, mouseEventButton);
if (repaintRequirements) {
auto annotationRect = documentRectForAnnotation(m_annotationTrackingState.trackedAnnotation());
setPDFChangedInDocumentRect(annotationRect);
setNeedsRepaintInDocumentRect(repaintRequirements, annotationRect);
}
}

void UnifiedPDFPlugin::finishTrackingAnnotation(WebEventType mouseEventType, WebMouseEventButton mouseEventButton)
void UnifiedPDFPlugin::finishTrackingAnnotation(WebEventType mouseEventType, WebMouseEventButton mouseEventButton, OptionSet<RepaintRequirement> repaintRequirements)
{
// FIXME: We need to distinguish betwene annoation changes that affect PDF tiles, and those that are just painted overlays.
auto annotationRect = documentRectForAnnotation(m_annotationTrackingState.trackedAnnotation());
auto repaint = m_annotationTrackingState.finishAnnotationTracking(mouseEventType, mouseEventButton);
if (repaint == ShouldRepaint::Yes)
setPDFChangedInDocumentRect(annotationRect);
repaintRequirements.add(m_annotationTrackingState.finishAnnotationTracking(mouseEventType, mouseEventButton));
setNeedsRepaintInDocumentRect(repaintRequirements, annotationRect);
}

void UnifiedPDFPlugin::scrollToPDFDestination(PDFDestination *destination)
Expand Down Expand Up @@ -2921,24 +2942,23 @@ static NSStringCompareOptions compareOptionsForFindOptions(WebCore::FindOptions
if (!supportsForms())
return;

if (m_activeAnnotation)
if (m_activeAnnotation) {
m_activeAnnotation->commit();

auto annotationRect = documentRectForAnnotation(m_activeAnnotation->annotation());
setNeedsRepaintInDocumentRect(repaintRequirementsForAnnotation(m_activeAnnotation->annotation(), IsAnnotationCommit::Yes), annotationRect);
}

if (annotation) {
ALLOW_DEPRECATED_DECLARATIONS_BEGIN
if ([annotation isKindOfClass:getPDFAnnotationTextWidgetClass()] && static_cast<PDFAnnotationTextWidget *>(annotation).isReadOnly) {
if ([annotation isKindOfClass:getPDFAnnotationTextWidgetClass()] && [annotation isReadOnly]) {
m_activeAnnotation = nullptr;
return;
}
ALLOW_DEPRECATED_DECLARATIONS_END

auto activeAnnotation = PDFPluginAnnotation::create(annotation.get(), this);
m_activeAnnotation = activeAnnotation.get();
activeAnnotation->attach(m_annotationContainer.get());
m_activeAnnotation = PDFPluginAnnotation::create(annotation.get(), this);
m_activeAnnotation->attach(m_annotationContainer.get());
} else
m_activeAnnotation = nullptr;

updateLayerHierarchy();
#endif
}

Expand Down Expand Up @@ -3009,62 +3029,56 @@ static NSStringCompareOptions compareOptionsForFindOptions(WebCore::FindOptions
}
#endif

ShouldRepaint AnnotationTrackingState::startAnnotationTracking(RetainPtr<PDFAnnotation>&& annotation, WebEventType mouseEventType, WebMouseEventButton mouseEventButton)
OptionSet<RepaintRequirement> AnnotationTrackingState::startAnnotationTracking(RetainPtr<PDFAnnotation>&& annotation, WebEventType mouseEventType, WebMouseEventButton mouseEventButton)
{
ASSERT(!m_trackedAnnotation);
m_trackedAnnotation = WTFMove(annotation);

auto needsRepaint = ShouldRepaint::No;
auto repaintRequirements = OptionSet<RepaintRequirement> { };

if ([m_trackedAnnotation isKindOfClass:getPDFAnnotationButtonWidgetClass()]) {
[m_trackedAnnotation setHighlighted:YES];
needsRepaint = ShouldRepaint::Yes;
repaintRequirements.add(UnifiedPDFPlugin::repaintRequirementsForAnnotation(m_trackedAnnotation.get()));
}

if (mouseEventType == WebEventType::MouseMove && mouseEventButton == WebMouseEventButton::None) {
if (!m_isBeingHovered)
needsRepaint = ShouldRepaint::Yes;
repaintRequirements.add(RepaintRequirement::HoverOverlay);

m_isBeingHovered = true;
}

return needsRepaint;
return repaintRequirements;
}

ShouldRepaint AnnotationTrackingState::finishAnnotationTracking(WebEventType mouseEventType, WebMouseEventButton mouseEventButton)
OptionSet<RepaintRequirement> AnnotationTrackingState::finishAnnotationTracking(WebEventType mouseEventType, WebMouseEventButton mouseEventButton)
{
ASSERT(m_trackedAnnotation);
auto needsRepaint = ShouldRepaint::No;
auto repaintRequirements = OptionSet<RepaintRequirement> { };

if (mouseEventType == WebEventType::MouseUp && mouseEventButton == WebMouseEventButton::Left) {
if ([m_trackedAnnotation isHighlighted]) {
[m_trackedAnnotation setHighlighted:NO];

needsRepaint = ShouldRepaint::Yes;
repaintRequirements.add(UnifiedPDFPlugin::repaintRequirementsForAnnotation(m_trackedAnnotation.get()));
}

if ([m_trackedAnnotation isKindOfClass:getPDFAnnotationButtonWidgetClass()] && [m_trackedAnnotation widgetControlType] != kPDFWidgetPushButtonControl) {
auto currentButtonState = [m_trackedAnnotation buttonWidgetState];
if (currentButtonState == PDFWidgetCellState::kPDFWidgetOnState && [m_trackedAnnotation allowsToggleToOff]) {
[m_trackedAnnotation setButtonWidgetState:PDFWidgetCellState::kPDFWidgetOffState];
needsRepaint = ShouldRepaint::Yes;
repaintRequirements.add(RepaintRequirement::PDFContent);
} else if (currentButtonState == PDFWidgetCellState::kPDFWidgetOffState) {
[m_trackedAnnotation setButtonWidgetState:PDFWidgetCellState::kPDFWidgetOnState];
needsRepaint = ShouldRepaint::Yes;
repaintRequirements.add(RepaintRequirement::PDFContent);
}
}
} else if (mouseEventType == WebEventType::MouseMove && mouseEventButton == WebMouseEventButton::Left) {
handleMouseDraggedOffTrackedAnnotation();
needsRepaint = ShouldRepaint::Yes;
[m_trackedAnnotation setHighlighted:NO];
repaintRequirements.add(UnifiedPDFPlugin::repaintRequirementsForAnnotation(m_trackedAnnotation.get()));
}

resetAnnotationTrackingState();
return needsRepaint;
}

void AnnotationTrackingState::handleMouseDraggedOffTrackedAnnotation()
{
ASSERT(m_trackedAnnotation);
[m_trackedAnnotation setHighlighted:NO];
return repaintRequirements;
}

bool AnnotationTrackingState::isBeingHovered() const
Expand Down

0 comments on commit 40fc435

Please sign in to comment.