Skip to content

Commit

Permalink
UnifiedPDF: Add instructions and icon to unlock UI
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=269345
rdar://122929864

Reviewed by Simon Fraser.

* Source/WebCore/WebCore.xcodeproj/project.pbxproj:
Export XMLNSNames.h.

* Source/WebCore/en.lproj/Localizable.strings:
* Source/WebCore/platform/LocalizedStrings.cpp:
(WebCore::pdfPasswordFormTitle):
(WebCore::pdfPasswordFormSubtitle):
(WebCore::pdfPasswordFormInvalidPasswordSubtitle):
* Source/WebCore/platform/LocalizedStrings.h:
Add some strings.

* Source/WebKit/SourcesCocoa.txt:
* Source/WebKit/WebKit.xcodeproj/project.pbxproj:
* Source/WebKit/WebProcess/Plugins/PDF/PDFPluginAnnotation.mm:
(WebKit::PDFPluginAnnotation::attach):
If a PDFPluginAnnotation subclass puts a class on its element, don't overwrite it.

* Source/WebKit/WebProcess/Plugins/PDF/PDFPluginBase.h:
Update our inline style and add some new rules for the password form.

* Source/WebKit/WebProcess/Plugins/PDF/PDFPluginPasswordField.h:
(WebKit::PDFPluginPasswordField::PDFPluginPasswordField):
* Source/WebKit/WebProcess/Plugins/PDF/PDFPluginPasswordField.mm:
(WebKit::PDFPluginPasswordField::resetField):
Add a method to clear the field.

* Source/WebKit/WebProcess/Plugins/PDF/PDFPluginTextAnnotation.h:
* Source/WebKit/WebProcess/Plugins/PDF/PDFPluginTextAnnotation.mm:
(WebKit::PDFPluginTextAnnotation::createAnnotationElement):
(WebKit::PDFPluginTextAnnotation::setValue):
Factor out setValue (and implement it in a simpler way).

* Source/WebKit/WebProcess/Plugins/PDF/UnifiedPDF/UnifiedPDFPlugin.h:
* Source/WebKit/WebProcess/Plugins/PDF/UnifiedPDF/UnifiedPDFPlugin.mm:
(WebKit::UnifiedPDFPlugin::createPasswordEntryForm):
Install the form (UnifiedPDF only) ahead of the field (used by both plugins).

(WebKit::UnifiedPDFPlugin::attemptToUnlockPDF):
If the unlock fails, clear the field and change the form's instructions to note that.

* Source/WebKit/WebProcess/Plugins/PDF/PDFPluginPasswordForm.h: Added.
* Source/WebKit/WebProcess/Plugins/PDF/PDFPluginPasswordForm.mm: Added.
Add PDFPluginPasswordForm, which vends the UI above the password entry field
for UnifiedPDF.

Canonical link: https://commits.webkit.org/274609@main
  • Loading branch information
hortont424 committed Feb 14, 2024
1 parent ba02cc6 commit 77ac337
Show file tree
Hide file tree
Showing 16 changed files with 265 additions and 32 deletions.
2 changes: 1 addition & 1 deletion Source/WebCore/WebCore.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -5842,7 +5842,7 @@
E152551516FD2350003D7ADB /* WebCoreResourceHandleAsOperationQueueDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = E152551316FD234F003D7ADB /* WebCoreResourceHandleAsOperationQueueDelegate.h */; };
E157A8E11817331C009F821D /* JSCryptoKey.h in Headers */ = {isa = PBXBuildFile; fileRef = E157A8DF1817331C009F821D /* JSCryptoKey.h */; };
E157A8E518173A3A009F821D /* CryptoKey.h in Headers */ = {isa = PBXBuildFile; fileRef = E157A8E318173A3A009F821D /* CryptoKey.h */; settings = {ATTRIBUTES = (Private, ); }; };
E15A36D71104572000B7B639 /* XMLNSNames.h in Headers */ = {isa = PBXBuildFile; fileRef = E15A36D61104572000B7B639 /* XMLNSNames.h */; };
E15A36D71104572000B7B639 /* XMLNSNames.h in Headers */ = {isa = PBXBuildFile; fileRef = E15A36D61104572000B7B639 /* XMLNSNames.h */; settings = {ATTRIBUTES = (Private, ); }; };
E15A36D91104572700B7B639 /* XMLNSNames.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E15A36D81104572700B7B639 /* XMLNSNames.cpp */; };
E15FF7D518C9553800FE4C87 /* KeypressCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = E15FF7D418C9553800FE4C87 /* KeypressCommand.h */; settings = {ATTRIBUTES = (Private, ); }; };
E164FAA318315BF400DB4E61 /* CryptoKeyRSA.h in Headers */ = {isa = PBXBuildFile; fileRef = E164FAA218315BF400DB4E61 /* CryptoKeyRSA.h */; };
Expand Down
9 changes: 9 additions & 0 deletions Source/WebCore/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -742,6 +742,9 @@
/* WKWebExtensionErrorInvalidManifestEntry description for web_accessible_resources */
"Invalid `web_accessible_resources` manifest entry." = "Invalid `web_accessible_resources` manifest entry.";

/* Message when a PDF fails to unlock with the given password */
"Invalid Password" = "Invalid Password";

/* Validation message for input form controls with a value not matching type */
"Invalid value" = "Invalid value";

Expand Down Expand Up @@ -1453,6 +1456,9 @@
/* WKErrorMalformedCredential description */
"This credential is malformed" = "This credential is malformed";

/* Title when a PDF needs a password to be unlocked */
"This document is password protected." = "This document is password protected.";

/* text that appears at the start of nearly-obsolete web pages in the form of a 'searchable index' */
"This is a searchable index. Enter search keywords: " = "This is a searchable index. Enter search keywords: ";

Expand Down Expand Up @@ -1876,6 +1882,9 @@
/* accessibility label for play button */
"play" = "play";

/* Subtitle when a PDF needs a password to be unlocked */
"Please enter the password below." = "Please enter the password below.";

/* Verb stating the action that will occur when a button is pressed, as used by accessibility */
"press" = "press";

Expand Down
15 changes: 15 additions & 0 deletions Source/WebCore/platform/LocalizedStrings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1548,4 +1548,19 @@ String genericTouchIDPromptTitle()
}
#endif // ENABLE(WEB_AUTHN)

String pdfPasswordFormTitle()
{
return WEB_UI_STRING("This document is password protected.", "Title when a PDF needs a password to be unlocked");
}

String pdfPasswordFormSubtitle()
{
return WEB_UI_STRING("Please enter the password below.", "Subtitle when a PDF needs a password to be unlocked");
}

String pdfPasswordFormInvalidPasswordSubtitle()
{
return WEB_UI_STRING("Invalid Password", "Message when a PDF fails to unlock with the given password");
}

} // namespace WebCore
4 changes: 4 additions & 0 deletions Source/WebCore/platform/LocalizedStrings.h
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,10 @@ namespace WebCore {
WEBCORE_EXPORT String contextMenuItemTitleRemoveBackground();
#endif

WEBCORE_EXPORT String pdfPasswordFormTitle();
WEBCORE_EXPORT String pdfPasswordFormSubtitle();
WEBCORE_EXPORT String pdfPasswordFormInvalidPasswordSubtitle();

#if PLATFORM(COCOA)
#define WEB_UI_STRING(string, description) WebCore::localizedString(CFSTR(string))
#define WEB_UI_STRING_KEY(string, key, description) WebCore::localizedString(CFSTR(key))
Expand Down
1 change: 1 addition & 0 deletions Source/WebKit/SourcesCocoa.txt
Original file line number Diff line number Diff line change
Expand Up @@ -688,6 +688,7 @@ WebProcess/Plugins/PDF/PDFPluginBase.mm
WebProcess/Plugins/PDF/PDFPluginAnnotation.mm
WebProcess/Plugins/PDF/PDFPluginChoiceAnnotation.mm
WebProcess/Plugins/PDF/PDFPluginPasswordField.mm
WebProcess/Plugins/PDF/PDFPluginPasswordForm.mm
WebProcess/Plugins/PDF/PDFPluginTextAnnotation.mm
WebProcess/Plugins/PDF/PDFScriptEvaluator.mm
WebProcess/Plugins/PDF/UnifiedPDF/UnifiedPDFPlugin.mm
Expand Down
4 changes: 4 additions & 0 deletions Source/WebKit/WebKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -4473,6 +4473,8 @@
2D65D194274B8E73009C4101 /* ScrollingAccelerationCurveMac.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ScrollingAccelerationCurveMac.mm; sourceTree = "<group>"; };
2D65D195274B8E84009C4101 /* ScrollingAccelerationCurve.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ScrollingAccelerationCurve.h; sourceTree = "<group>"; };
2D65D196274B8E84009C4101 /* ScrollingAccelerationCurve.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ScrollingAccelerationCurve.cpp; sourceTree = "<group>"; };
2D667CE82B7C076700F8D5A6 /* PDFPluginPasswordForm.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = PDFPluginPasswordForm.mm; path = PDF/PDFPluginPasswordForm.mm; sourceTree = "<group>"; };
2D667CE92B7C076700F8D5A6 /* PDFPluginPasswordForm.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = PDFPluginPasswordForm.h; path = PDF/PDFPluginPasswordForm.h; sourceTree = "<group>"; };
2D6B371918A967AD0042AE80 /* _WKThumbnailView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _WKThumbnailView.h; sourceTree = "<group>"; };
2D6B371A18A967AD0042AE80 /* _WKThumbnailView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = _WKThumbnailView.mm; sourceTree = "<group>"; };
2D6CD117189058A500E5A4A0 /* ViewSnapshotStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewSnapshotStore.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -15328,6 +15330,8 @@
2D2ADF0E16364D8200197E47 /* PDFPluginChoiceAnnotation.mm */,
2D429BFA1721E2BA00EC681F /* PDFPluginPasswordField.h */,
2D429BFB1721E2BA00EC681F /* PDFPluginPasswordField.mm */,
2D667CE92B7C076700F8D5A6 /* PDFPluginPasswordForm.h */,
2D667CE82B7C076700F8D5A6 /* PDFPluginPasswordForm.mm */,
2D2ADF0516362DC700197E47 /* PDFPluginTextAnnotation.h */,
2D2ADF0616362DC700197E47 /* PDFPluginTextAnnotation.mm */,
2DC2515E2AFE0E8F00EB4EC5 /* PDFScriptEvaluator.h */,
Expand Down
3 changes: 2 additions & 1 deletion Source/WebKit/WebProcess/Plugins/PDF/PDFPluginAnnotation.mm
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@
Ref element = createAnnotationElement();
m_element = element.copyRef();

element->setAttributeWithoutSynchronization(classAttr, "annotation"_s);
if (!element->hasClass())
element->setAttributeWithoutSynchronization(classAttr, "annotation"_s);
element->setAttributeWithoutSynchronization(x_apple_pdf_annotationAttr, "true"_s);
element->addEventListener(eventNames().changeEvent, *m_eventListener, false);
element->addEventListener(eventNames().blurEvent, *m_eventListener, false);
Expand Down
77 changes: 53 additions & 24 deletions Source/WebKit/WebProcess/Plugins/PDF/PDFPluginBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -358,31 +358,60 @@ class PDFPluginBase : public ThreadSafeRefCountedAndCanMakeThreadSafeWeakPtr<PDF
// will break rubber-banding.
static constexpr auto annotationStyle =
"#annotationContainer {"
" overflow: hidden; "
" position: absolute; "
" pointer-events: none; "
" top: 0; "
" left: 0; "
" right: 0; "
" bottom: 0; "
" display: -webkit-box; "
" -webkit-box-align: center; "
" -webkit-box-pack: center; "
"} "
".annotation { "
" position: absolute; "
" pointer-events: auto; "
"} "
" overflow: hidden;"
" position: absolute;"
" pointer-events: none;"
" top: 0;"
" left: 0;"
" right: 0;"
" bottom: 0;"
" display: flex;"
" flex-direction: column;"
" justify-content: center;"
" align-items: center;"
"}"
""
".annotation {"
" position: absolute;"
" pointer-events: auto;"
"}"
""
"textarea.annotation { "
" resize: none; "
"} "
"input.annotation[type='password'] { "
" position: static; "
" width: 238px; "
" height: 20px; "
" margin-top: 110px; "
" font-size: 15px; "
"} "_s;
" resize: none;"
"}"
""
"input.annotation[type='password'] {"
" position: static;"
" width: 238px;"
" margin-top: 110px;"
" font-size: 15px;"
"}"
""
".lock-icon {"
" width: 64px;"
" height: 64px;"
" margin-bottom: 12px;"
"}"
""
".password-form {"
" position: static;"
" display: block;"
" text-align: center;"
" font-family: system-ui;"
" font-size: 15px;"
"}"
""
".password-form p {"
" margin: 4pt;"
"}"
""
".password-form .subtitle {"
" font-size: 12px;"
"}"
""
".password-form + input.annotation[type='password'] {"
" margin-top: 16px;"
"}"_s;
};

} // namespace WebKit
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,11 @@ class PDFPluginPasswordField : public PDFPluginTextAnnotation {

void updateGeometry() override;

void resetField();

private:
PDFPluginPasswordField(PDFPluginBase* plugin)
: PDFPluginTextAnnotation(0, plugin)
: PDFPluginTextAnnotation(nullptr, plugin)
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@

void PDFPluginPasswordField::updateGeometry()
{
// Intentionally do not call the superclass.
}

bool PDFPluginPasswordField::handleEvent(WebCore::Event& event)
Expand All @@ -77,6 +78,11 @@

return false;
}

void PDFPluginPasswordField::resetField()
{
setValue(""_s);
}

} // namespace WebKit

Expand Down
56 changes: 56 additions & 0 deletions Source/WebKit/WebProcess/Plugins/PDF/PDFPluginPasswordForm.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright (C) 2024 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/

#pragma once

#if PLATFORM(MAC)

#include "PDFPluginAnnotation.h"

namespace WebKit {

class PDFPluginPasswordForm : public PDFPluginAnnotation {
public:
static Ref<PDFPluginPasswordForm> create(PDFPluginBase*);
virtual ~PDFPluginPasswordForm();

void updateGeometry() override;

void unlockFailed();

private:
PDFPluginPasswordForm(PDFPluginBase* plugin)
: PDFPluginAnnotation(nullptr, plugin)
{
}

Ref<WebCore::Element> createAnnotationElement() override;

RefPtr<WebCore::Element> m_subtitleElement;
};

} // namespace WebKit

#endif // PLATFORM(MAC)
91 changes: 91 additions & 0 deletions Source/WebKit/WebProcess/Plugins/PDF/PDFPluginPasswordForm.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Copyright (C) 2024 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/

#import "config.h"
#import "PDFPluginPasswordForm.h"

#if PLATFORM(MAC)

#import <WebCore/ElementInlines.h>
#import <WebCore/HTMLElement.h>
#import <WebCore/SVGNames.h>
#import <WebCore/XMLNSNames.h>

namespace WebKit {
using namespace WebCore;
using namespace HTMLNames;
using namespace SVGNames;
using namespace XMLNSNames;

Ref<PDFPluginPasswordForm> PDFPluginPasswordForm::create(PDFPluginBase* plugin)
{
return adoptRef(*new PDFPluginPasswordForm(plugin));
}

PDFPluginPasswordForm::~PDFPluginPasswordForm() = default;

Ref<Element> PDFPluginPasswordForm::createAnnotationElement()
{
Ref document = parent()->document();
Ref element = downcast<StyledElement>(document->createElement(divTag, false));
element->setAttributeWithoutSynchronization(classAttr, "password-form"_s);

auto iconElement = document->createElement(svgTag, false);
iconElement->setAttributeWithoutSynchronization(classAttr, "lock-icon"_s);
iconElement->setAttributeWithoutSynchronization(xmlnsAttr, "http://www.w3.org/2000/svg"_s);
iconElement->setAttributeWithoutSynchronization(viewBoxAttr, "0 -10 106.51 106.51"_s);
element->appendChild(iconElement);

auto iconPathElement = document->createElement(pathTag, false);
iconPathElement->setAttributeWithoutSynchronization(dAttr, "M30.898 91.338H75.599C82.77 91.338 86.57 87.454 86.57 79.725V46.13C86.57 38.442 82.77 34.558 75.6 34.558H30.898C23.738 34.558 19.938 38.442 19.938 46.13V79.725C19.938 87.454 23.738 91.338 30.898 91.338ZM31.166 84.002C29.084 84.002 27.813 82.678 27.813 80.263V45.592C27.813 43.177 29.083 41.894 31.166 41.894H75.34C77.465 41.894 78.695 43.177 78.695 45.592V80.263C78.695 82.678 77.465 84.002 75.34 84.002ZM28.516 38.309H36.237V21.845C36.236 9.505 44.13 2.984 53.228 2.984 62.356 2.984 70.312 9.504 70.312 21.844V38.31H78.032V22.899C78.032 4.5 66.025-4.351 53.228-4.351 40.47-4.352 28.517 4.5 28.517 22.9Z"_s);
iconPathElement->setAttributeWithoutSynchronization(fillAttr, "#4B4B4B"_s);
iconElement->appendChild(iconPathElement);

auto titleElement = document->createElement(pTag, false);
titleElement->setTextContent(pdfPasswordFormTitle());
titleElement->setAttributeWithoutSynchronization(classAttr, "title"_s);
element->appendChild(titleElement);

m_subtitleElement = document->createElement(pTag, false);
m_subtitleElement->setTextContent(pdfPasswordFormSubtitle());
m_subtitleElement->setAttributeWithoutSynchronization(classAttr, "subtitle"_s);
element->appendChild(*m_subtitleElement);

return element;
}

void PDFPluginPasswordForm::unlockFailed()
{
m_subtitleElement->setTextContent(pdfPasswordFormInvalidPasswordSubtitle());
}

void PDFPluginPasswordForm::updateGeometry()
{
// Intentionally do not call the superclass.
}

} // namespace WebKit

#endif // PLATFORM(MAC)
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ class PDFPluginTextAnnotation : public PDFPluginAnnotation {
void updateGeometry() override;
void commit() override;

void setValue(const String&);

protected:
PDFPluginTextAnnotation(PDFAnnotation *annotation, PDFPluginBase* plugin)
: PDFPluginAnnotation(annotation, plugin)
Expand Down
Loading

0 comments on commit 77ac337

Please sign in to comment.