jenkins-bot has submitted this change and it was merged. ( 
https://gerrit.wikimedia.org/r/347649 )

Change subject: Don't lazy load small images (smaller than 50px or 10ex)
......................................................................


Don't lazy load small images (smaller than 50px or 10ex)

Changes:
 - added a logic that skips lazy loading images smaller than 50px
 - added a config MFLazyLoadSkipSmallImages to disable/enable this feature

Bug: T162623
Change-Id: I9a631a6de9e5dbf348314571c28b491dff94f4de
---
M extension.json
M includes/MobileFormatter.php
M tests/phpunit/MobileFormatterTest.php
3 files changed, 114 insertions(+), 6 deletions(-)

Approvals:
  jenkins-bot: Verified
  Jdlrobson: Looks good to me, approved



diff --git a/extension.json b/extension.json
index 836a32d..842101e 100644
--- a/extension.json
+++ b/extension.json
@@ -1771,6 +1771,7 @@
                        "base": false,
                        "beta": true
                },
+               "MFLazyLoadSkipSmallImages": false,
                "MFLazyLoadReferences": {
                        "base": false,
                        "beta": false
diff --git a/includes/MobileFormatter.php b/includes/MobileFormatter.php
index 9a88fbb..b983892 100644
--- a/includes/MobileFormatter.php
+++ b/includes/MobileFormatter.php
@@ -13,6 +13,17 @@
         * Class name for collapsible section wrappers
         */
        const STYLE_COLLAPSIBLE_SECTION_CLASS = 'collapsible-block';
+
+       /**
+        * Do not lazy load images smaller than this size (in pixels)
+        * @var int
+        */
+       const SMALL_IMAGE_DIMENSION_THRESHOLD_IN_PX = 50;
+       /**
+        * Do not lazy load images smaller than this size (in relative to 
x-height of the current font)
+        * @var int
+        */
+       const SMALL_IMAGE_DIMENSION_THRESHOLD_IN_EX = 10;
        /**
         * Whether scripts can be added in the output.
         * @var boolean $scriptsEnabled
@@ -383,12 +394,54 @@
        }
 
        /**
+        * Is image dimension small enough to not lazy load it
+        *
+        * @param string $dimension in css format, supports only px|ex units
+        * @return bool
+        */
+       public function isDimensionSmallerThanThreshold( $dimension ) {
+               $matches = null;
+               if ( preg_match( '/(\d+)(\.\d+)?(px|ex)/', $dimension, $matches 
) === 0 ) {
+                       return false;
+               }
+
+               $size = $matches[1];
+               $unit = array_pop( $matches );
+
+               switch ( strtolower( $unit ) ) {
+                       case 'px':
+                               return $size <= 
self::SMALL_IMAGE_DIMENSION_THRESHOLD_IN_PX;
+                       case 'ex':
+                               return $size <= 
self::SMALL_IMAGE_DIMENSION_THRESHOLD_IN_EX;
+                       default:
+                               return false;
+               }
+       }
+
+       /**
+        * @param array $dimensions
+        * @return bool
+        */
+       private function skipLazyLoadingForSmallDimensions( array $dimensions ) 
{
+               if ( array_key_exists( 'width', $dimensions )
+                        && $this->isDimensionSmallerThanThreshold( 
$dimensions['width'] ) ) {
+                       return true;
+               };
+               if ( array_key_exists( 'height', $dimensions )
+                        && $this->isDimensionSmallerThanThreshold( 
$dimensions['height'] ) ) {
+                       return true;
+               }
+               return false;
+       }
+       /**
         * Enables images to be loaded asynchronously
         *
         * @param DOMElement|DOMDocument $el Element or document to rewrite 
images in.
         * @param DOMDocument $doc Document to create elements in
         */
        private function doRewriteImagesForLazyLoading( $el, DOMDocument $doc ) 
{
+               $lazyLoadSkipSmallImages = 
MobileContext::singleton()->getMFConfig()
+                       ->get( 'MFLazyLoadSkipSmallImages' );
 
                foreach ( $el->getElementsByTagName( 'img' ) as $img ) {
                        $parent = $img->parentNode;
@@ -397,6 +450,11 @@
                        $dimensionsStyle = ( isset( $dimensions['width'] ) ? 
"width: {$dimensions['width']};" : '' ) .
                                ( isset( $dimensions['height'] ) ? "height: 
{$dimensions['height']};" : '' );
 
+                       if ( $lazyLoadSkipSmallImages
+                                && $this->skipLazyLoadingForSmallDimensions( 
$dimensions ) ) {
+                               continue;
+                       }
+
                        // HTML only clients
                        $noscript = $doc->createElement( 'noscript' );
 
diff --git a/tests/phpunit/MobileFormatterTest.php 
b/tests/phpunit/MobileFormatterTest.php
index 05773fc..49f181e 100644
--- a/tests/phpunit/MobileFormatterTest.php
+++ b/tests/phpunit/MobileFormatterTest.php
@@ -72,8 +72,28 @@
                $mf->topHeadingTags = [ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6' ];
                $mf->filterContent( $removeDefaults, $lazyLoadReferences, 
$lazyLoadImages,
                        $showFirstParagraphBeforeInfobox );
+
                $html = $mf->getText();
                $this->assertEquals( str_replace( "\n", '', $expected ), 
str_replace( "\n", '', $html ) );
+       }
+
+       public function testHtmlTransformWhenSkippingLazyLoadingSmallImages() {
+               $smallPic =  '<img src="smallPicture.jpg" style="width: 4.4ex; 
height:3.34ex;">';
+               $enableSections = function ( MobileFormatter $mf ) {
+                       $mf->enableExpandableSections();
+               };
+               $this->setMwGlobals( [
+                       'wgMFLazyLoadSkipSmallImages' => true
+               ] );
+
+               $this->testHtmlTransform(
+                       '<p>text</p><h2>heading 1</h2>' . $smallPic,
+                       $this->makeSectionHtml( 0, '<p>text</p>' )
+                       . $this->makeSectionHeading( 'h2', 'heading 1' )
+                       . $this->makeSectionHtml( 1, $smallPic ),
+                       $enableSections,
+                       false, false, true
+               );
        }
 
        public function provideHtmlTransform() {
@@ -88,14 +108,15 @@
                        $f->setIsMainPage( true );
                };
                $citeUrl = SpecialPage::getTitleFor( 'MobileCite', '0' 
)->getLocalUrl();
-               $imageStyles = '<img src="math.jpg" style="vertical-align: 
-3.505ex; '
-                       . 'width: 24.412ex; height:7.343ex; background:none;">';
+               $lazyLoadedImageStyles = '<img src="bigPicture.jpg" 
style="vertical-align: -3.505ex; '
+                       . 'width: 84.412ex; height:70.343ex; 
background:none;">';
+
                $placeholderStyles = '<span class="lazy-image-placeholder" '
-                       . 'style="width: 24.412ex;height: 7.343ex;" '
-                       . 'data-src="math.jpg">'
+                       . 'style="width: 84.412ex;height: 70.343ex;" '
+                       . 'data-src="bigPicture.jpg">'
                        . ' '
                        . '</span>';
-               $noscriptStyles = '<noscript>' . $imageStyles . '</noscript>';
+               $noscriptStyles = '<noscript>' . $lazyLoadedImageStyles . 
'</noscript>';
                $originalImage = '<img alt="foo" src="foo.jpg" width="100" '
                        . 'height="100" srcset="foo-1.5x.jpg 1.5x, foo-2x.jpg 
2x">';
                $placeholder = '<span class="lazy-image-placeholder" '
@@ -157,7 +178,7 @@
                        ],
                        // Test lazy loading of images with style attributes
                        [
-                               '<p>text</p><h2>heading 1</h2><p>text</p>' . 
$imageStyles
+                               '<p>text</p><h2>heading 1</h2><p>text</p>' . 
$lazyLoadedImageStyles
                                        . '<h2>heading 2</h2>abc',
                                $this->makeSectionHtml( 0, '<p>text</p>' )
                                        . $this->makeSectionHeading( 'h2', 
'heading 1' )
@@ -796,6 +817,34 @@
                ];
        }
 
+       /**
+        * @dataProvider provideIsDimensionSmallerThanThreshold
+        * @covers MobileFormatter::isDimensionSmallerThanThreshold
+        */
+       public function testIsDimensionSmallerThanThreshold( $dimension, 
$expected ) {
+               $mf = new MobileFormatter( '', Title::newFromText( 'Test' ) );
+               $this->assertEquals( $expected, 
$mf->isDimensionSmallerThanThreshold( $dimension ) );
+       }
+
+       /**
+        * @see https://phabricator.wikimedia.org/T162623
+        */
+       public function provideIsDimensionSmallerThanThreshold() {
+               return [
+                       [ '40px', true ],
+                       [ '50px', true ],
+                       [ '57px', false ],
+                       [ '100ox', false ],
+                       [ '10', false ],
+                       [ '5.12ex', true ],
+                       [ '9.89ex', true ],
+                       [ '15.1ex', false ],
+                       [ '10in', false ],
+                       [ 'big', false ],
+                       [ '', false ]
+               ];
+       }
+
        public function testInsertTOCPlaceholder() {
                $input = '<p>Hello world.</p><h2>Heading</h2>Text.';
                $mf = new MobileFormatter( $input, Title::newFromText( 'Mobile' 
) );

-- 
To view, visit https://gerrit.wikimedia.org/r/347649
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I9a631a6de9e5dbf348314571c28b491dff94f4de
Gerrit-PatchSet: 10
Gerrit-Project: mediawiki/extensions/MobileFrontend
Gerrit-Branch: master
Gerrit-Owner: Pmiazga <[email protected]>
Gerrit-Reviewer: Jdlrobson <[email protected]>
Gerrit-Reviewer: Pmiazga <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to