summaryrefslogtreecommitdiff
path: root/includes/media/SVGMetadataExtractor.php
diff options
context:
space:
mode:
Diffstat (limited to 'includes/media/SVGMetadataExtractor.php')
-rw-r--r--includes/media/SVGMetadataExtractor.php92
1 files changed, 71 insertions, 21 deletions
diff --git a/includes/media/SVGMetadataExtractor.php b/includes/media/SVGMetadataExtractor.php
index 2e33bb98..2a1091d8 100644
--- a/includes/media/SVGMetadataExtractor.php
+++ b/includes/media/SVGMetadataExtractor.php
@@ -31,6 +31,7 @@
class SVGMetadataExtractor {
static function getMetadata( $filename ) {
$svg = new SVGReader( $filename );
+
return $svg->getMetadata();
}
}
@@ -42,10 +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;
- private $metadata = Array();
+
+ /** @var array */
+ private $metadata = array();
+ private $languages = array();
+ private $languagePrefixes = array();
/**
* Constructor
@@ -113,7 +123,7 @@ class SVGReader {
}
/**
- * @return Array with the known metadata
+ * @return array Array with the known metadata
*/
public function getMetadata() {
return $this->metadata;
@@ -148,7 +158,9 @@ class SVGReader {
$this->debug( "$tag" );
- if ( $isSVG && $tag == 'svg' && $type == XmlReader::END_ELEMENT && $this->reader->depth <= $exitDepth ) {
+ if ( $isSVG && $tag == 'svg' && $type == XmlReader::END_ELEMENT
+ && $this->reader->depth <= $exitDepth
+ ) {
break;
} elseif ( $isSVG && $tag == 'title' ) {
$this->readField( $tag, 'title' );
@@ -164,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).
@@ -176,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" );
@@ -192,7 +204,10 @@ class SVGReader {
}
$keepReading = $this->reader->read();
while ( $keepReading ) {
- if ( $this->reader->localName == $name && $this->reader->namespaceURI == self::NS_SVG && $this->reader->nodeType == XmlReader::END_ELEMENT ) {
+ if ( $this->reader->localName == $name
+ && $this->reader->namespaceURI == self::NS_SVG
+ && $this->reader->nodeType == XmlReader::END_ELEMENT
+ ) {
break;
} elseif ( $this->reader->nodeType == XmlReader::TEXT ) {
$this->metadata[$metafield] = trim( $this->reader->value );
@@ -204,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 ) {
@@ -212,21 +227,24 @@ 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 {
- throw new MWException( "The PHP XMLReader extension does not come with readInnerXML() method. Your libxml is probably out of date (need 2.6.20 or later)." );
+ throw new MWException( "The PHP XMLReader extension does not come " .
+ "with readInnerXML() method. Your libxml is probably out of " .
+ "date (need 2.6.20 or later)." );
}
$this->reader->next();
}
/**
- * 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;
@@ -238,9 +256,38 @@ class SVGReader {
$keepReading = $this->reader->read();
while ( $keepReading ) {
if ( $this->reader->localName == $name && $this->reader->depth <= $exitDepth
- && $this->reader->nodeType == XmlReader::END_ELEMENT ) {
+ && $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
@@ -261,6 +308,7 @@ class SVGReader {
}
}
+ // @todo FIXME: Unused, remove?
private function throwXmlError( $err ) {
$this->debug( "FAILURE: $err" );
wfDebug( "SVGReader XML error: $err\n" );
@@ -272,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" );
}
@@ -333,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(
@@ -347,7 +397,7 @@ class SVGReader {
'em' => 16.0, // fake it?
'ex' => 12.0, // fake it?
'' => 1.0, // "User units" pixels by default
- );
+ );
$matches = array();
if ( preg_match( '/^\s*(\d+(?:\.\d+)?)(em|ex|px|pt|pc|cm|mm|in|%|)\s*$/', $length, $matches ) ) {
$length = floatval( $matches[1] );