Skip to content

Commit

Permalink
[UnifiedPDF] Add ability to start focusing next/previous text annotat…
Browse files Browse the repository at this point in the history
…ions.

https://bugs.webkit.org/show_bug.cgi?id=268349
rdar://problem/121890426

Reviewed by Simon Fraser.

When a text annotation is currently active, the user should be able
to focus the next/previous one using the appropriate keyboard shortcut.
Effectivley, what we will need to do is iterate over the annotations in
the appropriate direction until we find a text annotation that can be
interacted with (this could be the same annotation if there are no
others to be found).

We start by checking the current page the active annotation is on. If
there are any remaining annotations on the page, then we will iterate
over them to see if the next one is on the page. If we could not find an
appropriate text annotation on the page then we repeat the process by
going to the next page in the appropriate direction. This process is
repeated until we find an appropriate text annotation to return. There
should always be at least one text annotation to return: the original
one.

* Source/WebKit/WebProcess/Plugins/PDF/UnifiedPDF/UnifiedPDFPlugin.h:
* Source/WebKit/WebProcess/Plugins/PDF/UnifiedPDF/UnifiedPDFPlugin.mm:
(WebKit::findFirstTextAnnotationStartingAtIndex):
(WebKit::UnifiedPDFPlugin::nextTextAnnotation const):
(WebKit::UnifiedPDFPlugin::focusNextAnnotation):
(WebKit::UnifiedPDFPlugin::focusPreviousAnnotation):

Canonical link: https://commits.webkit.org/274337@main
  • Loading branch information
sammygill committed Feb 9, 2024
1 parent 5e7cc9e commit 3b5f856
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ class AnnotationTrackingState {

enum class WebEventModifier : uint8_t;

enum class AnnotationSearchDirection : bool {
Forward,
Backward
};
class UnifiedPDFPlugin final : public PDFPluginBase, public WebCore::GraphicsLayerClient {
public:
static Ref<UnifiedPDFPlugin> create(WebCore::HTMLPlugInElement&);
Expand All @@ -82,6 +86,9 @@ class UnifiedPDFPlugin final : public PDFPluginBase, public WebCore::GraphicsLay
void setActiveAnnotation(RetainPtr<PDFAnnotation>&&) final;
void focusNextAnnotation() final;
void focusPreviousAnnotation() final;
#if PLATFORM(MAC)
RetainPtr<PDFAnnotation> nextTextAnnotation(AnnotationSearchDirection) const;
#endif

void attemptToUnlockPDF(const String& password) final;
void windowActivityDidChange() final;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1529,13 +1529,93 @@ static IntRect computeMarqueeSelectionRect(const WebCore::IntPoint& point1, cons
return pageSpaceBounds;
}

#if PLATFORM(MAC)
static RetainPtr<PDFAnnotation> findFirstTextAnnotationStartingAtIndex(const RetainPtr<NSArray>& annotations, unsigned startingIndex, AnnotationSearchDirection searchDirection)
{
ASSERT(annotations);
if (!annotations || startingIndex >= [annotations count])
return nullptr;

auto indexRange = [&] {
if (searchDirection == AnnotationSearchDirection::Forward)
return [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(startingIndex, [annotations count] - startingIndex)];
return [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, startingIndex + 1)];
}();

auto searchResult = [annotations indexOfObjectAtIndexes:indexRange options:searchDirection == AnnotationSearchDirection::Forward ? 0 : NSEnumerationReverse passingTest:^BOOL(PDFAnnotation* annotation, NSUInteger, BOOL *) {
return [annotation isKindOfClass:getPDFAnnotationTextWidgetClass()] && ![annotation isReadOnly] && [annotation shouldDisplay];
}];

return searchResult != NSNotFound ? [annotations objectAtIndex:searchResult] : nullptr;
}

RetainPtr<PDFAnnotation> UnifiedPDFPlugin::nextTextAnnotation(AnnotationSearchDirection searchDirection) const
{
ASSERT(m_activeAnnotation);
RetainPtr currentAnnotation = m_activeAnnotation->annotation();
RetainPtr currentPage = [currentAnnotation page];
if (!currentPage)
return nullptr;

RetainPtr annotationsForCurrentPage = [currentPage annotations];
auto indexOfCurrentAnnotation = [annotationsForCurrentPage indexOfObject:currentAnnotation.get()];
ASSERT(indexOfCurrentAnnotation != NSNotFound);
if (indexOfCurrentAnnotation == NSNotFound)
return nullptr;

bool isForwardSearchDirection = searchDirection == AnnotationSearchDirection::Forward;
if ((isForwardSearchDirection && indexOfCurrentAnnotation + 1 < [annotationsForCurrentPage count]) || (!isForwardSearchDirection && indexOfCurrentAnnotation)) {
auto startingIndexForSearch = isForwardSearchDirection ? indexOfCurrentAnnotation + 1 : indexOfCurrentAnnotation - 1;
if (RetainPtr nextTextAnnotationOnCurrentPage = findFirstTextAnnotationStartingAtIndex(annotationsForCurrentPage, startingIndexForSearch, searchDirection))
return nextTextAnnotationOnCurrentPage;
}

auto indexForCurrentPage = m_documentLayout.indexForPage(currentPage);
if (!indexForCurrentPage)
return nullptr;

RetainPtr<PDFAnnotation> nextAnnotation;
auto nextPageToSearchIndex = indexForCurrentPage.value();
while (!nextAnnotation) {
auto computeNextPageToSearchIndex = [this, isForwardSearchDirection](unsigned currentPageIndex) -> unsigned {
auto pageCount = m_documentLayout.pageCount();
if (!isForwardSearchDirection && !currentPageIndex)
return pageCount - 1;
return isForwardSearchDirection ? ((currentPageIndex + 1) % pageCount) : currentPageIndex - 1;
};
nextPageToSearchIndex = computeNextPageToSearchIndex(nextPageToSearchIndex);
RetainPtr nextPage = m_documentLayout.pageAtIndex(nextPageToSearchIndex);
if (!nextPage)
return nullptr;
if (RetainPtr nextPageAnnotations = [nextPage annotations]; nextPageAnnotations && [nextPageAnnotations count])
nextAnnotation = findFirstTextAnnotationStartingAtIndex(nextPageAnnotations, isForwardSearchDirection ? 0 : [nextPageAnnotations count] - 1, searchDirection);
}
return nextAnnotation;
}
#endif

void UnifiedPDFPlugin::focusNextAnnotation()
{
#if PLATFORM(MAC)
if (!m_activeAnnotation)
return;
RetainPtr nextTextAnnotation = this->nextTextAnnotation(AnnotationSearchDirection::Forward);
if (!nextTextAnnotation || nextTextAnnotation == m_activeAnnotation->annotation())
return;
setActiveAnnotation(WTFMove(nextTextAnnotation));
#endif
}

void UnifiedPDFPlugin::focusPreviousAnnotation()
{
#if PLATFORM(MAC)
if (!m_activeAnnotation)
return;
RetainPtr previousTextAnnotation = this->nextTextAnnotation(AnnotationSearchDirection::Backward);
if (!previousTextAnnotation || previousTextAnnotation == m_activeAnnotation->annotation())
return;
setActiveAnnotation(WTFMove(previousTextAnnotation));
#endif
}

void UnifiedPDFPlugin::setActiveAnnotation(RetainPtr<PDFAnnotation>&& annotation)
Expand Down

0 comments on commit 3b5f856

Please sign in to comment.