Skip to content

Commit

Permalink
[UnifiedPDF] Support radio buttons, checkboxes, and choice annotations.
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=268196
rdar://problem/121692745

Reviewed by Simon Fraser.

Choice annotations are similar to text widget annotations, which we
already support, in that they use a PDFPluginAnnotation to support
user interaction and just commit the result to the underlying annotation
afterwards.

Radio buttons and checkboxes involve slightly more work as we must keep
track of the mouse as the user interacts with them. Holding the left
mouse button on them will create a highlight effect indicating that this
action is occuring and releasing it will trigger the effect of the
checkbox/radio button. If the mouse is dragged off while the left mouse
button is held down on it, then the highlight disappears and no effect
should occur when the button is released. In order to accomplish this,
we need to start tracking the annotation that is being interacted with
through various mouse events. m_trackedAnnotation was added for this
purpose and is updated through the various events.

* Source/WebKit/WebProcess/Plugins/PDF/UnifiedPDF/UnifiedPDFPlugin.h:
* Source/WebKit/WebProcess/Plugins/PDF/UnifiedPDF/UnifiedPDFPlugin.mm:
(WebKit::UnifiedPDFPlugin::annotationForRootViewPoint const):
(WebKit::UnifiedPDFPlugin::handleMouseEvent):
(WebKit::UnifiedPDFPlugin::startAnnotationTracking):
(WebKit::UnifiedPDFPlugin::finishAnnotationTracking):
(WebKit::UnifiedPDFPlugin::handleMouseDraggedOffTrackedAnnotation):

Canonical link: https://commits.webkit.org/273921@main
  • Loading branch information
sammygill committed Feb 1, 2024
1 parent d8b27a8 commit dceee48
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ class UnifiedPDFPlugin final : public PDFPluginBase, public WebCore::GraphicsLay

CGRect boundsForAnnotation(RetainPtr<PDFAnnotation>&) const final;
void setActiveAnnotation(RetainPtr<PDFAnnotation>&&) final;
void startAnnotationTracking(RetainPtr<PDFAnnotation>&&);
void finishAnnotationTracking();
void handleMouseDraggedOffTrackedAnnotation();
void focusNextAnnotation() final;
void focusPreviousAnnotation() final;

Expand Down Expand Up @@ -218,6 +221,7 @@ class UnifiedPDFPlugin final : public PDFPluginBase, public WebCore::GraphicsLay

WebCore::IntPoint convertFromPluginToDocument(const WebCore::IntPoint&) const;
std::optional<PDFDocumentLayout::PageIndex> pageIndexForDocumentPoint(const WebCore::IntPoint&) const;
RetainPtr<PDFAnnotation> annotationForRootViewPoint(const WebCore::IntPoint&) const;
WebCore::IntPoint convertFromDocumentToPage(const WebCore::IntPoint&, PDFDocumentLayout::PageIndex) const;
WebCore::IntPoint convertFromPageToDocument(const WebCore::IntPoint&, PDFDocumentLayout::PageIndex) const;
PDFElementTypes pdfElementTypesForPluginPoint(const WebCore::IntPoint&) const;
Expand All @@ -239,6 +243,9 @@ class UnifiedPDFPlugin final : public PDFPluginBase, public WebCore::GraphicsLay

float m_scaleFactor { 1 };
bool m_inMagnificationGesture { false };

RetainPtr<PDFAnnotation> m_trackedAnnotation;

};

} // namespace WebKit
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -832,6 +832,17 @@
return std::nullopt;
}

RetainPtr<PDFAnnotation> UnifiedPDFPlugin::annotationForRootViewPoint(const WebCore::IntPoint& point) const
{
auto pointInDocumentSpace = convertFromPluginToDocument(convertFromRootViewToPlugin(point));
auto nearestPageIndex = pageIndexForDocumentPoint(pointInDocumentSpace);
if (!nearestPageIndex)
return nullptr;

auto page = m_documentLayout.pageAtIndex(nearestPageIndex.value());
return [page annotationAtPoint:convertFromDocumentToPage(pointInDocumentSpace, nearestPageIndex.value())];
}

static AffineTransform documentSpaceToPageSpaceTransform(const IntDegrees& pageRotation, const FloatRect& pageBounds)
{
return AffineTransform::makeRotation(pageRotation).translate([&pageBounds, pageRotation] () -> FloatPoint {
Expand Down Expand Up @@ -954,8 +965,17 @@ static AffineTransform documentSpaceToPageSpaceTransform(const IntDegrees& pageR
auto altKeyIsActive = event.altKey() ? AltKeyIsActive::Yes : AltKeyIsActive::No;
auto pdfElementTypes = pdfElementTypesForPluginPoint(m_lastMousePositionInPluginCoordinates);
notifyCursorChanged(toWebCoreCursorType(pdfElementTypes, altKeyIsActive));
if (m_trackedAnnotation)
handleMouseDraggedOffTrackedAnnotation();
return true;
}
case WebMouseEventButton::Left: {
if (m_trackedAnnotation && m_trackedAnnotation != annotationForRootViewPoint(event.position())) {
handleMouseDraggedOffTrackedAnnotation();
return true;
}
return false;
}
default:
return false;
}
Expand All @@ -966,18 +986,36 @@ static AffineTransform documentSpaceToPageSpaceTransform(const IntDegrees& pageR
auto nearestPageIndex = pageIndexForDocumentPoint(pointInDocumentSpace);
if (!nearestPageIndex)
return false;

auto page = m_documentLayout.pageAtIndex(nearestPageIndex.value());
auto pointInPDFPageSpace = convertFromDocumentToPage(pointInDocumentSpace, nearestPageIndex.value());
if (auto annotation = [page annotationAtPoint:pointInPDFPageSpace]; annotation && [annotation isKindOfClass:getPDFAnnotationTextWidgetClass()]) {
setActiveAnnotation(annotation);
return true;
if (RetainPtr<PDFAnnotation> annotation = annotationForRootViewPoint(event.position())) {
if (([annotation isKindOfClass:getPDFAnnotationButtonWidgetClass()] || [annotation isKindOfClass:getPDFAnnotationTextWidgetClass()] || [annotation isKindOfClass:getPDFAnnotationChoiceWidgetClass()]) && [annotation isReadOnly])
return true;

if ([annotation isKindOfClass:getPDFAnnotationTextWidgetClass()] || [annotation isKindOfClass:getPDFAnnotationChoiceWidgetClass()]) {
setActiveAnnotation(annotation.get());
return true;
}
if ([annotation isKindOfClass:getPDFAnnotationButtonWidgetClass()]) {
startAnnotationTracking(WTFMove(annotation));
return true;
}
return false;
}
return false;
}
default:
return false;
}
case WebEventType::MouseUp:
switch (event.button()) {
case WebMouseEventButton::Left:
if (m_trackedAnnotation) {
finishAnnotationTracking();
return true;
}
return false;
default:
return false;
}
default:
return false;
}
Expand Down Expand Up @@ -1241,6 +1279,46 @@ static AffineTransform documentSpaceToPageSpaceTransform(const IntDegrees& pageR
#endif
}

void UnifiedPDFPlugin::startAnnotationTracking(RetainPtr<PDFAnnotation>&& annotation)
{
ASSERT(!m_trackedAnnotation);
m_trackedAnnotation = annotation;

if ([annotation isKindOfClass:getPDFAnnotationButtonWidgetClass()])
[annotation setHighlighted:YES];

updateLayerHierarchy();
}

void UnifiedPDFPlugin::finishAnnotationTracking()
{
ASSERT(m_trackedAnnotation);

if ([m_trackedAnnotation isHighlighted])
[m_trackedAnnotation setHighlighted:NO];

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];
else if (currentButtonState == PDFWidgetCellState::kPDFWidgetOffState)
[m_trackedAnnotation setButtonWidgetState:PDFWidgetCellState::kPDFWidgetOnState];
} else
ASSERT_NOT_IMPLEMENTED_YET();
m_trackedAnnotation = nullptr;

updateLayerHierarchy();
}

void UnifiedPDFPlugin::handleMouseDraggedOffTrackedAnnotation()
{
ASSERT(m_trackedAnnotation);

[m_trackedAnnotation setHighlighted:NO];
m_trackedAnnotation = nullptr;
updateLayerHierarchy();
}

void UnifiedPDFPlugin::attemptToUnlockPDF(const String& password)
{
}
Expand Down

0 comments on commit dceee48

Please sign in to comment.