Make it possible to add a border around loading or failed-to-load images
authortimothy_horton@apple.com <timothy_horton@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 23 Jun 2018 00:52:56 +0000 (00:52 +0000)
committertimothy_horton@apple.com <timothy_horton@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 23 Jun 2018 00:52:56 +0000 (00:52 +0000)
https://bugs.webkit.org/show_bug.cgi?id=186614
<rdar://problem/39050152>

Reviewed by Zalan Bujtas.

Source/WebCore:

Tests: http/tests/images/loading-image-border.html
       http/tests/images/loading-image-no-border.html

* rendering/RenderImage.cpp:
(WebCore::RenderImage::paintIncompleteImageOutline):
(WebCore::RenderImage::paintReplaced):
* rendering/RenderImage.h:
Factor the missing-image outline out, and - if desired - paint it in
cases where the image is still loading or otherwise pending, not just
when the image fails to load.

* page/Settings.yaml:
* testing/InternalSettings.cpp:
(WebCore::InternalSettings::Backup::Backup):
(WebCore::InternalSettings::Backup::restoreTo):
(WebCore::InternalSettings::setIncompleteImageBorderEnabled):
* testing/InternalSettings.h:
* testing/InternalSettings.idl:
Add and expose a setting to enable the feature.

Source/WebKit:

* Shared/WebPreferences.yaml:
* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView _initializeWithConfiguration:]):
* UIProcess/API/Cocoa/WKWebViewConfiguration.mm:
(-[WKWebViewConfiguration init]):
(-[WKWebViewConfiguration copyWithZone:]):
(-[WKWebViewConfiguration _setColorFilterEnabled:]):
(-[WKWebViewConfiguration _incompleteImageBorderEnabled]):
(-[WKWebViewConfiguration _setIncompleteImageBorderEnabled:]):
* UIProcess/API/Cocoa/WKWebViewConfigurationPrivate.h:
Plumb the setting to WebKit2.

LayoutTests:

* http/tests/images/loading-image-border-expected.html: Added.
* http/tests/images/loading-image-border.html: Added.
* http/tests/images/loading-image-no-border-expected.html: Added.
* http/tests/images/loading-image-no-border.html: Added.
* platform/wk2/TestExpectations:
Add a test ensuring that the setting works correctly.
These and similar tests do not currently work in WebKitTestRunner, so they are skipped there.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@233115 268f45cc-cd09-0410-ab3c-d52691b4dbfc

18 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/images/loading-image-border-expected.html [new file with mode: 0644]
LayoutTests/http/tests/images/loading-image-border.html [new file with mode: 0644]
LayoutTests/http/tests/images/loading-image-no-border-expected.html [new file with mode: 0644]
LayoutTests/http/tests/images/loading-image-no-border.html [new file with mode: 0644]
LayoutTests/platform/wk2/TestExpectations
Source/WebCore/ChangeLog
Source/WebCore/page/Settings.yaml
Source/WebCore/rendering/RenderImage.cpp
Source/WebCore/rendering/RenderImage.h
Source/WebCore/testing/InternalSettings.cpp
Source/WebCore/testing/InternalSettings.h
Source/WebCore/testing/InternalSettings.idl
Source/WebKit/ChangeLog
Source/WebKit/Shared/WebPreferences.yaml
Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm
Source/WebKit/UIProcess/API/Cocoa/WKWebViewConfiguration.mm
Source/WebKit/UIProcess/API/Cocoa/WKWebViewConfigurationPrivate.h

index 681d22e..4debac0 100644 (file)
@@ -1,3 +1,19 @@
+2018-06-22  Tim Horton  <timothy_horton@apple.com>
+
+        Make it possible to add a border around loading or failed-to-load images
+        https://bugs.webkit.org/show_bug.cgi?id=186614
+        <rdar://problem/39050152>
+
+        Reviewed by Zalan Bujtas.
+
+        * http/tests/images/loading-image-border-expected.html: Added.
+        * http/tests/images/loading-image-border.html: Added.
+        * http/tests/images/loading-image-no-border-expected.html: Added.
+        * http/tests/images/loading-image-no-border.html: Added.
+        * platform/wk2/TestExpectations:
+        Add a test ensuring that the setting works correctly.
+        These and similar tests do not currently work in WebKitTestRunner, so they are skipped there.
+
 2018-06-22  Ross Kirsling  <ross.kirsling@sony.com>
 
         [WinCairo] Unreviewed test gardening.
diff --git a/LayoutTests/http/tests/images/loading-image-border-expected.html b/LayoutTests/http/tests/images/loading-image-border-expected.html
new file mode 100644 (file)
index 0000000..aa00d3f
--- /dev/null
@@ -0,0 +1,6 @@
+<body>
+    <img src="broken-image.png"  width="500px" height="500px">
+
+    <!-- Cover up the broken image icon (but not the border) to make this match the not-loaded state -->
+    <div style="width: 100px; height: 100px; position: absolute; top: 200px; left: 200px; background-color: white;">
+</body>
diff --git a/LayoutTests/http/tests/images/loading-image-border.html b/LayoutTests/http/tests/images/loading-image-border.html
new file mode 100644 (file)
index 0000000..9f1dd6f
--- /dev/null
@@ -0,0 +1,14 @@
+<body>
+    <img id="img" width="500px" height="500px">
+    <script>
+        internals.settings.setIncompleteImageBorderEnabled(true);
+
+        setTimeout(function () {
+            img.src = "http://127.0.0.1:8000/resources/load-and-stall.php?name=../../../fast/images/resources/green-400x400.png&mimeType=image%2Fpng&stallAt=0&stallFor=100";
+
+            testRunner.notifyDone();
+        }, 0);
+
+        testRunner.waitUntilDone();
+    </script>
+</body>
diff --git a/LayoutTests/http/tests/images/loading-image-no-border-expected.html b/LayoutTests/http/tests/images/loading-image-no-border-expected.html
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/LayoutTests/http/tests/images/loading-image-no-border.html b/LayoutTests/http/tests/images/loading-image-no-border.html
new file mode 100644 (file)
index 0000000..cec5494
--- /dev/null
@@ -0,0 +1,14 @@
+<body>
+    <img id="img" width="500px" height="500px">
+    <script>
+        internals.settings.setIncompleteImageBorderEnabled(false);
+
+        setTimeout(function () {
+            img.src = "http://127.0.0.1:8000/resources/load-and-stall.php?name=../../../fast/images/resources/green-400x400.png&mimeType=image%2Fpng&stallAt=0&stallFor=100";
+
+            testRunner.notifyDone();
+        }, 0);
+
+        testRunner.waitUntilDone();
+    </script>
+</body>
index b87ddb0..117a2ff 100644 (file)
@@ -199,6 +199,11 @@ http/tests/download/default-encoding.html
 http/tests/download/inherited-encoding-form-submission-result.html
 http/tests/download/inherited-encoding.html
 
+# Incomplete-image tests fail in WebKitTestRunner
+# https://bugs.webkit.org/show_bug.cgi?id=186613
+http/tests/images/loading-image-border.html
+http/tests/images/loading-image-no-border.html
+
 ### END OF (1) Classified failures with bug reports
 ########################################
 
index 8b6aeed..e1e781b 100644 (file)
@@ -1,3 +1,31 @@
+2018-06-22  Tim Horton  <timothy_horton@apple.com>
+
+        Make it possible to add a border around loading or failed-to-load images
+        https://bugs.webkit.org/show_bug.cgi?id=186614
+        <rdar://problem/39050152>
+
+        Reviewed by Zalan Bujtas.
+
+        Tests: http/tests/images/loading-image-border.html
+               http/tests/images/loading-image-no-border.html
+
+        * rendering/RenderImage.cpp:
+        (WebCore::RenderImage::paintIncompleteImageOutline):
+        (WebCore::RenderImage::paintReplaced):
+        * rendering/RenderImage.h:
+        Factor the missing-image outline out, and - if desired - paint it in
+        cases where the image is still loading or otherwise pending, not just
+        when the image fails to load.
+
+        * page/Settings.yaml:
+        * testing/InternalSettings.cpp:
+        (WebCore::InternalSettings::Backup::Backup):
+        (WebCore::InternalSettings::Backup::restoreTo):
+        (WebCore::InternalSettings::setIncompleteImageBorderEnabled):
+        * testing/InternalSettings.h:
+        * testing/InternalSettings.idl:
+        Add and expose a setting to enable the feature.
+
 2018-06-22  Brady Eidson  <beidson@apple.com>
 
         WKURLSchemeHandler doesn't handle sync XHR.
index dd9ed86..c1c41b3 100644 (file)
@@ -750,3 +750,6 @@ crossOriginWindowPolicySupportEnabled:
 accessibilityEventsEnabled:
   initial: true
   conditional: ACCESSIBILITY_EVENTS
+
+incompleteImageBorderEnabled:
+  initial: false
index 1264152..04aa7b8 100644 (file)
@@ -379,12 +379,32 @@ bool RenderImage::hasNonBitmapImage() const
     return image && !is<BitmapImage>(image);
 }
 
+void RenderImage::paintIncompleteImageOutline(PaintInfo& paintInfo, LayoutPoint paintOffset, LayoutUnit borderWidth) const
+{
+    auto contentSize = this->contentSize();
+    if (contentSize.width() <= 2 || contentSize.height() <= 2)
+        return;
+
+    auto leftBorder = borderLeft();
+    auto topBorder = borderTop();
+    auto leftPadding = paddingLeft();
+    auto topPadding = paddingTop();
+
+    // Draw an outline rect where the image should be.
+    GraphicsContext& context = paintInfo.context();
+    context.setStrokeStyle(SolidStroke);
+    context.setStrokeColor(Color::lightGray);
+    context.setFillColor(Color::transparent);
+    context.drawRect(snapRectToDevicePixels(LayoutRect({ paintOffset.x() + leftBorder + leftPadding, paintOffset.y() + topBorder + topPadding }, contentSize), document().deviceScaleFactor()), borderWidth);
+}
+
 void RenderImage::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
 {
-    LayoutSize contentSize = this->contentSize();
+    auto contentSize = this->contentSize();
 
     GraphicsContext& context = paintInfo.context();
     float deviceScaleFactor = document().deviceScaleFactor();
+    LayoutUnit missingImageBorderWidth(1 / deviceScaleFactor);
 
     if (!imageResource().cachedImage() || imageResource().errorOccurred()) {
         if (paintInfo.phase == PaintPhaseSelection)
@@ -393,31 +413,25 @@ void RenderImage::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOf
         if (paintInfo.phase == PaintPhaseForeground)
             page().addRelevantUnpaintedObject(this, visualOverflowRect());
 
-        if (contentSize.width() > 2 && contentSize.height() > 2) {
-            LayoutUnit borderWidth = LayoutUnit(1 / deviceScaleFactor);
+        paintIncompleteImageOutline(paintInfo, paintOffset, missingImageBorderWidth);
 
+        if (contentSize.width() > 2 && contentSize.height() > 2) {
             LayoutUnit leftBorder = borderLeft();
             LayoutUnit topBorder = borderTop();
             LayoutUnit leftPad = paddingLeft();
             LayoutUnit topPad = paddingTop();
 
-            // Draw an outline rect where the image should be.
-            context.setStrokeStyle(SolidStroke);
-            context.setStrokeColor(Color::lightGray);
-            context.setFillColor(Color::transparent);
-            context.drawRect(snapRectToDevicePixels(LayoutRect({ paintOffset.x() + leftBorder + leftPad, paintOffset.y() + topBorder + topPad }, contentSize), deviceScaleFactor), borderWidth);
-
             bool errorPictureDrawn = false;
             LayoutSize imageOffset;
             // When calculating the usable dimensions, exclude the pixels of
             // the ouline rect so the error image/alt text doesn't draw on it.
-            LayoutSize usableSize = contentSize - LayoutSize(2 * borderWidth, 2 * borderWidth);
+            LayoutSize usableSize = contentSize - LayoutSize(2 * missingImageBorderWidth, 2 * missingImageBorderWidth);
 
             RefPtr<Image> image = imageResource().image();
 
             if (imageResource().errorOccurred() && !image->isNull() && usableSize.width() >= image->width() && usableSize.height() >= image->height()) {
                 // Call brokenImage() explicitly to ensure we get the broken image icon at the appropriate resolution.
-                std::pair<Image*, float> brokenImageAndImageScaleFactor = cachedImage()->brokenImage(document().deviceScaleFactor());
+                std::pair<Image*, float> brokenImageAndImageScaleFactor = cachedImage()->brokenImage(deviceScaleFactor);
                 image = brokenImageAndImageScaleFactor.first;
                 FloatSize imageSize = image->size();
                 imageSize.scale(1 / brokenImageAndImageScaleFactor.second);
@@ -428,7 +442,7 @@ void RenderImage::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOf
                 LayoutUnit centerY = (usableSize.height() - imageSize.height()) / 2;
                 if (centerY < 0)
                     centerY = 0;
-                imageOffset = LayoutSize(leftBorder + leftPad + centerX + borderWidth, topBorder + topPad + centerY + borderWidth);
+                imageOffset = LayoutSize(leftBorder + leftPad + centerX + missingImageBorderWidth, topBorder + topPad + centerY + missingImageBorderWidth);
 
                 ImageOrientationDescription orientationDescription(shouldRespectImageOrientation());
 #if ENABLE(CSS_IMAGE_ORIENTATION)
@@ -445,7 +459,7 @@ void RenderImage::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOf
                 const FontMetrics& fontMetrics = font.fontMetrics();
                 LayoutUnit ascent = fontMetrics.ascent();
                 LayoutPoint altTextOffset = paintOffset;
-                altTextOffset.move(leftBorder + leftPad + (paddingWidth / 2) - borderWidth, topBorder + topPad + ascent + (paddingHeight / 2) - borderWidth);
+                altTextOffset.move(leftBorder + leftPad + (paddingWidth / 2) - missingImageBorderWidth, topBorder + topPad + ascent + (paddingHeight / 2) - missingImageBorderWidth);
 
                 // Only draw the alt text if it'll fit within the content box,
                 // and only if it fits above the error image.
@@ -464,8 +478,13 @@ void RenderImage::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOf
     if (contentSize.isEmpty())
         return;
 
+    bool showBorderForIncompleteImage = settings().incompleteImageBorderEnabled();
+
     RefPtr<Image> img = imageResource().image(flooredIntSize(contentSize));
     if (!img || img->isNull()) {
+        if (showBorderForIncompleteImage)
+            paintIncompleteImageOutline(paintInfo, paintOffset, missingImageBorderWidth);
+
         if (paintInfo.phase == PaintPhaseForeground)
             page().addRelevantUnpaintedObject(this, visualOverflowRect());
         return;
@@ -481,6 +500,9 @@ void RenderImage::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOf
         context.clip(contentBoxRect);
 
     ImageDrawResult result = paintIntoRect(paintInfo, snapRectToDevicePixels(replacedContentRect, deviceScaleFactor));
+
+    if (showBorderForIncompleteImage && (result != ImageDrawResult::DidDraw || (cachedImage() && cachedImage()->isLoading())))
+        paintIncompleteImageOutline(paintInfo, paintOffset, missingImageBorderWidth);
     
     if (cachedImage() && paintInfo.phase == PaintPhaseForeground) {
         // For now, count images as unpainted if they are still progressively loading. We may want 
index 5654310..eaafdd6 100644 (file)
@@ -107,6 +107,7 @@ private:
     bool isRenderImage() const final { return true; }
 
     void paintReplaced(PaintInfo&, const LayoutPoint&) override;
+    void paintIncompleteImageOutline(PaintInfo&, LayoutPoint, LayoutUnit) const;
 
     bool computeBackgroundIsKnownToBeObscured(const LayoutPoint& paintOffset) final;
 
index 24e4aae..3f8fc86 100644 (file)
@@ -93,6 +93,7 @@ InternalSettings::Backup::Backup(Settings& settings)
     , m_inlineMediaPlaybackRequiresPlaysInlineAttribute(settings.inlineMediaPlaybackRequiresPlaysInlineAttribute())
     , m_deferredCSSParserEnabled(settings.deferredCSSParserEnabled())
     , m_inputEventsEnabled(settings.inputEventsEnabled())
+    , m_incompleteImageBorderEnabled(settings.incompleteImageBorderEnabled())
 #if ENABLE(ACCESSIBILITY_EVENTS)
     , m_accessibilityEventsEnabled(settings.accessibilityEventsEnabled())
 #endif
@@ -204,6 +205,7 @@ void InternalSettings::Backup::restoreTo(Settings& settings)
     RenderTheme::singleton().setShouldMockBoldSystemFontForAccessibility(m_shouldMockBoldSystemFontForAccessibility);
     FontCache::singleton().setShouldMockBoldSystemFontForAccessibility(m_shouldMockBoldSystemFontForAccessibility);
     settings.setFrameFlattening(m_frameFlattening);
+    settings.setIncompleteImageBorderEnabled(m_incompleteImageBorderEnabled);
 #if ENABLE(ACCESSIBILITY_EVENTS)
     settings.setAccessibilityEventsEnabled(m_accessibilityEventsEnabled);
 #endif
@@ -902,6 +904,14 @@ ExceptionOr<void> InternalSettings::setAccessibilityEventsEnabled(bool enabled)
     return { };
 }
 
+ExceptionOr<void> InternalSettings::setIncompleteImageBorderEnabled(bool enabled)
+{
+    if (!m_page)
+        return Exception { InvalidAccessError };
+    settings().setIncompleteImageBorderEnabled(enabled);
+    return { };
+}
+
 static InternalSettings::ForcedAccessibilityValue settingsToInternalSettingsValue(Settings::ForcedAccessibilityValue value)
 {
     switch (value) {
index 9a48f15..6707fe6 100644 (file)
@@ -101,6 +101,7 @@ public:
     ExceptionOr<void> setShouldManageAudioSessionCategory(bool);
     ExceptionOr<void> setCustomPasteboardDataEnabled(bool);
     ExceptionOr<void> setAccessibilityEventsEnabled(bool);
+    ExceptionOr<void> setIncompleteImageBorderEnabled(bool);
 
     using FrameFlatteningValue = FrameFlattening;
     ExceptionOr<void> setFrameFlattening(FrameFlatteningValue);
@@ -192,6 +193,7 @@ private:
         bool m_inlineMediaPlaybackRequiresPlaysInlineAttribute;
         bool m_deferredCSSParserEnabled;
         bool m_inputEventsEnabled;
+        bool m_incompleteImageBorderEnabled;
 #if ENABLE(ACCESSIBILITY_EVENTS)
         bool m_accessibilityEventsEnabled;
 #endif
index ab6157f..d16986e 100644 (file)
@@ -85,6 +85,7 @@ enum FontLoadTimingOverride { "Block", "Swap", "Failure" };
     [MayThrowException] void setAllowsInlineMediaPlaybackAfterFullscreen(boolean allows);
     [MayThrowException] void setInlineMediaPlaybackRequiresPlaysInlineAttribute(boolean requires);
     [MayThrowException] void setFrameFlattening(FrameFlatteningValue frameFlattening);
+    [MayThrowException] void setIncompleteImageBorderEnabled(boolean enabled);
 
     // RuntimeEnabledFeatures.
     void setIndexedDBWorkersEnabled(boolean enabled);
index bf4c382..dd5eae1 100644 (file)
@@ -1,3 +1,23 @@
+2018-06-22  Tim Horton  <timothy_horton@apple.com>
+
+        Make it possible to add a border around loading or failed-to-load images
+        https://bugs.webkit.org/show_bug.cgi?id=186614
+        <rdar://problem/39050152>
+
+        Reviewed by Zalan Bujtas.
+
+        * Shared/WebPreferences.yaml:
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        (-[WKWebView _initializeWithConfiguration:]):
+        * UIProcess/API/Cocoa/WKWebViewConfiguration.mm:
+        (-[WKWebViewConfiguration init]):
+        (-[WKWebViewConfiguration copyWithZone:]):
+        (-[WKWebViewConfiguration _setColorFilterEnabled:]):
+        (-[WKWebViewConfiguration _incompleteImageBorderEnabled]):
+        (-[WKWebViewConfiguration _setIncompleteImageBorderEnabled:]):
+        * UIProcess/API/Cocoa/WKWebViewConfigurationPrivate.h:
+        Plumb the setting to WebKit2.
+
 2018-06-22  Brady Eidson  <beidson@apple.com>
 
         WKURLSchemeHandler doesn't handle sync XHR.
index d370f59..542a45c 100644 (file)
@@ -1303,3 +1303,7 @@ DisabledAdaptationsMetaTagEnabled:
 ColorFilterEnabled:
   type: bool
   defaultValue: false
+
+IncompleteImageBorderEnabled:
+  type: bool
+  defaultValue: false
index 3dc1bdb..305a03b 100644 (file)
@@ -556,6 +556,7 @@ static void validate(WKWebViewConfiguration *configuration)
     pageConfiguration->setInitialCapitalizationEnabled([_configuration _initialCapitalizationEnabled]);
     pageConfiguration->setWaitsForPaintAfterViewDidMoveToWindow([_configuration _waitsForPaintAfterViewDidMoveToWindow]);
     pageConfiguration->setControlledByAutomation([_configuration _isControlledByAutomation]);
+    pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::incompleteImageBorderEnabledKey(), WebKit::WebPreferencesStore::Value(!![_configuration _incompleteImageBorderEnabled]));
 
 #if ENABLE(APPLICATION_MANIFEST)
     pageConfiguration->setApplicationManifest([_configuration _applicationManifest] ? [configuration _applicationManifest]->_applicationManifest.get() : nullptr);
index 7cd12c8..d298ef7 100644 (file)
@@ -162,11 +162,11 @@ static _WKDragLiftDelay toDragLiftDelay(NSUInteger value)
     BOOL _needsStorageAccessFromFileURLsQuirk;
     BOOL _legacyEncryptedMediaAPIEnabled;
     BOOL _allowMediaContentTypesRequiringHardwareSupportAsFallback;
+    BOOL _colorFilterEnabled;
+    BOOL _incompleteImageBorderEnabled;
 
     RetainPtr<NSString> _overrideContentSecurityPolicy;
     RetainPtr<NSString> _mediaContentTypesRequiringHardwareSupport;
-
-    BOOL _colorFilterEnabled;
 }
 
 - (instancetype)init
@@ -248,6 +248,7 @@ static _WKDragLiftDelay toDragLiftDelay(NSUInteger value)
     _allowMediaContentTypesRequiringHardwareSupportAsFallback = YES;
 
     _colorFilterEnabled = NO;
+    _incompleteImageBorderEnabled = NO;
 
     return self;
 }
@@ -407,6 +408,7 @@ static _WKDragLiftDelay toDragLiftDelay(NSUInteger value)
 
     configuration->_groupIdentifier = adoptNS([self->_groupIdentifier copyWithZone:zone]);
     configuration->_colorFilterEnabled = self->_colorFilterEnabled;
+    configuration->_incompleteImageBorderEnabled = self->_incompleteImageBorderEnabled;
 
     return configuration;
 }
@@ -766,6 +768,16 @@ static NSString *defaultApplicationNameForUserAgent()
     _colorFilterEnabled = colorFilterEnabled;
 }
 
+- (BOOL)_incompleteImageBorderEnabled
+{
+    return _incompleteImageBorderEnabled;
+}
+
+- (void)_setIncompleteImageBorderEnabled:(BOOL)incompleteImageBorderEnabled
+{
+    _incompleteImageBorderEnabled = incompleteImageBorderEnabled;
+}
+
 - (BOOL)_requiresUserActionForVideoPlayback
 {
     return self.mediaTypesRequiringUserActionForPlayback & WKAudiovisualMediaTypeVideo;
index bd04920..db49965 100644 (file)
@@ -71,6 +71,7 @@ typedef NS_ENUM(NSUInteger, _WKDragLiftDelay) {
 @property (nonatomic, setter=_setControlledByAutomation:, getter=_isControlledByAutomation) BOOL _controlledByAutomation WK_API_AVAILABLE(macosx(10.12.3), ios(10.3));
 @property (nonatomic, setter=_setApplicationManifest:) _WKApplicationManifest *_applicationManifest WK_API_AVAILABLE(macosx(10.13.4), ios(11.3));
 @property (nonatomic, setter=_setColorFilterEnabled:) BOOL _colorFilterEnabled WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
+@property (nonatomic, setter=_setIncompleteImageBorderEnabled:) BOOL _incompleteImageBorderEnabled WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
 
 #if TARGET_OS_IPHONE
 @property (nonatomic, setter=_setAlwaysRunsAtForegroundPriority:) BOOL _alwaysRunsAtForegroundPriority WK_API_AVAILABLE(ios(9_0));