Merge "Normalize newlines in DjVu text-layer metadata."
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Sat, 7 Dec 2013 00:20:43 +0000 (00:20 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Sat, 7 Dec 2013 00:20:43 +0000 (00:20 +0000)
42 files changed:
includes/ImagePage.php
includes/Title.php
includes/filerepo/file/File.php
includes/media/BMP.php
includes/media/Bitmap.php
includes/media/BitmapMetadataHandler.php
includes/media/Bitmap_ClientOnly.php
includes/media/DjVu.php
includes/media/DjVuImage.php
includes/media/Exif.php
includes/media/ExifBitmap.php
includes/media/FormatMetadata.php
includes/media/GIF.php
includes/media/GIFMetadataExtractor.php
includes/media/IPTC.php
includes/media/ImageHandler.php
includes/media/Jpeg.php
includes/media/JpegMetadataExtractor.php
includes/media/MediaHandler.php
includes/media/MediaTransformOutput.php
includes/media/PNG.php
includes/media/PNGMetadataExtractor.php
includes/media/SVG.php
includes/media/SVGMetadataExtractor.php
includes/media/Tiff.php
includes/media/XCF.php
includes/media/XMP.php
includes/media/XMPInfo.php
includes/media/XMPValidate.php
includes/resourceloader/ResourceLoaderUserCSSPrefsModule.php
includes/resourceloader/ResourceLoaderUserGroupsModule.php
includes/templates/Usercreate.php
languages/messages/MessagesEn.php
languages/messages/MessagesQqq.php
maintenance/language/messageTypes.inc
maintenance/language/messages.inc
resources/mediawiki/mediawiki.Title.js
tests/phpunit/data/media/README
tests/phpunit/data/media/Speech_bubbles.svg [new file with mode: 0644]
tests/phpunit/includes/TitleTest.php
tests/phpunit/includes/media/SVGMetadataExtractorTest.php
tests/qunit/suites/resources/mediawiki/mediawiki.Title.test.js

index b2a53cd..2c303c9 100644 (file)
@@ -525,6 +525,16 @@ EOT
                                );
                        }
 
+                       $renderLangOptions = $this->displayImg->getAvailableLanguages();
+                       if ( count( $renderLangOptions ) >= 1 ) {
+                               $currentLanguage = $renderLang;
+                               $defaultLang = $this->displayImg->getDefaultRenderLanguage();
+                               if ( is_null( $currentLanguage ) ) {
+                                       $currentLanguage = $defaultLang;
+                               }
+                               $out->addHtml( $this->doRenderLangOpt( $renderLangOptions, $currentLanguage, $defaultLang ) );
+                       }
+
                        // Add cannot animate thumbnail warning
                        if ( !$this->displayImg->canAnimateThumbIfAppropriate() ) {
                                // Include the extension so wiki admins can
@@ -947,6 +957,72 @@ EOT
                        ? $wgImageLimits[$option]
                        : array( 800, 600 ); // if nothing is set, fallback to a hardcoded default
        }
+
+       /**
+        * Output a drop-down box for language options for the file
+        *
+        * @param Array $langChoices Array of string language codes
+        * @param String $curLang Language code file is being viewed in.
+        * @param String $defaultLang Language code that image is rendered in by default
+        * @return String HTML to insert underneath image.
+        */
+       protected function doRenderLangOpt( array $langChoices, $curLang, $defaultLang ) {
+               global $wgScript;
+               sort( $langChoices );
+               $curLang = wfBCP47( $curLang );
+               $defaultLang = wfBCP47( $defaultLang );
+               $opts = '';
+               $haveCurrentLang = false;
+               $haveDefaultLang = false;
+
+               // We make a list of all the language choices in the file.
+               // Additionally if the default language to render this file
+               // is not included as being in this file (for example, in svgs
+               // usually the fallback content is the english content) also
+               // include a choice for that. Last of all, if we're viewing
+               // the file in a language not on the list, add it as a choice.
+               foreach ( $langChoices as $lang ) {
+                       $code = wfBCP47( $lang );
+                       $name = Language::fetchLanguageName( $code, $this->getContext()->getLanguage()->getCode() );
+                       if ( $name !== '' ) {
+                               $display = wfMessage( 'img-lang-opt', $code, $name )->text();
+                       } else {
+                               $display = $code;
+                       }
+                       $opts .= "\n" . XML::Option( $display, $code, $curLang === $code );
+                       if ( $curLang === $code ) {
+                               $haveCurrentLang = true;
+                       }
+                       if ( $defaultLang === $code ) {
+                               $haveDefaultLang = true;
+                       }
+               }
+               if ( !$haveDefaultLang ) {
+                       // Its hard to know if the content is really in the default language, or
+                       // if its just unmarked content that could be in any language.
+                       $opts = XML::Option( wfMessage( 'img-lang-default' )->text(), '', $defaultLang === $curLang ) . $opts;
+               }
+               if ( !$haveCurrentLang && $defaultLang !== $curLang ) {
+                       $name = Language::fetchLanguageName( $curLang, $this->getContext()->getLanguage()->getCode() );
+                       if ( $name !== '' ) {
+                               $display = wfMessage( 'img-lang-opt', $curLang, $name )->text();
+                       } else {
+                               $display = $curLang;
+                       }
+                       $opts =  XML::Option( $display, $curLang, true ) . $opts;
+               }
+
+               $select = Html::rawElement( 'select', array( 'id' => 'mw-imglangselector', 'name' => 'lang' ), $opts );
+               $submit = Xml::submitButton( wfMessage( 'img-lang-go' )->text() );
+
+               $formContents = wfMessage( 'img-lang-info' )->rawParams( $select, $submit )->parse()
+                       . Html::hidden( 'title', $this->getTitle()->getPrefixedDBkey() );
+
+               $langSelectLine = Html::rawElement( 'div', array( 'id' => 'mw-imglangselector-line' ),
+                       Html::rawElement( 'form', array( 'action' => $wgScript ), $formContents )
+               );
+               return $langSelectLine;
+       }
 }
 
 /**
index 820842f..a949ac3 100644 (file)
@@ -3163,10 +3163,6 @@ class Title {
                $dbkey = preg_replace( '/[ _\xA0\x{1680}\x{180E}\x{2000}-\x{200A}\x{2028}\x{2029}\x{202F}\x{205F}\x{3000}]+/u', '_', $dbkey );
                $dbkey = trim( $dbkey, '_' );
 
-               if ( $dbkey == '' ) {
-                       return false;
-               }
-
                if ( strpos( $dbkey, UTF8_REPLACEMENT ) !== false ) {
                        # Contained illegal UTF-8 sequences or forbidden Unicode chars.
                        return false;
@@ -3176,12 +3172,16 @@ class Title {
 
                # Initial colon indicates main namespace rather than specified default
                # but should not create invalid {ns,title} pairs such as {0,Project:Foo}
-               if ( ':' == $dbkey[0] ) {
+               if ( $dbkey !== '' && ':' == $dbkey[0] ) {
                        $this->mNamespace = NS_MAIN;
                        $dbkey = substr( $dbkey, 1 ); # remove the colon but continue processing
                        $dbkey = trim( $dbkey, '_' ); # remove any subsequent whitespace
                }
 
+               if ( $dbkey == '' ) {
+                       return false;
+               }
+
                # Namespace or interwiki prefix
                $firstPass = true;
                $prefixRegexp = "/^(.+?)_*:_*(.*)$/S";
index 7d9e79d..1c9d8aa 100644 (file)
@@ -495,6 +495,42 @@ abstract class File {
                }
        }
 
+       /**
+        * Gives a (possibly empty) list of languages to render
+        * the file in.
+        *
+        * If the file doesn't have translations, or if the file
+        * format does not support that sort of thing, returns
+        * an empty array.
+        *
+        * @return Array
+        * @since 1.23
+        */
+       public function getAvailableLanguages() {
+               $handler = $this->getHandler();
+               if ( $handler ) {
+                       return $handler->getAvailableLanguages( $this );
+               } else {
+                       return array();
+               }
+       }
+
+       /**
+        * In files that support multiple language, what is the default language
+        * to use if none specified.
+        *
+        * @return String lang code, or null if filetype doesn't support multiple languages.
+        * @since 1.23
+        */
+       public function getDefaultRenderLanguage() {
+               $handler = $this->getHandler();
+               if ( $handler ) {
+                       return $handler->getDefaultRenderLanguage( $this );
+               } else {
+                       return null;
+               }
+       }
+
        /**
         * Will the thumbnail be animated if one would expect it to be.
         *
index 7271d99..967b017 100644 (file)
@@ -29,7 +29,7 @@
  */
 class BmpHandler extends BitmapHandler {
        /**
-        * @param $file
+        * @param File $file
         * @return bool
         */
        function mustRender( $file ) {
@@ -39,9 +39,9 @@ class BmpHandler extends BitmapHandler {
        /**
         * Render files as PNG
         *
-        * @param $text
-        * @param $mime
-        * @param $params
+        * @param string $text
+        * @param string $mime
+        * @param array $params
         * @return array
         */
        function getThumbType( $text, $mime, $params = null ) {
@@ -52,7 +52,7 @@ class BmpHandler extends BitmapHandler {
         * Get width and height from the bmp header.
         *
         * @param $image
-        * @param $filename
+        * @param string $filename
         * @return array
         */
        function getImageSize( $image, $filename ) {
index 804393a..13849f4 100644 (file)
@@ -28,7 +28,7 @@
  */
 class BitmapHandler extends ImageHandler {
        /**
-        * @param $image File
+        * @param File $image
         * @param array $params Transform parameters. Entries with the keys 'width'
         * and 'height' are the respective screen width and height, while the keys
         * 'physicalWidth' and 'physicalHeight' indicate the thumbnail dimensions.
@@ -106,10 +106,10 @@ class BitmapHandler extends ImageHandler {
        }
 
        /**
-        * @param $image File
-        * @param  $dstPath
-        * @param  $dstUrl
-        * @param  $params
+        * @param File $image
+        * @param string $dstPath
+        * @param string $dstUrl
+        * @param array $params
         * @param int $flags
         * @return MediaTransformError|ThumbnailImage|TransformParameterError
         */
@@ -201,6 +201,7 @@ class BitmapHandler extends ImageHandler {
                switch ( $scaler ) {
                        case 'hookaborted':
                                # Handled by the hook above
+                               /** @var MediaTransformOutput $mto */
                                $err = $mto->isError() ? $mto : false;
                                break;
                        case 'im':
@@ -243,7 +244,9 @@ class BitmapHandler extends ImageHandler {
         * Returns which scaler type should be used. Creates parent directories
         * for $dstPath and returns 'client' on error
         *
-        * @return string client,im,custom,gd
+        * @param string $dstPath
+        * @param bool $checkDstPath
+        * @return string One of client, im, custom, gd, imext
         */
        protected static function getScalerType( $dstPath, $checkDstPath = true ) {
                global $wgUseImageResize, $wgUseImageMagick, $wgCustomConvertCommand;
@@ -272,11 +275,11 @@ class BitmapHandler extends ImageHandler {
         * Get a ThumbnailImage that respresents an image that will be scaled
         * client side
         *
-        * @param $image File File associated with this thumbnail
+        * @param File $image File associated with this thumbnail
         * @param array $scalerParams Array with scaler params
         * @return ThumbnailImage
         *
-        * @todo fixme: no rotation support
+        * @todo FIXME: No rotation support
         */
        protected function getClientScalingThumbnailImage( $image, $scalerParams ) {
                $params = array(
@@ -290,7 +293,7 @@ class BitmapHandler extends ImageHandler {
        /**
         * Transform an image using ImageMagick
         *
-        * @param $image File File associated with this thumbnail
+        * @param File $image File associated with this thumbnail
         * @param array $params Array with scaler params
         *
         * @return MediaTransformError Error object if error occurred, false (=no error) otherwise
@@ -388,7 +391,7 @@ class BitmapHandler extends ImageHandler {
        /**
         * Transform an image using the Imagick PHP extension
         *
-        * @param $image File File associated with this thumbnail
+        * @param File $image File associated with this thumbnail
         * @param array $params Array with scaler params
         *
         * @return MediaTransformError Error object if error occurred, false (=no error) otherwise
@@ -464,7 +467,7 @@ class BitmapHandler extends ImageHandler {
        /**
         * Transform an image using a custom command
         *
-        * @param $image File File associated with this thumbnail
+        * @param File $image File associated with this thumbnail
         * @param array $params Array with scaler params
         *
         * @return MediaTransformError Error object if error occurred, false (=no error) otherwise
@@ -510,7 +513,7 @@ class BitmapHandler extends ImageHandler {
        /**
         * Transform an image using the built in GD library
         *
-        * @param $image File File associated with this thumbnail
+        * @param File $image File associated with this thumbnail
         * @param array $params Array with scaler params
         *
         * @return MediaTransformError Error object if error occurred, false (=no error) otherwise
@@ -598,7 +601,8 @@ class BitmapHandler extends ImageHandler {
        /**
         * Escape a string for ImageMagick's property input (e.g. -set -comment)
         * See InterpretImageProperties() in magick/property.c
-        * @return mixed|string
+        * @param string $s
+        * @return string
         */
        function escapeMagickProperty( $s ) {
                // Double the backslashes
@@ -646,6 +650,8 @@ class BitmapHandler extends ImageHandler {
        /**
         * Escape a string for ImageMagick's output filename. See
         * InterpretImageFilename() in magick/image.c.
+        * @param string $path The file path
+        * @param bool|string $scene The scene specification, or false if there is none
         * @return string
         */
        function escapeMagickOutput( $path, $scene = false ) {
@@ -692,7 +698,7 @@ class BitmapHandler extends ImageHandler {
         * Retrieve the version of the installed ImageMagick
         * You can use PHPs version_compare() to use this value
         * Value is cached for one hour.
-        * @return String representing the IM version.
+        * @return string Representing the IM version.
         */
        protected function getMagickVersion() {
                global $wgMemc;
@@ -748,9 +754,9 @@ class BitmapHandler extends ImageHandler {
        }
 
        /**
-        * @param $file File
+        * @param File $file
         * @param array $params Rotate parameters.
-        *    'rotation' clockwise rotation in degrees, allowed are multiples of 90
+        *   'rotation' clockwise rotation in degrees, allowed are multiples of 90
         * @since 1.21
         * @return bool
         */
@@ -770,6 +776,7 @@ class BitmapHandler extends ImageHandler {
                                wfDebug( __METHOD__ . ": running ImageMagick: $cmd\n" );
                                wfProfileIn( 'convert' );
                                $retval = 0;
+                               // @todo FIXME: Undefined variable %env
                                $err = wfShellExecWithStderr( $cmd, $retval, $env );
                                wfProfileOut( 'convert' );
                                if ( $retval !== 0 ) {
@@ -803,7 +810,7 @@ class BitmapHandler extends ImageHandler {
         * Rerurns whether the file needs to be rendered. Returns true if the
         * file requires rotation and we are able to rotate it.
         *
-        * @param $file File
+        * @param File $file
         * @return bool
         */
        public function mustRender( $file ) {
index 1e9419b..2a393db 100644 (file)
  * This sort of acts as an intermediary between MediaHandler::getMetadata
  * and the various metadata extractors.
  *
- * @todo other image formats.
+ * @todo Other image formats.
  * @ingroup Media
  */
 class BitmapMetadataHandler {
+       /** @var array */
        private $metadata = array();
 
+       /** @var array Metadata priority */
        private $metaPriority = array(
                20 => array( 'other' ),
                40 => array( 'native' ),
@@ -45,6 +47,7 @@ class BitmapMetadataHandler {
                120 => array( 'exif' ),
        );
 
+       /** @var string */
        private $iptcType = 'iptc-no-hash';
 
        /**
@@ -77,8 +80,8 @@ class BitmapMetadataHandler {
         *
         * Parameters are passed to the Exif class.
         *
-        * @param $filename string
-        * @param $byteOrder string
+        * @param string $filename
+        * @param string $byteOrder
         */
        function getExif( $filename, $byteOrder ) {
                global $wgShowEXIF;
@@ -95,7 +98,7 @@ class BitmapMetadataHandler {
         * doesn't have a priority, it will be silently discarded.
         *
         * @param array $metaArray array of metadata values
-        * @param string $type type. defaults to other. if two things have the same type they're merged
+        * @param string $type Type. defaults to other. if two things have the same type they're merged
         */
        function addMetadata( $metaArray, $type = 'other' ) {
                if ( isset( $this->metadata[$type] ) ) {
@@ -113,7 +116,7 @@ class BitmapMetadataHandler {
         *
         * This function is generally called by the media handlers' getMetadata()
         *
-        * @return Array metadata array
+        * @return array Metadata array
         */
        function getMetadataArray() {
                // this seems a bit ugly... This is all so its merged in right order
@@ -147,7 +150,7 @@ class BitmapMetadataHandler {
        /** Main entry point for jpeg's.
         *
         * @param string $filename filename (with full path)
-        * @return array metadata result array.
+        * @return array Metadata result array.
         * @throws MWException on invalid file.
         */
        static function Jpeg( $filename ) {
@@ -189,8 +192,8 @@ class BitmapMetadataHandler {
         * merge the png various tEXt chunks to that
         * are interesting, but for now it only does XMP
         *
-        * @param string $filename full path to file
-        * @return Array Array for storage in img_metadata.
+        * @param string $filename Full path to file
+        * @return array Array for storage in img_metadata.
         */
        public static function PNG( $filename ) {
                $showXMP = function_exists( 'xml_parser_create_ns' );
@@ -222,7 +225,7 @@ class BitmapMetadataHandler {
         * XMP and image comment.
         *
         * @param string $filename full path to file
-        * @return Array metadata array
+        * @return array Metadata array
         */
        public static function GIF( $filename ) {
 
@@ -257,13 +260,12 @@ class BitmapMetadataHandler {
         * but needs some further processing because PHP's exif support
         * is stupid...)
         *
-        * @todo Add XMP support, so this function actually makes
-        * sense to put here.
+        * @todo Add XMP support, so this function actually makes sense to put here.
         *
         * The various exceptions this throws are caught later.
-        * @param $filename String
+        * @param string $filename
         * @throws MWException
-        * @return Array The metadata.
+        * @return array The metadata.
         */
        public static function Tiff( $filename ) {
                if ( file_exists( $filename ) ) {
@@ -290,7 +292,7 @@ class BitmapMetadataHandler {
         * Little Endian or Big Endian. Needed for exif stuff.
         *
         * @param string $filename The filename
-        * @return String 'BE' or 'LE' or false
+        * @return string 'BE' or 'LE' or false
         */
        static function getTiffByteOrder( $filename ) {
                $fh = fopen( $filename, 'rb' );
index ac751fe..15ec794 100644 (file)
@@ -40,10 +40,10 @@ class BitmapHandler_ClientOnly extends BitmapHandler {
        }
 
        /**
-        * @param $image File
-        * @param  $dstPath
-        * @param  $dstUrl
-        * @param  $params
+        * @param File $image
+        * @param string $dstPath
+        * @param string $dstUrl
+        * @param array $params
         * @param int $flags
         * @return ThumbnailImage|TransformParameterError
         */
index ae46b2e..7da5a4c 100644 (file)
@@ -42,7 +42,7 @@ class DjVuHandler extends ImageHandler {
        }
 
        /**
-        * @param $file
+        * @param File $file
         * @return bool
         */
        function mustRender( $file ) {
@@ -50,7 +50,7 @@ class DjVuHandler extends ImageHandler {
        }
 
        /**
-        * @param $file
+        * @param File $file
         * @return bool
         */
        function isMultiPage( $file ) {
@@ -68,8 +68,8 @@ class DjVuHandler extends ImageHandler {
        }
 
        /**
-        * @param $name
-        * @param $value
+        * @param string $name
+        * @param mixed $value
         * @return bool
         */
        function validateParam( $name, $value ) {
@@ -85,7 +85,7 @@ class DjVuHandler extends ImageHandler {
        }
 
        /**
-        * @param $params
+        * @param array $params
         * @return bool|string
         */
        function makeParamString( $params ) {
@@ -98,7 +98,7 @@ class DjVuHandler extends ImageHandler {
        }
 
        /**
-        * @param $str
+        * @param string $str
         * @return array|bool
         */
        function parseParamString( $str ) {
@@ -111,7 +111,7 @@ class DjVuHandler extends ImageHandler {
        }
 
        /**
-        * @param $params
+        * @param array $params
         * @return array
         */
        function getScriptParams( $params ) {
@@ -122,10 +122,10 @@ class DjVuHandler extends ImageHandler {
        }
 
        /**
-        * @param $image File
-        * @param  $dstPath
-        * @param  $dstUrl
-        * @param  $params
+        * @param File $image
+        * @param string $dstPath
+        * @param string $dstUrl
+        * @param array $params
         * @param int $flags
         * @return MediaTransformError|ThumbnailImage|TransformParameterError
         */
@@ -211,6 +211,8 @@ class DjVuHandler extends ImageHandler {
        /**
         * Cache an instance of DjVuImage in an Image object, return that instance
         *
+        * @param File $image
+        * @param string $path
         * @return DjVuImage
         */
        function getDjVuImage( $image, $path ) {
@@ -227,12 +229,15 @@ class DjVuHandler extends ImageHandler {
 
        /**
         * Cache a document tree for the DjVu XML metadata
-        * @param $image File
-        * @param $gettext Boolean: DOCUMENT (Default: false)
-        * @return bool
+        * @param File $image
+        * @param bool $gettext DOCUMENT (Default: false)
+        * @return bool|SimpleXMLElement
         */
        function getMetaTree( $image, $gettext = false ) {
-               if ( isset( $image->dejaMetaTree ) ) {
+               if ( $gettext && isset( $image->djvuTextTree ) ) {
+                       return $image->djvuTextTree;
+               }
+               if ( !$gettext && isset( $image->dejaMetaTree ) ) {
                        return $image->dejaMetaTree;
                }
 
@@ -251,8 +256,11 @@ class DjVuHandler extends ImageHandler {
                        $image->djvuTextTree = false;
                        $tree = new SimpleXMLElement( $metadata );
                        if ( $tree->getName() == 'mw-djvu' ) {
+                               /** @var SimpleXMLElement $b */
                                foreach ( $tree->children() as $b ) {
                                        if ( $b->getName() == 'DjVuTxt' ) {
+                                               // @todo File::djvuTextTree and File::dejaMetaTree are declared
+                                               // dynamically. Add a public File::$data to facilitate this?
                                                $image->djvuTextTree = $b;
                                        } elseif ( $b->getName() == 'DjVuXML' ) {
                                                $image->dejaMetaTree = $b;
@@ -273,6 +281,11 @@ class DjVuHandler extends ImageHandler {
                }
        }
 
+       /**
+        * @param File $image
+        * @param string $path
+        * @return bool|array False on failure
+        */
        function getImageSize( $image, $path ) {
                return $this->getDjVuImage( $image, $path )->getImageSize();
        }
@@ -328,6 +341,11 @@ class DjVuHandler extends ImageHandler {
                }
        }
 
+       /**
+        * @param File $image
+        * @param int $page Page number to get information for
+        * @return bool|string Page text or false when no text found.
+        */
        function getPageText( $image, $page ) {
                $tree = $this->getMetaTree( $image, true );
                if ( !$tree ) {
index 971c865..1197552 100644 (file)
  * @ingroup Media
  */
 class DjVuImage {
+       /**
+        * @const DJVUTXT_MEMORY_LIMIT Memory limit for the DjVu description software
+        */
+       const DJVUTXT_MEMORY_LIMIT = 300000;
+
        /**
         * Constructor
         *
@@ -43,11 +48,6 @@ class DjVuImage {
                $this->mFilename = $filename;
        }
 
-       /**
-        * @const DJVUTXT_MEMORY_LIMIT Memory limit for the DjVu description software
-        */
-       const DJVUTXT_MEMORY_LIMIT = 300000;
-
        /**
         * Check if the given file is indeed a valid DjVu image file
         * @return bool
@@ -87,6 +87,8 @@ class DjVuImage {
                // @todo FIXME: Would be good to replace this extract() call with
                // something that explicitly initializes local variables.
                extract( unpack( 'a4magic/a4chunk/NchunkLength', $header ) );
+               /** @var string $chunk
+                *  @var string $chunkLength */
                echo "$chunk $chunkLength\n";
                $this->dumpForm( $file, $chunkLength, 1 );
                fclose( $file );
@@ -104,6 +106,8 @@ class DjVuImage {
                        // @todo FIXME: Would be good to replace this extract() call with
                        // something that explicitly initializes local variables.
                        extract( unpack( 'a4chunk/NchunkLength', $chunkHeader ) );
+                       /** @var string $chunk
+                        *  @var string $chunkLength */
                        echo str_repeat( ' ', $indent * 4 ) . "$chunk $chunkLength\n";
 
                        if ( $chunk == 'FORM' ) {
@@ -138,6 +142,10 @@ class DjVuImage {
                        // something that explicitly initializes local variables.
                        extract( unpack( 'a4magic/a4form/NformLength/a4subtype', $header ) );
 
+                       /** @var string $magic
+                        *  @var string $subtype
+                        *  @var string $formLength
+                        *  @var string $formType */
                        if ( $magic != 'AT&T' ) {
                                wfDebug( __METHOD__ . ": not a DjVu file\n" );
                        } elseif ( $subtype == 'DJVU' ) {
@@ -164,6 +172,8 @@ class DjVuImage {
                        // something that explicitly initializes local variables.
                        extract( unpack( 'a4chunk/Nlength', $header ) );
 
+                       /** @var string $chunk
+                        *  @var string $length */
                        return array( $chunk, $length );
                }
        }
@@ -238,6 +248,13 @@ class DjVuImage {
 
                # Newer files have rotation info in byte 10, but we don't use it yet.
 
+               /** @var string $width
+                *  @var string $height
+                *  @var string $major
+                *  @var string $minor
+                *  @var string $resolution
+                *  @var string $length
+                *  @var string $gamma */
                return array(
                        'width' => $width,
                        'height' => $height,
@@ -313,7 +330,8 @@ EOR;
 
        /**
         * Hack to temporarily work around djvutoxml bug
-        * @return bool|string
+        * @param $dump
+        * @return string
         */
        function convertDumpToXML( $dump ) {
                if ( strval( $dump ) == '' ) {
index ecce673..bb5e344 100644 (file)
@@ -66,77 +66,49 @@ class Exif {
        /** A fake value for things we don't want or don't support. */
        const IGNORE = -1;
 
-       //@{
-       /* @var array
-        * @private
+       /** @var array Exif tags grouped by category, the tagname itself is the key
+        *    and the type is the value, in the case of more than one possible value
+        *    type they are separated by commas.
         */
+       private $mExifTags;
 
-       /**
-        * Exif tags grouped by category, the tagname itself is the key and the type
-        * is the value, in the case of more than one possible value type they are
-        * separated by commas.
-        */
-       var $mExifTags;
-
-       /**
-        * The raw Exif data returned by exif_read_data()
-        */
-       var $mRawExifData;
+       /** @var array The raw Exif data returned by exif_read_data() */
+       private $mRawExifData;
 
-       /**
-        * A Filtered version of $mRawExifData that has been pruned of invalid
-        * tags and tags that contain content they shouldn't contain according
-        * to the Exif specification
+       /** @var array A Filtered version of $mRawExifData that has been pruned
+        *    of invalid tags and tags that contain content they shouldn't contain
+        *    according to the Exif specification
         */
-       var $mFilteredExifData;
+       private $mFilteredExifData;
 
-       /**
-        * Filtered and formatted Exif data, see FormatMetadata::getFormattedData()
-        */
-       var $mFormattedExifData;
+       /** @var array Filtered and formatted Exif data, see FormatMetadata::getFormattedData() */
+       private $mFormattedExifData;
 
-       //@}
+       /** @var string The file being processed */
+       private $file;
 
-       //@{
-       /* @var string
-        * @private
-        */
+       /** @var string The basename of the file being processed */
+       private $basename;
 
-       /**
-        * The file being processed
-        */
-       var $file;
+       /** @var string The private log to log to, e.g. 'exif' */
+       private $log = false;
 
-       /**
-        * The basename of the file being processed
-        */
-       var $basename;
-
-       /**
-        * The private log to log to, e.g. 'exif'
-        */
-       var $log = false;
-
-       /**
-        * The byte order of the file. Needed because php's
-        * extension doesn't fully process some obscure props.
+       /** @var string The byte order of the file. Needed because php's extension
+        *    doesn't fully process some obscure props.
         */
        private $byteOrder;
 
-       //@}
-
        /**
         * Constructor
         *
-        * @param string $file filename.
+        * @param string $file Filename.
         * @param string $byteOrder Type of byte ordering either 'BE' (Big Endian)
         *   or 'LE' (Little Endian). Default ''.
         * @throws MWException
         * @todo FIXME: The following are broke:
-        * SubjectArea. Need to test the more obscure tags.
-        *
-        * DigitalZoomRatio = 0/0 is rejected. need to determine if that's valid.
-        * possibly should treat 0/0 = 0. need to read exif spec on that.
+        *   SubjectArea. Need to test the more obscure tags.
+        *   DigitalZoomRatio = 0/0 is rejected. need to determine if that's valid.
+        *   Possibly should treat 0/0 = 0. need to read exif spec on that.
         */
        function __construct( $file, $byteOrder = '' ) {
                /**
@@ -194,7 +166,7 @@ class Exif {
 
                        # Exif IFD Attribute Information (p30-31)
                        'EXIF' => array(
-                               # TODO: NOTE: Nonexistence of this field is taken to mean nonconformance
+                               # @todo NOTE: Nonexistence of this field is taken to mean nonconformance
                                # to the Exif 2.1 AND 2.2 standards
                                'ExifVersion' => Exif::UNDEFINED, # Exif version
                                'FlashPixVersion' => Exif::UNDEFINED, # Supported Flashpix version #p32
@@ -537,7 +509,7 @@ class Exif {
         * Convert an Exif::UNDEFINED from a raw binary string
         * to its value. This is sometimes needed depending on
         * the type of UNDEFINED field
-        * @param string $prop name of property
+        * @param string $prop Name of property
         */
        private function exifPropToOrd( $prop ) {
                if ( isset( $this->mFilteredExifData[$prop] ) ) {
@@ -548,7 +520,7 @@ class Exif {
        /**
         * Convert gps in exif form to a single floating point number
         * for example 10 degress 20`40`` S -> -10.34444
-        * @param string $prop a gps coordinate exif tag name (like GPSLongitude)
+        * @param string $prop A GPS coordinate exif tag name (like GPSLongitude)
         */
        private function exifGPStoNumber( $prop ) {
                $loc =& $this->mFilteredExifData[$prop];
@@ -651,9 +623,7 @@ class Exif {
        /**#@+
         * Validates if a tag value is of the type it should be according to the Exif spec
         *
-        * @private
-        *
-        * @param $in Mixed: the input value to check
+        * @param mixed $in The input value to check
         * @return bool
         */
        private function isByte( $in ) {
@@ -669,7 +639,7 @@ class Exif {
        }
 
        /**
-        * @param $in
+        * @param mixed $in The input value to check
         * @return bool
         */
        private function isASCII( $in ) {
@@ -693,7 +663,7 @@ class Exif {
        }
 
        /**
-        * @param $in
+        * @param mixed $in The input value to check
         * @return bool
         */
        private function isShort( $in ) {
@@ -709,7 +679,7 @@ class Exif {
        }
 
        /**
-        * @param $in
+        * @param mixed $in The input value to check
         * @return bool
         */
        private function isLong( $in ) {
@@ -725,7 +695,7 @@ class Exif {
        }
 
        /**
-        * @param $in
+        * @param mixed $in The input value to check
         * @return bool
         */
        private function isRational( $in ) {
@@ -744,7 +714,7 @@ class Exif {
        }
 
        /**
-        * @param $in
+        * @param mixed $in The input value to check
         * @return bool
         */
        private function isUndefined( $in ) {
@@ -754,7 +724,7 @@ class Exif {
        }
 
        /**
-        * @param $in
+        * @param mixed $in The input value to check
         * @return bool
         */
        private function isSlong( $in ) {
@@ -770,7 +740,7 @@ class Exif {
        }
 
        /**
-        * @param $in
+        * @param mixed $in The input value to check
         * @return bool
         */
        private function isSrational( $in ) {
@@ -793,11 +763,10 @@ class Exif {
        /**
         * Validates if a tag has a legal value according to the Exif spec
         *
-        * @private
         * @param string $section section where tag is located.
         * @param string $tag the tag to check.
-        * @param $val Mixed: the value of the tag.
-        * @param $recursive Boolean: true if called recursively for array types.
+        * @param mixed $val The value of the tag.
+        * @param bool $recursive True if called recursively for array types.
         * @return bool
         */
        private function validate( $section, $tag, $val, $recursive = false ) {
@@ -877,11 +846,9 @@ class Exif {
        /**
         * Convenience function for debugging output
         *
-        * @private
-        *
-        * @param $in Mixed:
-        * @param $fname String:
-        * @param $action Mixed: , default NULL.
+        * @param mixed $in Arrays will be processed with print_r().
+        * @param string $fname Function name to log.
+        * @param string|bool|null $action Default null.
         */
        private function debug( $in, $fname, $action = null ) {
                if ( !$this->log ) {
@@ -907,10 +874,8 @@ class Exif {
        /**
         * Convenience function for debugging output
         *
-        * @private
-        *
         * @param string $fname the name of the function calling this function
-        * @param $io Boolean: Specify whether we're beginning or ending
+        * @param bool $io Specify whether we're beginning or ending
         */
        private function debugFile( $fname, $io ) {
                if ( !$this->log ) {
index 0a14ca8..fe037b7 100644 (file)
@@ -79,6 +79,11 @@ class ExifBitmapHandler extends BitmapHandler {
                return $metadata;
        }
 
+       /**
+        * @param $image
+        * @param array $metadata
+        * @return bool|int
+        */
        function isMetadataValid( $image, $metadata ) {
                global $wgShowEXIF;
                if ( !$wgShowEXIF ) {
@@ -119,7 +124,7 @@ class ExifBitmapHandler extends BitmapHandler {
        }
 
        /**
-        * @param $image File
+        * @param File $image
         * @return array|bool
         */
        function formatMetadata( $image ) {
@@ -214,8 +219,7 @@ class ExifBitmapHandler extends BitmapHandler {
         *
         * @param string $data
         * @return int 0, 90, 180 or 270
-        * @todo FIXME orientation can include flipping as well; see if this is an
-        * issue!
+        * @todo FIXME: Orientation can include flipping as well; see if this is an issue!
         */
        protected function getRotationForExif( $data ) {
                if ( !$data ) {
index fe8c4f4..adaba76 100644 (file)
@@ -49,7 +49,7 @@
 class FormatMetadata extends ContextSource {
        /**
         * Only output a single language for multi-language fields
-        * @var boolean
+        * @var bool
         * @since 1.23
         */
        protected $singleLang = false;
@@ -57,7 +57,7 @@ class FormatMetadata extends ContextSource {
        /**
         * Trigger only outputting single language for multilanguage fields
         *
-        * @param Boolean $val
+        * @param bool $val
         * @since 1.23
         */
        public function setSingleLanguage( $val ) {
@@ -73,8 +73,8 @@ class FormatMetadata extends ContextSource {
         * This is the usual entry point for this class.
         *
         * @param array $tags the Exif data to format ( as returned by
-        *                    Exif::getFilteredData() or BitmapMetadataHandler )
-        * @param IContextSource $context Context to use (optional)
+        *   Exif::getFilteredData() or BitmapMetadataHandler )
+        * @param bool|IContextSource $context Context to use (optional)
         * @return array
         */
        public static function getFormattedData( $tags, $context = false ) {
@@ -93,7 +93,7 @@ class FormatMetadata extends ContextSource {
         * formats Exif (and other metadata) values into human readable form.
         *
         * @param array $tags the Exif data to format ( as returned by
-        *                    Exif::getFilteredData() or BitmapMetadataHandler )
+        *   Exif::getFilteredData() or BitmapMetadataHandler )
         * @return array
         * @since 1.23
         */
@@ -977,14 +977,14 @@ class FormatMetadata extends ContextSource {
        /**
         * Flatten an array, using the content language for any messages.
         *
-        * @param array $vals array of values
+        * @param array $vals Array of values
         * @param string $type Type of array (either lang, ul, ol).
-        *     lang = language assoc array with keys being the lang code
-        *     ul = unordered list, ol = ordered list
-        *     type can also come from the '_type' member of $vals.
-        * @param $noHtml Boolean If to avoid returning anything resembling
-        *     html. (Ugly hack for backwards compatibility with old mediawiki).
-        * @param IContextSource $context
+        *   lang = language assoc array with keys being the lang code
+        *   ul = unordered list, ol = ordered list
+        *   type can also come from the '_type' member of $vals.
+        * @param bool $noHtml If to avoid returning anything resembling HTML.
+        *   (Ugly hack for backwards compatibility with old MediaWiki).
+        * @param bool|IContextSource $context
         * @return String single value (in wiki-syntax).
         * @since 1.23
         */
@@ -1008,13 +1008,13 @@ class FormatMetadata extends ContextSource {
         *
         * @param array $vals array of values
         * @param string $type Type of array (either lang, ul, ol).
-        *     lang = language assoc array with keys being the lang code
-        *     ul = unordered list, ol = ordered list
-        *     type can also come from the '_type' member of $vals.
-        * @param $noHtml Boolean If to avoid returning anything resembling
-        *     html. (Ugly hack for backwards compatibility with old mediawiki).
-        * @param IContextSource $context
-        * @return String single value (in wiki-syntax).
+        *   lang = language assoc array with keys being the lang code
+        *   ul = unordered list, ol = ordered list
+        *   type can also come from the '_type' member of $vals.
+        * @param bool $noHtml If to avoid returning anything resembling HTML.
+        *   (Ugly hack for backwards compatibility with old MediaWiki).
+        * @param bool|IContextSource $context
+        * @return string Single value (in wiki-syntax).
         */
        public static function flattenArray( $vals, $type = 'ul', $noHtml = false, $context = false ) {
                $obj = new FormatMetadata;
@@ -1036,8 +1036,8 @@ class FormatMetadata extends ContextSource {
         *     lang = language assoc array with keys being the lang code
         *     ul = unordered list, ol = ordered list
         *     type can also come from the '_type' member of $vals.
-        * @param $noHtml Boolean If to avoid returning anything resembling
-        *     html. (Ugly hack for backwards compatibility with old mediawiki).
+        * @param $noHtml Boolean If to avoid returning anything resembling HTML.
+        *   (Ugly hack for backwards compatibility with old mediawiki).
         * @return String single value (in wiki-syntax).
         * @since 1.23
         */
@@ -1158,11 +1158,11 @@ class FormatMetadata extends ContextSource {
         *
         * @param string $value value (this is not escaped)
         * @param string $lang lang code of item or false
-        * @param $default Boolean if it is default value.
-        * @param $noHtml Boolean If to avoid html (for back-compat)
+        * @param bool $default If it is default value.
+        * @param bool $noHtml If to avoid html (for back-compat)
         * @throws MWException
-        * @return string language item (Note: despite how this looks,
-        * this is treated as wikitext not html).
+        * @return string Language item (Note: despite how this looks, this is
+        *   treated as wikitext, not as HTML).
         */
        private function langItem( $value, $lang, $default = false, $noHtml = false ) {
                if ( $lang === false && $default === false ) {
@@ -1221,12 +1221,10 @@ class FormatMetadata extends ContextSource {
        /**
         * Convenience function for getFormattedData()
         *
-        * @private
-        *
-        * @param string $tag the tag name to pass on
-        * @param string $val the value of the tag
-        * @param string $arg an argument to pass ($1)
-        * @param string $arg2 a 2nd argument to pass ($2)
+        * @param string $tag The tag name to pass on
+        * @param string $val The value of the tag
+        * @param string $arg An argument to pass ($1)
+        * @param string $arg2 A 2nd argument to pass ($2)
         * @return string The text content of "exif-$tag-$val" message in lower case
         */
        private function exifMsg( $tag, $val, $arg = null, $arg2 = null ) {
@@ -1243,8 +1241,8 @@ class FormatMetadata extends ContextSource {
         * Format a number, convert numbers from fractions into floating point
         * numbers, joins arrays of numbers with commas.
         *
-        * @param $num Mixed: the value to format
-        * @param $round float|int|bool digits to round to or false.
+        * @param mixed $num The value to format
+        * @param float|int|bool $round Digits to round to or false.
         * @return mixed A floating point number or whatever we were fed
         */
        private function formatNum( $num, $round = false ) {
@@ -1280,9 +1278,7 @@ class FormatMetadata extends ContextSource {
        /**
         * Format a rational number, reducing fractions
         *
-        * @private
-        *
-        * @param $num Mixed: the value to format
+        * @param mixed $num The value to format
         * @return mixed A floating point number or whatever we were fed
         */
        private function formatFraction( $num ) {
@@ -1303,8 +1299,8 @@ class FormatMetadata extends ContextSource {
        /**
         * Calculate the greatest common divisor of two integers.
         *
-        * @param $a Integer: Numerator
-        * @param $b Integer: Denominator
+        * @param int $a Numerator
+        * @param int $b Denominator
         * @return int
         * @private
         */
@@ -1411,8 +1407,8 @@ class FormatMetadata extends ContextSource {
         * Format a coordinate value, convert numbers from floating point
         * into degree minute second representation.
         *
-        * @param int $coord degrees, minutes and seconds
-        * @param string $type latitude or longitude (for if its a NWS or E)
+        * @param int $coord Degrees, minutes and seconds
+        * @param string $type Latitude or longitude (for if its a NWS or E)
         * @return mixed A floating point number or whatever we were fed
         */
        private function formatCoords( $coord, $type ) {
@@ -1447,16 +1443,15 @@ class FormatMetadata extends ContextSource {
        /**
         * Format the contact info field into a single value.
         *
-        * @param array $vals array with fields of the ContactInfo
-        *    struct defined in the IPTC4XMP spec. Or potentially
-        *    an array with one element that is a free form text
-        *    value from the older iptc iim 1:118 prop.
-        *
         * This function might be called from
         * JpegHandler::convertMetadataVersion which is why it is
         * public.
         *
-        * @return String of html-ish looking wikitext
+        * @param array $vals Array with fields of the ContactInfo
+        *    struct defined in the IPTC4XMP spec. Or potentially
+        *    an array with one element that is a free form text
+        *    value from the older iptc iim 1:118 prop.
+        * @return string HTML-ish looking wikitext
         * @since 1.23 no longer static
         */
        public function collapseContactInfo( $vals ) {
@@ -1888,7 +1883,7 @@ class FormatExif {
        private $meta;
 
        /**
-        * @param $meta array
+        * @param array $meta
         */
        function __construct( $meta ) {
                wfDeprecated( __METHOD__, '1.18' );
index 830b5ca..bde889c 100644 (file)
@@ -43,7 +43,7 @@ class GIFHandler extends BitmapHandler {
        }
 
        /**
-        * @param $image File
+        * @param File $image
         * @return array|bool
         */
        function formatMetadata( $image ) {
@@ -76,8 +76,9 @@ class GIFHandler extends BitmapHandler {
        }
 
        /**
-        * @param $image File
-        * @todo unittests
+        * @todo Add unit tests
+        *
+        * @param File$image
         * @return bool
         */
        function getImageArea( $image ) {
@@ -92,7 +93,7 @@ class GIFHandler extends BitmapHandler {
        }
 
        /**
-        * @param $image File
+        * @param File $image
         * @return bool
         */
        function isAnimatedImage( $image ) {
@@ -151,7 +152,7 @@ class GIFHandler extends BitmapHandler {
        }
 
        /**
-        * @param $image File
+        * @param File $image
         * @return string
         */
        function getLongDesc( $image ) {
index 59fe15c..178b0bf 100644 (file)
@@ -50,7 +50,7 @@ class GIFMetadataExtractor {
 
        /**
         * @throws Exception
-        * @param $filename string
+        * @param string $filename
         * @return array
         */
        static function getMetadata( $filename ) {
@@ -261,8 +261,8 @@ class GIFMetadataExtractor {
        }
 
        /**
-        * @param $fh
-        * @param $bpp
+        * @param resource $fh
+        * @param int $bpp
         * @return void
         */
        static function readGCT( $fh, $bpp ) {
@@ -275,7 +275,7 @@ class GIFMetadataExtractor {
        }
 
        /**
-        * @param $data
+        * @param string $data
         * @throws Exception
         * @return int
         */
@@ -294,7 +294,7 @@ class GIFMetadataExtractor {
        }
 
        /**
-        * @param $fh
+        * @param resource $fh
         * @throws Exception
         */
        static function skipBlock( $fh ) {
@@ -318,8 +318,8 @@ class GIFMetadataExtractor {
         * saying how long the sub-block is, followed by the sub-block.
         * The entire block is terminated by a sub-block of length
         * 0.
-        * @param $fh FileHandle
-        * @param $includeLengths Boolean Include the length bytes of the
+        * @param resource $fh File handle
+        * @param bool $includeLengths Include the length bytes of the
         *  sub-blocks in the returned value. Normally this is false,
         *  except XMP is weird and does a hack where you need to keep
         *  these length bytes.
index ee0233e..503b968 100644 (file)
@@ -35,7 +35,7 @@ class IPTC {
         * @see http://www.iptc.org/std/IIM/4.1/specification/IIMV4.1.pdf
         *
         * @param string $rawData app13 block from jpeg containing iptc/iim data
-        * @return Array iptc metadata array
+        * @return array IPTC metadata array
         */
        static function parse( $rawData ) {
                $parsed = iptcparse( $rawData );
@@ -353,8 +353,8 @@ class IPTC {
         * @todo Potentially this should also capture the timezone offset.
         * @param array $date The date tag
         * @param array $time The time tag
-        * @param $c
-        * @return String Date in exif format.
+        * @param string $c The charset
+        * @return string Date in EXIF format.
         */
        private static function timeHelper( $date, $time, $c ) {
                if ( count( $date ) === 1 ) {
@@ -438,7 +438,7 @@ class IPTC {
 
        /**
         * Helper function of a helper function to convert charset for iptc values.
-        * @param $data Mixed String or Array: The iptc string
+        * @param string|array $data The IPTC string
         * @param string $charset The charset
         *
         * @return string
index eecef1d..4dd79a8 100644 (file)
@@ -28,7 +28,7 @@
  */
 abstract class ImageHandler extends MediaHandler {
        /**
-        * @param $file File
+        * @param File $file
         * @return bool
         */
        function canRender( $file ) {
@@ -79,8 +79,8 @@ abstract class ImageHandler extends MediaHandler {
        }
 
        /**
-        * @param $image File
-        * @param  $params
+        * @param File $image
+        * @param array $params
         * @return bool
         */
        function normaliseParams( $image, &$params ) {
@@ -151,11 +151,11 @@ abstract class ImageHandler extends MediaHandler {
        /**
         * Validate thumbnail parameters and fill in the correct height
         *
-        * @param $width Integer: specified width (input/output)
-        * @param $height Integer: height (output only)
-        * @param $srcWidth Integer: width of the source image
-        * @param $srcHeight Integer: height of the source image
-        * @param $mimeType
+        * @param int $width Specified width (input/output)
+        * @param int $height Height (output only)
+        * @param int $srcWidth Width of the source image
+        * @param int $srcHeight Height of the source image
+        * @param string $mimeType Unused
         * @return bool False to indicate that an error should be returned to the user.
         */
        function validateThumbParams( &$width, &$height, $srcWidth, $srcHeight, $mimeType ) {
@@ -183,10 +183,10 @@ abstract class ImageHandler extends MediaHandler {
        }
 
        /**
-        * @param $image File
-        * @param  $script
-        * @param  $params
-        * @return bool|ThumbnailImage
+        * @param File $image
+        * @param string $script
+        * @param array $params
+        * @return bool|MediaTransformOutput
         */
        function getScriptedTransform( $image, $script, $params ) {
                if ( !$this->normaliseParams( $image, $params ) ) {
@@ -221,7 +221,7 @@ abstract class ImageHandler extends MediaHandler {
        }
 
        /**
-        * @param $file File
+        * @param File $file
         * @return string
         */
        function getShortDesc( $file ) {
@@ -234,7 +234,7 @@ abstract class ImageHandler extends MediaHandler {
        }
 
        /**
-        * @param $file File
+        * @param File $file
         * @return string
         */
        function getLongDesc( $file ) {
@@ -255,7 +255,7 @@ abstract class ImageHandler extends MediaHandler {
        }
 
        /**
-        * @param $file File
+        * @param File $file
         * @return string
         */
        function getDimensionsString( $file ) {
index 213bee0..ee7eff8 100644 (file)
@@ -61,7 +61,7 @@ class JpegHandler extends ExifBitmapHandler {
        }
 
        /**
-        * @param $file File
+        * @param File $file
         * @param array $params Rotate parameters.
         *    'rotation' clockwise rotation in degrees, allowed are multiples of 90
         * @since 1.21
@@ -80,6 +80,7 @@ class JpegHandler extends ExifBitmapHandler {
                        wfDebug( __METHOD__ . ": running jpgtran: $cmd\n" );
                        wfProfileIn( 'jpegtran' );
                        $retval = 0;
+                       // @todo FIXME Undefined variable $env
                        $err = wfShellExecWithStderr( $cmd, $retval, $env );
                        wfProfileOut( 'jpegtran' );
                        if ( $retval !== 0 ) {
index 00be258..a0f8524 100644 (file)
@@ -44,7 +44,7 @@ class JpegMetadataExtractor {
         * and those can't extract xmp on files containing both exif and xmp data
         *
         * @param string $filename name of jpeg file
-        * @return Array of interesting segments.
+        * @return array of interesting segments.
         * @throws MWException if given invalid file.
         */
        static function segmentSplitter( $filename ) {
@@ -167,9 +167,9 @@ class JpegMetadataExtractor {
 
        /**
         * Helper function for jpegSegmentSplitter
-        * @param &$fh FileHandle for jpeg file
+        * @param resource &$fh File handle for JPEG file
         * @throws MWException
-        * @return string data content of segment.
+        * @return string Data content of segment.
         */
        private static function jpegExtractMarker( &$fh ) {
                $size = wfUnpack( "nint", fread( $fh, 2 ), 2 );
@@ -195,7 +195,8 @@ class JpegMetadataExtractor {
         *
         * @param string $app13 photoshop psir app13 block from jpg.
         * @throws MWException (It gets caught next level up though)
-        * @return String if the iptc hash is good or not.
+        * @return string If the iptc hash is good or not. One of 'iptc-no-hash',
+        *   'iptc-good-hash', 'iptc-bad-hash'.
         */
        public static function doPSIR( $app13 ) {
                if ( !$app13 ) {
index 562de13..1dc74ce 100644 (file)
@@ -31,6 +31,10 @@ abstract class MediaHandler {
        const METADATA_GOOD = true;
        const METADATA_BAD = false;
        const METADATA_COMPATIBLE = 2; // for old but backwards compatible.
+       /**
+        * Max length of error logged by logErrorForExternalProcess()
+        */
+       const MAX_ERR_LOG_SIZE = 65535;
 
        /** @var MediaHandler[] Instance cache with array of MediaHandler */
        protected static $handlers = array();
@@ -39,7 +43,6 @@ abstract class MediaHandler {
         * Get a MediaHandler for a given MIME type from the instance cache
         *
         * @param string $type
-        *
         * @return MediaHandler
         */
        static function getHandler( $type ) {
@@ -72,7 +75,7 @@ abstract class MediaHandler {
         * If you return false, the parser will do something quiet and forgiving.
         *
         * @param string $name
-        * @param $value
+        * @param mixed $value
         */
        abstract function validateParam( $name, $value );
 
@@ -96,8 +99,8 @@ abstract class MediaHandler {
         * Changes the parameter array as necessary, ready for transformation.
         * Should be idempotent.
         * Returns false if the parameters are unacceptable and the transform should fail
-        * @param $image
-        * @param $params
+        * @param File $image
+        * @param array $params
         */
        abstract function normaliseParams( $image, &$params );
 
@@ -107,7 +110,8 @@ abstract class MediaHandler {
         *
         * @param File $image The image object, or false if there isn't one
         * @param string $path the filename
-        * @return array Follow the format of PHP getimagesize() internal function. See http://www.php.net/getimagesize
+        * @return array Follow the format of PHP getimagesize() internal function.
+        *   See http://www.php.net/getimagesize
         */
        abstract function getImageSize( $image, $path );
 
@@ -151,7 +155,7 @@ abstract class MediaHandler {
         * By default just returns $metadata, but can be used to allow
         * media handlers to convert between metadata versions.
         *
-        * @param mixed|string|array $metadata Metadata array (serialized if string)
+        * @param string|array $metadata Metadata array (serialized if string)
         * @param int $version Target version
         * @return array Serialized metadata in specified version, or $metadata on fail.
         */
@@ -171,7 +175,7 @@ abstract class MediaHandler {
 
        /**
         * Get a string describing the type of metadata, for display purposes.
-        * @param $image
+        * @param File $image
         * @return string
         */
        function getMetadataType( $image ) {
@@ -185,6 +189,8 @@ abstract class MediaHandler {
         * MediaHandler::METADATA_GOOD for if the metadata is a-ok,
         * MediaHanlder::METADATA_COMPATIBLE if metadata is old but backwards
         * compatible (which may or may not trigger a metadata reload).
+        * @param File $image
+        * @param array $metadata
         * @return bool
         */
        function isMetadataValid( $image, $metadata ) {
@@ -220,7 +226,6 @@ abstract class MediaHandler {
         * this interface, it should return an empty array, not false.
         *
         * @param File $file
-        *
         * @return array|bool False if interface not supported
         * @since 1.23
         */
@@ -235,7 +240,10 @@ abstract class MediaHandler {
         * Used when the repository has a thumbnailScriptUrl option configured.
         *
         * Return false to fall back to the regular getTransform().
-        * @return bool
+        * @param File $image
+        * @param string $script
+        * @param array $params
+        * @return bool|ThumbnailImage
         */
        function getScriptedTransform( $image, $script, $params ) {
                return false;
@@ -246,7 +254,7 @@ abstract class MediaHandler {
         * actually do the transform.
         *
         * @param File $image The image object
-        * @param string $dstPath filesystem destination path
+        * @param string $dstPath Filesystem destination path
         * @param string $dstUrl Destination URL to use in output HTML
         * @param array $params Arbitrary set of parameters validated by $this->validateParam()
         * @return MediaTransformOutput
@@ -260,12 +268,11 @@ abstract class MediaHandler {
         * transform unless $flags contains self::TRANSFORM_LATER.
         *
         * @param File $image The image object
-        * @param string $dstPath filesystem destination path
-        * @param string $dstUrl destination URL to use in output HTML
-        * @param array $params arbitrary set of parameters validated by $this->validateParam()
+        * @param string $dstPath Filesystem destination path
+        * @param string $dstUrl Destination URL to use in output HTML
+        * @param array $params Arbitrary set of parameters validated by $this->validateParam()
         *   Note: These parameters have *not* gone through $this->normaliseParams()
         * @param int $flags A bitfield, may contain self::TRANSFORM_LATER
-        *
         * @return MediaTransformOutput
         */
        abstract function doTransform( $image, $dstPath, $dstUrl, $params, $flags = 0 );
@@ -274,7 +281,7 @@ abstract class MediaHandler {
         * Get the thumbnail extension and MIME type for a given source MIME type
         *
         * @param string $ext Extension of original file
-        * @param string $mime Mime type of original file
+        * @param string $mime MIME type of original file
         * @param array $params Handler specific rendering parameters
         * @return array thumbnail extension and MIME type
         */
@@ -296,6 +303,7 @@ abstract class MediaHandler {
 
        /**
         * Get useful response headers for GET/HEAD requests for a file with the given metadata
+        *
         * @param mixed $metadata Result of the getMetadata() function of this handler for a file
         * @return array
         */
@@ -305,6 +313,8 @@ abstract class MediaHandler {
 
        /**
         * True if the handled types can be transformed
+        *
+        * @param File $file
         * @return bool
         */
        function canRender( $file ) {
@@ -314,6 +324,8 @@ abstract class MediaHandler {
        /**
         * True if handled types cannot be displayed directly in a browser
         * but can be rendered
+        *
+        * @param File $file
         * @return bool
         */
        function mustRender( $file ) {
@@ -322,6 +334,8 @@ abstract class MediaHandler {
 
        /**
         * True if the type has multi-page capabilities
+        *
+        * @param File $file
         * @return bool
         */
        function isMultiPage( $file ) {
@@ -330,6 +344,8 @@ abstract class MediaHandler {
 
        /**
         * Page count for a multi-page document, false if unsupported or unknown
+        *
+        * @param File $file
         * @return bool
         */
        function pageCount( $file ) {
@@ -338,6 +354,8 @@ abstract class MediaHandler {
 
        /**
         * The material is vectorized and thus scaling is lossless
+        *
+        * @param File $file
         * @return bool
         */
        function isVectorized( $file ) {
@@ -348,6 +366,8 @@ abstract class MediaHandler {
         * The material is an image, and is animated.
         * In particular, video material need not return true.
         * @note Before 1.20, this was a method of ImageHandler only
+        *
+        * @param File $file
         * @return bool
         */
        function isAnimatedImage( $file ) {
@@ -357,6 +377,8 @@ abstract class MediaHandler {
        /**
         * If the material is animated, we can animate the thumbnail
         * @since 1.20
+        *
+        * @param File $file
         * @return bool If material is not animated, handler may return any value.
         */
        function canAnimateThumbnail( $file ) {
@@ -402,7 +424,9 @@ abstract class MediaHandler {
        /**
         * Generic getter for text layer.
         * Currently overloaded by PDF and DjVu handlers
-        * @return bool
+        * @param File $image
+        * @param int $page Page number to get information for
+        * @return bool|string Page text or false when no text found.
         */
        function getPageText( $image, $page ) {
                return false;
@@ -428,12 +452,12 @@ abstract class MediaHandler {
         */
 
        /**
-        * @todo FIXME: I don't really like this interface, it's not very flexible
-        * I think the media handler should generate HTML instead. It can do
-        * all the formatting according to some standard. That makes it possible
-        * to do things like visual indication of grouped and chained streams
-        * in ogg container files.
-        * @return bool
+        * @todo FIXME: This interface is not very flexible. The media handler
+        * should generate HTML instead. It can do all the formatting according
+        * to some standard. That makes it possible to do things like visual
+        * indication of grouped and chained streams in ogg container files.
+        * @param File $image
+        * @return array|bool
         */
        function formatMetadata( $image ) {
                return false;
@@ -445,7 +469,7 @@ abstract class MediaHandler {
         *
         * This is used by the media handlers that use the FormatMetadata class
         *
-        * @param array $metadataArray metadata array
+        * @param array $metadataArray Metadata array
         * @return array for use displaying metadata.
         */
        function formatMetadataHelper( $metadataArray ) {
@@ -475,7 +499,6 @@ abstract class MediaHandler {
         * the metadata table is collapsed.
         *
         * @return array of strings
-        * @access protected
         */
        function visibleMetadataFields() {
                return FormatMetadata::getVisibleFields();
@@ -486,21 +509,21 @@ abstract class MediaHandler {
         * That array is then used to generate the table of metadata values
         * on the image page
         *
-        * @param &$array Array An array containing elements for each type of visibility
-        * and each of those elements being an array of metadata items. This function adds
-        * a value to that array.
+        * @param array &$array An array containing elements for each type of visibility
+        *   and each of those elements being an array of metadata items. This function adds
+        *   a value to that array.
         * @param string $visibility ('visible' or 'collapsed') if this value is hidden
-        * by default.
-        * @param string $type type of metadata tag (currently always 'exif')
-        * @param string $id the name of the metadata tag (like 'artist' for example).
-        * its name in the table displayed is the message "$type-$id" (Ex exif-artist ).
-        * @param string $value thingy goes into a wikitext table; it used to be escaped but
-        * that was incompatible with previous practise of customized display
-        * with wikitext formatting via messages such as 'exif-model-value'.
-        * So the escaping is taken back out, but generally this seems a confusing
-        * interface.
-        * @param string $param value to pass to the message for the name of the field
-        * as $1. Currently this parameter doesn't seem to ever be used.
+        *   by default.
+        * @param string $type Type of metadata tag (currently always 'exif')
+        * @param string $id The name of the metadata tag (like 'artist' for example).
+        *   its name in the table displayed is the message "$type-$id" (Ex exif-artist ).
+        * @param string $value Thingy goes into a wikitext table; it used to be escaped but
+        *   that was incompatible with previous practise of customized display
+        *   with wikitext formatting via messages such as 'exif-model-value'.
+        *   So the escaping is taken back out, but generally this seems a confusing
+        *   interface.
+        * @param bool|string $param Value to pass to the message for the name of the field
+        *   as $1. Currently this parameter doesn't seem to ever be used.
         *
         * Note, everything here is passed through the parser later on (!)
         */
@@ -527,7 +550,7 @@ abstract class MediaHandler {
        /**
         * Used instead of getLongDesc if there is no handler registered for file.
         *
-        * @param $file File
+        * @param File $file
         * @return string
         */
        function getShortDesc( $file ) {
@@ -539,7 +562,7 @@ abstract class MediaHandler {
        /**
         * Short description. Shown on Special:Search results.
         *
-        * @param $file File
+        * @param File $file
         * @return string
         */
        function getLongDesc( $file ) {
@@ -552,7 +575,7 @@ abstract class MediaHandler {
        /**
         * Long description. Shown under image on image description page surounded by ().
         *
-        * @param $file File
+        * @param File $file
         * @return string
         */
        static function getGeneralShortDesc( $file ) {
@@ -564,7 +587,7 @@ abstract class MediaHandler {
        /**
         * Used instead of getShortDesc if there is no handler registered for file.
         *
-        * @param $file File
+        * @param File $file
         * @return string
         */
        static function getGeneralLongDesc( $file ) {
@@ -577,10 +600,10 @@ abstract class MediaHandler {
        /**
         * Calculate the largest thumbnail width for a given original file size
         * such that the thumbnail's height is at most $maxHeight.
-        * @param $boxWidth Integer Width of the thumbnail box.
-        * @param $boxHeight Integer Height of the thumbnail box.
-        * @param $maxHeight Integer Maximum height expected for the thumbnail.
-        * @return Integer.
+        * @param int $boxWidth Width of the thumbnail box.
+        * @param int $boxHeight Height of the thumbnail box.
+        * @param int $maxHeight Maximum height expected for the thumbnail.
+        * @return int
         */
        public static function fitBoxWidth( $boxWidth, $boxHeight, $maxHeight ) {
                $idealWidth = $boxWidth * $maxHeight / $boxHeight;
@@ -697,7 +720,7 @@ abstract class MediaHandler {
         *
         * For files we don't know, we return 0.
         *
-        * @param $file File
+        * @param File $file
         * @return int 0, 90, 180 or 270
         */
        public function getRotation( $file ) {
@@ -710,14 +733,44 @@ abstract class MediaHandler {
         * Moved from BitmapHandler to MediaHandler with MediaWiki 1.23
         *
         * @since 1.23
-        * @param $retval int
-        * @param $err int
-        * @param $cmd string
+        * @param int $retval
+        * @param string $err Error reported by command. Anything longer than
+        * MediaHandler::MAX_ERR_LOG_SIZE is stripped off.
+        * @param string $cmd
         */
        protected function logErrorForExternalProcess( $retval, $err, $cmd ) {
+               # Keep error output limited (bug 57985)
+               $errMessage = trim( substr( $err, 0, self::MAX_ERR_LOG_SIZE ) );
+
                wfDebugLog( 'thumbnail',
                        sprintf( 'thumbnail failed on %s: error %d "%s" from "%s"',
-                                       wfHostname(), $retval, trim( $err ), $cmd ) );
+                                       wfHostname(), $retval, $errMessage, $cmd ) );
+       }
+
+       /**
+        * Get list of languages file can be viewed in.
+        *
+        * @param File $file
+        * @return Array Array of language codes, or empty array if unsupported.
+        * @since 1.23
+        */
+       public function getAvailableLanguages( File $file ) {
+               return array();
        }
 
+       /**
+        * On file types that support renderings in multiple languages,
+        * which language is used by default if unspecified.
+        *
+        * If getAvailableLanguages returns a non-empty array, this must return
+        * a valid language code. Otherwise can return null if files of this
+        * type do not support alternative language renderings.
+        *
+        * @param File $file
+        * @return String language code or null if multi-language not supported for filetype.
+        * @since 1.23
+        */
+       public function getDefaultRenderLanguage( File $file ) {
+               return null;
+       }
 }
index 81b285e..41b09e6 100644 (file)
@@ -27,9 +27,8 @@
  * @ingroup Media
  */
 abstract class MediaTransformOutput {
-       /**
-        * @var array Associative array mapping optional supplementary image files
-        * from pixel density (eg 1.5 or 2) to additional URLs.
+       /** @var array Associative array mapping optional supplementary image files
+        *  from pixel density (eg 1.5 or 2) to additional URLs.
         */
        public $responsiveUrls = array();
 
@@ -58,14 +57,14 @@ abstract class MediaTransformOutput {
        protected $storagePath = false;
 
        /**
-        * @return integer Width of the output box
+        * @return int Width of the output box
         */
        public function getWidth() {
                return $this->width;
        }
 
        /**
-        * @return integer Height of the output box
+        * @return int Height of the output box
         */
        public function getHeight() {
                return $this->height;
@@ -138,7 +137,7 @@ abstract class MediaTransformOutput {
         * thumbnail is to be handled client-side only, or if
         * transformation was deferred via TRANSFORM_LATER.
         *
-        * @return Bool
+        * @return bool
         */
        public function hasFile() {
                // If TRANSFORM_LATER, $this->path will be false.
@@ -150,7 +149,7 @@ abstract class MediaTransformOutput {
         * Check if the output thumbnail is the same as the source.
         * This can occur if the requested width was bigger than the source.
         *
-        * @return Bool
+        * @return bool
         */
        public function fileIsSource() {
                return ( !$this->isError() && $this->path === null );
@@ -182,7 +181,7 @@ abstract class MediaTransformOutput {
         * Stream the file if there were no errors
         *
         * @param array $headers Additional HTTP headers to send on success
-        * @return Bool success
+        * @return bool Success
         */
        public function streamFile( $headers = array() ) {
                if ( !$this->path ) {
@@ -199,9 +198,8 @@ abstract class MediaTransformOutput {
        /**
         * Wrap some XHTML text in an anchor tag with the given attributes
         *
-        * @param $linkAttribs array
-        * @param $contents string
-        *
+        * @param array $linkAttribs
+        * @param string $contents
         * @return string
         */
        protected function linkWrap( $linkAttribs, $contents ) {
@@ -214,7 +212,7 @@ abstract class MediaTransformOutput {
 
        /**
         * @param $title string
-        * @param $params string|array Query parameters to add
+        * @param string|array $params Query parameters to add
         * @return array
         */
        public function getDescLinkAttribs( $title = null, $params = array() ) {
@@ -259,11 +257,10 @@ class ThumbnailImage extends MediaTransformOutput {
         * $parameters should include, as a minimum, (file) 'width' and 'height'.
         * It may also include a 'page' parameter for multipage files.
         *
-        * @param $file File object
+        * @param File $file
         * @param string $url URL path to the thumb
-        * @param $path String|bool|null: filesystem path to the thumb
+        * @param string|bool $path Filesystem path to the thumb
         * @param array $parameters Associative array of parameters
-        * @private
         */
        function __construct( $file, $url, $path = false, $parameters = array() ) {
                # Previous parameters:
@@ -318,6 +315,8 @@ class ThumbnailImage extends MediaTransformOutput {
         *     desc-query   String, description link query params
         *     override-width     Override width attribute. Should generally not set
         *     override-height    Override height attribute. Should generally not set
+        *     no-dimensions      Boolean, skip width and height attributes (useful if
+        *                        set in CSS)
         *     custom-url-link    Custom URL to link to
         *     custom-title-link  Custom Title object to link to
         *     custom target-link Value of the target attribute, for custom-target-link
@@ -354,6 +353,7 @@ class ThumbnailImage extends MediaTransformOutput {
                                $linkAttribs['rel'] = $options['parser-extlink-rel'];
                        }
                } elseif ( !empty( $options['custom-title-link'] ) ) {
+                       /** @var Title $title */
                        $title = $options['custom-title-link'];
                        $linkAttribs = array(
                                'href' => $title->getLinkURL(),
@@ -373,9 +373,11 @@ class ThumbnailImage extends MediaTransformOutput {
                $attribs = array(
                        'alt' => $alt,
                        'src' => $this->url,
-                       'width' => $this->width,
-                       'height' => $this->height
                );
+               if ( empty( $options['no-dimensions'] ) ) {
+                       $attribs['width'] = $this->width;
+                       $attribs['height'] = $this->height;
+               }
                if ( !empty( $options['valign'] ) ) {
                        $attribs['style'] = "vertical-align: {$options['valign']}";
                }
index fd26575..968db10 100644 (file)
@@ -48,7 +48,7 @@ class PNGHandler extends BitmapHandler {
        }
 
        /**
-        * @param $image File
+        * @param File $image
         * @return array|bool
         */
        function formatMetadata( $image ) {
@@ -63,7 +63,7 @@ class PNGHandler extends BitmapHandler {
        /**
         * Get a file type independent array of metadata.
         *
-        * @param $image File
+        * @param File $image
         * @return array The metadata array
         */
        public function getCommonMetaArray( File $image ) {
@@ -82,7 +82,7 @@ class PNGHandler extends BitmapHandler {
        }
 
        /**
-        * @param $image File
+        * @param File $image
         * @return bool
         */
        function isAnimatedImage( $image ) {
@@ -99,7 +99,7 @@ class PNGHandler extends BitmapHandler {
 
        /**
         * We do not support making APNG thumbnails, so always false
-        * @param $image File
+        * @param File $image
         * @return bool false
         */
        function canAnimateThumbnail( $image ) {
@@ -139,7 +139,7 @@ class PNGHandler extends BitmapHandler {
        }
 
        /**
-        * @param $image File
+        * @param File $image
         * @return string
         */
        function getLongDesc( $image ) {
index b9377be..30376f1 100644 (file)
@@ -411,10 +411,10 @@ class PNGMetadataExtractor {
        /**
         * Read a chunk, checking to make sure its not too big.
         *
-        * @param $fh resource The file handle
-        * @param $size Integer size in bytes.
+        * @param resource $fh The file handle
+        * @param int $size Size in bytes.
         * @throws Exception if too big.
-        * @return String The chunk.
+        * @return string The chunk.
         */
        private static function read( $fh, $size ) {
                if ( $size > self::MAX_CHUNK_SIZE ) {
index fef67f8..17891fc 100644 (file)
 class SvgHandler extends ImageHandler {
        const SVG_METADATA_VERSION = 2;
 
-       /**
-        * A list of metadata tags that can be converted
-        * to the commonly used exif tags. This allows messages
-        * to be reused, and consistent tag names for {{#formatmetadata:..}}
+       /** @var array A list of metadata tags that can be converted
+        *  to the commonly used exif tags. This allows messages
+        *  to be reused, and consistent tag names for {{#formatmetadata:..}}
         */
        private static $metaConversion = array(
                'originalwidth' => 'ImageWidth',
@@ -61,11 +60,11 @@ class SvgHandler extends ImageHandler {
        }
 
        /**
-        * @param $file File
+        * @param File $file
         * @return bool
         */
        function isAnimatedImage( $file ) {
-               # TODO: detect animated SVGs
+               # @todo Detect animated SVGs
                $metadata = $file->getMetadata();
                if ( $metadata ) {
                        $metadata = $this->unpackMetadata( $metadata );
@@ -77,6 +76,43 @@ class SvgHandler extends ImageHandler {
                return false;
        }
 
+       /**
+        * Which languages (systemLanguage attribute) is supported.
+        *
+        * @note This list is not guaranteed to be exhaustive.
+        * To avoid OOM errors, we only look at first bit of a file.
+        * Thus all languages on this list are present in the file,
+        * but its possible for the file to have a language not on
+        * this list.
+        *
+        * @param File $file
+        * @return Array of language codes, or empty if no language switching supported.
+        */
+       public function getAvailableLanguages( File $file ) {
+               $metadata = $file->getMetadata();
+               $langList = array();
+               if ( $metadata ) {
+                       $metadata = $this->unpackMetadata( $metadata );
+                       if ( isset( $metadata['translations'] ) ) {
+                               foreach( $metadata['translations'] as $lang => $langType ) {
+                                       if ( $langType === SvgReader::LANG_FULL_MATCH ) {
+                                               $langList[] = $lang;
+                                       }
+                               }
+                       }
+               }
+               return $langList;
+       }
+
+       /**
+        * What language to render file in if none selected.
+        *
+        * @return String language code.
+        */
+       public function getDefaultRenderLanguage( File $file ) {
+               return 'en';
+       }
+
        /**
         * We do not support making animated svg thumbnails
         */
@@ -85,8 +121,8 @@ class SvgHandler extends ImageHandler {
        }
 
        /**
-        * @param $image File
-        * @param  $params
+        * @param File $image
+        * @param array $params
         * @return bool
         */
        function normaliseParams( $image, &$params ) {
@@ -115,10 +151,10 @@ class SvgHandler extends ImageHandler {
        }
 
        /**
-        * @param $image File
-        * @param  $dstPath
-        * @param  $dstUrl
-        * @param  $params
+        * @param File $image
+        * @param string $dstPath
+        * @param string $dstUrl
+        * @param array $params
         * @param int $flags
         * @return bool|MediaTransformError|ThumbnailImage|TransformParameterError
         */
@@ -130,7 +166,7 @@ class SvgHandler extends ImageHandler {
                $clientHeight = $params['height'];
                $physicalWidth = $params['physicalWidth'];
                $physicalHeight = $params['physicalHeight'];
-               $lang = isset( $params['lang'] ) ? $params['lang'] : 'en';
+               $lang = isset( $params['lang'] ) ? $params['lang'] : $this->getDefaultRenderLanguage( $image );
 
                if ( $flags & self::TRANSFORM_LATER ) {
                        return new ThumbnailImage( $image, $dstUrl, $dstPath, $params );
@@ -164,7 +200,7 @@ class SvgHandler extends ImageHandler {
         * @param string $dstPath
         * @param string $width
         * @param string $height
-        * @param string $lang Language code of the language to render the SVG in
+        * @param bool|string $lang Language code of the language to render the SVG in
         * @throws MWException
         * @return bool|MediaTransformError
         */
@@ -230,9 +266,9 @@ class SvgHandler extends ImageHandler {
        }
 
        /**
-        * @param $file File
-        * @param  $path
-        * @param bool $metadata
+        * @param File $file
+        * @param string $path Unused
+        * @param bool|array $metadata
         * @return array
         */
        function getImageSize( $file, $path, $metadata = false ) {
@@ -259,7 +295,7 @@ class SvgHandler extends ImageHandler {
         * a "nominal" resolution, and not a fixed one,
         * as well as so animation can be denoted.
         *
-        * @param $file File
+        * @param File $file
         * @return string
         */
        function getLongDesc( $file ) {
@@ -283,6 +319,11 @@ class SvgHandler extends ImageHandler {
                return $msg->parse();
        }
 
+       /**
+        * @param File $file
+        * @param string $filename
+        * @return string Serialised metadata
+        */
        function getMetadata( $file, $filename ) {
                $metadata = array( 'version' => self::SVG_METADATA_VERSION );
                try {
@@ -334,7 +375,7 @@ class SvgHandler extends ImageHandler {
        }
 
        /**
-        * @param $file File
+        * @param File $file
         * @return array|bool
         */
        function formatMetadata( $file ) {
@@ -351,7 +392,7 @@ class SvgHandler extends ImageHandler {
                        return false;
                }
 
-               /* TODO: add a formatter
+               /* @todo Add a formatter
                $format = new FormatSVG( $metadata );
                $formatted = $format->getFormattedData();
                */
@@ -382,7 +423,7 @@ class SvgHandler extends ImageHandler {
 
        /**
         * @param string $name Parameter name
-        * @param $string $value Parameter value
+        * @param mixed $value Parameter value
         * @return bool Validity
         */
        function validateParam( $name, $value ) {
@@ -437,14 +478,16 @@ class SvgHandler extends ImageHandler {
        }
 
        /**
-        * @param $params
+        * @param array $params
         * @return array
         */
        function getScriptParams( $params ) {
-               return array(
-                       'width' => $params['width'],
-                       'lang' => $params['lang'],
-               );
+               $scriptParams = array( 'width' => $params['width'] );
+               if ( isset( $params['lang'] ) ) {
+                       $scriptParams['lang'] = $params['lang'];
+               }
+
+               return $scriptParams;
        }
 
        public function getCommonMetaArray( File $file ) {
index d332c3f..3f0edb3 100644 (file)
@@ -43,12 +43,19 @@ class SVGReader {
        const DEFAULT_WIDTH = 512;
        const DEFAULT_HEIGHT = 512;
        const NS_SVG = 'http://www.w3.org/2000/svg';
+       const LANG_PREFIX_MATCH = 1;
+       const LANG_FULL_MATCH = 2;
 
+       /** @var null|XMLReader */
        private $reader = null;
 
+       /** @var bool */
        private $mDebug = false;
 
+       /** @var array */
        private $metadata = array();
+       private $languages = array();
+       private $languagePrefixes = array();
 
        /**
         * Constructor
@@ -169,10 +176,8 @@ class SVGReader {
                        } elseif ( $tag !== '#text' ) {
                                $this->debug( "Unhandled top-level XML tag $tag" );
 
-                               if ( !isset( $this->metadata['animated'] ) ) {
-                                       // Recurse into children of current tag, looking for animation.
-                                       $this->animateFilter( $tag );
-                               }
+                               // Recurse into children of current tag, looking for animation and languages.
+                               $this->animateFilterAndLang( $tag );
                        }
 
                        // Goto next element, which is sibling of current (Skip children).
@@ -181,14 +186,16 @@ class SVGReader {
 
                $this->reader->close();
 
+               $this->metadata['translations'] = $this->languages + $this->languagePrefixes;
+
                return true;
        }
 
        /**
         * Read a textelement from an element
         *
-        * @param string $name of the element that we are reading from
-        * @param string $metafield that we will fill with the result
+        * @param string $name Name of the element that we are reading from
+        * @param string $metafield Field that we will fill with the result
         */
        private function readField( $name, $metafield = null ) {
                $this->debug( "Read field $metafield" );
@@ -212,7 +219,7 @@ class SVGReader {
        /**
         * Read an XML snippet from an element
         *
-        * @param string $metafield that we will fill with the result
+        * @param string $metafield Field that we will fill with the result
         * @throws MWException
         */
        private function readXml( $metafield = null ) {
@@ -220,7 +227,7 @@ class SVGReader {
                if ( !$metafield || $this->reader->nodeType != XmlReader::ELEMENT ) {
                        return;
                }
-               // TODO: find and store type of xml snippet. metadata['metadataType'] = "rdf"
+               // @todo Find and store type of xml snippet. metadata['metadataType'] = "rdf"
                if ( method_exists( $this->reader, 'readInnerXML' ) ) {
                        $this->metadata[$metafield] = trim( $this->reader->readInnerXML() );
                } else {
@@ -232,11 +239,12 @@ class SVGReader {
        }
 
        /**
-        * Filter all children, looking for animate elements
+        * Filter all children, looking for animated elements.
+        * Also get a list of languages that can be targeted.
         *
-        * @param string $name of the element that we are reading from
+        * @param string $name Name of the element that we are reading from
         */
-       private function animateFilter( $name ) {
+       private function animateFilterAndLang( $name ) {
                $this->debug( "animate filter for tag $name" );
                if ( $this->reader->nodeType != XmlReader::ELEMENT ) {
                        return;
@@ -251,9 +259,35 @@ class SVGReader {
                                && $this->reader->nodeType == XmlReader::END_ELEMENT
                        ) {
                                break;
-                       } elseif ( $this->reader->namespaceURI ==
-                               self::NS_SVG && $this->reader->nodeType == XmlReader::ELEMENT
+                       } elseif ( $this->reader->namespaceURI == self::NS_SVG
+                               && $this->reader->nodeType == XmlReader::ELEMENT
                        ) {
+
+                               $sysLang = $this->reader->getAttribute( 'systemLanguage' );
+                               if ( !is_null( $sysLang ) && $sysLang !== '' ) {
+                                       // See http://www.w3.org/TR/SVG/struct.html#SystemLanguageAttribute
+                                       $langList = explode( ',', $sysLang );
+                                       foreach( $langList as $langItem ) {
+                                               $langItem = trim( $langItem );
+                                               if ( Language::isWellFormedLanguageTag( $langItem ) ) {
+                                                       $this->languages[$langItem] = self::LANG_FULL_MATCH;
+                                               }
+                                               // Note, the standard says that any prefix should work,
+                                               // here we do only the initial prefix, since that will catch
+                                               // 99% of cases, and we are going to compare against fallbacks.
+                                               // This differs mildly from how the spec says languages should be
+                                               // handled, however it matches better how the MediaWiki language
+                                               // preference is generally handled.
+                                               $dash = strpos( $langItem, '-' );
+                                               // Intentionally checking both !false and > 0 at the same time.
+                                               if ( $dash ) {
+                                                       $itemPrefix = substr( $langItem, 0, $dash );
+                                                       if ( Language::isWellFormedLanguageTag( $itemPrefix ) ) {
+                                                               $this->languagePrefixes[$itemPrefix] = self::LANG_PREFIX_MATCH;
+                                                       }
+                                               }
+                                       }
+                               }
                                switch ( $this->reader->localName ) {
                                        case 'script':
                                                // Normally we disallow files with
@@ -274,6 +308,7 @@ class SVGReader {
                }
        }
 
+       // @todo FIXME: Unused, remove?
        private function throwXmlError( $err ) {
                $this->debug( "FAILURE: $err" );
                wfDebug( "SVGReader XML error: $err\n" );
@@ -285,10 +320,12 @@ class SVGReader {
                }
        }
 
+       // @todo FIXME: Unused, remove?
        private function warn( $data ) {
                wfDebug( "SVGReader: $data\n" );
        }
 
+       // @todo FIXME: Unused, remove?
        private function notice( $data ) {
                wfDebug( "SVGReader WARN: $data\n" );
        }
@@ -346,8 +383,8 @@ class SVGReader {
         * http://www.w3.org/TR/SVG11/coords.html#UnitIdentifiers
         *
         * @param string $length CSS/SVG length.
-        * @param $viewportSize : Float optional scale for percentage units...
-        * @return float: length in pixels
+        * @param float|int $viewportSize Optional scale for percentage units...
+        * @return float Length in pixels
         */
        static function scaleSVGUnit( $length, $viewportSize = 512 ) {
                static $unitLength = array(
index dda8265..6964170 100644 (file)
@@ -35,8 +35,7 @@ class TiffHandler extends ExifBitmapHandler {
         * InstantCommons will have thumbnails managed from the remote instance,
         * so we can skip this check.
         *
-        * @param $file
-        *
+        * @param File $file
         * @return bool
         */
        function canRender( $file ) {
@@ -50,8 +49,7 @@ class TiffHandler extends ExifBitmapHandler {
         * Browsers don't support TIFF inline generally...
         * For inline display, we need to convert to PNG.
         *
-        * @param $file
-        *
+        * @param File $file
         * @return bool
         */
        function mustRender( $file ) {
@@ -59,9 +57,9 @@ class TiffHandler extends ExifBitmapHandler {
        }
 
        /**
-        * @param $ext
-        * @param $mime
-        * @param $params
+        * @param string $ext
+        * @param string $mime
+        * @param array $params
         * @return bool
         */
        function getThumbType( $ext, $mime, $params = null ) {
index 9f11ca7..41e6f03 100644 (file)
@@ -34,7 +34,7 @@
  */
 class XCFHandler extends BitmapHandler {
        /**
-        * @param $file
+        * @param File $file
         * @return bool
         */
        function mustRender( $file ) {
@@ -44,9 +44,9 @@ class XCFHandler extends BitmapHandler {
        /**
         * Render files as PNG
         *
-        * @param $ext
-        * @param $mime
-        * @param $params
+        * @param string $ext
+        * @param string $mime
+        * @param array $params
         * @return array
         */
        function getThumbType( $ext, $mime, $params = null ) {
@@ -56,8 +56,8 @@ class XCFHandler extends BitmapHandler {
        /**
         * Get width and height from the XCF header.
         *
-        * @param $image
-        * @param $filename
+        * @param File $image
+        * @param string $filename
         * @return array
         */
        function getImageSize( $image, $filename ) {
@@ -146,6 +146,8 @@ class XCFHandler extends BitmapHandler {
        /**
         * Must use "im" for XCF
         *
+        * @param string $dstPath
+        * @param bool $checkDstPath
         * @return string
         */
        protected static function getScalerType( $dstPath, $checkDstPath = true ) {
index 795299c..08d416a 100644 (file)
  *
  */
 class XMPReader {
-       private $curItem = array(); // array to hold the current element (and previous element, and so on)
+       /** @var array XMP item configuration array */
+       protected $items;
+
+       /** @var array Array to hold the current element (and previous element, and so on) */
+       private $curItem = array();
 
-       private $ancestorStruct = false; // the structure name when processing nested structures.
+       /** @var bool|string The structure name when processing nested structures. */
+       private $ancestorStruct = false;
 
-       private $charContent = false; // temporary holder for character data that appears in xmp doc.
+       /** @var bool|string Temporary holder for character data that appears in xmp doc. */
+       private $charContent = false;
 
-       private $mode = array(); // stores the state the xmpreader is in (see MODE_FOO constants)
+       /** @var array Stores the state the xmpreader is in (see MODE_FOO constants) */
+       private $mode = array();
 
-       private $results = array(); // array to hold results
+       /** @var array Array to hold results */
+       private $results = array();
 
-       private $processingArray = false; // if we're doing a seq or bag.
+       /** @var bool If we're doing a seq or bag. */
+       private $processingArray = false;
 
-       private $itemLang = false; // used for lang alts only
+       /** @var bool|string Used for lang alts only */
+       private $itemLang = false;
 
+       /** @var resource A resource handle for the XML parser */
        private $xmlParser;
 
+       /** @var bool|string Character set like 'UTF-8' */
        private $charset = false;
 
+       /** @var int */
        private $extendedXMPOffset = 0;
 
-       protected $items;
-
        /**
         * These are various mode constants.
         * they are used to figure out what to do
@@ -244,10 +255,10 @@ class XMPReader {
         * debug log, blanks result array and returns false.
         *
         * @param string $content XMP data
-        * @param $allOfIt Boolean: If this is all the data (true) or if its split up (false). Default true
-        * @param $reset Boolean: does xml parser need to be reset. Default false
+        * @param bool $allOfIt If this is all the data (true) or if its split up (false). Default true
+        * @param bool $reset Does xml parser need to be reset. Default false
         * @throws MWException
-        * @return Boolean success.
+        * @return bool Success.
         */
        public function parse( $content, $allOfIt = true, $reset = false ) {
                if ( $reset ) {
@@ -320,7 +331,7 @@ class XMPReader {
         * @todo In serious need of testing
         * @see http://www.adobe.ge/devnet/xmp/pdfs/XMPSpecificationPart3.pdf XMP spec part 3 page 20
         * @param string $content XMPExtended block minus the namespace signature
-        * @return Boolean If it succeeded.
+        * @return bool If it succeeded.
         */
        public function parseExtended( $content ) {
                // @todo FIXME: This is untested. Hard to find example files
@@ -393,7 +404,7 @@ class XMPReader {
         * <exif:DigitalZoomRatio>0/10</exif:DigitalZoomRatio>
         * and are processing the 0/10 bit.
         *
-        * @param $parser XMLParser reference to the xml parser
+        * @param XMLParser $parser XMLParser reference to the xml parser
         * @param string $data Character data
         * @throws MWException on invalid data
         */
@@ -452,7 +463,7 @@ class XMPReader {
         * Or it could be if we hit the end element of a property
         * of a compound data structure (like a member of an array).
         *
-        * @param string $elm namespace, space, and tag name.
+        * @param string $elm Namespace, space, and tag name.
         */
        private function endElementModeSimple( $elm ) {
                if ( $this->charContent !== false ) {
@@ -486,7 +497,7 @@ class XMPReader {
         *
         * This method is called when we hit the "</exif:ISOSpeedRatings>" tag.
         *
-        * @param string $elm namespace . space . tag name.
+        * @param string $elm Namespace . space . tag name.
         * @throws MWException
         */
        private function endElementNested( $elm ) {
@@ -553,7 +564,7 @@ class XMPReader {
         * (For comparison, we call endElementModeSimple when we
         * hit the "</rdf:li>")
         *
-        * @param string $elm namespace . ' ' . element name
+        * @param string $elm Namespace . ' ' . element name
         * @throws MWException
         */
        private function endElementModeLi( $elm ) {
@@ -593,7 +604,7 @@ class XMPReader {
         * Qualifiers aren't all that common, and we don't do anything
         * with them.
         *
-        * @param string $elm namespace and element
+        * @param string $elm Namespace and element
         */
        private function endElementModeQDesc( $elm ) {
 
@@ -617,8 +628,8 @@ class XMPReader {
         * Ignores the outer wrapping elements that are optional in
         * xmp and have no meaning.
         *
-        * @param $parser XMLParser
-        * @param string $elm namespace . ' ' . element name
+        * @param XMLParser $parser
+        * @param string $elm Namespace . ' ' . element name
         * @throws MWException
         */
        function endElement( $parser, $elm ) {
@@ -701,7 +712,7 @@ class XMPReader {
         * in which case we add it to the item stack, so we can ignore things
         * that are nested, correctly.
         *
-        * @param string $elm namespace . ' ' . tag name
+        * @param string $elm Namespace . ' ' . tag name
         */
        private function startElementModeIgnore( $elm ) {
                if ( $elm === $this->curItem[0] ) {
@@ -714,7 +725,7 @@ class XMPReader {
         *  Start element in MODE_BAG (unordered array)
         * this should always be <rdf:Bag>
         *
-        * @param string $elm namespace . ' ' . tag
+        * @param string $elm Namespace . ' ' . tag
         * @throws MWException if we have an element that's not <rdf:Bag>
         */
        private function startElementModeBag( $elm ) {
@@ -729,7 +740,7 @@ class XMPReader {
         * Start element in MODE_SEQ (ordered array)
         * this should always be <rdf:Seq>
         *
-        * @param string $elm namespace . ' ' . tag
+        * @param string $elm Namespace . ' ' . tag
         * @throws MWException if we have an element that's not <rdf:Seq>
         */
        private function startElementModeSeq( $elm ) {
@@ -756,7 +767,7 @@ class XMPReader {
         * which are really only used for thumbnails, which
         * we don't care about.
         *
-        * @param string $elm namespace . ' ' . tag
+        * @param string $elm Namespace . ' ' . tag
         * @throws MWException if we have an element that's not <rdf:Alt>
         */
        private function startElementModeLang( $elm ) {
@@ -781,7 +792,7 @@ class XMPReader {
         *
         * This method is called when processing the <rdf:Description> element
         *
-        * @param string $elm namespace and tag names separated by space.
+        * @param string $elm Namespace and tag names separated by space.
         * @param array $attribs Attributes of the element.
         * @throws MWException
         */
@@ -819,7 +830,7 @@ class XMPReader {
         *   </exif:DigitalZoomRatio>
         * Called when processing the <rdf:value> or <foo:someQualifier>.
         *
-        * @param string $elm namespace and tag name separated by a space.
+        * @param string $elm Namespace and tag name separated by a space.
         *
         */
        private function startElementModeQDesc( $elm ) {
@@ -901,9 +912,9 @@ class XMPReader {
         * <exif:Flash rdf:parseType='Resource'> <exif:Fired>True</exif:Fired>
         *  <exif:Mode>1</exif:Mode></exif:Flash>
         *
-        * @param string $ns namespace
-        * @param string $tag tag name (no ns)
-        * @param array $attribs array of attribs w/ values.
+        * @param string $ns Namespace
+        * @param string $tag Tag name (no ns)
+        * @param array $attribs Array of attribs w/ values.
         * @throws MWException
         */
        private function startElementModeStruct( $ns, $tag, $attribs ) {
@@ -950,7 +961,7 @@ class XMPReader {
         *   </rdf:Seq> </exif:ISOSpeedRatings>
         * This method is called when we hit the <rdf:li> element.
         *
-        * @param string $elm namespace . ' ' . tagname
+        * @param string $elm Namespace . ' ' . tagname
         * @param array $attribs Attributes. (needed for BAGSTRUCTS)
         * @throws MWException if gets a tag other than <rdf:li>
         */
@@ -1000,9 +1011,9 @@ class XMPReader {
         *
         * This method is called when we hit the <rdf:li> element.
         *
-        * @param string $elm namespace . ' ' . tag
-        * @param array $attribs array of elements (most importantly xml:lang)
-        * @throws MWException if gets a tag other than <rdf:li> or if no xml:lang
+        * @param string $elm Namespace . ' ' . tag
+        * @param array $attribs Array of elements (most importantly xml:lang)
+        * @throws MWException If gets a tag other than <rdf:li> or if no xml:lang
         */
        private function startElementModeLiLang( $elm, $attribs ) {
                if ( $elm !== self::NS_RDF . ' li' ) {
@@ -1031,8 +1042,8 @@ class XMPReader {
         * Also does some initial set up for the wrapper element
         *
         * @param $parser XMLParser
-        * @param string $elm namespace "<space>" element
-        * @param array $attribs attribute name => value
+        * @param string $elm Namespace "<space>" element
+        * @param array $attribs Attribute name => value
         * @throws MWException
         */
        function startElement( $parser, $elm, $attribs ) {
@@ -1124,7 +1135,7 @@ class XMPReader {
         * <rdf:Description rdf:about="" xmlns:exif="http://ns.adobe.com/exif/1.0/" exif:DigitalZoomRatio="0/10">
         * @endcode
         *
-        * @param array $attribs attribute=>value array.
+        * @param array $attribs Array attribute=>value
         * @throws MWException
         */
        // @codingStandardsIgnoreEnd
@@ -1173,9 +1184,9 @@ class XMPReader {
         * $this->processingArray to determine what name to
         * save the value under. (in addition to $tag).
         *
-        * @param string $ns namespace of tag this is for
-        * @param string $tag tag name
-        * @param string $val value to save
+        * @param string $ns Namespace of tag this is for
+        * @param string $tag Tag name
+        * @param string $val Value to save
         */
        private function saveValue( $ns, $tag, $val ) {
 
index d57af5d..3272fef 100644 (file)
@@ -27,8 +27,8 @@
  * extract.
  */
 class XMPInfo {
-       /** get the items array
-        * @return Array XMP item configuration array.
+       /** Get the items array
+        * @return array XMP item configuration array.
         */
        public static function getItems() {
                if ( !self::$ranHooks ) {
@@ -66,7 +66,7 @@ class XMPInfo {
         *     * children - for MODE_STRUCT items, allowed children.
         *   * structPart - Indicates that this element can only appear as a member of a structure.
         *
-        * currently this just has a bunch of exif values as this class is only half-done
+        * Currently this just has a bunch of exif values as this class is only half-done
         */
        static private $items = array(
                'http://ns.adobe.com/exif/1.0/' => array(
index 8919601..4362217 100644 (file)
  */
 class XMPValidate {
        /**
-        * function to validate boolean properties ( True or False )
+        * Function to validate boolean properties ( True or False )
         *
-        * @param array $info information about current property
-        * @param &$val Mixed current value to validate
-        * @param $standalone Boolean if this is a simple property or array
+        * @param array $info Information about current property
+        * @param mixed &$val Current value to validate
+        * @param bool $standalone If this is a simple property or array
         */
        public static function validateBoolean( $info, &$val, $standalone ) {
                if ( !$standalone ) {
@@ -62,9 +62,9 @@ class XMPValidate {
        /**
         * function to validate rational properties ( 12/10 )
         *
-        * @param array $info information about current property
-        * @param &$val Mixed current value to validate
-        * @param $standalone Boolean if this is a simple property or array
+        * @param array $info Information about current property
+        * @param mixed &$val Current value to validate
+        * @param bool $standalone If this is a simple property or array
         */
        public static function validateRational( $info, &$val, $standalone ) {
                if ( !$standalone ) {
@@ -83,9 +83,9 @@ class XMPValidate {
         * if its outside of range put it into range.
         *
         * @see MWG spec
-        * @param array $info information about current property
-        * @param &$val Mixed current value to validate
-        * @param $standalone Boolean if this is a simple property or array
+        * @param array $info Information about current property
+        * @param mixed &$val Current value to validate
+        * @param bool $standalone If this is a simple property or array
         */
        public static function validateRating( $info, &$val, $standalone ) {
                if ( !$standalone ) {
@@ -122,9 +122,9 @@ class XMPValidate {
        /**
         * function to validate integers
         *
-        * @param array $info information about current property
-        * @param &$val Mixed current value to validate
-        * @param $standalone Boolean if this is a simple property or array
+        * @param array $info Information about current property
+        * @param mixed &$val Current value to validate
+        * @param bool $standalone If this is a simple property or array
         */
        public static function validateInteger( $info, &$val, $standalone ) {
                if ( !$standalone ) {
@@ -141,9 +141,9 @@ class XMPValidate {
         * function to validate properties with a fixed number of allowed
         * choices. (closed choice)
         *
-        * @param array $info information about current property
+        * @param array $info Information about current property
         * @param &$val Mixed current value to validate
-        * @param $standalone Boolean if this is a simple property or array
+        * @param bool $standalone If this is a simple property or array
         */
        public static function validateClosed( $info, &$val, $standalone ) {
                if ( !$standalone ) {
@@ -171,9 +171,9 @@ class XMPValidate {
        /**
         * function to validate and modify flash structure
         *
-        * @param array $info information about current property
+        * @param array $info Information about current property
         * @param &$val Mixed current value to validate
-        * @param $standalone Boolean if this is a simple property or array
+        * @param bool $standalone If this is a simple property or array
         */
        public static function validateFlash( $info, &$val, $standalone ) {
                if ( $standalone ) {
@@ -205,9 +205,9 @@ class XMPValidate {
         * @see rfc 3066
         * @see http://www.adobe.com/devnet/xmp/pdfs/XMPSpecificationPart1.pdf page 30 (section 8.2.2.5)
         *
-        * @param array $info information about current property
+        * @param array $info Information about current property
         * @param &$val Mixed current value to validate
-        * @param $standalone Boolean if this is a simple property or array
+        * @param bool $standalone If this is a simple property or array
         */
        public static function validateLangCode( $info, &$val, $standalone ) {
                if ( !$standalone ) {
@@ -232,11 +232,11 @@ class XMPValidate {
         * YYYY-MM-DDThh:mm:ssTZD
         * YYYY-MM-DDThh:mm:ss.sTZD
         *
-        * @param array $info information about current property
-        * @param &$val Mixed current value to validate. Converts to TS_EXIF as a side-effect.
+        * @param array $info Information about current property
+        * @param mixed &$val Current value to validate. Converts to TS_EXIF as a side-effect.
         *    in cases where there's only a partial date, it will give things like
         *    2011:04.
-        * @param $standalone Boolean if this is a simple property or array
+        * @param bool $standalone If this is a simple property or array
         */
        public static function validateDate( $info, &$val, $standalone ) {
                if ( !$standalone ) {
@@ -334,10 +334,10 @@ class XMPValidate {
         * @see http://www.adobe.com/devnet/xmp/pdfs/XMPSpecificationPart2.pdf
         *        section 1.2.7.4 on page 23
         *
-        * @param array $info unused (info about prop)
-        * @param &$val String GPS string in either DDD,MM,SSk or
-        *           or DDD,MM.mmk form
-        * @param $standalone Boolean if its a simple prop (should always be true)
+        * @param array $info Unused (info about prop)
+        * @param string &$val GPS string in either DDD,MM,SSk or
+        *   or DDD,MM.mmk form
+        * @param bool $standalone If its a simple prop (should always be true)
         */
        public static function validateGPS( $info, &$val, $standalone ) {
                if ( !$standalone ) {
index bda8653..aafe432 100644 (file)
@@ -71,8 +71,8 @@ class ResourceLoaderUserCSSPrefsModule extends ResourceLoaderModule {
                                ( $options['underline'] ? 'underline' : 'none' ) . "; }";
                } else {
                        # The scripts of these languages are very hard to read with underlines
-                       $rules[] = 'a:lang(ar), a:lang(ckb), a:lang(kk-arab), ' .
-                       'a:lang(mzn), a:lang(ps), a:lang(ur) { text-decoration: none; }';
+                       $rules[] = 'a:lang(ar), a:lang(kk-arab), a:lang(mzn), ' .
+                       'a:lang(ps), a:lang(ur) { text-decoration: none; }';
                }
                if ( $options['justify'] ) {
                        $rules[] = "#article, #bodyContent, #mw_content { text-align: justify; }\n";
index 9004267..6757d39 100644 (file)
@@ -59,7 +59,7 @@ class ResourceLoaderUserGroupsModule extends ResourceLoaderWikiModule {
 
                $pages = array();
                foreach ( $user->getEffectiveGroups() as $group ) {
-                       if ( in_array( $group, array( '*', 'user' ) ) ) {
+                       if ( $group == '*' ) {
                                continue;
                        }
                        if ( $wgUseSiteJs ) {
index 2f569d9..12210d0 100644 (file)
@@ -46,6 +46,9 @@ class UsercreateTemplate extends BaseTemplate {
                <div id="languagelinks">
                        <p><?php $this->html( 'languages' ); ?></p>
                </div>
+       <?php }
+             if ( !wfMessage( 'signupstart' )->isDisabled() ) { ?>
+               <div id="signupstart"><?php $this->msgWiki( 'signupstart' ); ?></div>
        <?php } ?>
        <div id="userloginForm">
                <h2 class="createaccount-join">
@@ -261,6 +264,9 @@ class UsercreateTemplate extends BaseTemplate {
                        <?php if ( $this->haveData( 'uselang' ) ) { ?><input type="hidden" name="uselang" value="<?php $this->text( 'uselang' ); ?>" /><?php } ?>
                        <?php if ( $this->haveData( 'token' ) ) { ?><input type="hidden" name="wpCreateaccountToken" value="<?php $this->text( 'token' ); ?>" /><?php } ?>
                </form>
+               <?php if ( !wfMessage( 'signupend' )->isDisabled() ) { ?>
+                       <div id="signupend"><?php $this->html( 'signupend' ); ?></div>
+               <?php } ?>
        </div>
        <div class="mw-createacct-benefits-container">
                <h2><?php $this->msg( 'createacct-benefit-heading' ); ?></h2>
index 954940e..f03b60f 100644 (file)
@@ -3786,6 +3786,7 @@ You can view its source',
 'print.css'               => '/* CSS placed here will affect the print output */', # only translate this message to other languages if you have to change it
 'noscript.css'            => '/* CSS placed here will affect users with JavaScript disabled */', # only translate this message to other languages if you have to change it
 'group-autoconfirmed.css' => '/* CSS placed here will affect autoconfirmed users only */', # only translate this message to other languages if you have to change it
+'group-user.css'          => '/* CSS placed here will affect registered users only */', # only translate this message to other languages if you have to change it
 'group-bot.css'           => '/* CSS placed here will affect bots only */', # only translate this message to other languages if you have to change it
 'group-sysop.css'         => '/* CSS placed here will affect sysops only */', # only translate this message to other languages if you have to change it
 'group-bureaucrat.css'    => '/* CSS placed here will affect bureaucrats only */', # only translate this message to other languages if you have to change it
@@ -3797,6 +3798,7 @@ You can view its source',
 'modern.js'              => '/* Any JavaScript here will be loaded for users using the Modern skin */', # only translate this message to other languages if you have to change it
 'vector.js'              => '/* Any JavaScript here will be loaded for users using the Vector skin */', # only translate this message to other languages if you have to change it
 'group-autoconfirmed.js' => '/* Any JavaScript here will be loaded for autoconfirmed users only */', # only translate this message to other languages if you have to change it
+'group-user.js'          => '/* Any JavaScript here will be loaded for registered users only */', # only translate this message to other languages if you have to change it
 'group-bot.js'           => '/* Any JavaScript here will be loaded for bots only */', # only translate this message to other languages if you have to change it
 'group-sysop.js'         => '/* Any JavaScript here will be loaded for sysops only */', # only translate this message to other languages if you have to change it
 'group-bureaucrat.js'    => '/* Any JavaScript here will be loaded for bureaucrats only */', # only translate this message to other languages if you have to change it
@@ -4626,6 +4628,11 @@ Please confirm that you really want to recreate this page.",
 'imgmultigo'       => 'Go!',
 'imgmultigoto'     => 'Go to page $1',
 
+'img-lang-opt' => '$2 ($1)',
+'img-lang-default' => '(default language)',
+'img-lang-info' => 'Render this image in $1 $2.',
+'img-lang-go' => 'Go',
+
 # Table pager
 'ascending_abbrev'         => 'asc',
 'descending_abbrev'        => 'desc',
index 11eff9e..1c7d11f 100644 (file)
@@ -7852,6 +7852,7 @@ CSS applied to users using Monobook skin.',
 'print.css' => '{{optional}}',
 'noscript.css' => '{{optional}}',
 'group-autoconfirmed.css' => '{{doc-group|autoconfirmed|css}}',
+'group-user.css' => '{{doc-group|user|css}}',
 'group-bot.css' => '{{doc-group|bot|css}}',
 'group-sysop.css' => '{{doc-group|sysop|css}}',
 'group-bureaucrat.css' => '{{doc-group|bureaucrat|css}}',
@@ -7865,6 +7866,7 @@ JS for users using Monobook skin.',
 'modern.js' => '{{optional}}',
 'vector.js' => '{{optional}}',
 'group-autoconfirmed.js' => '{{doc-group|autoconfirmed|js}}',
+'group-user.js' => '{{doc-group|user|js}}',
 'group-bot.js' => '{{doc-group|bot|js}}',
 'group-sysop.js' => '{{doc-group|sysop|js}}',
 'group-bureaucrat.js' => '{{doc-group|bureaucrat|js}}',
@@ -9571,6 +9573,17 @@ See also:
 See also:
 * {{msg-mw|Imgmultigo|Submit button text}}',
 
+'img-lang-opt' => '{{optional}} Items in the language drop down on the image page for a translated SVG file. For an example see [[:File:Gerrit patchset 25838 test.svg]]. See also {{msg-mw|img-lang-info}}
+
+* $1 Language code
+* $2 Language name (Either in the language in question, or the name of that language translated to the current users interface language)',
+'img-lang-default' => 'An option in the drop down of a translatable file. For example see [[:File:Gerrit patchset 25838 test.svg]]. Used when it cannot be determined what the default fallback language is. However it should be noted that most of the time, the content displayed for this option would be in English.',
+'img-lang-info' => 'Label for drop down box. Appears underneath the image on the image description page. See [[:File:Gerrit patchset 25838 test.svg]] for an example.
+
+* $1 is a drop down box with language options (See also {{msg-mw|img-lang-opt}})
+* $2 is a submit button, which uses the text from {{msg-mw|img-lang-go}}',
+'img-lang-go' => 'Go button for the language select for translatable files. See [[:File:Gerrit patchset 25838 test.svg]] for an example. See {{msg-mw|img-lang-info}}.',
+
 # Table pager
 'ascending_abbrev' => 'Abbreviation of ascending order.
 See also:
index b06c11f..80a31bc 100644 (file)
@@ -322,6 +322,7 @@ $wgOptionalMessages = array(
        'print.css',
        'noscript.css',
        'group-autoconfirmed.css',
+       'group-user.css',
        'group-bot.css',
        'group-sysop.css',
        'group-bureaucrat.css',
@@ -331,6 +332,7 @@ $wgOptionalMessages = array(
        'modern.js',
        'vector.js',
        'group-autoconfirmed.js',
+       'group-user.js',
        'group-bot.js',
        'group-sysop.js',
        'group-bureaucrat.js',
@@ -486,6 +488,7 @@ $wgOptionalMessages = array(
        'limitreport-expansiondepth-value',
        'limitreport-expensivefunctioncount-value',
        'interlanguage-link-title',
+       'img-lang-opt',
 );
 
 /** Exif messages, which may be set as optional in several checks, but are generally mandatory */
index 8689dc0..6aeb3ae 100644 (file)
@@ -2704,6 +2704,7 @@ $wgMessageStructure = array(
                'print.css',
                'noscript.css',
                'group-autoconfirmed.css',
+               'group-user.css',
                'group-bot.css',
                'group-sysop.css',
                'group-bureaucrat.css',
@@ -2715,6 +2716,7 @@ $wgMessageStructure = array(
                'modern.js',
                'vector.js',
                'group-autoconfirmed.js',
+               'group-user.js',
                'group-bot.js',
                'group-sysop.js',
                'group-bureaucrat.js',
@@ -3496,6 +3498,12 @@ $wgMessageStructure = array(
                'imgmultigo',
                'imgmultigoto',
        ),
+       'img-lang' => array(
+               'img-lang-opt',
+               'img-lang-default',
+               'img-lang-info',
+               'img-lang-go',
+       ),
        'tablepager' => array(
                'ascending_abbrev',
                'descending_abbrev',
@@ -4167,6 +4175,7 @@ Variants for Chinese language",
        'watch-unwatch' => 'action=watch/unwatch',
        'separators' => 'Separators for various lists, etc.',
        'imgmulti' => 'Multipage image navigation',
+       'img-lang' => 'Language selector for translatable SVGs',
        'tablepager' => 'Table pager',
        'autosumm' => 'Auto-summaries',
        'autoblock_whitelist' => 'Autoblock whitelist',
index de2d013..51770fd 100644 (file)
                        // Trim underscores
                        .replace( rUnderscoreTrim, '' );
 
-               if ( title === '' ) {
-                       return false;
-               }
-
                // Process initial colon
-               if ( title.charAt( 0 ) === ':' ) {
+               if ( title !== '' && title.charAt( 0 ) === ':' ) {
                        // Initial colon means main namespace instead of specified default
                        namespace = NS_MAIN;
                        title = title
                                .replace( rUnderscoreTrim, '' );
                }
 
+               if ( title === '' ) {
+                       return false;
+               }
+
                // Process namespace prefix (if any)
                m = title.match( rSplit );
                if ( m ) {
index 4b489a9..4fcd5fc 100644 (file)
@@ -41,3 +41,8 @@ https://commons.wikimedia.org/wiki/File:Tux.svg
 Larry Ewing, Simon Budig, Anja Gerwinski
 "The copyright holder of this file allows anyone to use it for any purpose, provided that the copyright holder is properly attributed. Redistribution, derivative work, commercial use, and all other use is permitted."
 
+Speech_bubbles.svg (Modified slightly)
+https://commons.wikimedia.org/wiki/File:Speech_bubbles.svg
+CC-BY-SA 3.0
+Jarry1250
+
diff --git a/tests/phpunit/data/media/Speech_bubbles.svg b/tests/phpunit/data/media/Speech_bubbles.svg
new file mode 100644 (file)
index 0000000..6b1ef7a
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="17.7cm" height="13cm" id="svg2" version="1.1" inkscape:version="0.48.2 r9819" sodipodi:docname="New document 1">
+  <defs id="defs4"/>
+  <sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="0.7" inkscape:cx="296.43458" inkscape:cy="130.17435" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="false" fit-margin-top="0" fit-margin-left="0" fit-margin-right="0" fit-margin-bottom="0" inkscape:window-width="1366" inkscape:window-height="706" inkscape:window-x="-8" inkscape:window-y="-8" inkscape:window-maximized="1"/>
+  <g inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1" transform="translate(-0.28125,-1.21875)">
+    <switch style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"><text xml:space="preserve" x="90" y="108.07646" id="text2985-de" sodipodi:linespacing="125%" systemLanguage="de"><tspan text-decoration="normal" font-style="normal" font-weight="normal" id="tspan2987-de">Hallo!</tspan></text><text xml:space="preserve" x="90" y="108.07646" id="text2985-fr" sodipodi:linespacing="125%" systemLanguage="fr"><tspan x="80" y="108.07646" text-decoration="normal" font-style="normal" font-weight="normal" id="tspan2987-fr">Bonjour</tspan></text><text xml:space="preserve" x="90" y="108.07646" id="text2985-nl" sodipodi:linespacing="125%" systemLanguage="nl, tlh-ca"><tspan x="90" y="108.07646" text-decoration="normal" font-style="normal" font-weight="normal" id="tspan2987-nl">Hallo!</tspan></text><text xml:space="preserve" x="90" y="108.07646" id="text2985" sodipodi:linespacing="125%"><tspan x="90" y="108.07646" text-decoration="normal" font-style="normal" font-weight="normal" id="tspan2987" sodipodi:role="line">Hello!</tspan></text></switch>
+    <switch style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"><text xml:space="preserve" x="330" y="188.07648" id="text2989-de" sodipodi:linespacing="125%" systemLanguage="de"><tspan x="323" y="188.07648" text-decoration="normal" font-style="normal" font-weight="normal" id="tspan2991-de">Hallo! Wie</tspan><tspan x="350" y="238.07648" text-decoration="normal" font-style="normal" font-weight="normal" id="tspan2993-de" sodipodi:role="line">geht's?</tspan></text><text xml:space="preserve" x="330" y="188.07648" id="text2989-fr" sodipodi:linespacing="125%" systemLanguage="fr"><tspan x="335" y="188.07648" text-decoration="normal" font-style="normal" font-weight="normal" id="tspan2991-fr">Bonjour,</tspan><tspan x="350" y="238.07648" text-decoration="normal" font-style="normal" font-weight="normal" id="tspan2993-fr">ça va?</tspan></text><text xml:space="preserve" x="330" y="188.07648" id="text2989-nl" sodipodi:linespacing="125%" systemLanguage="nl, tlh-ca"><tspan x="310" y="188.07648" text-decoration="normal" font-style="normal" font-weight="normal" id="tspan2991-nl">Hallo! Hoe</tspan><tspan x="330" y="238.07648" text-decoration="normal" font-style="normal" font-weight="normal" id="tspan2993-nl">gaat het?</tspan></text><text xml:space="preserve" x="330" y="188.07648" id="text2989" sodipodi:linespacing="125%"><tspan x="330" y="188.07648" text-decoration="normal" font-style="normal" font-weight="normal" id="tspan2991" sodipodi:role="line">Hello! How</tspan><tspan x="330" y="238.07648" text-decoration="normal" font-style="normal" font-weight="normal" id="tspan2993" sodipodi:role="line">are you?</tspan></text></switch>
+    <switch style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"><text xml:space="preserve" x="101.42857" y="318.64789" id="text2995-fr" sodipodi:linespacing="125%" systemLanguage="fr"><tspan x="82" y="323" text-decoration="normal" font-style="normal" font-weight="normal" id="tspan2997-fr">Ça va bien,</tspan><tspan x="117.42857" y="368.64789" text-decoration="normal" font-style="normal" font-weight="normal" id="tspan2999-fr">et toi?</tspan></text><text xml:space="preserve" x="101.42857" y="318.64789" id="text2995-nl" sodipodi:linespacing="125%" systemLanguage="nl, tlh-ca"><tspan x="101.42857" y="318.64789" text-decoration="normal" font-style="normal" font-weight="normal" id="tspan2997-nl">Goed,</tspan><tspan x="101.42857" y="368.64789" font-size="90%" text-decoration="normal" font-style="normal" font-weight="normal" id="tspan2999-nl">met jou?</tspan></text><text xml:space="preserve" x="101.42857" y="318.64789" id="text2995" sodipodi:linespacing="125%"><tspan x="101.42857" y="318.64789" text-decoration="normal" font-style="normal" font-weight="normal" id="tspan2997" sodipodi:role="line">I'm well,</tspan><tspan x="101.42857" y="368.64789" text-decoration="normal" font-style="normal" font-weight="normal" id="tspan2999" sodipodi:role="line">   you?</tspan></text></switch>
+    <path style="color:#000000;fill:none;stroke:#808080;stroke-width:8.19999980999999960;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" d="m 145.41518,24.660714 c -54.439497,0 -98.562501,30.043022 -98.562501,67.125 0,9.936246 3.188468,19.358966 8.875,27.843746 -3.477405,24.25473 -24,58.71875 -24,58.71875 0,0 55.316401,-29.49598 68.544641,-28.55804 2.17169,0.15398 -0.660951,4.01645 -2.044641,0.93304 14.019951,5.22007 30.083661,8.21875 47.187501,8.21875 54.4395,0 98.59375,-30.07427 98.59375,-67.156246 0,-37.081978 -44.15425,-67.125 -98.59375,-67.125 z" id="path3769" inkscape:connector-curvature="0" sodipodi:nodetypes="ssccscsss"/>
+    <path style="color:#000000;fill:none;stroke:#808080;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" d="m 416.54255,99.214524 c 73.5252,0 133.11712,43.566276 133.11712,97.339926 0,14.40884 -4.3063,28.073 -11.98645,40.37703 4.69653,35.1725 32.41406,85.14978 32.41406,85.14978 0,0 -74.70955,-42.77297 -92.57542,-41.41284 -2.93306,0.22328 0.89266,5.82436 2.76145,1.35303 -18.93514,7.56977 -40.63057,11.91824 -63.73076,11.91824 -73.52523,0 -133.15935,-43.61157 -133.15935,-97.38524 0,-53.77365 59.63412,-97.339926 133.15935,-97.339926 z" id="path3769-1" inkscape:connector-curvature="0" sodipodi:nodetypes="ssccscsss"/>
+    <path style="color:#000000;fill:none;stroke:#808080;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" d="m 173.1621,250.34923 c -64.02996,0 -115.926026,34.29807 -115.926026,76.63201 0,11.34353 3.750173,22.1008 10.438488,31.7873 -4.090007,27.68997 -28.228023,67.03517 -28.228023,67.03517 0,0 65.061361,-33.67353 80.619991,-32.60275 2.55427,0.17578 -0.77738,4.5853 -2.40483,1.06519 16.4898,5.95939 35.38343,9.38278 55.5004,9.38278 64.02999,0 115.96279,-34.33373 115.96279,-76.66769 0,-42.33394 -51.9328,-76.63201 -115.96279,-76.63201 z" id="path3769-1-7" inkscape:connector-curvature="0" sodipodi:nodetypes="ssccscsss"/>
+  </g>
+</svg>
index 6bfe545..58f0146 100644 (file)
@@ -66,6 +66,7 @@ class TitleTest extends MediaWikiTestCase {
                // Invalid
                foreach ( array(
                        '',
+                       ':',
                        '__  __',
                        '  __  ',
                        // Bad characters forbidden regardless of wgLegalTitleChars
index d00a33d..ec7b0c9 100644 (file)
@@ -54,6 +54,7 @@ class SVGMetadataExtractorTest extends MediaWikiTestCase {
                                        'height' => 1024,
                                        'originalWidth' => '1024',
                                        'originalHeight' => '1024',
+                                       'translations' => array(),
                                )
                        ),
                        array(
@@ -63,6 +64,7 @@ class SVGMetadataExtractorTest extends MediaWikiTestCase {
                                        'height' => 60,
                                        'originalWidth' => '60',
                                        'originalHeight' => '60',
+                                       'translations' => array(),
                                )
                        ),
                        array(
@@ -72,6 +74,7 @@ class SVGMetadataExtractorTest extends MediaWikiTestCase {
                                        'height' => 60,
                                        'originalWidth' => '60.0000000',
                                        'originalHeight' => '60.0000000',
+                                       'translations' => array(),
                                )
                        ),
                        array(
@@ -82,6 +85,7 @@ class SVGMetadataExtractorTest extends MediaWikiTestCase {
                                        'height' => 385,
                                        'originalWidth' => '385',
                                        'originalHeight' => '385.0004883',
+                                       'translations' => array(),
                                )
                        ),
                        array(
@@ -92,9 +96,26 @@ class SVGMetadataExtractorTest extends MediaWikiTestCase {
                                        'originalWidth' => '100%',
                                        'originalHeight' => '100%',
                                        'title' => 'Tux',
+                                       'translations' => array(),
                                        'description' => 'For more information see: http://commons.wikimedia.org/wiki/Image:Tux.svg',
                                )
-                       )
+                       ),
+                       array(
+                               "$base/Speech_bubbles.svg",
+                               array(
+                                       'width' => 627,
+                                       'height' => 461,
+                                       'originalWidth' => '17.7cm',
+                                       'originalHeight' => '13cm',
+                                       'translations' => array(
+                                               'de' => SVGReader::LANG_FULL_MATCH,
+                                               'fr' => SVGReader::LANG_FULL_MATCH,
+                                               'nl' => SVGReader::LANG_FULL_MATCH,
+                                               'tlh-ca' => SVGReader::LANG_FULL_MATCH,
+                                               'tlh' => SVGReader::LANG_PREFIX_MATCH
+                                       ),
+                               )
+                       ),
                );
        }
 
@@ -116,6 +137,7 @@ class SVGMetadataExtractorTest extends MediaWikiTestCase {
                                        'width' => 959,
                                        'originalWidth' => '958.69',
                                        'originalHeight' => '592.78998',
+                                       'translations' => array(),
                                )
                        ),
                );
index cb0bf69..4083564 100644 (file)
@@ -80,6 +80,7 @@
                ],
                invalid: [
                        '',
+                       ':',
                        '__  __',
                        '  __  ',
                        // Bad characters forbidden regardless of wgLegalTitleChars