Diff
Modified: trunk/LayoutTests/ChangeLog (233114 => 233115)
--- trunk/LayoutTests/ChangeLog 2018-06-23 00:45:06 UTC (rev 233114)
+++ trunk/LayoutTests/ChangeLog 2018-06-23 00:52:56 UTC (rev 233115)
@@ -1,3 +1,19 @@
+2018-06-22 Tim Horton <[email protected]>
+
+ 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 <[email protected]>
[WinCairo] Unreviewed test gardening.
Added: trunk/LayoutTests/http/tests/images/loading-image-border-expected.html (0 => 233115)
--- trunk/LayoutTests/http/tests/images/loading-image-border-expected.html (rev 0)
+++ trunk/LayoutTests/http/tests/images/loading-image-border-expected.html 2018-06-23 00:52:56 UTC (rev 233115)
@@ -0,0 +1,6 @@
+<body>
+ <img src="" 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>
Added: trunk/LayoutTests/http/tests/images/loading-image-border.html (0 => 233115)
--- trunk/LayoutTests/http/tests/images/loading-image-border.html (rev 0)
+++ trunk/LayoutTests/http/tests/images/loading-image-border.html 2018-06-23 00:52:56 UTC (rev 233115)
@@ -0,0 +1,14 @@
+<body>
+ <img id="img" width="500px" height="500px">
+ <script>
+ internals.settings.setIncompleteImageBorderEnabled(true);
+
+ setTimeout(function () {
+ img.src = ""
+
+ testRunner.notifyDone();
+ }, 0);
+
+ testRunner.waitUntilDone();
+ </script>
+</body>
Added: trunk/LayoutTests/http/tests/images/loading-image-no-border-expected.html ( => )
Added: trunk/LayoutTests/http/tests/images/loading-image-no-border.html
===================================================================
--- trunk/LayoutTests/http/tests/images/loading-image-no-border.html (rev 0)
+++ trunk/LayoutTests/http/tests/images/loading-image-no-border.html 2018-06-23 00:52:56 UTC (rev 233115)
@@ -0,0 +1,14 @@
+<body>
+ <img id="img" width="500px" height="500px">
+ <script>
+ internals.settings.setIncompleteImageBorderEnabled(false);
+
+ setTimeout(function () {
+ img.src = ""
+
+ testRunner.notifyDone();
+ }, 0);
+
+ testRunner.waitUntilDone();
+ </script>
+</body>
Modified: trunk/LayoutTests/platform/wk2/TestExpectations (233114 => 233115)
--- trunk/LayoutTests/platform/wk2/TestExpectations 2018-06-23 00:45:06 UTC (rev 233114)
+++ trunk/LayoutTests/platform/wk2/TestExpectations 2018-06-23 00:52:56 UTC (rev 233115)
@@ -199,6 +199,11 @@
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
########################################
Modified: trunk/Source/WebCore/ChangeLog (233114 => 233115)
--- trunk/Source/WebCore/ChangeLog 2018-06-23 00:45:06 UTC (rev 233114)
+++ trunk/Source/WebCore/ChangeLog 2018-06-23 00:52:56 UTC (rev 233115)
@@ -1,3 +1,31 @@
+2018-06-22 Tim Horton <[email protected]>
+
+ 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 <[email protected]>
WKURLSchemeHandler doesn't handle sync XHR.
Modified: trunk/Source/WebCore/page/Settings.yaml (233114 => 233115)
--- trunk/Source/WebCore/page/Settings.yaml 2018-06-23 00:45:06 UTC (rev 233114)
+++ trunk/Source/WebCore/page/Settings.yaml 2018-06-23 00:52:56 UTC (rev 233115)
@@ -750,3 +750,6 @@
accessibilityEventsEnabled:
initial: true
conditional: ACCESSIBILITY_EVENTS
+
+incompleteImageBorderEnabled:
+ initial: false
Modified: trunk/Source/WebCore/rendering/RenderImage.cpp (233114 => 233115)
--- trunk/Source/WebCore/rendering/RenderImage.cpp 2018-06-23 00:45:06 UTC (rev 233114)
+++ trunk/Source/WebCore/rendering/RenderImage.cpp 2018-06-23 00:52:56 UTC (rev 233115)
@@ -379,12 +379,32 @@
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 @@
if (paintInfo.phase == PaintPhaseForeground)
page().addRelevantUnpaintedObject(this, visualOverflowRect());
+ paintIncompleteImageOutline(paintInfo, paintOffset, missingImageBorderWidth);
+
if (contentSize.width() > 2 && contentSize.height() > 2) {
- LayoutUnit borderWidth = LayoutUnit(1 / deviceScaleFactor);
-
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 @@
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 @@
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 @@
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 @@
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
Modified: trunk/Source/WebCore/rendering/RenderImage.h (233114 => 233115)
--- trunk/Source/WebCore/rendering/RenderImage.h 2018-06-23 00:45:06 UTC (rev 233114)
+++ trunk/Source/WebCore/rendering/RenderImage.h 2018-06-23 00:52:56 UTC (rev 233115)
@@ -107,6 +107,7 @@
bool isRenderImage() const final { return true; }
void paintReplaced(PaintInfo&, const LayoutPoint&) override;
+ void paintIncompleteImageOutline(PaintInfo&, LayoutPoint, LayoutUnit) const;
bool computeBackgroundIsKnownToBeObscured(const LayoutPoint& paintOffset) final;
Modified: trunk/Source/WebCore/testing/InternalSettings.cpp (233114 => 233115)
--- trunk/Source/WebCore/testing/InternalSettings.cpp 2018-06-23 00:45:06 UTC (rev 233114)
+++ trunk/Source/WebCore/testing/InternalSettings.cpp 2018-06-23 00:52:56 UTC (rev 233115)
@@ -93,6 +93,7 @@
, 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 @@
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 @@
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) {
Modified: trunk/Source/WebCore/testing/InternalSettings.h (233114 => 233115)
--- trunk/Source/WebCore/testing/InternalSettings.h 2018-06-23 00:45:06 UTC (rev 233114)
+++ trunk/Source/WebCore/testing/InternalSettings.h 2018-06-23 00:52:56 UTC (rev 233115)
@@ -101,6 +101,7 @@
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 @@
bool m_inlineMediaPlaybackRequiresPlaysInlineAttribute;
bool m_deferredCSSParserEnabled;
bool m_inputEventsEnabled;
+ bool m_incompleteImageBorderEnabled;
#if ENABLE(ACCESSIBILITY_EVENTS)
bool m_accessibilityEventsEnabled;
#endif
Modified: trunk/Source/WebCore/testing/InternalSettings.idl (233114 => 233115)
--- trunk/Source/WebCore/testing/InternalSettings.idl 2018-06-23 00:45:06 UTC (rev 233114)
+++ trunk/Source/WebCore/testing/InternalSettings.idl 2018-06-23 00:52:56 UTC (rev 233115)
@@ -85,6 +85,7 @@
[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);
Modified: trunk/Source/WebKit/ChangeLog (233114 => 233115)
--- trunk/Source/WebKit/ChangeLog 2018-06-23 00:45:06 UTC (rev 233114)
+++ trunk/Source/WebKit/ChangeLog 2018-06-23 00:52:56 UTC (rev 233115)
@@ -1,3 +1,23 @@
+2018-06-22 Tim Horton <[email protected]>
+
+ 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 <[email protected]>
WKURLSchemeHandler doesn't handle sync XHR.
Modified: trunk/Source/WebKit/Shared/WebPreferences.yaml (233114 => 233115)
--- trunk/Source/WebKit/Shared/WebPreferences.yaml 2018-06-23 00:45:06 UTC (rev 233114)
+++ trunk/Source/WebKit/Shared/WebPreferences.yaml 2018-06-23 00:52:56 UTC (rev 233115)
@@ -1303,3 +1303,7 @@
ColorFilterEnabled:
type: bool
defaultValue: false
+
+IncompleteImageBorderEnabled:
+ type: bool
+ defaultValue: false
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm (233114 => 233115)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm 2018-06-23 00:45:06 UTC (rev 233114)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm 2018-06-23 00:52:56 UTC (rev 233115)
@@ -556,6 +556,7 @@
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);
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewConfiguration.mm (233114 => 233115)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewConfiguration.mm 2018-06-23 00:45:06 UTC (rev 233114)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewConfiguration.mm 2018-06-23 00:52:56 UTC (rev 233115)
@@ -162,11 +162,11 @@
BOOL _needsStorageAccessFromFileURLsQuirk;
BOOL _legacyEncryptedMediaAPIEnabled;
BOOL _allowMediaContentTypesRequiringHardwareSupportAsFallback;
+ BOOL _colorFilterEnabled;
+ BOOL _incompleteImageBorderEnabled;
RetainPtr<NSString> _overrideContentSecurityPolicy;
RetainPtr<NSString> _mediaContentTypesRequiringHardwareSupport;
-
- BOOL _colorFilterEnabled;
}
- (instancetype)init
@@ -248,6 +248,7 @@
_allowMediaContentTypesRequiringHardwareSupportAsFallback = YES;
_colorFilterEnabled = NO;
+ _incompleteImageBorderEnabled = NO;
return self;
}
@@ -407,6 +408,7 @@
configuration->_groupIdentifier = adoptNS([self->_groupIdentifier copyWithZone:zone]);
configuration->_colorFilterEnabled = self->_colorFilterEnabled;
+ configuration->_incompleteImageBorderEnabled = self->_incompleteImageBorderEnabled;
return configuration;
}
@@ -766,6 +768,16 @@
_colorFilterEnabled = colorFilterEnabled;
}
+- (BOOL)_incompleteImageBorderEnabled
+{
+ return _incompleteImageBorderEnabled;
+}
+
+- (void)_setIncompleteImageBorderEnabled:(BOOL)incompleteImageBorderEnabled
+{
+ _incompleteImageBorderEnabled = incompleteImageBorderEnabled;
+}
+
- (BOOL)_requiresUserActionForVideoPlayback
{
return self.mediaTypesRequiringUserActionForPlayback & WKAudiovisualMediaTypeVideo;
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewConfigurationPrivate.h (233114 => 233115)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewConfigurationPrivate.h 2018-06-23 00:45:06 UTC (rev 233114)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewConfigurationPrivate.h 2018-06-23 00:52:56 UTC (rev 233115)
@@ -71,6 +71,7 @@
@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));