mirror of
https://github.com/moodle/moodle.git
synced 2025-01-18 05:58:34 +01:00
Merge branch 'wip-MDL-22955-m24' of git://github.com/samhemelryk/moodle
This commit is contained in:
commit
dbaf9d448d
@ -683,7 +683,7 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
$row = new html_table_row();
|
||||
$row->attributes['class'] = 'type-' . $plugin->type . ' name-' . $plugin->type . '_' . $plugin->name;
|
||||
|
||||
if ($this->page->theme->resolve_image_location('icon', $plugin->type . '_' . $plugin->name)) {
|
||||
if ($this->page->theme->resolve_image_location('icon', $plugin->type . '_' . $plugin->name, null)) {
|
||||
$icon = $this->output->pix_icon('icon', '', $plugin->type . '_' . $plugin->name, array('class' => 'smallicon pluginicon'));
|
||||
} else {
|
||||
$icon = $this->output->pix_icon('spacer', '', 'moodle', array('class' => 'smallicon pluginicon noicon'));
|
||||
|
@ -442,6 +442,18 @@ $CFG->admin = 'admin';
|
||||
//
|
||||
// $CFG->disableupdatenotifications = true;
|
||||
//
|
||||
// As of version 2.4 Moodle serves icons as SVG images if the users browser appears
|
||||
// to support SVG.
|
||||
// For those wanting to control the serving of SVG images the following setting can
|
||||
// be defined in your config.php.
|
||||
// If it is not defined then the default (browser detection) will occur.
|
||||
//
|
||||
// To ensure they are always used when available:
|
||||
// $CFG->svgicons = true;
|
||||
//
|
||||
// To ensure they are never used even when available:
|
||||
// $CFG->svgicons = false;
|
||||
//
|
||||
//=========================================================================
|
||||
// 8. SETTINGS FOR DEVELOPMENT SERVERS - not intended for production use!!!
|
||||
//=========================================================================
|
||||
|
@ -198,7 +198,7 @@ class tiynce_subplugins_settings extends admin_setting {
|
||||
$displayname = html_writer::tag('span', $namestr, array('class'=>'dimmed_text'));
|
||||
}
|
||||
|
||||
if ($PAGE->theme->resolve_image_location('icon', 'tinymce_' . $name)) {
|
||||
if ($PAGE->theme->resolve_image_location('icon', 'tinymce_' . $name, false)) {
|
||||
$icon = $OUTPUT->pix_icon('icon', '', 'tinymce_' . $name, array('class' => 'smallicon pluginicon'));
|
||||
} else {
|
||||
$icon = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'smallicon pluginicon noicon'));
|
||||
|
@ -3784,7 +3784,7 @@ function file_pluginfile($relativepath, $forcedownload, $preview = null) {
|
||||
}
|
||||
// no redirect here because it is not cached
|
||||
$theme = theme_config::load($themename);
|
||||
$imagefile = $theme->resolve_image_location('u/'.$filename, 'moodle');
|
||||
$imagefile = $theme->resolve_image_location('u/'.$filename, 'moodle', null);
|
||||
send_file($imagefile, basename($imagefile), 60*60*24*14);
|
||||
}
|
||||
|
||||
|
@ -38,10 +38,17 @@ M.util.image_url = function(imagename, component) {
|
||||
component = 'core';
|
||||
}
|
||||
|
||||
var url = M.cfg.wwwroot + '/theme/image.php';
|
||||
if (M.cfg.themerev > 0 && M.cfg.slasharguments == 1) {
|
||||
var url = M.cfg.wwwroot + '/theme/image.php/' + M.cfg.theme + '/' + component + '/' + M.cfg.themerev + '/' + imagename;
|
||||
if (!M.cfg.svgicons) {
|
||||
url += '/_s';
|
||||
}
|
||||
url += '/' + M.cfg.theme + '/' + component + '/' + M.cfg.themerev + '/' + imagename;
|
||||
} else {
|
||||
var url = M.cfg.wwwroot + '/theme/image.php?theme=' + M.cfg.theme + '&component=' + component + '&rev=' + M.cfg.themerev + '&image=' + imagename;
|
||||
url += '?theme=' + M.cfg.theme + '&component=' + component + '&rev=' + M.cfg.themerev + '&image=' + imagename;
|
||||
if (!M.cfg.svgicons) {
|
||||
url += '&svg=0';
|
||||
}
|
||||
}
|
||||
|
||||
return url;
|
||||
|
@ -334,6 +334,12 @@ class theme_config {
|
||||
*/
|
||||
public $supportscssoptimisation = true;
|
||||
|
||||
/**
|
||||
* Used to determine whether we can serve SVG images or not.
|
||||
* @var bool
|
||||
*/
|
||||
private $usesvg = null;
|
||||
|
||||
/**
|
||||
* Load the config.php file for a particular theme, and return an instance
|
||||
* of this class. (That is, this is a factory method.)
|
||||
@ -942,6 +948,11 @@ class theme_config {
|
||||
public function post_process($css) {
|
||||
// now resolve all image locations
|
||||
if (preg_match_all('/\[\[pix:([a-z_]+\|)?([^\]]+)\]\]/', $css, $matches, PREG_SET_ORDER)) {
|
||||
// We are going to disable the use of SVG images when available in CSS background-image properties
|
||||
// as support for it in browsers is at best quirky.
|
||||
// When we choose to support SVG in background css we will need to remove this code and implement a solution that is
|
||||
// either consistent or varies the URL for serving CSS depending upon SVG being used if available, or not.
|
||||
$this->force_svg_use(false);
|
||||
$replaced = array();
|
||||
foreach ($matches as $match) {
|
||||
if (isset($replaced[$match[0]])) {
|
||||
@ -977,6 +988,7 @@ class theme_config {
|
||||
global $CFG;
|
||||
|
||||
$params = array('theme'=>$this->name);
|
||||
$svg = $this->use_svg_icons();
|
||||
|
||||
if (empty($component) or $component === 'moodle' or $component === 'core') {
|
||||
$params['component'] = 'core';
|
||||
@ -991,11 +1003,22 @@ class theme_config {
|
||||
|
||||
$params['image'] = $imagename;
|
||||
|
||||
$url = new moodle_url("$CFG->httpswwwroot/theme/image.php");
|
||||
if (!empty($CFG->slasharguments) and $rev > 0) {
|
||||
$url = new moodle_url("$CFG->httpswwwroot/theme/image.php");
|
||||
$url->set_slashargument('/'.$params['theme'].'/'.$params['component'].'/'.$params['rev'].'/'.$params['image'], 'noparam', true);
|
||||
$path = '/'.$params['theme'].'/'.$params['component'].'/'.$params['rev'].'/'.$params['image'];
|
||||
if (!$svg) {
|
||||
// We add a simple /_s to the start of the path.
|
||||
// The underscore is used to ensure that it isn't a valid theme name.
|
||||
$path = '/_s'.$path;
|
||||
}
|
||||
$url->set_slashargument($path, 'noparam', true);
|
||||
} else {
|
||||
$url = new moodle_url("$CFG->httpswwwroot/theme/image.php", $params);
|
||||
if (!$svg) {
|
||||
// We add an SVG param so that we know not to serve SVG images.
|
||||
// We do this because all modern browsers support SVG and this param will one day be removed.
|
||||
$params['svg'] = '0';
|
||||
}
|
||||
$url->params($params);
|
||||
}
|
||||
|
||||
return $url;
|
||||
@ -1003,26 +1026,41 @@ class theme_config {
|
||||
|
||||
/**
|
||||
* Resolves the real image location.
|
||||
*
|
||||
* $svg was introduced as an arg in 2.4. It is important because not all supported browsers support the use of SVG
|
||||
* and we need a way in which to turn it off.
|
||||
* By default SVG won't be used unless asked for. This is done for two reasons:
|
||||
* 1. It ensures that we don't serve svg images unless we really want to. The admin has selected to force them, of the users
|
||||
* browser supports SVG.
|
||||
* 2. We only serve SVG images from locations we trust. This must NOT include any areas where the image may have been uploaded
|
||||
* by the user due to security concerns.
|
||||
*
|
||||
* @param string $image name of image, may contain relative path
|
||||
* @param string $component
|
||||
* @param bool $svg If set to true SVG images will also be looked for.
|
||||
* @return string full file path
|
||||
*/
|
||||
public function resolve_image_location($image, $component) {
|
||||
public function resolve_image_location($image, $component, $svg = false) {
|
||||
global $CFG;
|
||||
|
||||
if (!is_bool($svg)) {
|
||||
// If $svg isn't a bool then we need to decide for ourselves.
|
||||
$svg = $this->use_svg_icons();
|
||||
}
|
||||
|
||||
if ($component === 'moodle' or $component === 'core' or empty($component)) {
|
||||
if ($imagefile = $this->image_exists("$this->dir/pix_core/$image")) {
|
||||
if ($imagefile = $this->image_exists("$this->dir/pix_core/$image", $svg)) {
|
||||
return $imagefile;
|
||||
}
|
||||
foreach (array_reverse($this->parent_configs) as $parent_config) { // base first, the immediate parent last
|
||||
if ($imagefile = $this->image_exists("$parent_config->dir/pix_core/$image")) {
|
||||
if ($imagefile = $this->image_exists("$parent_config->dir/pix_core/$image", $svg)) {
|
||||
return $imagefile;
|
||||
}
|
||||
}
|
||||
if ($imagefile = $this->image_exists("$CFG->dataroot/pix/$image")) {
|
||||
if ($imagefile = $this->image_exists("$CFG->dataroot/pix/$image", $svg)) {
|
||||
return $imagefile;
|
||||
}
|
||||
if ($imagefile = $this->image_exists("$CFG->dirroot/pix/$image")) {
|
||||
if ($imagefile = $this->image_exists("$CFG->dirroot/pix/$image", $svg)) {
|
||||
return $imagefile;
|
||||
}
|
||||
return null;
|
||||
@ -1031,11 +1069,11 @@ class theme_config {
|
||||
if ($image === 'favicon') {
|
||||
return "$this->dir/pix/favicon.ico";
|
||||
}
|
||||
if ($imagefile = $this->image_exists("$this->dir/pix/$image")) {
|
||||
if ($imagefile = $this->image_exists("$this->dir/pix/$image", $svg)) {
|
||||
return $imagefile;
|
||||
}
|
||||
foreach (array_reverse($this->parent_configs) as $parent_config) { // base first, the immediate parent last
|
||||
if ($imagefile = $this->image_exists("$parent_config->dir/pix/$image")) {
|
||||
if ($imagefile = $this->image_exists("$parent_config->dir/pix/$image", $svg)) {
|
||||
return $imagefile;
|
||||
}
|
||||
}
|
||||
@ -1047,36 +1085,92 @@ class theme_config {
|
||||
}
|
||||
list($type, $plugin) = explode('_', $component, 2);
|
||||
|
||||
if ($imagefile = $this->image_exists("$this->dir/pix_plugins/$type/$plugin/$image")) {
|
||||
if ($imagefile = $this->image_exists("$this->dir/pix_plugins/$type/$plugin/$image", $svg)) {
|
||||
return $imagefile;
|
||||
}
|
||||
foreach (array_reverse($this->parent_configs) as $parent_config) { // base first, the immediate parent last
|
||||
if ($imagefile = $this->image_exists("$parent_config->dir/pix_plugins/$type/$plugin/$image")) {
|
||||
if ($imagefile = $this->image_exists("$parent_config->dir/pix_plugins/$type/$plugin/$image", $svg)) {
|
||||
return $imagefile;
|
||||
}
|
||||
}
|
||||
if ($imagefile = $this->image_exists("$CFG->dataroot/pix_plugins/$type/$plugin/$image")) {
|
||||
if ($imagefile = $this->image_exists("$CFG->dataroot/pix_plugins/$type/$plugin/$image", $svg)) {
|
||||
return $imagefile;
|
||||
}
|
||||
$dir = get_plugin_directory($type, $plugin);
|
||||
if ($imagefile = $this->image_exists("$dir/pix/$image")) {
|
||||
if ($imagefile = $this->image_exists("$dir/pix/$image", $svg)) {
|
||||
return $imagefile;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if we should look for SVG images as well.
|
||||
*
|
||||
* @staticvar bool $svg
|
||||
* @return bool
|
||||
*/
|
||||
public function use_svg_icons() {
|
||||
global $CFG;
|
||||
if ($this->usesvg === null) {
|
||||
if (!isset($CFG->svgicons) || !is_bool($CFG->svgicons)) {
|
||||
// IE 5 - 8 don't support SVG at all.
|
||||
if (empty($_SERVER['HTTP_USER_AGENT'])) {
|
||||
// Can't be sure, just say no.
|
||||
$this->usesvg = false;
|
||||
} else if (preg_match('#MSIE +[5-8]\.#', $_SERVER['HTTP_USER_AGENT'])) {
|
||||
// IE < 9 doesn't support SVG. Say no.
|
||||
$this->usesvg = false;
|
||||
} else if (preg_match('#Android +[0-2]\.#', $_SERVER['HTTP_USER_AGENT'])) {
|
||||
// Android < 3 doesn't support SVG. Say no.
|
||||
$this->usesvg = false;
|
||||
} else {
|
||||
// Presumed fine.
|
||||
$this->usesvg = true;
|
||||
}
|
||||
} else {
|
||||
// Force them on/off depending upon the setting.
|
||||
$this->usesvg = $CFG->svgicons;
|
||||
}
|
||||
}
|
||||
return $this->usesvg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces the usesvg setting to either true or false, avoiding any decision making.
|
||||
*
|
||||
* This function should only ever be used when absolutely required, and before any generation of image URL's has occurred.
|
||||
*
|
||||
* @param bool $setting True to force the use of svg when available, null otherwise.
|
||||
*/
|
||||
private function force_svg_use($setting) {
|
||||
$this->usesvg = (bool)$setting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if file with any image extension exists.
|
||||
*
|
||||
* The order to these images was adjusted prior to the release of 2.4
|
||||
* At that point the were the following image counts in Moodle core:
|
||||
*
|
||||
* - png = 667 in pix dirs (1499 total)
|
||||
* - gif = 385 in pix dirs (606 total)
|
||||
* - jpg = 62 in pix dirs (74 total)
|
||||
* - jpeg = 0 in pix dirs (1 total)
|
||||
*
|
||||
* There is work in progress to move towards SVG presently hence that has been prioritiesed.
|
||||
*
|
||||
* @param string $filepath
|
||||
* @param bool $svg If set to true SVG images will also be looked for.
|
||||
* @return string image name with extension
|
||||
*/
|
||||
private static function image_exists($filepath) {
|
||||
if (file_exists("$filepath.gif")) {
|
||||
return "$filepath.gif";
|
||||
private static function image_exists($filepath, $svg = false) {
|
||||
if ($svg && file_exists("$filepath.svg")) {
|
||||
return "$filepath.svg";
|
||||
} else if (file_exists("$filepath.png")) {
|
||||
return "$filepath.png";
|
||||
} else if (file_exists("$filepath.gif")) {
|
||||
return "$filepath.gif";
|
||||
} else if (file_exists("$filepath.jpg")) {
|
||||
return "$filepath.jpg";
|
||||
} else if (file_exists("$filepath.jpeg")) {
|
||||
|
@ -264,6 +264,7 @@ class page_requirements_manager {
|
||||
'slasharguments' => (int)(!empty($CFG->slasharguments)),
|
||||
'theme' => $page->theme->name,
|
||||
'jsrev' => ((empty($CFG->cachejs) or empty($CFG->jsrev)) ? -1 : $CFG->jsrev),
|
||||
'svgicons' => $page->theme->use_svg_icons()
|
||||
);
|
||||
if (debugging('', DEBUG_DEVELOPER)) {
|
||||
$this->M_cfg['developerdebug'] = true;
|
||||
|
@ -133,3 +133,100 @@ class xhtml_container_stack_testcase extends advanced_testcase {
|
||||
$this->assertDebuggingNotCalled();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the theme config class.
|
||||
*
|
||||
* @copyright 2012 Sam Hemelryk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class theme_config_testcase extends advanced_testcase {
|
||||
/**
|
||||
* This function will test directives used to serve SVG images to make sure
|
||||
* this are making the right decisions.
|
||||
*/
|
||||
public function test_svg_image_use() {
|
||||
global $CFG;
|
||||
|
||||
$this->resetAfterTest();
|
||||
|
||||
if (isset($_SERVER['HTTP_USER_AGENT'])) {
|
||||
$ua = $_SERVER['HTTP_USER_AGENT'];
|
||||
} else {
|
||||
$ua = null;
|
||||
}
|
||||
|
||||
// The two required tests.
|
||||
$this->assertTrue(file_exists($CFG->dirroot.'/pix/i/test.svg'));
|
||||
$this->assertTrue(file_exists($CFG->dirroot.'/pix/i/test.png'));
|
||||
|
||||
$theme = theme_config::load(theme_config::DEFAULT_THEME);
|
||||
|
||||
// First up test the forced setting.
|
||||
$imagefile = $theme->resolve_image_location('i/test', 'moodle', true);
|
||||
$this->assertEquals('test.svg', basename($imagefile));
|
||||
$imagefile = $theme->resolve_image_location('i/test', 'moodle', false);
|
||||
$this->assertEquals('test.png', basename($imagefile));
|
||||
|
||||
// Now test the use of the svgicons config setting.
|
||||
// We need to clone the theme as usesvg property is calculated only once.
|
||||
$testtheme = clone $theme;
|
||||
$CFG->svgicons = true;
|
||||
$imagefile = $testtheme->resolve_image_location('i/test', 'moodle', null);
|
||||
$this->assertEquals('test.svg', basename($imagefile));
|
||||
$CFG->svgicons = false;
|
||||
// We need to clone the theme as usesvg property is calculated only once.
|
||||
$testtheme = clone $theme;
|
||||
$imagefile = $testtheme->resolve_image_location('i/test', 'moodle', null);
|
||||
$this->assertEquals('test.png', basename($imagefile));
|
||||
unset($CFG->svgicons);
|
||||
|
||||
// Finally test a few user agents.
|
||||
$useragents = array(
|
||||
// IE7 on XP.
|
||||
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)' => false,
|
||||
// IE8 on Vista.
|
||||
'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)' => false,
|
||||
// IE8 on Vista in compatability mode.
|
||||
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Trident/4.0)' => false,
|
||||
// IE8 on Windows 7.
|
||||
'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0)' => false,
|
||||
// IE9 on Windows 7.
|
||||
'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)' => true,
|
||||
// IE9 on Windows 7 in compatability mode.
|
||||
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Trident/5.0)' => false,
|
||||
// Chrome 11 on Windows.
|
||||
'Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/534.17 (KHTML, like Gecko) Chrome/11.0.652.0 Safari/534.17' => true,
|
||||
// Chrome 22 on Windows.
|
||||
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1' => true,
|
||||
// Chrome 21 on Ubuntu 12.04.
|
||||
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.89 Safari/537.1' => true,
|
||||
// Firefox 4 on Windows.
|
||||
'Mozilla/5.0 (Windows NT 6.1; rv:1.9) Gecko/20100101 Firefox/4.0' => true,
|
||||
// Firefox 15 on Windows.
|
||||
'Mozilla/5.0 (Windows NT 6.1; rv:15.0) Gecko/20120716 Firefox/15.0.1' => true,
|
||||
// Firefox 15 on Ubuntu.
|
||||
'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:15.0) Gecko/20100101 Firefox/15.0.1' => true,
|
||||
// Opera 12.02 on Ubuntu.
|
||||
'Opera/9.80 (X11; Linux x86_64; U; en) Presto/2.10.289 Version/12.02' => true,
|
||||
// Android browser pre 1.0
|
||||
'Mozilla/5.0 (Linux; U; Android 0.5; en-us) AppleWebKit/522+ (KHTML, like Gecko) Safari/419.3' => false,
|
||||
// Android browser 2.3 (HTC)
|
||||
'Mozilla/5.0 (Linux; U; Android 2.3.5; en-us; HTC Vision Build/GRI40) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1' => false,
|
||||
// Android browser 3.0 (Motorola)
|
||||
'Mozilla/5.0 (Linux; U; Android 3.0; en-us; Xoom Build/HRI39) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13' => true
|
||||
);
|
||||
foreach ($useragents as $agent => $expected) {
|
||||
$_SERVER['HTTP_USER_AGENT'] = $agent;
|
||||
// We need to clone the theme as usesvg property is calculated only once.
|
||||
$testtheme = clone $theme;
|
||||
$imagefile = $testtheme->resolve_image_location('i/test', 'moodle', null);
|
||||
$this->assertEquals($expected ? 'test.svg' : 'test.png', basename($imagefile),
|
||||
'Incorrect image returned for user agent `'.$agent.'`');
|
||||
}
|
||||
|
||||
if ($ua !== null) {
|
||||
$_SERVER['HTTP_USER_AGENT'] = $ua;
|
||||
}
|
||||
}
|
||||
}
|
BIN
pix/i/test.png
Normal file
BIN
pix/i/test.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
133
pix/i/test.svg
Normal file
133
pix/i/test.svg
Normal file
@ -0,0 +1,133 @@
|
||||
<?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:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="114.88917"
|
||||
height="114.88917"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.3.1 r9886"
|
||||
sodipodi:docname="New document 1">
|
||||
<defs
|
||||
id="defs4">
|
||||
<linearGradient
|
||||
id="linearGradient3988">
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:0"
|
||||
offset="0"
|
||||
id="stop3990" />
|
||||
<stop
|
||||
style="stop-color:#ff8000;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3992" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3982">
|
||||
<stop
|
||||
id="stop3984"
|
||||
offset="0"
|
||||
style="stop-color:#ffab00;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop3986"
|
||||
offset="1"
|
||||
style="stop-color:#ff8000;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3982"
|
||||
id="radialGradient3980"
|
||||
cx="360.68207"
|
||||
cy="435.11246"
|
||||
fx="360.68207"
|
||||
fy="435.11246"
|
||||
r="45.40649"
|
||||
gradientTransform="matrix(1,0,0,0.98110214,0,8.2226956)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
spreadMethod="pad" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3988"
|
||||
id="linearGradient4005"
|
||||
x1="323.18604"
|
||||
y1="445.29483"
|
||||
x2="375.84158"
|
||||
y2="514.34235"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<filter
|
||||
inkscape:collect="always"
|
||||
id="filter4055"
|
||||
color-interpolation-filters="sRGB">
|
||||
<feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="2.1197264"
|
||||
id="feGaussianBlur4057" />
|
||||
</filter>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1.7480769"
|
||||
inkscape:cx="-31.349998"
|
||||
inkscape:cy="12.481512"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1855"
|
||||
inkscape:window-height="1056"
|
||||
inkscape:window-x="65"
|
||||
inkscape:window-y="24"
|
||||
inkscape:window-maximized="1"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-304.95364,-378.52595)">
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="fill:url(#radialGradient3980);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
id="path3204"
|
||||
sodipodi:cx="360.68207"
|
||||
sodipodi:cy="435.11246"
|
||||
sodipodi:rx="44.90649"
|
||||
sodipodi:ry="44.048405"
|
||||
d="m 405.58856,435.11246 c 0,24.32726 -20.10532,44.0484 -44.90649,44.0484 -24.80117,0 -44.90649,-19.72114 -44.90649,-44.0484 0,-24.32726 20.10532,-44.04841 44.90649,-44.04841 24.80117,0 44.90649,19.72115 44.90649,44.04841 z" />
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
id="path3994"
|
||||
sodipodi:cx="374.98349"
|
||||
sodipodi:cy="445.12344"
|
||||
sodipodi:rx="52.343235"
|
||||
sodipodi:ry="52.343235"
|
||||
d="m 427.32673,445.12344 c 0,28.90837 -23.43487,52.34324 -52.34324,52.34324 -28.90837,0 -52.34324,-23.43487 -52.34324,-52.34324 0,-28.90837 23.43487,-52.34323 52.34324,-52.34323 28.90837,0 52.34324,23.43486 52.34324,52.34323 z"
|
||||
transform="matrix(0.95405918,-0.29961823,0.29961823,0.95405918,-128.72531,123.64832)"
|
||||
style="opacity:0.47736631;fill:url(#linearGradient4005);fill-opacity:1;filter:url(#filter4055)" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 4.3 KiB |
101
theme/image.php
101
theme/image.php
@ -37,6 +37,13 @@ if ($slashargument = min_get_slash_argument()) {
|
||||
if (substr_count($slashargument, '/') < 3) {
|
||||
image_not_found();
|
||||
}
|
||||
if (strpos($slashargument, '_s/') === 0) {
|
||||
// Can't use SVG
|
||||
$slashargument = substr($slashargument, 3);
|
||||
$usesvg = false;
|
||||
} else {
|
||||
$usesvg = true;
|
||||
}
|
||||
// image must be last because it may contain "/"
|
||||
list($themename, $component, $rev, $image) = explode('/', $slashargument, 4);
|
||||
$themename = min_clean_param($themename, 'SAFEDIR');
|
||||
@ -49,6 +56,7 @@ if ($slashargument = min_get_slash_argument()) {
|
||||
$component = min_optional_param('component', 'core', 'SAFEDIR');
|
||||
$rev = min_optional_param('rev', -1, 'INT');
|
||||
$image = min_optional_param('image', '', 'SAFEPATH');
|
||||
$usesvg = (bool)min_optional_param('svg', '1', 'INT');
|
||||
}
|
||||
|
||||
if (empty($component) or $component === 'moodle' or $component === 'core') {
|
||||
@ -77,12 +85,15 @@ if ($rev > -1) {
|
||||
image_not_found();
|
||||
}
|
||||
$cacheimage = false;
|
||||
if (file_exists("$candidatelocation/$image.gif")) {
|
||||
$cacheimage = "$candidatelocation/$image.gif";
|
||||
$ext = 'gif';
|
||||
if ($usesvg && file_exists("$candidatelocation/$image.svg")) {
|
||||
$cacheimage = "$candidatelocation/$image.svg";
|
||||
$ext = 'svg';
|
||||
} else if (file_exists("$candidatelocation/$image.png")) {
|
||||
$cacheimage = "$candidatelocation/$image.png";
|
||||
$ext = 'png';
|
||||
} else if (file_exists("$candidatelocation/$image.gif")) {
|
||||
$cacheimage = "$candidatelocation/$image.gif";
|
||||
$ext = 'gif';
|
||||
} else if (file_exists("$candidatelocation/$image.jpg")) {
|
||||
$cacheimage = "$candidatelocation/$image.jpg";
|
||||
$ext = 'jpg';
|
||||
@ -120,11 +131,38 @@ define('NO_UPGRADE_CHECK', true); // Ignore upgrade check
|
||||
require("$CFG->dirroot/lib/setup.php");
|
||||
|
||||
$theme = theme_config::load($themename);
|
||||
$imagefile = $theme->resolve_image_location($image, $component);
|
||||
|
||||
$rev = theme_get_revision();
|
||||
$etag = sha1("$themename/$component/$rev/$image");
|
||||
|
||||
// We're not using SVG and there is no cached version of this file (in any format).
|
||||
// As we're going to be caching a format other than svg, and because svg use is conditional we need to ensure that at the same
|
||||
// time we cache a version of the SVG if it exists. If we don't do this other users who ask for SVG would not ever get it as
|
||||
// there is a cached image already of another format.
|
||||
// Remember this only gets run once before any candidate exists, and only if we want a cached revision.
|
||||
if (!$usesvg && $rev > -1) {
|
||||
$imagefile = $theme->resolve_image_location($image, $component, true);
|
||||
if (!empty($imagefile) && is_readable($imagefile)) {
|
||||
$cacheimage = cache_image($image, $imagefile, $candidatelocation);
|
||||
$pathinfo = pathinfo($imagefile);
|
||||
// There is no SVG equivilant, we've just successfully cached an image of another format.
|
||||
if ($pathinfo['extension'] !== 'svg') {
|
||||
// Serve the file as we would in a normal request.
|
||||
if (connection_aborted()) {
|
||||
die;
|
||||
}
|
||||
// make sure nothing failed
|
||||
clearstatcache();
|
||||
if (file_exists($cacheimage)) {
|
||||
send_cached_image($cacheimage, $etag);
|
||||
}
|
||||
send_uncached_image($imagefile);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Either SVG was requested or we've cached a SVG version and are ready to serve a regular format.
|
||||
$imagefile = $theme->resolve_image_location($image, $component, $usesvg);
|
||||
if (empty($imagefile) or !is_readable($imagefile)) {
|
||||
if ($rev > -1) {
|
||||
if (!file_exists($candidatelocation)) {
|
||||
@ -139,23 +177,7 @@ if (empty($imagefile) or !is_readable($imagefile)) {
|
||||
}
|
||||
|
||||
if ($rev > -1) {
|
||||
$pathinfo = pathinfo($imagefile);
|
||||
$cacheimage = "$candidatelocation/$image.".$pathinfo['extension'];
|
||||
|
||||
clearstatcache();
|
||||
if (!file_exists(dirname($cacheimage))) {
|
||||
@mkdir(dirname($cacheimage), $CFG->directorypermissions, true);
|
||||
}
|
||||
|
||||
// Prevent serving of incomplete file from concurrent request,
|
||||
// the rename() should be more atomic than copy().
|
||||
ignore_user_abort(true);
|
||||
if (@copy($imagefile, $cacheimage.'.tmp')) {
|
||||
rename($cacheimage.'.tmp', $cacheimage);
|
||||
@chmod($cacheimage, $CFG->filepermissions);
|
||||
@unlink($cacheimage.'.tmp'); // just in case anything fails
|
||||
}
|
||||
ignore_user_abort(false);
|
||||
$cacheimage = cache_image($image, $imagefile, $candidatelocation);
|
||||
if (connection_aborted()) {
|
||||
die;
|
||||
}
|
||||
@ -229,10 +251,12 @@ function image_not_found() {
|
||||
|
||||
function get_contenttype_from_ext($ext) {
|
||||
switch ($ext) {
|
||||
case 'gif':
|
||||
return 'image/gif';
|
||||
case 'svg':
|
||||
return 'image/svg+xml';
|
||||
case 'png':
|
||||
return 'image/png';
|
||||
case 'gif':
|
||||
return 'image/gif';
|
||||
case 'jpg':
|
||||
case 'jpeg':
|
||||
return 'image/jpeg';
|
||||
@ -241,3 +265,32 @@ function get_contenttype_from_ext($ext) {
|
||||
}
|
||||
return 'document/unknown';
|
||||
}
|
||||
|
||||
/**
|
||||
* Caches a given image file.
|
||||
*
|
||||
* @param string $image The name of the image that was requested.
|
||||
* @param string $imagefile The location of the image file we want to cache.
|
||||
* @param string $candidatelocation The location to cache it in.
|
||||
* @return string The path to the cached image.
|
||||
*/
|
||||
function cache_image($image, $imagefile, $candidatelocation) {
|
||||
global $CFG;
|
||||
$pathinfo = pathinfo($imagefile);
|
||||
$cacheimage = "$candidatelocation/$image.".$pathinfo['extension'];
|
||||
|
||||
clearstatcache();
|
||||
if (!file_exists(dirname($cacheimage))) {
|
||||
@mkdir(dirname($cacheimage), $CFG->directorypermissions, true);
|
||||
}
|
||||
|
||||
// Prevent serving of incomplete file from concurrent request,
|
||||
// the rename() should be more atomic than copy().
|
||||
ignore_user_abort(true);
|
||||
if (@copy($imagefile, $cacheimage.'.tmp')) {
|
||||
rename($cacheimage.'.tmp', $cacheimage);
|
||||
@chmod($cacheimage, $CFG->filepermissions);
|
||||
@unlink($cacheimage.'.tmp'); // just in case anything fails
|
||||
}
|
||||
return $cacheimage;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user