resourceloader: Use SVG url when ResourceLoaderImageModule can't embed
authorWMDE-Fisch <christoph.jauera@wikimedia.de>
Wed, 15 Mar 2017 19:09:17 +0000 (20:09 +0100)
committerKrinkle <krinklemail@gmail.com>
Thu, 16 Mar 2017 22:11:11 +0000 (22:11 +0000)
When the SVG is too big to be embeded it is now included via URL.
Previously it would produce an empty/broken 'url()' value.

Bug: T160532
Change-Id: I158781f9430cfa35737397ac7537a471634c4480

includes/resourceloader/ResourceLoaderImageModule.php
tests/phpunit/includes/resourceloader/ResourceLoaderImageModuleTest.php

index ff1b7b1..1a3463f 100644 (file)
@@ -315,11 +315,7 @@ class ResourceLoaderImageModule extends ResourceLoaderModule {
                $selectors = $this->getSelectors();
 
                foreach ( $this->getImages( $context ) as $name => $image ) {
-                       $declarations = $this->getCssDeclarations(
-                               $image->getDataUri( $context, null, 'original' ),
-                               $image->getUrl( $context, $script, null, 'rasterized' )
-                       );
-                       $declarations = implode( "\n\t", $declarations );
+                       $declarations = $this->getStyleDeclarations( $context, $image, $script );
                        $selector = strtr(
                                $selectors['selectorWithoutVariant'],
                                [
@@ -331,11 +327,7 @@ class ResourceLoaderImageModule extends ResourceLoaderModule {
                        $rules[] = "$selector {\n\t$declarations\n}";
 
                        foreach ( $image->getVariants() as $variant ) {
-                               $declarations = $this->getCssDeclarations(
-                                       $image->getDataUri( $context, $variant, 'original' ),
-                                       $image->getUrl( $context, $script, $variant, 'rasterized' )
-                               );
-                               $declarations = implode( "\n\t", $declarations );
+                               $declarations = $this->getStyleDeclarations( $context, $image, $script, $variant );
                                $selector = strtr(
                                        $selectors['selectorWithVariant'],
                                        [
@@ -352,6 +344,28 @@ class ResourceLoaderImageModule extends ResourceLoaderModule {
                return [ 'all' => $style ];
        }
 
+       /**
+        * @param ResourceLoaderContext $context
+        * @param ResourceLoaderImage $image Image to get the style for
+        * @param string $script URL to load.php
+        * @param string|null $variant Variant to get the style for
+        * @return string
+        */
+       private function getStyleDeclarations(
+               ResourceLoaderContext $context,
+               ResourceLoaderImage $image,
+               $script,
+               $variant = null
+       ) {
+               $imageDataUri = $image->getDataUri( $context, $variant, 'original' );
+               $primaryUrl = $imageDataUri ?: $image->getUrl( $context, $script, $variant, 'original' );
+               $declarations = $this->getCssDeclarations(
+                       $primaryUrl,
+                       $image->getUrl( $context, $script, $variant, 'rasterized' )
+               );
+               return implode( "\n\t", $declarations );
+       }
+
        /**
         * SVG support using a transparent gradient to guarantee cross-browser
         * compatibility (browsers able to understand gradient syntax support also SVG).
index aeb82d1..a1acea6 100644 (file)
@@ -197,6 +197,62 @@ class ResourceLoaderImageModuleTest extends ResourceLoaderTestCase {
                ] ) );
                $this->assertInstanceOf( ResourceLoaderImage::class, $context->getImageObj() );
        }
+
+       public static function providerGetStyleDeclarations() {
+               return [
+                       [
+                               false,
+<<<TEXT
+background-image: url(rasterized.png);
+       background-image: linear-gradient(transparent, transparent), url(original.svg);
+       background-image: -o-linear-gradient(transparent, transparent), url(rasterized.png);
+TEXT
+                       ],
+                       [
+                               'data:image/svg+xml',
+<<<TEXT
+background-image: url(rasterized.png);
+       background-image: linear-gradient(transparent, transparent), url(data:image/svg+xml);
+       background-image: -o-linear-gradient(transparent, transparent), url(rasterized.png);
+TEXT
+                       ],
+
+               ];
+       }
+
+       /**
+        * @dataProvider providerGetStyleDeclarations
+        * @covers ResourceLoaderContext::getStyleDeclarations
+        */
+       public function testGetStyleDeclarations( $dataUriReturnValue, $expected ) {
+               $module = TestingAccessWrapper::newFromObject( new ResourceLoaderImageModule() );
+               $context = $this->getResourceLoaderContext();
+               $image = $this->getImageMock( $context, $dataUriReturnValue );
+
+               $styles = $module->getStyleDeclarations(
+                       $context,
+                       $image,
+                       'load.php'
+               );
+
+               $this->assertEquals( $expected, $styles );
+       }
+
+       private function getImageMock( ResourceLoaderContext $context, $dataUriReturnValue ) {
+               $image = $this->getMockBuilder( 'ResourceLoaderImage' )
+                       ->disableOriginalConstructor()
+                       ->getMock();
+               $image->method( 'getDataUri' )
+                       ->will( $this->returnValue( $dataUriReturnValue ) );
+               $image->expects( $this->any() )
+                       ->method( 'getUrl' )
+                       ->will( $this->returnValueMap( [
+                               [ $context, 'load.php', null, 'original', 'original.svg' ],
+                               [ $context, 'load.php', null, 'rasterized', 'rasterized.png' ],
+                       ] ) );
+
+               return $image;
+       }
 }
 
 class ResourceLoaderImageModuleTestable extends ResourceLoaderImageModule {