Source/WebCore/ChangeLog

 12019-06-12 Rob Buis <rbuis@igalia.com>
 2
 3 Support lazy image and iframe loading (loading="lazy")
 4 https://bugs.webkit.org/show_bug.cgi?id=196698
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 Implement lazy image loading as specified here [1]. Lazy image loading
 9 is controlled by the loading attribute and automatic for CSS
 10 background images. When the loading attribute is auto or not
 11 specified, the behavior is like before this patch, i.e. loading is
 12 eager.
 13
 14 [1] https://github.com/whatwg/html/pull/3752/files
 15
 16 Tests: http/tests/lazyload/attribute.html
 17 http/tests/lazyload/fixed-dimension.html
 18 http/tests/lazyload/js-image.html
 19 http/tests/lazyload/lazy.html
 20 http/tests/lazyload/scroll.html
 21 http/tests/lazyload/style-dimension.html
 22 imported/w3c/web-platform-tests/loading/lazyload/attribute_off_image.tentative.html
 23 imported/w3c/web-platform-tests/loading/lazyload/change_attribute_to_off_image.tentative.html
 24 imported/w3c/web-platform-tests/loading/lazyload/scroll_to_attribute_auto_image.tentative.html
 25 imported/w3c/web-platform-tests/loading/lazyload/scroll_to_attribute_invalid_image.tentative.html
 26 imported/w3c/web-platform-tests/loading/lazyload/scroll_to_attribute_on_image.tentative.html
 27 imported/w3c/web-platform-tests/loading/lazyload/scroll_to_attribute_unset_image.tentative.html
 28 imported/w3c/web-platform-tests/loading/lazyload/window_load_event_occurs_with_below_viewport_image.tentative.html
 29
 30 * Sources.txt:
 31 * WebCore.xcodeproj/project.pbxproj:
 32 * css/CSSImageValue.cpp:
 33 (WebCore::CSSImageValue::loadImage):
 34 * css/CSSImageValue.h:
 35 * css/parser/CSSParser.cpp:
 36 (WebCore::CSSParser::parseInlineStyleDeclaration):
 37 * css/parser/CSSParser.h:
 38 * css/parser/CSSParserImpl.cpp:
 39 (WebCore::CSSParserImpl::parseInlineStyleDeclaration):
 40 * css/parser/CSSParserImpl.h:
 41 * dom/Document.cpp:
 42 (WebCore::Document::ensureLazyLoadImageObserver):
 43 * dom/Document.h:
 44 * html/HTMLAttributeNames.in:
 45 * html/HTMLImageElement.cpp:
 46 (WebCore::HTMLImageElement::HTMLImageElement):
 47 (WebCore::HTMLImageElement::create):
 48 (WebCore::HTMLImageElement::createForJSConstructor):
 49 (WebCore::HTMLImageElement::parseAttribute):
 50 (WebCore::HTMLImageElement::loadDeferredImage):
 51 (WebCore::HTMLImageElement::isDimensionSmallAndAbsoluteForLazyLoad):
 52 (WebCore::HTMLImageElement::isInlineStyleDimensionsSmall):
 53 * html/HTMLImageElement.h:
 54 (WebCore::HTMLImageElement::createdByParser const):
 55 * html/HTMLImageElement.idl:
 56 * html/HTMLTagNames.in:
 57 * html/ImageDocument.cpp:
 58 * html/LazyLoadImageObserver.cpp: Added.
 59 (WebCore::LazyLoadImageObserver::startMonitoring):
 60 (WebCore::LazyLoadImageObserver::stopMonitoring):
 61 (WebCore::LazyLoadImageObserver::startMonitoringNearViewport):
 62 * html/LazyLoadImageObserver.h: Copied from Tools/DumpRenderTree/TestOptions.h.
 63 * html/parser/HTMLPreloadScanner.cpp:
 64 (WebCore::TokenPreloadScanner::StartTagScanner::createPreloadRequest):
 65 (WebCore::TokenPreloadScanner::StartTagScanner::processAttribute):
 66 * html/parser/HTMLResourcePreloader.cpp:
 67 (WebCore::PreloadRequest::resourceRequest):
 68 * html/parser/HTMLResourcePreloader.h:
 69 (WebCore::PreloadRequest::setLazyloadImageEnabled):
 70 * loader/ImageLoader.cpp:
 71 (WebCore::isLazyLoadableImage):
 72 (WebCore::ImageLoader::updateFromElement):
 73 (WebCore::ImageLoader::notifyFinished):
 74 (WebCore::ImageLoader::loadDeferredImage):
 75 * loader/ImageLoader.h:
 76 * page/RuntimeEnabledFeatures.h:
 77 (WebCore::RuntimeEnabledFeatures::setLazyImageLoadingEnabled):
 78 (WebCore::RuntimeEnabledFeatures::lazyImageLoadingEnabled const):
 79 * page/Settings.yaml:
 80 * rendering/style/RenderStyle.cpp:
 81 (WebCore::RenderStyle::loadDeferredImages const):
 82 * rendering/style/RenderStyle.h:
 83 * rendering/style/StyleCachedImage.cpp:
 84 (WebCore::StyleCachedImage::addClient):
 85 (WebCore::StyleCachedImage::removeClient):
 86 (WebCore::StyleCachedImage::loadDeferredImage):
 87 * rendering/style/StyleCachedImage.h:
 88 * rendering/style/StyleImage.h:
 89 (WebCore::StyleImage::isLazyloadPossiblyDeferred const):
 90 (WebCore::StyleImage::StyleImage):
 91
1922019-06-11 Wenson Hsieh <wenson_hsieh@apple.com>
293
394 [iOS] Idempotent text autosizing needs to react properly to viewport changes

Source/WebKit/ChangeLog

 12019-06-12 Rob Buis <rbuis@igalia.com>
 2
 3 Support lazy image and iframe loading (loading="lazy")
 4 https://bugs.webkit.org/show_bug.cgi?id=196698
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 Add LazyImageLoading preference.
 9
 10 * Shared/WebPreferences.yaml:
 11
1122019-06-11 Wenson Hsieh <wenson_hsieh@apple.com>
213
314 [iOS] Idempotent text autosizing needs to react properly to viewport changes

Source/WebKitLegacy/mac/ChangeLog

 12019-06-12 Rob Buis <rbuis@igalia.com>
 2
 3 Support lazy image and iframe loading (loading="lazy")
 4 https://bugs.webkit.org/show_bug.cgi?id=196698
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 Set lazyImageLoading runtime flag is preference is set.
 9
 10 * WebView/WebPreferenceKeysPrivate.h:
 11 * WebView/WebPreferences.mm:
 12 (+[WebPreferences initialize]):
 13 (-[WebPreferences lazyImageLoadingEnabled]):
 14 (-[WebPreferences setLazyImageLoadingEnabled:]):
 15 * WebView/WebPreferencesPrivate.h:
 16 * WebView/WebView.mm:
 17 (-[WebView _preferencesChanged:]):
 18
1192019-06-10 Sam Weinig <weinig@apple.com>
220
321 Remove Dashboard support

Source/WebKitLegacy/win/ChangeLog

 12019-06-12 Rob Buis <rbuis@igalia.com>
 2
 3 Support lazy image and iframe loading (loading="lazy")
 4 https://bugs.webkit.org/show_bug.cgi?id=196698
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 Set lazyImageLoading runtime flag is preference is set.
 9
 10 * Interfaces/IWebPreferencesPrivate.idl:
 11 * WebPreferenceKeysPrivate.h:
 12 * WebPreferences.cpp:
 13 (WebPreferences::initializeDefaultSettings):
 14 (WebPreferences::lazyImageLoadingEnabled):
 15 (WebPreferences::setLazyImageLoadingEnabled):
 16 * WebPreferences.h:
 17 * WebView.cpp:
 18 (WebView::notifyPreferencesChanged):
 19
1202019-05-31 Don Olmstead <don.olmstead@sony.com>
221
322 [CMake] Add WebKit::WTF target

Source/WebCore/Sources.txt

@@html/InputType.cpp
11881188html/InputTypeNames.cpp
11891189html/LabelableElement.cpp
11901190html/LabelsNodeList.cpp
 1191html/LazyLoadImageObserver.cpp
11911192html/LinkIconCollector.cpp
11921193html/LinkRelAttribute.cpp
11931194html/MediaController.cpp

Source/WebCore/WebCore.xcodeproj/project.pbxproj

33773377 AA7FEEAD16A4E74B004C0C33 /* JSSpeechSynthesis.h in Headers */ = {isa = PBXBuildFile; fileRef = AA7FEEAC16A4E74B004C0C33 /* JSSpeechSynthesis.h */; };
33783378 AAA728F716D1D8BC00D3BBC6 /* WebAccessibilityObjectWrapperIOS.h in Headers */ = {isa = PBXBuildFile; fileRef = AAA728F116D1D8BC00D3BBC6 /* WebAccessibilityObjectWrapperIOS.h */; };
33793379 AAC08CF315F941FD00F1E188 /* AccessibilitySVGRoot.h in Headers */ = {isa = PBXBuildFile; fileRef = AAC08CF115F941FC00F1E188 /* AccessibilitySVGRoot.h */; };
 3380 AAD9D0B521DFA810001B11C7 /* LazyLoadImageObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = AAD9D0B321DFA80E001B11C7 /* LazyLoadImageObserver.h */; settings = {ATTRIBUTES = (Private, ); }; };
33803381 AB23A32809BBA7D00067CC53 /* BeforeTextInsertedEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = AB23A32609BBA7D00067CC53 /* BeforeTextInsertedEvent.h */; };
33813382 AB247A6D0AFD6383003FA5FD /* RenderSlider.h in Headers */ = {isa = PBXBuildFile; fileRef = AB247A6B0AFD6383003FA5FD /* RenderSlider.h */; };
33823383 AB31C91E10AE1B8E000C7B92 /* LineClampValue.h in Headers */ = {isa = PBXBuildFile; fileRef = AB31C91D10AE1B8E000C7B92 /* LineClampValue.h */; settings = {ATTRIBUTES = (Private, ); }; };

1199011991 AAA728F316D1D8BC00D3BBC6 /* AXObjectCacheIOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AXObjectCacheIOS.mm; sourceTree = "<group>"; };
1199111992 AAC08CF015F941FC00F1E188 /* AccessibilitySVGRoot.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AccessibilitySVGRoot.cpp; sourceTree = "<group>"; };
1199211993 AAC08CF115F941FC00F1E188 /* AccessibilitySVGRoot.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AccessibilitySVGRoot.h; sourceTree = "<group>"; };
 11994 AAD9D0B121DFA80C001B11C7 /* LazyLoadImageObserver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LazyLoadImageObserver.cpp; sourceTree = "<group>"; };
 11995 AAD9D0B321DFA80E001B11C7 /* LazyLoadImageObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LazyLoadImageObserver.h; sourceTree = "<group>"; };
1199311996 AAE27B7416CBFC0D00623043 /* PlatformSpeechSynthesizerMock.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PlatformSpeechSynthesizerMock.cpp; sourceTree = "<group>"; };
1199411997 AAE27B7516CBFC0D00623043 /* PlatformSpeechSynthesizerMock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlatformSpeechSynthesizerMock.h; sourceTree = "<group>"; };
1199511998 AAE3755D17429BCC006200C2 /* PlatformSpeechSynthesizerIOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PlatformSpeechSynthesizerIOS.mm; sourceTree = "<group>"; };

2157321576 450CEBEF15073BBE002BB149 /* LabelableElement.h */,
2157421577 A456FA2411AD4A830020B420 /* LabelsNodeList.cpp */,
2157521578 A456FA2511AD4A830020B420 /* LabelsNodeList.h */,
 21579 AAD9D0B121DFA80C001B11C7 /* LazyLoadImageObserver.cpp */,
 21580 AAD9D0B321DFA80E001B11C7 /* LazyLoadImageObserver.h */,
2157621581 1A4DA41F1CDD3A8300F4473C /* LinkIconCollector.cpp */,
2157721582 1A4DA4201CDD3A8300F4473C /* LinkIconCollector.h */,
2157821583 1A250E0C1CDD632000D0BE63 /* LinkIconType.h */,

3047930484 6F7CA3C6208C2957002F29AB /* LayoutState.h in Headers */,
3048030485 11310CF220BA4A320065A8D0 /* LayoutTreeBuilder.h in Headers */,
3048130486 141DC0481648348F00371E5A /* LayoutUnit.h in Headers */,
 30487 AAD9D0B521DFA810001B11C7 /* LazyLoadImageObserver.h in Headers */,
3048230488 CDE8B5ED1A69777300B4B66A /* LegacyCDMPrivateClearKey.h in Headers */,
3048330489 CDF4B7121E0087AE00E235A2 /* LegacyCDMSession.h in Headers */,
3048430490 CDE8B5F11A69778B00B4B66A /* LegacyCDMSessionClearKey.h in Headers */,

Source/WebCore/css/CSSImageValue.cpp

@@bool CSSImageValue::isPending() const
5858 return !m_accessedImage;
5959}
6060
61 CachedImage* CSSImageValue::loadImage(CachedResourceLoader& loader, const ResourceLoaderOptions& options)
 61CachedImage* CSSImageValue::loadImage(CachedResourceLoader& loader, const ResourceLoaderOptions& options, bool defer)
6262{
63  if (!m_accessedImage) {
 63 if (!m_accessedImage || defer) {
6464 m_accessedImage = true;
6565
6666 ResourceLoaderOptions loadOptions = options;
6767 loadOptions.loadedFromOpaqueSource = m_loadedFromOpaqueSource;
68  CachedResourceRequest request(ResourceRequest(loader.document()->completeURL(m_url.string())), loadOptions);
 68 ResourceRequest resourceRequest(loader.document()->completeURL(m_url.string()));
 69 if (defer) {
 70 resourceRequest.setHTTPHeaderField(HTTPHeaderName::Range, "bytes=0-2047");
 71 loadOptions.cache = FetchOptions::Cache::NoStore;
 72 }
 73
 74 CachedResourceRequest request(WTFMove(resourceRequest), loadOptions);
6975 if (m_initiatorName.isEmpty())
7076 request.setInitiator(cachedResourceRequestInitiators().css);
7177 else

Source/WebCore/css/CSSImageValue.h

@@public:
4141 ~CSSImageValue();
4242
4343 bool isPending() const;
44  CachedImage* loadImage(CachedResourceLoader&, const ResourceLoaderOptions&);
 44 CachedImage* loadImage(CachedResourceLoader&, const ResourceLoaderOptions&, bool defer = false);
4545 CachedImage* cachedImage() const { return m_cachedImage.get(); }
4646
4747 const URL& url() const { return m_url; }

Source/WebCore/css/parser/CSSParser.cpp

@@Ref<ImmutableStyleProperties> CSSParser::parseInlineStyleDeclaration(const Strin
167167 return CSSParserImpl::parseInlineStyleDeclaration(string, element);
168168}
169169
 170Ref<ImmutableStyleProperties> CSSParser::parseInlineStyleDeclaration(const String& string, const CSSParserMode& mode)
 171{
 172 return CSSParserImpl::parseInlineStyleDeclaration(string, mode);
 173}
 174
170175bool CSSParser::parseDeclaration(MutableStyleProperties& declaration, const String& string)
171176{
172177 return CSSParserImpl::parseDeclarationList(&declaration, string, m_context);

Source/WebCore/css/parser/CSSParser.h

@@public:
7575
7676 WEBCORE_EXPORT bool parseDeclaration(MutableStyleProperties&, const String&);
7777 static Ref<ImmutableStyleProperties> parseInlineStyleDeclaration(const String&, const Element*);
 78 static Ref<ImmutableStyleProperties> parseInlineStyleDeclaration(const String&, const CSSParserMode&);
7879
7980 void parseSelector(const String&, CSSSelectorList&);
8081

Source/WebCore/css/parser/CSSParserImpl.cpp

@@Ref<ImmutableStyleProperties> CSSParserImpl::parseInlineStyleDeclaration(const S
166166 return createStyleProperties(parser.m_parsedProperties, context.mode);
167167}
168168
 169Ref<ImmutableStyleProperties> CSSParserImpl::parseInlineStyleDeclaration(const String& string, const CSSParserMode& mode)
 170{
 171 CSSParserContext context(mode);
 172
 173 CSSParserImpl parser(context, string);
 174 parser.consumeDeclarationList(parser.tokenizer()->tokenRange(), StyleRule::Style);
 175 return createStyleProperties(parser.m_parsedProperties, context.mode);
 176}
 177
169178Ref<ImmutableStyleProperties> CSSParserImpl::parseDeferredDeclaration(CSSParserTokenRange tokenRange, const CSSParserContext& context, StyleSheetContents* styleSheet)
170179{
171180 if (!styleSheet) {

Source/WebCore/css/parser/CSSParserImpl.h

@@public:
8585 static CSSParser::ParseResult parseValue(MutableStyleProperties*, CSSPropertyID, const String&, bool important, const CSSParserContext&);
8686 static CSSParser::ParseResult parseCustomPropertyValue(MutableStyleProperties*, const AtomicString& propertyName, const String&, bool important, const CSSParserContext&);
8787 static Ref<ImmutableStyleProperties> parseInlineStyleDeclaration(const String&, const Element*);
 88 static Ref<ImmutableStyleProperties> parseInlineStyleDeclaration(const String&, const CSSParserMode&);
8889 static bool parseDeclarationList(MutableStyleProperties*, const String&, const CSSParserContext&);
8990 static RefPtr<StyleRuleBase> parseRule(const String&, const CSSParserContext&, StyleSheetContents*, AllowedRulesType);
9091 static void parseStyleSheet(const String&, const CSSParserContext&, StyleSheetContents*, CSSParser::RuleParsing);

Source/WebCore/dom/Document.cpp

117117#include "KeyboardEvent.h"
118118#include "KeyframeEffect.h"
119119#include "LayoutDisallowedScope.h"
 120#include "LazyLoadImageObserver.h"
120121#include "LibWebRTCProvider.h"
121122#include "LoaderStrategy.h"
122123#include "Logging.h"

@@void Document::setApplePayIsActive()
82308231
82318232#endif
82328233
 8234LazyLoadImageObserver& Document::ensureLazyLoadImageObserver()
 8235{
 8236 if (!m_lazyLoadImageObserver)
 8237 m_lazyLoadImageObserver = new LazyLoadImageObserver();
 8238 return *m_lazyLoadImageObserver;
 8239}
 8240
82338241} // namespace WebCore

Source/WebCore/dom/Document.h

@@class IntPoint;
147147class JSNode;
148148class LayoutPoint;
149149class LayoutRect;
 150class LazyLoadImageObserver;
150151class LiveNodeList;
151152class Locale;
152153class Location;

@@public:
15221523 bool inHitTesting() const { return m_inHitTesting; }
15231524#endif
15241525
 1526 LazyLoadImageObserver& ensureLazyLoadImageObserver();
 1527
15251528protected:
15261529 enum ConstructionFlags { Synthesized = 1, NonRenderedPlaceholder = 1 << 1 };
15271530 Document(Frame*, const URL&, unsigned = DefaultDocumentClass, unsigned constructionFlags = 0);

@@private:
17091712
17101713 Element* m_cssTarget { nullptr };
17111714
 1715 LazyLoadImageObserver* m_lazyLoadImageObserver { nullptr };
 1716
17121717 RefPtr<SerializedScriptValue> m_pendingStateObject;
17131718 MonotonicTime m_documentCreationTime;
17141719 bool m_overMinimumLayoutThreshold { false };

Source/WebCore/html/HTMLAttributeNames.in

@@language
165165leftmargin
166166link
167167list
 168loading
168169longdesc
169170loop
170171low

Source/WebCore/html/HTMLImageElement.cpp

5555#include "Settings.h"
5656#include "ShadowRoot.h"
5757#include "SizesAttributeParser.h"
 58#include "StyleProperties.h"
5859#include <wtf/IsoMallocInlines.h>
5960#include <wtf/text/StringBuilder.h>
6061

@@WTF_MAKE_ISO_ALLOCATED_IMPL(HTMLImageElement);
6869
6970using namespace HTMLNames;
7071
71 HTMLImageElement::HTMLImageElement(const QualifiedName& tagName, Document& document, HTMLFormElement* form)
 72HTMLImageElement::HTMLImageElement(const QualifiedName& tagName, Document& document, HTMLFormElement* form, bool createdByParser)
7273 : HTMLElement(tagName, document)
7374 , m_imageLoader(*this)
7475 , m_form(nullptr)

@@HTMLImageElement::HTMLImageElement(const QualifiedName& tagName, Document& docum
7677 , m_compositeOperator(CompositeSourceOver)
7778 , m_imageDevicePixelRatio(1.0f)
7879 , m_experimentalImageMenuEnabled(false)
 80 , m_createdByParser(createdByParser)
7981{
8082 ASSERT(hasTagName(imgTag));
8183 setHasCustomStyleResolveCallbacks();

@@HTMLImageElement::HTMLImageElement(const QualifiedName& tagName, Document& docum
8385
8486Ref<HTMLImageElement> HTMLImageElement::create(Document& document)
8587{
86  return adoptRef(*new HTMLImageElement(imgTag, document));
 88 return adoptRef(*new HTMLImageElement(imgTag, document, nullptr, false));
8789}
8890
89 Ref<HTMLImageElement> HTMLImageElement::create(const QualifiedName& tagName, Document& document, HTMLFormElement* form)
 91Ref<HTMLImageElement> HTMLImageElement::create(const QualifiedName& tagName, Document& document, HTMLFormElement* form, bool createdByParser)
9092{
91  return adoptRef(*new HTMLImageElement(tagName, document, form));
 93 return adoptRef(*new HTMLImageElement(tagName, document, form, createdByParser));
9294}
9395
9496HTMLImageElement::~HTMLImageElement()

@@HTMLImageElement::~HTMLImageElement()
100102
101103Ref<HTMLImageElement> HTMLImageElement::createForJSConstructor(Document& document, Optional<unsigned> width, Optional<unsigned> height)
102104{
103  auto image = adoptRef(*new HTMLImageElement(imgTag, document));
 105 auto image = adoptRef(*new HTMLImageElement(imgTag, document, nullptr, false));
104106 if (width)
105107 image->setWidth(width.value());
106108 if (height)

@@void HTMLImageElement::parseAttribute(const QualifiedName& name, const AtomicStr
240242 m_experimentalImageMenuEnabled = !value.isNull();
241243 updateImageControls();
242244#endif
243  } else if (name == x_apple_editable_imageAttr)
 245 } else if (name == x_apple_editable_imageAttr) {
244246 updateEditableImage();
245  else {
 247 } else if (name == loadingAttr && equalLettersIgnoringASCIICase(value, "eager")) {
 248// !GetDocument().IsLazyLoadPolicyEnforced()) {
 249 loadDeferredImage();
 250 } else {
246251 if (name == nameAttr) {
247252 bool willHaveName = !value.isNull();
248253 if (m_hadNameBeforeAttributeChanged != willHaveName && isConnected() && !isInShadowTree() && is<HTMLDocument>(document())) {

@@void HTMLImageElement::defaultEventHandler(Event& event)
834839 HTMLElement::defaultEventHandler(event);
835840}
836841
 842void HTMLImageElement::loadDeferredImage()
 843{
 844 m_imageLoader.loadDeferredImage();
 845}
 846
 847// Minimum height or width of the image to start lazyloading.
 848constexpr int kMinDimensionToLazyLoad = 10;
 849
 850bool HTMLImageElement::isDimensionSmallAndAbsoluteForLazyLoad(const AtomicString& attributeValue)
 851{
 852 auto optionalDimension = parseValidHTMLNonNegativeInteger(attributeValue);
 853 return optionalDimension && optionalDimension.value() <= kMinDimensionToLazyLoad;
 854}
 855
 856bool HTMLImageElement::isInlineStyleDimensionsSmall(const StyleProperties* propertySet)
 857{
 858 if (!propertySet)
 859 return false;
 860 auto height = propertySet->getPropertyCSSValue(CSSPropertyHeight);
 861 auto width = propertySet->getPropertyCSSValue(CSSPropertyWidth);
 862 if (!height || !height->isPrimitiveValue() || !width || !width->isPrimitiveValue())
 863 return false;
 864 const auto& widthPrim = downcast<CSSPrimitiveValue>(*width);
 865 const auto& heightPrim = downcast<CSSPrimitiveValue>(*height);
 866 return heightPrim.isPx() && (heightPrim.doubleValue() <= kMinDimensionToLazyLoad)
 867 && widthPrim.isPx() && (widthPrim.doubleValue() <= kMinDimensionToLazyLoad);
 868}
 869
837870}

Source/WebCore/html/HTMLImageElement.h

@@class HTMLImageElement : public HTMLElement, public FormNamedItem {
4444 friend class HTMLFormElement;
4545public:
4646 static Ref<HTMLImageElement> create(Document&);
47  static Ref<HTMLImageElement> create(const QualifiedName&, Document&, HTMLFormElement*);
 47 static Ref<HTMLImageElement> create(const QualifiedName&, Document&, HTMLFormElement*, bool createdByParser);
4848 static Ref<HTMLImageElement> createForJSConstructor(Document&, Optional<unsigned> width, Optional<unsigned> height);
4949
5050 virtual ~HTMLImageElement();

@@public:
123123
124124 void defaultEventHandler(Event&) final;
125125
 126 void loadDeferredImage();
 127
 128 bool createdByParser() const { return m_createdByParser; }
 129
 130 static bool isDimensionSmallAndAbsoluteForLazyLoad(const AtomicString&);
 131 static bool isInlineStyleDimensionsSmall(const StyleProperties*);
 132
126133protected:
127  HTMLImageElement(const QualifiedName&, Document&, HTMLFormElement* = 0);
 134 HTMLImageElement(const QualifiedName&, Document&, HTMLFormElement*, bool createdByParser);
128135
129136 void didMoveToNewDocument(Document& oldDocument, Document& newDocument) override;
130137

@@private:
183190 float m_imageDevicePixelRatio;
184191 bool m_experimentalImageMenuEnabled;
185192 bool m_hadNameBeforeAttributeChanged { false }; // FIXME: We only need this because parseAttribute() can't see the old value.
 193 bool m_createdByParser { false };
186194
187195 RefPtr<EditableImageReference> m_editableImage;
188196 WeakPtr<HTMLPictureElement> m_pictureElement;

Source/WebCore/html/HTMLImageElement.idl

4444
4545 [Conditional=ATTACHMENT_ELEMENT, EnabledAtRuntime=AttachmentElement] readonly attribute DOMString attachmentIdentifier;
4646
 47 [EnabledAtRuntime=LazyImageLoading, CEReactions, Reflect] attribute DOMString loading;
 48
4749 // Extensions
4850 readonly attribute boolean complete;
4951 [CEReactions=NotNeeded, Reflect, URL] attribute USVString lowsrc;

Source/WebCore/html/HTMLTagNames.in

@@html
6767i interfaceName=HTMLElement
6868iframe interfaceName=HTMLIFrameElement
6969image interfaceName=HTMLUnknownElement
70 img interfaceName=HTMLImageElement, constructorNeedsFormElement
 70img interfaceName=HTMLImageElement, constructorNeedsFormElement, constructorNeedsCreatedByParser
7171input constructorNeedsFormElement, constructorNeedsCreatedByParser
7272ins interfaceName=HTMLModElement
7373kbd interfaceName=HTMLElement

Source/WebCore/html/ImageDocument.cpp

@@public:
103103
104104private:
105105 ImageDocumentElement(ImageDocument& document)
106  : HTMLImageElement(imgTag, document)
 106 : HTMLImageElement(imgTag, document, nullptr, false)
107107 , m_imageDocument(&document)
108108 {
109109 }

Source/WebCore/html/LazyLoadImageObserver.cpp

 1/*
 2 * Copyright (C) 2019 Igalia S.L.
 3 *
 4 * Redistribution and use in source and binary forms, with or without
 5 * modification, are permitted provided that the following conditions
 6 * are met:
 7 * 1. Redistributions of source code must retain the above copyright
 8 * notice, this list of conditions and the following disclaimer.
 9 * 2. Redistributions in binary form must reproduce the above copyright
 10 * notice, this list of conditions and the following disclaimer in the
 11 * documentation and/or other materials provided with the distribution.
 12 *
 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 23 * THE POSSIBILITY OF SUCH DAMAGE.
 24 */
 25
 26#include "config.h"
 27#include "LazyLoadImageObserver.h"
 28
 29#include "Frame.h"
 30#include "HTMLImageElement.h"
 31#include "IntersectionObserverCallback.h"
 32#include "RenderStyle.h"
 33
 34#include <limits>
 35
 36namespace WebCore {
 37
 38class IntersectionObserverCallbackImpl final : public IntersectionObserverCallback {
 39public:
 40 static Ref<IntersectionObserverCallbackImpl> create(Document* document)
 41 {
 42 return adoptRef(*new IntersectionObserverCallbackImpl(document));
 43 }
 44 IntersectionObserverCallbackImpl(Document* document)
 45 : IntersectionObserverCallback(document), m_document(document)
 46 {
 47 }
 48 CallbackResult<void> handleEvent(const Vector<Ref<IntersectionObserverEntry>>& entries, IntersectionObserver&)
 49 {
 50 ASSERT(!entries.isEmpty());
 51
 52 for (auto& entry : entries) {
 53 if (!entry->isIntersecting())
 54 continue;
 55 Element* element = entry->target();
 56 if (is<HTMLImageElement>(element))
 57 downcast<HTMLImageElement>(*element).loadDeferredImage();
 58
 59 // Load the background image if the element has one deferred.
 60 if (const auto* style = element->computedStyle())
 61 style->loadDeferredImages(*m_document);
 62
 63 m_document->ensureLazyLoadImageObserver().stopMonitoring(*element);
 64 }
 65 return { };
 66 }
 67private:
 68 Document* m_document;
 69};
 70
 71namespace {
 72
 73Document* getRootDocumentOrNull(const Element& element)
 74{
 75 if (Frame* frame = element.document().frame())
 76 return frame->tree().top().document();
 77 return nullptr;
 78}
 79
 80} // namespace
 81
 82void LazyLoadImageObserver::startMonitoring(Element& element)
 83{
 84 if (Document* document = getRootDocumentOrNull(element))
 85 document->ensureLazyLoadImageObserver().startMonitoringNearViewport(document, element);
 86}
 87
 88void LazyLoadImageObserver::stopMonitoring(Element& element)
 89{
 90 if (Document* document = getRootDocumentOrNull(element))
 91 document->ensureLazyLoadImageObserver().m_lazyLoadIntersectionObserver->unobserve(element);
 92}
 93
 94LazyLoadImageObserver::LazyLoadImageObserver() = default;
 95
 96void LazyLoadImageObserver::startMonitoringNearViewport(Document* rootDocument, Element& element)
 97{
 98 if (!m_lazyLoadIntersectionObserver) {
 99 auto callback = IntersectionObserverCallbackImpl::create(rootDocument);
 100 auto options = IntersectionObserver::Init { nullptr, "", { } };
 101 auto observer = IntersectionObserver::create(*rootDocument, WTFMove(callback), WTFMove(options));
 102 if (observer.hasException())
 103 return;
 104 m_lazyLoadIntersectionObserver = observer.returnValue().ptr();
 105 }
 106 m_lazyLoadIntersectionObserver->observe(element);
 107}
 108
 109}

Source/WebCore/html/LazyLoadImageObserver.h

 1/*
 2 * Copyright (C) 2019 Igalia S.L.
 3 *
 4 * Redistribution and use in source and binary forms, with or without
 5 * modification, are permitted provided that the following conditions
 6 * are met:
 7 * 1. Redistributions of source code must retain the above copyright
 8 * notice, this list of conditions and the following disclaimer.
 9 * 2. Redistributions in binary form must reproduce the above copyright
 10 * notice, this list of conditions and the following disclaimer in the
 11 * documentation and/or other materials provided with the distribution.
 12 *
 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 23 * THE POSSIBILITY OF SUCH DAMAGE.
 24 */
 25
 26#pragma once
 27
 28#include "IntersectionObserver.h"
 29
 30namespace WebCore {
 31
 32class Document;
 33class Element;
 34
 35class LazyLoadImageObserver {
 36public:
 37 LazyLoadImageObserver();
 38
 39 static void startMonitoring(Element&);
 40 static void stopMonitoring(Element&);
 41
 42private:
 43 void startMonitoringNearViewport(Document*, Element&);
 44
 45 // The intersection observer responsible for loading the image once it's near
 46 // the viewport.
 47 RefPtr<IntersectionObserver> m_lazyLoadIntersectionObserver;
 48};
 49
 50} // namespace

Source/WebCore/html/parser/HTMLPreloadScanner.cpp

2828#include "config.h"
2929#include "HTMLPreloadScanner.h"
3030
 31#include "HTMLImageElement.h"
3132#include "HTMLNames.h"
3233#include "HTMLParserIdioms.h"
3334#include "HTMLSrcsetParser.h"

4344#include "RenderView.h"
4445#include "RuntimeEnabledFeatures.h"
4546#include "SizesAttributeParser.h"
 47#include "StyleProperties.h"
4648#include <wtf/MainThread.h>
4749
4850namespace WebCore {

@@public:
165167 request->setCrossOriginMode(m_crossOriginMode);
166168 request->setNonce(m_nonceAttribute);
167169
 170 if (equalLettersIgnoringASCIICase(m_lazyloadAttribute, "lazy")
 171 && !((m_widthAttrSmallAbsolute && m_heightAttrSmallAbsolute) || m_inlineStyleDimensionsSmall))
 172 request->setLazyloadImageEnabled(true);
 173
168174 // According to the spec, the module tag ignores the "charset" attribute as the same to the worker's
169175 // importScript. But WebKit supports the "charset" for importScript intentionally. So to be consistent,
170176 // even for the module tags, we handle the "charset" attribute.

@@private:
206212 m_sizesAttribute = attributeValue;
207213 break;
208214 }
 215 if (match(attributeName, loadingAttr) && m_lazyloadAttribute.isNull()) {
 216 m_lazyloadAttribute = attributeValue;
 217 break;
 218 }
 219 if (RuntimeEnabledFeatures::sharedFeatures().lazyImageLoadingEnabled()) {
 220 if (match(attributeName, widthAttr) && !m_widthAttrSmallAbsolute) {
 221 m_widthAttrSmallAbsolute = HTMLImageElement::isDimensionSmallAndAbsoluteForLazyLoad(attributeValue);
 222 break;
 223 }
 224 if (match(attributeName, heightAttr) && !m_heightAttrSmallAbsolute) {
 225 m_heightAttrSmallAbsolute = HTMLImageElement::isDimensionSmallAndAbsoluteForLazyLoad(attributeValue);
 226 break;
 227 }
 228 if (match(attributeName, styleAttr) && !m_inlineStyleDimensionsSmall) {
 229 CSSParserMode mode = /*media_values_->StrictMode() ? HTMLStandardMode :*/ HTMLQuirksMode;
 230 const auto propertySet = CSSParser::parseInlineStyleDeclaration(attributeValue, mode);
 231 m_inlineStyleDimensionsSmall = HTMLImageElement::isInlineStyleDimensionsSmall(propertySet.ptr());
 232 }
 233 }
 234
209235 processImageAndScriptAttribute(attributeName, attributeValue);
210236 break;
211237 case TagId::Source:

@@private:
365391 String m_metaContent;
366392 String m_asAttribute;
367393 String m_typeAttribute;
 394 String m_lazyloadAttribute;
368395 bool m_metaIsViewport;
369396 bool m_metaIsDisabledAdaptations;
370397 bool m_inputIsImage;
 398 bool m_widthAttrSmallAbsolute { false };
 399 bool m_heightAttrSmallAbsolute { false };
 400 bool m_inlineStyleDimensionsSmall { false };
371401 float m_deviceScaleFactor;
372402 PreloadRequest::ModuleScript m_moduleScript { PreloadRequest::ModuleScript::No };
373403};

Source/WebCore/html/parser/HTMLResourcePreloader.cpp

@@CachedResourceRequest PreloadRequest::resourceRequest(Document& document)
5454 if (skipContentSecurityPolicyCheck)
5555 options.contentSecurityPolicyImposition = ContentSecurityPolicyImposition::SkipPolicyCheck;
5656
 57 ResourceRequest resourceRequest(completeURL(document));
 58 if (m_lazyloadImageEnabled) {
 59 resourceRequest.setHTTPHeaderField(HTTPHeaderName::Range, "bytes=0-2047");
 60 options.cache = FetchOptions::Cache::NoStore;
 61 }
 62
5763 String crossOriginMode = m_crossOriginMode;
5864 if (m_moduleScript == ModuleScript::Yes) {
5965 if (crossOriginMode.isNull())
6066 crossOriginMode = "omit"_s;
6167 }
62  auto request = createPotentialAccessControlRequest(completeURL(document), document, crossOriginMode, WTFMove(options));
 68 auto request = createPotentialAccessControlRequest(WTFMove(resourceRequest), document, crossOriginMode, WTFMove(options));
6369 request.setInitiator(m_initiator);
6470 return request;
6571}

Source/WebCore/html/parser/HTMLResourcePreloader.h

@@public:
5454 void setCharset(const String& charset) { m_charset = charset.isolatedCopy(); }
5555 void setCrossOriginMode(const String& mode) { m_crossOriginMode = mode; }
5656 void setNonce(const String& nonce) { m_nonceAttribute = nonce; }
 57 void setLazyloadImageEnabled(bool enabled) { m_lazyloadImageEnabled = enabled; }
5758 CachedResource::Type resourceType() const { return m_resourceType; }
5859
5960private:

@@private:
6869 String m_crossOriginMode;
6970 String m_nonceAttribute;
7071 ModuleScript m_moduleScript;
 72 bool m_lazyloadImageEnabled { false };
7173};
7274
7375typedef Vector<std::unique_ptr<PreloadRequest>> PreloadRequestStream;

Source/WebCore/loader/ImageLoader.cpp

3838#include "HTMLObjectElement.h"
3939#include "HTMLParserIdioms.h"
4040#include "InspectorInstrumentation.h"
 41#include "LazyLoadImageObserver.h"
4142#include "Page.h"
4243#include "RenderImage.h"
4344#include "RenderSVGImage.h"
 45#include "RuntimeEnabledFeatures.h"
 46#include "StyleProperties.h"
4447#include <wtf/NeverDestroyed.h>
4548
4649#if ENABLE(VIDEO)

@@template<> struct ValueCheck<WebCore::ImageLoader*> {
6669
6770namespace WebCore {
6871
 72static bool isLazyLoadableImage(const HTMLImageElement& htmlImage, const URL& url)
 73{
 74 // Do not lazyload image elements created from javascript.
 75 if (!htmlImage.createdByParser())
 76 return false;
 77 if (!url.protocolIsInHTTPFamily())
 78 return false;
 79 if (!equalLettersIgnoringASCIICase(htmlImage.attributeWithoutSynchronization(HTMLNames::loadingAttr), "lazy"))
 80 return false;
 81 // Avoid lazyloading if width and height attributes are small. This
 82 // heuristic helps avoid double fetching tracking pixels.
 83 if (HTMLImageElement::isDimensionSmallAndAbsoluteForLazyLoad(htmlImage.attributeWithoutSynchronization(HTMLNames::widthAttr))
 84 && HTMLImageElement::isDimensionSmallAndAbsoluteForLazyLoad(htmlImage.attributeWithoutSynchronization(HTMLNames::heightAttr)))
 85 return false;
 86 // Avoid lazyloading if width or height is specified in inline style and is
 87 // small enough. This heuristic helps avoid double fetching tracking pixels.
 88 if (HTMLImageElement::isInlineStyleDimensionsSmall(htmlImage.inlineStyle()))
 89 return false;
 90 return true;
 91}
 92
6993static ImageEventSender& beforeLoadEventSender()
7094{
7195 static NeverDestroyed<ImageEventSender> sender(eventNames().beforeloadEvent);

@@void ImageLoader::updateFromElement()
183207
184208 ResourceRequest resourceRequest(document.completeURL(sourceURI(attr)));
185209 resourceRequest.setInspectorInitiatorNodeIdentifier(InspectorInstrumentation::identifierForNode(m_element));
 210 if (m_lazyImageLoadState == LazyImageLoadState::kNone) {
 211 if (is<HTMLImageElement>(element())) {
 212 if (isLazyLoadableImage(downcast<HTMLImageElement>(element()), resourceRequest.url())
 213 && RuntimeEnabledFeatures::sharedFeatures().lazyImageLoadingEnabled()) {
 214 m_lazyImageLoadState = LazyImageLoadState::kDeferred;
 215 resourceRequest.setHTTPHeaderField(HTTPHeaderName::Range, "bytes=0-2047");
 216 options.cache = FetchOptions::Cache::NoStore;
 217 }
 218 }
 219 }
186220
187221 auto request = createPotentialAccessControlRequest(WTFMove(resourceRequest), document, crossOriginAttribute, WTFMove(options));
188222 request.setInitiator(element());

@@void ImageLoader::updateFromElement()
250284 } else
251285 updateRenderer();
252286
 287 if (m_lazyImageLoadState == LazyImageLoadState::kDeferred)
 288 LazyLoadImageObserver::startMonitoring(element());
253289 // If newImage is cached, addClient() will result in the load event
254290 // being queued to fire. Ensure this happens after beforeload is
255291 // dispatched.

@@void ImageLoader::notifyFinished(CachedResource& resource)
280316 ASSERT(m_failedLoadURL.isEmpty());
281317 ASSERT_UNUSED(resource, &resource == m_image.get());
282318
 319 if (m_lazyImageLoadState == LazyImageLoadState::kDeferred) {
 320 // LazyImages: if a placeholder is loaded, suppress load events and do not
 321 // consider the image as loaded, except for unblocking document load events.
 322 // The final image load (including load events) occurs when the
 323 // non-placeholder image loading (triggered by loadDeferredImage()) is
 324 // finished.
 325 if (resource.response().httpStatusCode() == 206)
 326 return;
 327 // A placeholder was requested, but the result was an error or a full image.
 328 // In these cases, consider this as the final image and suppress further
 329 // reloading and proceed to the image load completion process below.
 330 LazyLoadImageObserver::stopMonitoring(element());
 331 m_lazyImageLoadState = LazyImageLoadState::kFullImage;
 332 }
 333
283334 m_imageComplete = true;
284335 if (!hasPendingBeforeLoadEvent())
285336 updateRenderer();

@@inline void ImageLoader::clearFailedLoadURL()
542593 m_failedLoadURL = nullAtom();
543594}
544595
 596void ImageLoader::loadDeferredImage()
 597{
 598 if (m_lazyImageLoadState != LazyImageLoadState::kDeferred)
 599 return;
 600 m_lazyImageLoadState = LazyImageLoadState::kFullImage;
 601 updateFromElement();
 602}
 603
545604}

Source/WebCore/loader/ImageLoader.h

@@public:
7474 static void dispatchPendingLoadEvents();
7575 static void dispatchPendingErrorEvents();
7676
 77 void loadDeferredImage();
 78
7779protected:
7880 explicit ImageLoader(Element&);
7981 void notifyFinished(CachedResource&) override;
8082
8183private:
 84 // LazyImages: Defer the image load until the image is near the viewport.
 85 enum class LazyImageLoadState { kNone, kDeferred, kFullImage };
 86
8287 virtual void dispatchLoadEvent() = 0;
8388 virtual String sourceURI(const AtomicString&) const = 0;
8489

@@private:
112117 bool m_imageComplete : 1;
113118 bool m_loadManually : 1;
114119 bool m_elementIsProtected : 1;
 120 LazyImageLoadState m_lazyImageLoadState { LazyImageLoadState::kNone };
115121};
116122
117123}

Source/WebCore/page/RuntimeEnabledFeatures.h

@@public:
363363 bool linkPreloadResponsiveImagesEnabled() const { return m_linkPreloadResponsiveImagesEnabled; }
364364 void setLinkPreloadResponsiveImagesEnabled(bool isEnabled) { m_linkPreloadResponsiveImagesEnabled = isEnabled; }
365365
 366 void setLazyImageLoadingEnabled(bool areEnabled) { m_lazyImageLoadingEnabled = areEnabled; }
 367 bool lazyImageLoadingEnabled() const { return m_lazyImageLoadingEnabled; }
 368
366369 WEBCORE_EXPORT static RuntimeEnabledFeatures& sharedFeatures();
367370
368371private:

@@private:
550553
551554 bool m_linkPreloadResponsiveImagesEnabled { false };
552555
 556 bool m_lazyImageLoadingEnabled { false };
 557
553558 friend class WTF::NeverDestroyed<RuntimeEnabledFeatures>;
554559};
555560

Source/WebCore/page/Settings.yaml

@@resizeObserverEnabled:
736736 initial: false
737737 conditional: RESIZE_OBSERVER
738738
 739lazyImageLoadingEnabled:
 740 initial: false
 741
739742# Only set by Layout Tests.
740743mediaTypeOverride:
741744 type: String

Source/WebCore/rendering/style/RenderStyle.cpp

2828#include "CSSParser.h"
2929#include "CSSPropertyNames.h"
3030#include "CSSPropertyParser.h"
 31#include "CachedImage.h"
3132#include "ContentData.h"
3233#include "CursorList.h"
3334#include "FloatRoundedRect.h"

4243#include "ScaleTransformOperation.h"
4344#include "ShadowData.h"
4445#include "StyleBuilderConverter.h"
 46#include "StyleCachedImage.h"
4547#include "StyleImage.h"
4648#include "StyleInheritedData.h"
4749#include "StyleResolver.h"

@@Color RenderStyle::computedStrokeColor() const
24572459 return visitedDependentColor(propertyID);
24582460}
24592461
 2462void RenderStyle::loadDeferredImages(Document& document) const
 2463{
 2464 if (hasBackgroundImage()) {
 2465 for (auto* layer = &backgroundLayers(); layer; layer = layer->next()) {
 2466 if (layer->image() && is<StyleCachedImage>(*layer->image()))
 2467 downcast<StyleCachedImage>(*layer->image()).loadDeferredImage(document);
 2468 }
 2469 }
 2470}
 2471
24602472} // namespace WebCore

Source/WebCore/rendering/style/RenderStyle.h

@@public:
14401440
14411441 void setHasExplicitlyInheritedProperties() { m_nonInheritedFlags.hasExplicitlyInheritedProperties = true; }
14421442 bool hasExplicitlyInheritedProperties() const { return m_nonInheritedFlags.hasExplicitlyInheritedProperties; }
1443 
 1443
 1444 void loadDeferredImages(Document&) const;
 1445
14441446 // Initial values for all the properties
14451447 static Overflow initialOverflowX() { return Overflow::Visible; }
14461448 static Overflow initialOverflowY() { return Overflow::Visible; }

Source/WebCore/rendering/style/StyleCachedImage.cpp

2828#include "CSSImageSetValue.h"
2929#include "CSSImageValue.h"
3030#include "CachedImage.h"
 31#include "LazyLoadImageObserver.h"
3132#include "RenderElement.h"
3233#include "RenderView.h"
3334

@@void StyleCachedImage::addClient(RenderElement* renderer)
192193 return;
193194 ASSERT(renderer);
194195 m_cachedImage->addClient(*renderer);
 196 if (isLazyloadPossiblyDeferred() && is<CSSImageValue>(m_cssValue) && renderer->element())
 197 LazyLoadImageObserver::startMonitoring(*renderer->element());
195198}
196199
197200void StyleCachedImage::removeClient(RenderElement* renderer)

@@void StyleCachedImage::removeClient(RenderElement* renderer)
202205 ASSERT(renderer);
203206
204207 m_cachedImage->removeClient(*renderer);
 208 if (isLazyloadPossiblyDeferred() && is<CSSImageValue>(m_cssValue) && renderer->element())
 209 LazyLoadImageObserver::stopMonitoring(*renderer->element());
205210}
206211
207212RefPtr<Image> StyleCachedImage::image(RenderElement* renderer, const FloatSize&) const

@@bool StyleCachedImage::knownToBeOpaque(const RenderElement* renderer) const
224229 return m_cachedImage->currentFrameKnownToBeOpaque(renderer);
225230}
226231
 232void StyleCachedImage::loadDeferredImage(Document& document)
 233{
 234 if (!is<CSSImageValue>(m_cssValue))
 235 return;
 236 ResourceLoaderOptions options;
 237 options.cache = FetchOptions::Cache::Reload;
 238 auto& imageValue = downcast<CSSImageValue>(m_cssValue.get());
 239 m_cachedImage = imageValue.loadImage(document.cachedResourceLoader(), options, !imageURL().protocolIsInHTTPFamily());
 240 m_cachedImage->setLoading(true);
 241}
 242
227243}

Source/WebCore/rendering/style/StyleCachedImage.h

@@public:
6363 float imageScaleFactor() const final;
6464 bool knownToBeOpaque(const RenderElement*) const final;
6565
 66 void loadDeferredImage(Document&);
 67
6668private:
6769 StyleCachedImage(CSSValue&);
6870 URL imageURL();

Source/WebCore/rendering/style/StyleImage.h

@@public:
7171 ALWAYS_INLINE bool isCachedImage() const { return m_isCachedImage; }
7272 ALWAYS_INLINE bool isGeneratedImage() const { return m_isGeneratedImage; }
7373
 74 bool isLazyloadPossiblyDeferred() const { return m_isLazyloadPossiblyDeferred; }
 75
7476protected:
7577 StyleImage()
7678 : m_isCachedImage(false)
7779 , m_isGeneratedImage(false)
 80 , m_isLazyloadPossiblyDeferred(false)
7881 {
7982 }
8083 bool m_isCachedImage : 1;
8184 bool m_isGeneratedImage : 1;
 85 bool m_isLazyloadPossiblyDeferred : 1;
8286};
8387
8488} // namespace WebCore

Source/WebKit/Shared/WebPreferences.yaml

@@MediaCaptureRequiresSecureConnection:
17101710 type: bool
17111711 defaultValue: true
17121712 condition: ENABLE(MEDIA_STREAM)
 1713
 1714LazyImageLoadingEnabled:
 1715 type: bool
 1716 defaultValue: false
 1717 humanReadableName: "Lazy Image Loading"
 1718 humanReadableDescription: "Enable Lazy Image Loading support"
 1719 category: experimental
 1720 webcoreBinding: RuntimeEnabledFeatures

Source/WebKitLegacy/mac/WebView/WebPreferenceKeysPrivate.h

270270#define WebKitResizeObserverEnabledPreferenceKey @"WebKitResizeObserverEnabled"
271271#define WebKitCoreMathMLEnabledPreferenceKey @"WebKitCoreMathMLEnabled"
272272#define WebKitLinkPreloadResponsiveImagesEnabledPreferenceKey @"WebKitLinkPreloadResponsiveImagesEnabled"
 273#define WebKitLazyImageLoadingEnabledPreferenceKey @"WebKitLazyImageLoadingEnabled"
273274

Source/WebKitLegacy/mac/WebView/WebPreferences.mm

@@public:
690690#if ENABLE(RESIZE_OBSERVER)
691691 @NO, WebKitResizeObserverEnabledPreferenceKey,
692692#endif
 693 @NO, WebKitLazyImageLoadingEnabledPreferenceKey,
693694 @NO, WebKitCoreMathMLEnabledPreferenceKey,
694695 @NO, WebKitLinkPreloadResponsiveImagesEnabledPreferenceKey,
695696 nil];

@@static NSString *classIBCreatorID = nil;
34783479 [self _setBoolValue:flag forKey:WebKitLinkPreloadResponsiveImagesEnabledPreferenceKey];
34793480}
34803481
 3482- (BOOL)lazyImageLoadingEnabled
 3483{
 3484 return [self _boolValueForKey:WebKitLazyImageLoadingEnabledPreferenceKey];
 3485}
 3486
 3487- (void)setLazyImageLoadingEnabled:(BOOL)flag
 3488{
 3489 [self _setBoolValue:flag forKey:WebKitLazyImageLoadingEnabledPreferenceKey];
 3490}
 3491
34813492@end
34823493
34833494@implementation WebPreferences (WebInternal)

Source/WebKitLegacy/mac/WebView/WebPreferencesPrivate.h

@@extern NSString *WebPreferencesCacheModelChangedInternalNotification WEBKIT_DEPR
643643@property (nonatomic) BOOL resizeObserverEnabled;
644644@property (nonatomic) BOOL coreMathMLEnabled;
645645@property (nonatomic) BOOL linkPreloadResponsiveImagesEnabled;
 646@property (nonatomic) BOOL lazyImageLoadingEnabled;
646647
647648#if TARGET_OS_IPHONE
648649@property (nonatomic) BOOL quickLookDocumentSavingEnabled;

Source/WebKitLegacy/mac/WebView/WebView.mm

@@static bool needsSelfRetainWhileLoadingQuirk()
31783178 RuntimeEnabledFeatures::sharedFeatures().setFetchAPIKeepAliveEnabled([preferences fetchAPIKeepAliveEnabled]);
31793179 RuntimeEnabledFeatures::sharedFeatures().setReferrerPolicyAttributeEnabled([preferences referrerPolicyAttributeEnabled]);
31803180 RuntimeEnabledFeatures::sharedFeatures().setLinkPreloadResponsiveImagesEnabled([preferences linkPreloadResponsiveImagesEnabled]);
 3181 RuntimeEnabledFeatures::sharedFeatures().setLazyImageLoadingEnabled([preferences referrerPolicyAttributeEnabled]);
31813182
31823183#if ENABLE(LEGACY_ENCRYPTED_MEDIA)
31833184 RuntimeEnabledFeatures::sharedFeatures().setLegacyEncryptedMediaAPIEnabled(preferences.legacyEncryptedMediaAPIEnabled);

@@static bool needsSelfRetainWhileLoadingQuirk()
32323233#if ENABLE(RESIZE_OBSERVER)
32333234 settings.setResizeObserverEnabled([preferences resizeObserverEnabled]);
32343235#endif
 3236
 3237 settings.setLazyImageLoadingEnabled([preferences lazyImageLoadingEnabled]);
32353238}
32363239
32373240static inline IMP getMethod(id o, SEL s)

Source/WebKitLegacy/win/Interfaces/IWebPreferencesPrivate.idl

@@interface IWebPreferencesPrivate7 : IWebPreferencesPrivate6
242242 HRESULT setResizeObserverEnabled([in] BOOL enabled);
243243 HRESULT coreMathMLEnabled([out, retval] BOOL* enabled);
244244 HRESULT setCoreMathMLEnabled([in] BOOL enabled);
 245 HRESULT lazyImageLoadingEnabled([out, retval] BOOL*);
 246 HRESULT setLazyImageLoadingEnabled([in] BOOL enabled);
245247}

Source/WebKitLegacy/win/WebPreferenceKeysPrivate.h

209209#define WebKitResizeObserverEnabledPreferenceKey "WebKitResizeObserverEnabled"
210210
211211#define WebKitCoreMathMLEnabledPreferenceKey "WebKitCoreMathMLEnabled"
 212
 213#define WebKitLazyImageLoadingEnabledPreferenceKey "WebKitLazyImageLoadingEnabled"

Source/WebKitLegacy/win/WebPreferences.cpp

@@void WebPreferences::initializeDefaultSettings()
333333
334334 CFDictionaryAddValue(defaults, CFSTR(WebKitCoreMathMLEnabledPreferenceKey), kCFBooleanFalse);
335335
 336 CFDictionaryAddValue(defaults, CFSTR(WebKitLazyImageLoadingEnabledPreferenceKey), kCFBooleanFalse);
 337
336338 defaultSettings = defaults;
337339}
338340

@@HRESULT WebPreferences::setResizeObserverEnabled(BOOL enabled)
22922294 setBoolValue(WebKitResizeObserverEnabledPreferenceKey, enabled);
22932295 return S_OK;
22942296}
 2297
 2298HRESULT WebPreferences::lazyImageLoadingEnabled(_Out_ BOOL* enabled)
 2299{
 2300 if (!enabled)
 2301 return E_POINTER;
 2302 *enabled = boolValueForKey(WebKitLazyImageLoadingEnabledPreferenceKey);
 2303 return S_OK;
 2304}
 2305
 2306HRESULT WebPreferences::setLazyImageLoadingEnabled(BOOL enabled)
 2307{
 2308 setBoolValue(WebKitLazyImageLoadingEnabledPreferenceKey, enabled);
 2309 return S_OK;
 2310}

Source/WebKitLegacy/win/WebPreferences.h

@@public:
287287 virtual HRESULT STDMETHODCALLTYPE setResizeObserverEnabled(BOOL);
288288 virtual HRESULT STDMETHODCALLTYPE coreMathMLEnabled(_Out_ BOOL*);
289289 virtual HRESULT STDMETHODCALLTYPE setCoreMathMLEnabled(BOOL);
 290 virtual HRESULT STDMETHODCALLTYPE lazyImageLoadingEnabled(_Out_ BOOL*);
 291 virtual HRESULT STDMETHODCALLTYPE setLazyImageLoadingEnabled(BOOL);
290292
291293 // WebPreferences
292294

Source/WebKitLegacy/win/WebView.cpp

@@HRESULT WebView::notifyPreferencesChanged(IWebNotification* notification)
56065606 return hr;
56075607 settings.setCoreMathMLEnabled(!!enabled);
56085608
 5609 hr = prefsPrivate->lazyImageLoadingEnabled(&enabled);
 5610 if (FAILED(hr))
 5611 return hr;
 5612 RuntimeEnabledFeatures::sharedFeatures().setLazyImageLoadingEnabled(!!enabled);
 5613
56095614 return S_OK;
56105615}
56115616

Tools/ChangeLog

 12019-06-12 Rob Buis <rbuis@igalia.com>
 2
 3 Support lazy image and iframe loading (loading="lazy")
 4 https://bugs.webkit.org/show_bug.cgi?id=196698
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 Set lazyImageLoading preference as part of experimental features.
 9
 10 * DumpRenderTree/TestOptions.cpp:
 11 (TestOptions::TestOptions):
 12 * DumpRenderTree/TestOptions.h:
 13 * DumpRenderTree/mac/DumpRenderTree.mm:
 14 (enableExperimentalFeatures):
 15 (setWebPreferencesForTestOptions):
 16 * DumpRenderTree/win/DumpRenderTree.cpp:
 17 (enableExperimentalFeatures):
 18
1192019-06-11 Keith Rollin <krollin@apple.com>
220
321 Open up xcfilelist processing to more platforms

Tools/DumpRenderTree/TestOptions.cpp

@@TestOptions::TestOptions(const std::string& pathOrURL, const std::string& absolu
117117 enableResizeObserver = parseBooleanTestHeaderValue(value);
118118 else if (key == "experimental:CoreMathMLEnabled")
119119 enableCoreMathML = parseBooleanTestHeaderValue(value);
 120 else if (key == "experimental:LazyImageLoadingEnabled")
 121 enableLazyImageLoading = parseBooleanTestHeaderValue(value);
120122 pairStart = pairEnd + 1;
121123 }
122124}

Tools/DumpRenderTree/TestOptions.h

@@struct TestOptions {
4848 bool adClickAttributionEnabled { false };
4949 bool enableResizeObserver { false };
5050 bool enableCoreMathML { false };
 51 bool enableLazyImageLoading { false };
5152 std::string jscOptions;
5253 std::string additionalSupportedImageTypes;
5354

Tools/DumpRenderTree/mac/DumpRenderTree.mm

@@static void enableExperimentalFeatures(WebPreferences* preferences)
875875 [preferences setCSSOMViewScrollingAPIEnabled:YES];
876876 [preferences setMediaRecorderEnabled:YES];
877877 [preferences setReferrerPolicyAttributeEnabled:YES];
878  [preferences setReferrerPolicyAttributeEnabled:YES];
 878 [preferences setLazyImageLoadingEnabled:YES];
879879 [preferences setLinkPreloadResponsiveImagesEnabled:YES];
880880}
881881

@@static void setWebPreferencesForTestOptions(const TestOptions& options)
10221022 preferences.adClickAttributionEnabled = options.adClickAttributionEnabled;
10231023 preferences.resizeObserverEnabled = options.enableResizeObserver;
10241024 preferences.coreMathMLEnabled = options.enableCoreMathML;
 1025 preferences.lazyImageLoadingEnabled = options.enableLazyImageLoading;
10251026}
10261027
10271028// Called once on DumpRenderTree startup.

Tools/DumpRenderTree/win/DumpRenderTree.cpp

@@static void enableExperimentalFeatures(IWebPreferences* preferences)
793793 prefsPrivate->setResizeObserverEnabled(TRUE);
794794 prefsPrivate->setWebAnimationsEnabled(TRUE);
795795 prefsPrivate->setServerTimingEnabled(TRUE);
 796 prefsPrivate->setLazyImageLoadingEnabled(TRUE);
796797 // FIXME: WebGL2
797798 // FIXME: WebRTC
798799}

LayoutTests/ChangeLog

 12019-06-12 Rob Buis <rbuis@igalia.com>
 2
 3 Support lazy image and iframe loading (loading="lazy")
 4 https://bugs.webkit.org/show_bug.cgi?id=196698
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 Add lazyload tests.
 9
 10 * http/tests/lazyload/attribute-expected.txt: Added.
 11 * http/tests/lazyload/attribute.html: Added.
 12 * http/tests/lazyload/fixed-dimension-expected.txt: Added.
 13 * http/tests/lazyload/fixed-dimension.html: Added.
 14 * http/tests/lazyload/js-image-expected.txt: Added.
 15 * http/tests/lazyload/js-image.html: Added.
 16 * http/tests/lazyload/lazy-expected.txt: Added.
 17 * http/tests/lazyload/lazy.html: Added.
 18 * http/tests/lazyload/placeholder.js: Added.
 19 (is_image_fully_loaded):
 20 * http/tests/lazyload/scroll-expected.txt: Added.
 21 * http/tests/lazyload/scroll.html: Added.
 22 * http/tests/lazyload/style-dimension-expected.txt: Added.
 23 * http/tests/lazyload/style-dimension.html: Added.
 24 * platform/ios-simulator-wk2/TestExpectations:
 25 * platform/mac-wk1/TestExpectations:
 26 * platform/win/TestExpectations:
 27 * platform/wincairo-wk1/TestExpectations:
 28
1292019-06-11 Wenson Hsieh <wenson_hsieh@apple.com>
230
331 [iOS] Idempotent text autosizing needs to react properly to viewport changes

LayoutTests/imported/w3c/ChangeLog

 12019-06-12 Rob Buis <rbuis@igalia.com>
 2
 3 Support lazy image and iframe loading (loading="lazy")
 4 https://bugs.webkit.org/show_bug.cgi?id=196698
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 Import lazyload WPT tests.
 9
 10 * web-platform-tests/loading/lazyload/attribute_off_image.tentative-expected.txt: Added.
 11 * web-platform-tests/loading/lazyload/attribute_off_image.tentative.html: Added.
 12 * web-platform-tests/loading/lazyload/change_attribute_to_off_image.tentative-expected.txt: Added.
 13 * web-platform-tests/loading/lazyload/change_attribute_to_off_image.tentative.html: Added.
 14 * web-platform-tests/loading/lazyload/resources/image_1.png: Added.
 15 * web-platform-tests/loading/lazyload/resources/image_2.png: Added.
 16 * web-platform-tests/loading/lazyload/resources/image_3.png: Added.
 17 * web-platform-tests/loading/lazyload/resources/image_4.png: Added.
 18 * web-platform-tests/loading/lazyload/resources/subframe_1.html: Added.
 19 * web-platform-tests/loading/lazyload/resources/subframe_2.html: Added.
 20 * web-platform-tests/loading/lazyload/resources/subframe_3.html: Added.
 21 * web-platform-tests/loading/lazyload/resources/subframe_4.html: Added.
 22 * web-platform-tests/loading/lazyload/scroll_to_attribute_auto_image.tentative-expected.txt: Added.
 23 * web-platform-tests/loading/lazyload/scroll_to_attribute_auto_image.tentative.html: Added.
 24 * web-platform-tests/loading/lazyload/scroll_to_attribute_invalid_image.tentative-expected.txt: Added.
 25 * web-platform-tests/loading/lazyload/scroll_to_attribute_invalid_image.tentative.html: Added.
 26 * web-platform-tests/loading/lazyload/scroll_to_attribute_on_image.tentative-expected.txt: Added.
 27 * web-platform-tests/loading/lazyload/scroll_to_attribute_on_image.tentative.html: Added.
 28 * web-platform-tests/loading/lazyload/scroll_to_attribute_unset_image.tentative-expected.txt: Added.
 29 * web-platform-tests/loading/lazyload/scroll_to_attribute_unset_image.tentative.html: Added.
 30 * web-platform-tests/loading/lazyload/window_load_event_occurs_with_below_viewport_image.tentative-expected.txt: Added.
 31 * web-platform-tests/loading/lazyload/window_load_event_occurs_with_below_viewport_image.tentative.html: Added.
 32
1332019-06-11 Devin Rousso <drousso@apple.com>
234
335 Sort the computed styles list

LayoutTests/http/tests/lazyload/attribute-expected.txt

 1CONSOLE MESSAGE: line 2451: Error: assert_equals: expected (object) null but got (string) "eager"
 2CONSOLE MESSAGE: line 2451: Error: assert_equals: expected "auto" but got "eager"
 3CONSOLE MESSAGE: line 2451: Error: assert_equals: expected "invalid-value-default" but got "eager"
 4
 5
 6Harness Error (FAIL), message = Error: assert_equals: expected "invalid-value-default" but got "eager"
 7
 8PASS Test that document load event is fired
 9PASS Test that <img> with loading=lazy or auto or no attribute or invalid value are loaded as a placeholder
 10PASS Test that <img> with loading=eager is fully loaded, and not a placeholder
 11PASS Test that <img> with no loading attribute is fully loaded, and not a placeholder
 12PASS Test that <img> with loading=auto is fully loaded, and not a placeholder
 13PASS Test that <img> with invalid loading attribute is fully loaded, and not a placeholder
 14PASS Test that deferred <img> are fully loaded when lazyload is turned off
 15

LayoutTests/http/tests/lazyload/attribute.html

 1<!DOCTYPE html><!-- webkit-test-runner [ experimental:LazyImageLoadingEnabled=true ] -->
 2<script src="/resources/testharness.js"></script>
 3<script src="/resources/testharnessreport.js"></script>
 4<script src="placeholder.js"></script>
 5
 6<body>
 7 <div style="height:10000px;"></div>
 8 <img id="no_attribute_img" src='../loading/resources/base-image1.png'>
 9 <img loading="auto" id="auto_attribute_img" src='../loading/resources/base-image2.png'>
 10 <img loading="invalid-value-default" id="invalid_attribute_img" src='../loading/resources/base-image3.png'>
 11 <img loading="lazy" id="lazy_attribute_img" src='../loading/resources/dup-image1.png'>
 12 <img loading="eager" id="eager_attribute_img" src='../loading/resources/dup-image2.png'>
 13</body>
 14
 15<script>
 16 var no_attribute_img = document.getElementById("no_attribute_img");
 17 var auto_attribute_img = document.getElementById("auto_attribute_img");
 18 var invalid_attribute_img = document.getElementById("invalid_attribute_img");
 19 var lazy_attribute_img = document.getElementById("lazy_attribute_img");
 20 var eager_attribute_img = document.getElementById("eager_attribute_img");
 21
 22 async_test(function(t) {
 23 window.addEventListener("load", t.step_func_done());
 24 }, "Test that document load event is fired");
 25
 26 async_test(function(t) {
 27 window.addEventListener("load", t.step_func_done(function() {
 28 assert_false(is_image_fully_loaded(lazy_attribute_img));
 29 assert_true(is_image_fully_loaded(no_attribute_img));
 30 }));
 31 lazy_attribute_img.addEventListener("load",
 32 t.unreached_func("Load event should not be fired for below viewport image with loading=lazy"));
 33 }, "Test that <img> with loading=lazy or auto or no attribute or invalid value are loaded as a placeholder");
 34
 35 async_test(function(t) {
 36 eager_attribute_img.addEventListener("load",
 37 t.step_func_done(function() {
 38 assert_true(is_image_fully_loaded(eager_attribute_img));
 39 }));
 40 }, "Test that <img> with loading=eager is fully loaded, and not a placeholder");
 41
 42 async_test(function(t) {
 43 no_attribute_img.addEventListener("load",
 44 t.step_func_done(function() {
 45 assert_true(is_image_fully_loaded(eager_attribute_img));
 46 }));
 47 }, "Test that <img> with no loading attribute is fully loaded, and not a placeholder");
 48
 49 async_test(function(t) {
 50 auto_attribute_img.addEventListener("load",
 51 t.step_func_done(function() {
 52 assert_true(is_image_fully_loaded(eager_attribute_img));
 53 }));
 54 }, "Test that <img> with loading=auto is fully loaded, and not a placeholder");
 55
 56 async_test(function(t) {
 57 invalid_attribute_img.addEventListener("load",
 58 t.step_func_done(function() {
 59 assert_true(is_image_fully_loaded(eager_attribute_img));
 60 }));
 61 }, "Test that <img> with invalid loading attribute is fully loaded, and not a placeholder");
 62
 63 async_test(function(t) {
 64 var complete = 0;
 65 var onload_callback = function() {
 66 if (++complete == 4) {
 67 // The four images with loading=lazy,auto or default or invalid attribute are loaded.
 68 assert_true(is_image_fully_loaded(no_attribute_img));
 69 assert_true(is_image_fully_loaded(lazy_attribute_img));
 70 assert_true(is_image_fully_loaded(auto_attribute_img));
 71 assert_true(is_image_fully_loaded(invalid_attribute_img));
 72 t.done();
 73 }
 74 assert_equals("eager", this.getAttribute('loading'));
 75 };
 76 no_attribute_img.addEventListener("load", onload_callback);
 77 lazy_attribute_img.addEventListener("load", onload_callback);
 78 auto_attribute_img.addEventListener("load", onload_callback);
 79 invalid_attribute_img.addEventListener("load", onload_callback);
 80 window.addEventListener("load", t.step_func(function() {
 81 assert_equals(null, no_attribute_img.getAttribute('loading'));
 82 assert_equals("lazy", lazy_attribute_img.getAttribute('loading'));
 83 assert_equals("auto", auto_attribute_img.getAttribute('loading'));
 84 assert_equals("invalid-value-default", invalid_attribute_img.getAttribute('loading'));
 85 no_attribute_img.setAttribute('loading', 'eager');
 86 lazy_attribute_img.setAttribute('loading', 'eager');
 87 auto_attribute_img.setAttribute('loading', 'eager');
 88 invalid_attribute_img.setAttribute('loading', 'eager');
 89 }));
 90 }, "Test that deferred <img> are fully loaded when lazyload is turned off");
 91</script>

LayoutTests/http/tests/lazyload/fixed-dimension-expected.txt

 1
 2
 3PASS Test that document load event is fired
 4PASS Test that small <img> with fixed height and width is loaded, and not a placeholder
 5PASS Test that <img> with non fixed height and width below the viewport is loaded as placeholder
 6

LayoutTests/http/tests/lazyload/fixed-dimension.html

 1<!DOCTYPE html>
 2<script src="/resources/testharness.js"></script>
 3<script src="/resources/testharnessreport.js"></script>
 4<script src="placeholder.js"></script>
 5
 6<body>
 7 <div style="height:10000px;"></div>
 8 <img id="fixed_dimension_img" src='../loading/resources/base-image1.png' width="10" height="10" loading="lazy">
 9 <img id="large_dimension_img" src='../loading/resources/base-image2.png' width="100" height="100" loading="lazy">
 10 <img id="percent_dimension_img" src='../loading/resources/base-image3.png' width="10%" height="10%" loading="lazy">
 11 <img id="fixed_width_only_img" src='../loading/resources/dup-image1.png' width="10" loading="lazy">
 12 <img id="fixed_height_only_img" src='../loading/resources/dup-image2.png' height="10" loading="lazy">
 13</body>
 14
 15<script>
 16 async_test(function(t) {
 17 window.addEventListener("load", t.step_func_done());
 18 }, "Test that document load event is fired");
 19
 20 async_test(function(t) {
 21 var fixed_dimension_img = document.getElementById("fixed_dimension_img");
 22 fixed_dimension_img.addEventListener("load",
 23 t.step_func_done(function() {
 24 assert_true(is_image_fully_loaded(fixed_dimension_img));
 25 }));
 26 }, "Test that small <img> with fixed height and width is loaded, and not a placeholder");
 27
 28 async_test(function(t) {
 29 var large_dimension_img = document.getElementById("large_dimension_img");
 30 var percent_dimension_img = document.getElementById("percent_dimension_img");
 31 var fixed_width_only_img = document.getElementById("fixed_width_only_img");
 32 var fixed_height_only_img = document.getElementById("fixed_height_only_img");
 33 window.addEventListener("load", t.step_func_done(function() {
 34 assert_false(is_image_fully_loaded(large_dimension_img));
 35 assert_false(is_image_fully_loaded(percent_dimension_img));
 36 assert_false(is_image_fully_loaded(fixed_width_only_img));
 37 assert_false(is_image_fully_loaded(fixed_height_only_img));
 38 }));
 39 large_dimension_img.addEventListener("load",
 40 t.unreached_func("Load event should not be fired for below viewport image with large fixed dimension"));
 41 percent_dimension_img.addEventListener("load",
 42 t.unreached_func("Load event should not be fired for below viewport image with percentage dimension"));
 43 fixed_width_only_img.addEventListener("load",
 44 t.unreached_func("Load event should not be fired for below viewport image with only fixed width"));
 45 fixed_height_only_img.addEventListener("load",
 46 t.unreached_func("Load event should not be fired for below viewport image with only fixed height"));
 47 }, "Test that <img> with non fixed height and width below the viewport is loaded as placeholder");
 48</script>

LayoutTests/http/tests/lazyload/js-image-expected.txt

 1
 2
 3PASS Test that load event is fired for JS Image() fetches
 4PASS Test that load event is fired for <img> created via JS and attached below viewport
 5

LayoutTests/http/tests/lazyload/js-image.html

 1<!DOCTYPE html><!-- webkit-test-runner [ experimental:LazyImageLoadingEnabled=true ] -->
 2<script src="/resources/testharness.js"></script>
 3<script src="/resources/testharnessreport.js"></script>
 4<script src="placeholder.js"></script>
 5
 6<body>
 7 <div style="height:10000px;"></div>
 8</body>
 9
 10<script>
 11 async_test(function(t) {
 12 const img = new Image();
 13 img.onload = t.step_func_done(function() {
 14 assert_true(is_image_fully_loaded(img));
 15 });
 16 img.src = '../loading/resources/base-image1.png';
 17 }, "Test that load event is fired for JS Image() fetches");
 18
 19 async_test(function(t) {
 20 const attached_img = document.createElement("IMG");
 21 document.body.appendChild(attached_img);
 22 attached_img.onload = t.step_func_done(function() {
 23 assert_true(is_image_fully_loaded(attached_img));
 24 });
 25 attached_img.src = "../loading/resources/base-image2.png";
 26 }, "Test that load event is fired for <img> created via JS and attached below viewport");
 27</script>

LayoutTests/http/tests/lazyload/lazy-expected.txt

 1
 2
 3
 4PASS Test that document load event is fired
 5PASS Test that <img> in viewport is loaded, and not a placeholder
 6PASS Test that <img> below viewport is a placeholder, with lazyimage enabled
 7

LayoutTests/http/tests/lazyload/lazy.html

 1<!DOCTYPE html><!-- webkit-test-runner [ experimental:LazyImageLoadingEnabled=true ] -->
 2<script src="/resources/testharness.js"></script>
 3<script src="/resources/testharnessreport.js"></script>
 4<script src="placeholder.js"></script>
 5
 6<body>
 7 <img id="in_viewport" src='../loading/resources/base-image1.png' loading="lazy">
 8 <div style="height:10000px;"></div>
 9 <img id="below_viewport" src='../loading/resources/base-image2.png' loading="lazy">
 10</body>
 11
 12<script>
 13 var in_viewport_element = document.getElementById("in_viewport");
 14 var below_viewport_element = document.getElementById("below_viewport");
 15 async_test(function(t) {
 16 window.addEventListener("load", t.step_func_done());
 17 }, "Test that document load event is fired");
 18
 19 async_test(function(t) {
 20 in_viewport_element.addEventListener("load",
 21 t.step_func_done(function() {
 22 assert_true(is_image_fully_loaded(in_viewport_element));
 23 }));
 24 }, "Test that <img> in viewport is loaded, and not a placeholder");
 25
 26 async_test(function(t) {
 27 var complete = 0;
 28 var onload_callback = function() {
 29 if (++complete == 2) {
 30 // Document and the above viewport image has loaded.
 31 assert_false(is_image_fully_loaded(below_viewport_element));
 32 t.done();
 33 }
 34 };
 35 window.addEventListener("load", t.step_func(onload_callback));
 36 in_viewport_element.addEventListener("load",
 37 t.step_func(onload_callback));
 38 below_viewport_element.addEventListener("load",
 39 t.unreached_func("Load event should not be fired for below viewport image"));
 40 }, "Test that <img> below viewport is a placeholder, with lazyimage enabled");
 41</script>

LayoutTests/http/tests/lazyload/placeholder.js

 1// Returns if the image is complete and fully loaded as a non-placeholder image.
 2function is_image_fully_loaded(image) {
 3 if (!image.complete) {
 4 return false;
 5 }
 6
 7 let canvas = document.createElement('canvas');
 8 canvas.width = canvas.height = 1;
 9 let canvasContext = canvas.getContext("2d");
 10 canvasContext.drawImage(image, 0, 0);
 11 let data = canvasContext.getImageData(0, 0, canvas.width, canvas.height).data;
 12
 13 // Fully loaded image should not be a placeholder which is drawn as a
 14 // translucent gray rectangle in placeholder_image.cc
 15 return data[0] != 0xd9 || data[1] != 0xd9 || data[2] != 0xd9;
 16}

LayoutTests/http/tests/lazyload/scroll-expected.txt

 1
 2
 3
 4PASS Test that document load event is fired
 5PASS Test that <img> in viewport is loaded, and not a placeholder
 6PASS Test that <img> below viewport is loaded when scrolled near, and not a placeholder
 7

LayoutTests/http/tests/lazyload/scroll.html

 1<!DOCTYPE html><!-- webkit-test-runner [ experimental:LazyImageLoadingEnabled=true ] -->
 2<script src="/resources/testharness.js"></script>
 3<script src="/resources/testharnessreport.js"></script>
 4<script src="placeholder.js"></script>
 5
 6<body>
 7 <img id="in_viewport" src='../loading/resources/base-image1.png'>
 8 <div style="height:10000px;"></div>
 9 <img id="below_viewport" src='../loading/resources/base-image2.png'>
 10</body>
 11
 12<script>
 13 var in_viewport_element = document.getElementById("in_viewport");
 14 var below_viewport_element = document.getElementById("below_viewport");
 15 async_test(function(t) {
 16 window.addEventListener("load", t.step_func_done());
 17 }, "Test that document load event is fired");
 18
 19 async_test(function(t) {
 20 in_viewport_element.addEventListener("load",
 21 t.step_func_done(function() {
 22 assert_true(is_image_fully_loaded(in_viewport_element));
 23 }));
 24 }, "Test that <img> in viewport is loaded, and not a placeholder");
 25
 26 async_test(function(t) {
 27 in_viewport_element.addEventListener("load", t.step_func(function() {
 28 below_viewport_element.scrollIntoView();
 29 }));
 30 below_viewport_element.addEventListener("load",
 31 t.step_func_done(function() {
 32 assert_true(is_image_fully_loaded(below_viewport_element));
 33 }));
 34 }, "Test that <img> below viewport is loaded when scrolled near, and not a placeholder");
 35</script>

LayoutTests/http/tests/lazyload/style-dimension-expected.txt

 1
 2
 3PASS Test that document load event is fired
 4PASS Test that small <img> with width and height mentioned in inline dimensions is not deferred by lazyload
 5PASS Test that <img> with non small height or width below the viewport is loaded as placeholder
 6

LayoutTests/http/tests/lazyload/style-dimension.html

 1<!DOCTYPE html><!-- webkit-test-runner [ experimental:LazyImageLoadingEnabled=true ] -->
 2<script src="/resources/testharness.js"></script>
 3<script src="/resources/testharnessreport.js"></script>
 4<script src="placeholder.js"></script>
 5
 6<body>
 7 <div style="height:10000px;"></div>
 8 <img id="small_dimension_img" style="height:1px; width:10px" src='../loading/resources/base-image1.png' loading="lazy">
 9 <img id="large_dimension_img" src='../loading/resources/base-image2.png' style="height:20px; width:20px" loading="lazy">
 10 <img id="height_only_img" src='../loading/resources/base-image3.png' style="height:1px;" loading='lazy'>
 11 <img id="width_only_img" src='../loading/resources/dup-image1.png' style="width:1px;" loading='lazy'>
 12 <img id="percent_dimension_img" src='../loading/resources/dup-image2.png' style="height:10%; width:10%" loading="lazy">
 13</body>
 14
 15<script>
 16 async_test(function(t) {
 17 window.addEventListener("load", t.step_func_done());
 18 }, "Test that document load event is fired");
 19
 20 async_test(function(t) {
 21 var small_dimension_img = document.getElementById("small_dimension_img");
 22 small_dimension_img.addEventListener("load",
 23 t.step_func_done(function() {
 24 assert_true(is_image_fully_loaded(small_dimension_img));
 25 }));
 26 }, "Test that small <img> with width and height mentioned in inline dimensions is not deferred by lazyload ");
 27
 28 async_test(function(t) {
 29 var large_dimension_img = document.getElementById("large_dimension_img");
 30 var height_only_img = document.getElementById("height_only_img");
 31 var width_only_img = document.getElementById("width_only_img");
 32 var percent_dimension_img = document.getElementById("percent_dimension_img");
 33 window.addEventListener("load", t.step_func_done(function() {
 34 assert_false(is_image_fully_loaded(large_dimension_img));
 35 assert_false(is_image_fully_loaded(height_only_img));
 36 assert_false(is_image_fully_loaded(width_only_img));
 37 assert_false(is_image_fully_loaded(percent_dimension_img));
 38 }));
 39 large_dimension_img.addEventListener("load",
 40 t.unreached_func("Load event should not be fired for below viewport image with large inline dimension"));
 41 height_only_img.addEventListener("load",
 42 t.unreached_func("Load event should not be fired for below viewport image with only inline height"));
 43 width_only_img.addEventListener("load",
 44 t.unreached_func("Load event should not be fired for below viewport image with only inline width"));
 45 percent_dimension_img.addEventListener("load",
 46 t.unreached_func("Load event should not be fired for below viewport image with percentage inline dimension"));
 47 }, "Test that <img> with non small height or width below the viewport is loaded as placeholder");
 48</script>

LayoutTests/imported/w3c/web-platform-tests/loading/lazyload/attribute_off_image.tentative-expected.txt

 1main frame - didStartProvisionalLoadForFrame
 2main frame - didCommitLoadForFrame
 3main frame - didReceiveTitle: Loading images with loading="eager"
 4main frame - didFinishDocumentLoadForFrame
 5main frame - didHandleOnloadEventsForFrame
 6main frame - didFinishLoadForFrame
 7
 8
 9
 10PASS Test that both images load immediately and block the window's load event.
 11

LayoutTests/imported/w3c/web-platform-tests/loading/lazyload/attribute_off_image.tentative.html

 1<!DOCTYPE html>
 2<head>
 3 <title>Loading images with loading="eager"</title>
 4 <link rel="author" title="Scott Little" href="mailto:sclittle@chromium.org">
 5 <link rel="help" href="https://github.com/whatwg/html/pull/3752">
 6 <script src="/resources/testharness.js"></script>
 7 <script src="/resources/testharnessreport.js"></script>
 8</head>
 9
 10<!--
 11Marked as tentative until https://github.com/whatwg/html/pull/3752 is landed.
 12-->
 13
 14<body>
 15 <img id="in_viewport" src="resources/image_1.png" loading="eager">
 16 <div style="height:10000px;"></div>
 17 <img id="below_viewport" src="resources/image_2.png" loading="eager">
 18</body>
 19
 20<script>
 21 var t = async_test("Test that both images load immediately and block the window's load event.");
 22
 23 var has_in_viewport_image_loaded = false;
 24 document.getElementById("in_viewport").addEventListener("load",
 25 t.step_func(function() {
 26 assert_false(has_in_viewport_image_loaded);
 27 has_in_viewport_image_loaded = true;
 28 }));
 29
 30 var has_below_viewport_image_loaded = false;
 31 document.getElementById("below_viewport").addEventListener("load",
 32 t.step_func(function() {
 33 assert_false(has_below_viewport_image_loaded);
 34 has_below_viewport_image_loaded = true;
 35 }));
 36
 37 window.addEventListener("load", t.step_func_done(function() {
 38 assert_true(has_in_viewport_image_loaded);
 39 assert_true(has_below_viewport_image_loaded);
 40 }));
 41</script>

LayoutTests/imported/w3c/web-platform-tests/loading/lazyload/change_attribute_to_off_image.tentative-expected.txt

 1main frame - didStartProvisionalLoadForFrame
 2main frame - didCommitLoadForFrame
 3main frame - didReceiveTitle: Images load immediately when load attribute is changed to "off"
 4main frame - didFinishDocumentLoadForFrame
 5main frame - didHandleOnloadEventsForFrame
 6main frame - didFinishLoadForFrame
 7
 8
 9PASS Test that a below viewport image that has its load attribute changed to off is loaded.
 10

LayoutTests/imported/w3c/web-platform-tests/loading/lazyload/change_attribute_to_off_image.tentative.html

 1<!DOCTYPE html>
 2<head>
 3 <title>Images load immediately when load attribute is changed to "off"</title>
 4 <link rel="author" title="Scott Little" href="mailto:sclittle@chromium.org">
 5 <link rel="help" href="https://github.com/whatwg/html/pull/3752">
 6 <script src="/resources/testharness.js"></script>
 7 <script src="/resources/testharnessreport.js"></script>
 8</head>
 9
 10<!--
 11Marked as tentative until https://github.com/whatwg/html/pull/3752 is landed.
 12-->
 13
 14<body>
 15 <div style="height:10000px;"></div>
 16 <img id="attribute_unset" src="resources/image_1.png">
 17 <img id="attribute_invalid" src="resources/image_2.png" load="invalid_value">
 18 <img id="attribute_auto" src="resources/image_3.png" load="auto">
 19 <img id="attribute_on" src="resources/image_4.png" load="lazy">
 20</body>
 21
 22<script>
 23 var t = async_test("Test that a below viewport image that has its load attribute changed to off is loaded.");
 24
 25 var has_attribute_unset_loaded = false;
 26 var has_attribute_invalid_loaded = false;
 27 var has_attribute_auto_loaded = false;
 28 var has_attribute_on_loaded = false;
 29
 30 function checkIfDone() {
 31 if (has_attribute_unset_loaded &&
 32 has_attribute_invalid_loaded &&
 33 has_attribute_auto_loaded &&
 34 has_attribute_on_loaded) {
 35 t.done();
 36 }
 37 }
 38
 39 document.getElementById("attribute_unset").addEventListener("load", t.step_func(function() {
 40 assert_false(has_attribute_unset_loaded);
 41 has_attribute_unset_loaded = true;
 42 checkIfDone();
 43 }));
 44 document.getElementById("attribute_invalid").addEventListener("load", t.step_func(function() {
 45 assert_false(has_attribute_invalid_loaded);
 46 has_attribute_invalid_loaded = true;
 47 checkIfDone();
 48 }));
 49 document.getElementById("attribute_auto").addEventListener("load", t.step_func(function() {
 50 assert_false(has_attribute_auto_loaded);
 51 has_attribute_auto_loaded = true;
 52 checkIfDone();
 53 }));
 54 document.getElementById("attribute_on").addEventListener("load", t.step_func(function() {
 55 assert_false(has_attribute_on_loaded);
 56 has_attribute_on_loaded = true;
 57 checkIfDone();
 58 }));
 59
 60 window.addEventListener("load", t.step_func_done(function() {
 61 document.getElementById("attribute_unset").setAttribute("load", "eager");
 62 document.getElementById("attribute_invalid").setAttribute("load", "eager");
 63 document.getElementById("attribute_auto").setAttribute("load", "eager");
 64 document.getElementById("attribute_on").setAttribute("load", "eager");
 65 }));
 66</script>

LayoutTests/imported/w3c/web-platform-tests/loading/lazyload/resources/image_1.png

Exception raised during decoding git binary patch:
Error running git apply --directory=/tmp
with patch:
diff --git a/PrettyPatch20260621-40734-16mt7q8.bin b/PrettyPatch20260621-40734-16mt7q8.bin
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 0
HcmV?d00001

...
error: invalid path '/tmp/PrettyPatch20260621-40734-16mt7q8.bin'

/var/www/bugs.webkit.org/Websites/bugs.webkit.org/PrettyPatch/PrettyPatch.rb:924:in `run_git_apply_on_patch'
/var/www/bugs.webkit.org/Websites/bugs.webkit.org/PrettyPatch/PrettyPatch.rb:935:in `extract_contents_from_git_binary_literal_chunk'
/var/www/bugs.webkit.org/Websites/bugs.webkit.org/PrettyPatch/PrettyPatch.rb:950:in `extract_contents_from_remote'
/var/www/bugs.webkit.org/Websites/bugs.webkit.org/PrettyPatch/PrettyPatch.rb:713:in `initialize'
/var/www/bugs.webkit.org/Websites/bugs.webkit.org/PrettyPatch/PrettyPatch.rb:845:in `new'
/var/www/bugs.webkit.org/Websites/bugs.webkit.org/PrettyPatch/PrettyPatch.rb:845:in `block in parse'
/var/www/bugs.webkit.org/Websites/bugs.webkit.org/PrettyPatch/PrettyPatch.rb:845:in `collect'
/var/www/bugs.webkit.org/Websites/bugs.webkit.org/PrettyPatch/PrettyPatch.rb:845:in `parse'
/var/www/bugs.webkit.org/Websites/bugs.webkit.org/PrettyPatch/PrettyPatch.rb:21:in `prettify'
/var/www/html/PrettyPatch/prettify.rb:30:in `<main>'

LayoutTests/imported/w3c/web-platform-tests/loading/lazyload/resources/image_2.png

Exception raised during decoding git binary patch:
Error running git apply --directory=/tmp
with patch:
diff --git a/PrettyPatch20260621-40734-q6hezp.bin b/PrettyPatch20260621-40734-q6hezp.bin
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 0
HcmV?d00001

...
error: invalid path '/tmp/PrettyPatch20260621-40734-q6hezp.bin'

/var/www/bugs.webkit.org/Websites/bugs.webkit.org/PrettyPatch/PrettyPatch.rb:924:in `run_git_apply_on_patch'
/var/www/bugs.webkit.org/Websites/bugs.webkit.org/PrettyPatch/PrettyPatch.rb:935:in `extract_contents_from_git_binary_literal_chunk'
/var/www/bugs.webkit.org/Websites/bugs.webkit.org/PrettyPatch/PrettyPatch.rb:950:in `extract_contents_from_remote'
/var/www/bugs.webkit.org/Websites/bugs.webkit.org/PrettyPatch/PrettyPatch.rb:713:in `initialize'
/var/www/bugs.webkit.org/Websites/bugs.webkit.org/PrettyPatch/PrettyPatch.rb:845:in `new'
/var/www/bugs.webkit.org/Websites/bugs.webkit.org/PrettyPatch/PrettyPatch.rb:845:in `block in parse'
/var/www/bugs.webkit.org/Websites/bugs.webkit.org/PrettyPatch/PrettyPatch.rb:845:in `collect'
/var/www/bugs.webkit.org/Websites/bugs.webkit.org/PrettyPatch/PrettyPatch.rb:845:in `parse'
/var/www/bugs.webkit.org/Websites/bugs.webkit.org/PrettyPatch/PrettyPatch.rb:21:in `prettify'
/var/www/html/PrettyPatch/prettify.rb:30:in `<main>'

LayoutTests/imported/w3c/web-platform-tests/loading/lazyload/resources/image_3.png

Exception raised during decoding git binary patch:
Error running git apply --directory=/tmp
with patch:
diff --git a/PrettyPatch20260621-40734-a0popt.bin b/PrettyPatch20260621-40734-a0popt.bin
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 0
HcmV?d00001

...
error: invalid path '/tmp/PrettyPatch20260621-40734-a0popt.bin'

/var/www/bugs.webkit.org/Websites/bugs.webkit.org/PrettyPatch/PrettyPatch.rb:924:in `run_git_apply_on_patch'
/var/www/bugs.webkit.org/Websites/bugs.webkit.org/PrettyPatch/PrettyPatch.rb:935:in `extract_contents_from_git_binary_literal_chunk'
/var/www/bugs.webkit.org/Websites/bugs.webkit.org/PrettyPatch/PrettyPatch.rb:950:in `extract_contents_from_remote'
/var/www/bugs.webkit.org/Websites/bugs.webkit.org/PrettyPatch/PrettyPatch.rb:713:in `initialize'
/var/www/bugs.webkit.org/Websites/bugs.webkit.org/PrettyPatch/PrettyPatch.rb:845:in `new'
/var/www/bugs.webkit.org/Websites/bugs.webkit.org/PrettyPatch/PrettyPatch.rb:845:in `block in parse'
/var/www/bugs.webkit.org/Websites/bugs.webkit.org/PrettyPatch/PrettyPatch.rb:845:in `collect'
/var/www/bugs.webkit.org/Websites/bugs.webkit.org/PrettyPatch/PrettyPatch.rb:845:in `parse'
/var/www/bugs.webkit.org/Websites/bugs.webkit.org/PrettyPatch/PrettyPatch.rb:21:in `prettify'
/var/www/html/PrettyPatch/prettify.rb:30:in `<main>'

LayoutTests/imported/w3c/web-platform-tests/loading/lazyload/resources/image_4.png

Exception raised during decoding git binary patch:
Error running git apply --directory=/tmp
with patch:
diff --git a/PrettyPatch20260621-40734-1am9cbj.bin b/PrettyPatch20260621-40734-1am9cbj.bin
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 0
HcmV?d00001

...
error: invalid path '/tmp/PrettyPatch20260621-40734-1am9cbj.bin'

/var/www/bugs.webkit.org/Websites/bugs.webkit.org/PrettyPatch/PrettyPatch.rb:924:in `run_git_apply_on_patch'
/var/www/bugs.webkit.org/Websites/bugs.webkit.org/PrettyPatch/PrettyPatch.rb:935:in `extract_contents_from_git_binary_literal_chunk'
/var/www/bugs.webkit.org/Websites/bugs.webkit.org/PrettyPatch/PrettyPatch.rb:950:in `extract_contents_from_remote'
/var/www/bugs.webkit.org/Websites/bugs.webkit.org/PrettyPatch/PrettyPatch.rb:713:in `initialize'
/var/www/bugs.webkit.org/Websites/bugs.webkit.org/PrettyPatch/PrettyPatch.rb:845:in `new'
/var/www/bugs.webkit.org/Websites/bugs.webkit.org/PrettyPatch/PrettyPatch.rb:845:in `block in parse'
/var/www/bugs.webkit.org/Websites/bugs.webkit.org/PrettyPatch/PrettyPatch.rb:845:in `collect'
/var/www/bugs.webkit.org/Websites/bugs.webkit.org/PrettyPatch/PrettyPatch.rb:845:in `parse'
/var/www/bugs.webkit.org/Websites/bugs.webkit.org/PrettyPatch/PrettyPatch.rb:21:in `prettify'
/var/www/html/PrettyPatch/prettify.rb:30:in `<main>'

LayoutTests/imported/w3c/web-platform-tests/loading/lazyload/resources/subframe_1.html

 1<html>
 2 <body>
 3 <p>Subframe 1.</p>
 4 </body>
 5</html>

LayoutTests/imported/w3c/web-platform-tests/loading/lazyload/resources/subframe_2.html

 1<html>
 2 <body>
 3 <p>Subframe 2.</p>
 4 </body>
 5</html>

LayoutTests/imported/w3c/web-platform-tests/loading/lazyload/resources/subframe_3.html

 1<html>
 2 <body>
 3 <p>Subframe 3.</p>
 4 </body>
 5</html>

LayoutTests/imported/w3c/web-platform-tests/loading/lazyload/resources/subframe_4.html

 1<html>
 2 <body>
 3 <p>Subframe 4.</p>
 4 </body>
 5</html>

LayoutTests/imported/w3c/web-platform-tests/loading/lazyload/scroll_to_attribute_auto_image.tentative-expected.txt

 1main frame - didStartProvisionalLoadForFrame
 2main frame - didCommitLoadForFrame
 3main frame - didReceiveTitle: Images with loading="auto" load when in the viewport
 4main frame - didFinishDocumentLoadForFrame
 5main frame - didHandleOnloadEventsForFrame
 6main frame - didFinishLoadForFrame
 7
 8
 9
 10PASS Test that images with loading='auto' that enter the viewport get loaded.
 11

LayoutTests/imported/w3c/web-platform-tests/loading/lazyload/scroll_to_attribute_auto_image.tentative.html

 1<!DOCTYPE html>
 2<head>
 3 <title>Images with loading="auto" load when in the viewport</title>
 4 <link rel="author" title="Scott Little" href="mailto:sclittle@chromium.org">
 5 <link rel="help" href="https://github.com/whatwg/html/pull/3752">
 6 <script src="/resources/testharness.js"></script>
 7 <script src="/resources/testharnessreport.js"></script>
 8</head>
 9
 10<!--
 11Marked as tentative until https://github.com/whatwg/html/pull/3752 is landed.
 12-->
 13
 14<body>
 15 <img id="in_viewport" src="resources/image_1.png" loading="auto">
 16 <div style="height:10000px;"></div>
 17 <img id="below_viewport" src="resources/image_2.png" loading="auto">
 18</body>
 19
 20<script>
 21 var t = async_test("Test that images with loading='auto' that enter the viewport get loaded.");
 22
 23 var has_in_viewport_loaded = false;
 24 var has_below_viewport_loaded = false;
 25
 26 document.getElementById("in_viewport").addEventListener("load", t.step_func(function() {
 27 assert_false(has_in_viewport_loaded);
 28 has_in_viewport_loaded = true;
 29 if (has_below_viewport_loaded) {
 30 // Note that the below_viewport element's load event could happen before
 31 // the window.load event occurs, if the browser decides to load it
 32 // immediately instead of lazily loading. This is valid behavior, so the
 33 // test has passed if the below_viewport element has loaded.
 34 t.done();
 35 } else {
 36 document.getElementById("below_viewport").scrollIntoView();
 37 }
 38 }));
 39
 40 document.getElementById("below_viewport").addEventListener("load", t.step_func(function() {
 41 assert_false(has_below_viewport_loaded);
 42 has_below_viewport_loaded = true;
 43 if (has_in_viewport_loaded) {
 44 t.done();
 45 }
 46 }));
 47</script>

LayoutTests/imported/w3c/web-platform-tests/loading/lazyload/scroll_to_attribute_invalid_image.tentative-expected.txt

 1main frame - didStartProvisionalLoadForFrame
 2main frame - didCommitLoadForFrame
 3main frame - didReceiveTitle: Images with an invalid loading attribute load when in the viewport
 4main frame - didFinishDocumentLoadForFrame
 5main frame - didHandleOnloadEventsForFrame
 6main frame - didFinishLoadForFrame
 7
 8
 9
 10PASS Test that images with invalid loading attributes that enter the viewport get loaded.
 11

LayoutTests/imported/w3c/web-platform-tests/loading/lazyload/scroll_to_attribute_invalid_image.tentative.html

 1<!DOCTYPE html>
 2<head>
 3 <title>Images with an invalid loading attribute load when in the viewport</title>
 4 <link rel="author" title="Scott Little" href="mailto:sclittle@chromium.org">
 5 <link rel="help" href="https://github.com/whatwg/html/pull/3752">
 6 <script src="/resources/testharness.js"></script>
 7 <script src="/resources/testharnessreport.js"></script>
 8</head>
 9
 10<!--
 11Marked as tentative until https://github.com/whatwg/html/pull/3752 is landed.
 12-->
 13
 14<body>
 15 <img id="in_viewport" src="resources/image_1.png" loading="invalid_value">
 16 <div style="height:10000px;"></div>
 17 <img id="below_viewport" src="resources/image_2.png" loading="invalid_value">
 18</body>
 19
 20<script>
 21 var t = async_test("Test that images with invalid loading attributes that enter the viewport get loaded.");
 22
 23 var has_in_viewport_loaded = false;
 24 var has_below_viewport_loaded = false;
 25
 26 document.getElementById("in_viewport").addEventListener("load", t.step_func(function() {
 27 assert_false(has_in_viewport_loaded);
 28 has_in_viewport_loaded = true;
 29 if (has_below_viewport_loaded) {
 30 // Note that the below_viewport element's load event could happen before
 31 // the window.load event occurs, if the browser decides to load it
 32 // immediately instead of lazily loading. This is valid behavior, so the
 33 // test has passed if the below_viewport element has loaded.
 34 t.done();
 35 } else {
 36 document.getElementById("below_viewport").scrollIntoView();
 37 }
 38 }));
 39
 40 document.getElementById("below_viewport").addEventListener("load", t.step_func(function() {
 41 assert_false(has_below_viewport_loaded);
 42 has_below_viewport_loaded = true;
 43 if (has_in_viewport_loaded) {
 44 t.done();
 45 }
 46 }));
 47</script>

LayoutTests/imported/w3c/web-platform-tests/loading/lazyload/scroll_to_attribute_on_image.tentative-expected.txt

 1main frame - didStartProvisionalLoadForFrame
 2main frame - didCommitLoadForFrame
 3main frame - didReceiveTitle: Images with loading="lazy" load when in the viewport
 4main frame - didFinishDocumentLoadForFrame
 5main frame - didHandleOnloadEventsForFrame
 6main frame - didFinishLoadForFrame
 7
 8
 9
 10PASS Test that images with loading='lazy' that enter the viewport get loaded.
 11

LayoutTests/imported/w3c/web-platform-tests/loading/lazyload/scroll_to_attribute_on_image.tentative.html

 1<!DOCTYPE html>
 2<head>
 3 <title>Images with loading="lazy" load when in the viewport</title>
 4 <link rel="author" title="Scott Little" href="mailto:sclittle@chromium.org">
 5 <link rel="help" href="https://github.com/whatwg/html/pull/3752">
 6 <script src="/resources/testharness.js"></script>
 7 <script src="/resources/testharnessreport.js"></script>
 8</head>
 9
 10<!--
 11Marked as tentative until https://github.com/whatwg/html/pull/3752 is landed.
 12-->
 13
 14<body>
 15 <img id="in_viewport" src="resources/image_1.png" loading="lazy">
 16 <div style="height:10000px;"></div>
 17 <img id="below_viewport" src="resources/image_2.png" loading="lazy">
 18</body>
 19
 20<script>
 21 var t = async_test("Test that images with loading='lazy' that enter the viewport get loaded.");
 22
 23 var has_in_viewport_loaded = false;
 24 var has_below_viewport_loaded = false;
 25
 26 document.getElementById("in_viewport").addEventListener("load", t.step_func(function() {
 27 assert_false(has_in_viewport_loaded);
 28 has_in_viewport_loaded = true;
 29 if (has_below_viewport_loaded) {
 30 // Note that the below_viewport element's load event could happen before
 31 // the window.load event occurs, if the browser decides to load it
 32 // immediately instead of lazily loading. This is valid behavior, so the
 33 // test has passed if the below_viewport element has loaded.
 34 t.done();
 35 } else {
 36 document.getElementById("below_viewport").scrollIntoView();
 37 }
 38 }));
 39
 40 document.getElementById("below_viewport").addEventListener("load", t.step_func(function() {
 41 assert_false(has_below_viewport_loaded);
 42 has_below_viewport_loaded = true;
 43 if (has_in_viewport_loaded) {
 44 t.done();
 45 }
 46 }));
 47</script>

LayoutTests/imported/w3c/web-platform-tests/loading/lazyload/scroll_to_attribute_unset_image.tentative-expected.txt

 1main frame - didStartProvisionalLoadForFrame
 2main frame - didCommitLoadForFrame
 3main frame - didReceiveTitle: Images without a lazyload attribute load when in the viewport
 4main frame - didFinishDocumentLoadForFrame
 5main frame - didHandleOnloadEventsForFrame
 6main frame - didFinishLoadForFrame
 7
 8
 9
 10PASS Test that images without a lazyload attribute that enter the viewport get loaded.
 11

LayoutTests/imported/w3c/web-platform-tests/loading/lazyload/scroll_to_attribute_unset_image.tentative.html

 1<!DOCTYPE html>
 2<head>
 3 <title>Images without a lazyload attribute load when in the viewport</title>
 4 <link rel="author" title="Scott Little" href="mailto:sclittle@chromium.org">
 5 <link rel="help" href="https://github.com/whatwg/html/pull/3752">
 6 <script src="/resources/testharness.js"></script>
 7 <script src="/resources/testharnessreport.js"></script>
 8</head>
 9
 10<!--
 11Marked as tentative until https://github.com/whatwg/html/pull/3752 is landed.
 12-->
 13
 14<body>
 15 <img id="in_viewport" src="resources/image_1.png">
 16 <div style="height:10000px;"></div>
 17 <img id="below_viewport" src="resources/image_2.png">
 18</body>
 19
 20<script>
 21 var t = async_test("Test that images without a lazyload attribute that enter the viewport get loaded.");
 22
 23 var has_in_viewport_loaded = false;
 24 var has_below_viewport_loaded = false;
 25
 26 document.getElementById("in_viewport").addEventListener("load", t.step_func(function() {
 27 assert_false(has_in_viewport_loaded);
 28 has_in_viewport_loaded = true;
 29 if (has_below_viewport_loaded) {
 30 // Note that the below_viewport element's load event could happen before
 31 // the window.load event occurs, if the browser decides to load it
 32 // immediately instead of lazily loading. This is valid behavior, so the
 33 // test has passed if the below_viewport element has loaded.
 34 t.done();
 35 } else {
 36 document.getElementById("below_viewport").scrollIntoView();
 37 }
 38 }));
 39
 40 document.getElementById("below_viewport").addEventListener("load", t.step_func(function() {
 41 assert_false(has_below_viewport_loaded);
 42 has_below_viewport_loaded = true;
 43 if (has_in_viewport_loaded) {
 44 t.done();
 45 }
 46 }));
 47</script>

LayoutTests/imported/w3c/web-platform-tests/loading/lazyload/window_load_event_occurs_with_below_viewport_image.tentative-expected.txt

 1main frame - didStartProvisionalLoadForFrame
 2main frame - didCommitLoadForFrame
 3main frame - didReceiveTitle: Below-viewport images don't endlessly delay the window load event.
 4main frame - didFinishDocumentLoadForFrame
 5main frame - didHandleOnloadEventsForFrame
 6main frame - didFinishLoadForFrame
 7
 8
 9PASS Test that below-viewport images don't endlessly delay the window load event.
 10

LayoutTests/imported/w3c/web-platform-tests/loading/lazyload/window_load_event_occurs_with_below_viewport_image.tentative.html

 1<!DOCTYPE html>
 2<head>
 3 <title>Below-viewport images don't endlessly delay the window load event.</title>
 4 <link rel="author" title="Scott Little" href="mailto:sclittle@chromium.org">
 5 <link rel="help" href="https://github.com/whatwg/html/pull/3752">
 6 <script src="/resources/testharness.js"></script>
 7 <script src="/resources/testharnessreport.js"></script>
 8</head>
 9
 10<!--
 11Marked as tentative until https://github.com/whatwg/html/pull/3752 is landed.
 12-->
 13
 14<body>
 15 <div style="height:10000px;"></div>
 16 <img id="attribute_unset" src="resources/image_1.png">
 17 <img id="attribute_invalid" src="resources/image_2.png" loading="invalid_value">
 18 <img id="attribute_auto" src="resources/image_3.png" loading="auto">
 19 <img id="attribute_on" src="resources/image_4.png" loading="lazy">
 20</body>
 21
 22<script>
 23 var t = async_test("Test that below-viewport images don't endlessly delay the window load event.");
 24
 25 // Note that the below-viewport elements' load events could happen before the
 26 // window.load event occurs, if the browser decides to load immediately
 27 // instead of lazily loading. This is valid behavior, since loading="lazy" is
 28 // only a strong hint to the browser that the element is well suited to being
 29 // lazily loaded, so the browser is not required to lazily load it. The unset,
 30 // invalid, and "auto" attribute values similarly leave it up to the browser
 31 // to decide whether or not to lazily load the element. As a result, the test
 32 // passes once the below-viewport elements load.
 33 window.addEventListener("load", t.step_func_done());
 34</script>

LayoutTests/platform/ios-simulator-wk2/TestExpectations

@@webkit.org/b/182849 imported/w3c/web-platform-tests/xhr/event-upload-progress-cr
9090
9191imported/w3c/web-platform-tests/IndexedDB/keypath-special-identifiers.htm [ Slow ]
9292
93 webkit.org/b/198185 http/tests/resourceLoadStatistics/website-data-removal-for-site-navigated-to-with-link-decoration.html [ Skip ]
9493\ No newline at end of file
 94webkit.org/b/198185 http/tests/resourceLoadStatistics/website-data-removal-for-site-navigated-to-with-link-decoration.html [ Skip ]
 95
 96webkit.org/b/196698 http/tests/lazyload/attribute.html [ Skip ]

LayoutTests/platform/mac-wk1/TestExpectations

@@webkit.org/b/198177 pointerevents/mouse/compatibility-mouse-events-prevention-mo
723723webkit.org/b/198459 [ HighSierra Debug ] inspector/canvas/recording-2d-full.html [ Slow ]
724724webkit.org/b/198459 [ HighSierra Debug ] inspector/canvas/recording-webgl-full.html [ Slow ]
725725
726 webkit.org/b/196508 compositing/repaint/scroller-with-foreground-layer-repaints.html [ Pass Failure ]
727726\ No newline at end of file
 727webkit.org/b/196508 compositing/repaint/scroller-with-foreground-layer-repaints.html [ Pass Failure ]
 728
 729webkit.org/b/196698 http/tests/lazyload/lazy.html [ Skip ]
 730webkit.org/b/196698 imported/w3c/web-platform-tests/loading/lazyload/scroll_to_attribute_on_image.tentative.html [ Skip ]

LayoutTests/platform/win/TestExpectations

@@webkit.org/b/195623 http/tests/cache/link-prefetch-main-resource-iframe.html [ S
44094409webkit.org/b/198112 http/tests/security/showModalDialog-sync-cross-origin-page-load2.html [ Skip ]
44104410
44114411webkit.org/b/198679 fast/events/fire-mousedown-while-pressing-mouse-button.html [ Failure ]
 4412
 4413webkit.org/b/196698 http/tests/lazyload/lazy.html [ Skip ]

LayoutTests/platform/wincairo-wk1/TestExpectations

@@fast/css/transition-color-unspecified.html [ Skip ]
339339fast/filter-image/filter-image-animation.html [ Skip ]
340340resize-observer/modify-frametree-in-callback.html [ Skip ]
341341resize-observer/multi-frames.html [ Skip ]
 342http/tests/lazyload/lazy.html [ Skip ]