From 14624cb8150005815924fae8aedb6b2d520d05e2 Mon Sep 17 00:00:00 2001 From: fredj Date: Wed, 18 Jan 2012 14:03:25 +0100 Subject: [PATCH 1/7] New OpenLayers.CANVAS_SUPPORTED constant --- lib/OpenLayers/Renderer/Canvas.js | 3 +-- lib/OpenLayers/Util.js | 9 +++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/OpenLayers/Renderer/Canvas.js b/lib/OpenLayers/Renderer/Canvas.js index 4edaf92a7b..daf9e19e35 100644 --- a/lib/OpenLayers/Renderer/Canvas.js +++ b/lib/OpenLayers/Renderer/Canvas.js @@ -110,8 +110,7 @@ OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, { * {Boolean} Whether or not the browser supports the renderer class */ supported: function() { - var canvas = document.createElement("canvas"); - return !!canvas.getContext; + return OpenLayers.CANVAS_SUPPORTED; }, /** diff --git a/lib/OpenLayers/Util.js b/lib/OpenLayers/Util.js index 2458a54b67..5ca8c35201 100644 --- a/lib/OpenLayers/Util.js +++ b/lib/OpenLayers/Util.js @@ -1435,6 +1435,15 @@ OpenLayers.IS_GECKO = (function() { return ua.indexOf("webkit") == -1 && ua.indexOf("gecko") != -1; })(); +/** + * Constant: CANVAS_SUPPORTED + * {Boolean} True if canvas 2d is supported. + */ +OpenLayers.CANVAS_SUPPORTED = (function() { + var elem = document.createElement('canvas'); + return !!(elem.getContext && elem.getContext('2d')); +})(); + /** * Constant: BROWSER_NAME * {String} From 57ae02f3812280d25f521f4f4ba9dc1e358e4a79 Mon Sep 17 00:00:00 2001 From: fredj Date: Wed, 18 Jan 2012 14:06:01 +0100 Subject: [PATCH 2/7] Set image.crossOrigin attribute in OpenLayers.Tile.Image --- lib/OpenLayers/Tile/Image.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/OpenLayers/Tile/Image.js b/lib/OpenLayers/Tile/Image.js index 23a7c9668a..28dab38773 100644 --- a/lib/OpenLayers/Tile/Image.js +++ b/lib/OpenLayers/Tile/Image.js @@ -297,6 +297,7 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, { } else { OpenLayers.Event.observe(img, "load", load); OpenLayers.Event.observe(img, "error", load); + img.crossOrigin = null; img.src = this.blankImageUrl; } } @@ -314,6 +315,8 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, { img.style.visibility = 'hidden'; img.style.opacity = 0; if (url) { + // don't set crossOrigin if the url is a data URL + img.crossOrigin = url.indexOf('data:') === 0 ? null : ''; img.src = url; } }, From b4ac0af5d86e51f9c317e7546a0e3865b1f06417 Mon Sep 17 00:00:00 2001 From: fredj Date: Wed, 18 Jan 2012 14:06:22 +0100 Subject: [PATCH 3/7] New OpenLayers.Tile.Image.getCanvasContext function --- lib/OpenLayers/Tile/Image.js | 32 ++++++++++++++++++++++++++++++++ tests/Tile/Image.html | 25 +++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/lib/OpenLayers/Tile/Image.js b/lib/OpenLayers/Tile/Image.js index 28dab38773..7baf8bf98e 100644 --- a/lib/OpenLayers/Tile/Image.js +++ b/lib/OpenLayers/Tile/Image.js @@ -81,6 +81,13 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, { */ maxGetUrlLength: null, + /** + * Property: canvasContext + * {CanvasRenderingContext2D} A canvas context associated with + * the tile image. + */ + canvasContext: null, + /** TBD 3.0 - reorder the parameters to the init function to remove * URL. the getUrl() function on the layer gets called on * each draw(), so no need to specify it here. @@ -216,6 +223,7 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, { } OpenLayers.Element.removeClass(img, "olImageLoadError"); } + this.canvasContext = null; }, /** @@ -369,6 +377,7 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, { img.style.opacity = this.layer.opacity; this.isLoading = false; + this.canvasContext = null; this.events.triggerEvent("loadend"); // IE<7 needs a reflow when the tiles are loaded because of the @@ -409,6 +418,29 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, { } }, + /** + * APIMethod: getCanvasContext + * Returns a canvas context associated with the tile image (with + * the image drawn on it). + * Returns undefined if the browser does not support canvas, if + * the tile has no image or if it's currently loading. + * + * Returns: + * {Boolean} + */ + getCanvasContext: function() { + if (OpenLayers.CANVAS_SUPPORTED && this.imgDiv && !this.isLoading) { + if (!this.canvasContext) { + var canvas = document.createElement("canvas"); + canvas.width = this.size.w; + canvas.height = this.size.h; + this.canvasContext = canvas.getContext("2d"); + this.canvasContext.drawImage(this.imgDiv, 0, 0); + } + return this.canvasContext; + } + }, + CLASS_NAME: "OpenLayers.Tile.Image" }); diff --git a/tests/Tile/Image.html b/tests/Tile/Image.html index 0b42064265..f202f6dfe1 100644 --- a/tests/Tile/Image.html +++ b/tests/Tile/Image.html @@ -399,6 +399,31 @@ map.destroy(); }); } + + function test_getCanvasContext(t) { + if (!OpenLayers.CANVAS_SUPPORTED) { + t.plan(0); + } else { + t.plan(1); + + var map = new OpenLayers.Map('map'); + var layer = new OpenLayers.Layer.WMS("OpenLayers WMS", + "http://labs.metacarta.com/wms/vmap0?", {layers: 'basic'}); + map.addLayer(layer); + map.setCenter(new OpenLayers.LonLat(0, 0), 5); + + t.delay_call(5, function() { + var tile = layer.grid[0][0]; + if (tile.isLoading) { + t.ok(false, "test_getCanvasContext timeout"); + } else { + t.ok(tile.getCanvasContext() instanceof CanvasRenderingContext2D, + "getCanvasContext() returns CanvasRenderingContext2D instance"); + } + map.destroy(); + }); + } + } From e9097ce066b920269645b01e04708ad6092da813 Mon Sep 17 00:00:00 2001 From: fredj Date: Thu, 19 Jan 2012 16:12:52 +0100 Subject: [PATCH 4/7] More APIdoc for OpenLayers.Tile.Image.getCanvasContext --- lib/OpenLayers/Tile/Image.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/OpenLayers/Tile/Image.js b/lib/OpenLayers/Tile/Image.js index 7baf8bf98e..690e494ed4 100644 --- a/lib/OpenLayers/Tile/Image.js +++ b/lib/OpenLayers/Tile/Image.js @@ -425,6 +425,15 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, { * Returns undefined if the browser does not support canvas, if * the tile has no image or if it's currently loading. * + * The function returns a canvas context instance but the + * underlying canvas is still available in the 'canvas' property: + * (code) + * var context = tile.getCanvasContext(); + * if (context) { + * var data = context.canvas.toDataURL('image/jpeg'); + * } + * (end) + * * Returns: * {Boolean} */ From b34f272fa702ee4028fbd6e102973609e4a0bea7 Mon Sep 17 00:00:00 2001 From: fredj Date: Fri, 20 Jan 2012 12:00:20 +0100 Subject: [PATCH 5/7] Optimize the string test --- lib/OpenLayers/Tile/Image.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/OpenLayers/Tile/Image.js b/lib/OpenLayers/Tile/Image.js index 690e494ed4..d9ee4e76e9 100644 --- a/lib/OpenLayers/Tile/Image.js +++ b/lib/OpenLayers/Tile/Image.js @@ -324,7 +324,7 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, { img.style.opacity = 0; if (url) { // don't set crossOrigin if the url is a data URL - img.crossOrigin = url.indexOf('data:') === 0 ? null : ''; + img.crossOrigin = url.substr(0, 5) === 'data:' ? null : ''; img.src = url; } }, From 342d624616efd12e67d42cf52ad24ee00a853d7f Mon Sep 17 00:00:00 2001 From: ahocevar Date: Fri, 10 Feb 2012 12:50:13 +0100 Subject: [PATCH 6/7] New crossOriginKeyword property. Set to 'anonymous' for Layer.OSM and Layer.Bing, and not used by default for other layers. --- lib/OpenLayers/Layer/Bing.js | 3 +++ lib/OpenLayers/Layer/OSM.js | 6 ++++++ lib/OpenLayers/Tile/Image.js | 16 ++++++++++++++-- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/lib/OpenLayers/Layer/Bing.js b/lib/OpenLayers/Layer/Bing.js index a33202a724..703c2b5e43 100644 --- a/lib/OpenLayers/Layer/Bing.js +++ b/lib/OpenLayers/Layer/Bing.js @@ -107,6 +107,9 @@ OpenLayers.Layer.Bing = OpenLayers.Class(OpenLayers.Layer.XYZ, { var newArgs = [name, null, options]; OpenLayers.Layer.XYZ.prototype.initialize.apply(this, newArgs); + this.tileOptions = OpenLayers.Util.extend({ + crossOriginKeyword: 'anonymous' + }, this.options.tileOptions); this.loadMetadata(); }, diff --git a/lib/OpenLayers/Layer/OSM.js b/lib/OpenLayers/Layer/OSM.js index 320c4540ef..69f411756b 100644 --- a/lib/OpenLayers/Layer/OSM.js +++ b/lib/OpenLayers/Layer/OSM.js @@ -73,6 +73,12 @@ OpenLayers.Layer.OSM = OpenLayers.Class(OpenLayers.Layer.XYZ, { * layer option can be set in this object (e.g. * ). */ + initialize: function(name, url, options) { + OpenLayers.Layer.XYZ.prototype.initialize.apply(this, arguments); + this.tileOptions = OpenLayers.Util.extend({ + crossOriginKeyword: 'anonymous' + }, this.options && this.options.tileOptions); + }, /** * Method: clone diff --git a/lib/OpenLayers/Tile/Image.js b/lib/OpenLayers/Tile/Image.js index d9ee4e76e9..309976a22f 100644 --- a/lib/OpenLayers/Tile/Image.js +++ b/lib/OpenLayers/Tile/Image.js @@ -87,6 +87,16 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, { * the tile image. */ canvasContext: null, + + /** + * APIProperty: crossOriginKeyword + * The value of the crossorigin keyword to use when loading images. This is + * only relevant when using for tiles from remote + * origins and should be set to either 'anonymous' or 'use-credentials' + * for servers that send Access-Control-Allow-Origin headers with their + * tiles. + */ + crossOriginKeyword: null, /** TBD 3.0 - reorder the parameters to the init function to remove * URL. the getUrl() function on the layer gets called on @@ -305,7 +315,7 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, { } else { OpenLayers.Event.observe(img, "load", load); OpenLayers.Event.observe(img, "error", load); - img.crossOrigin = null; + delete img.crossOrigin; img.src = this.blankImageUrl; } } @@ -324,7 +334,9 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, { img.style.opacity = 0; if (url) { // don't set crossOrigin if the url is a data URL - img.crossOrigin = url.substr(0, 5) === 'data:' ? null : ''; + if (this.crossOriginKeyword && url.substr(0, 5 !== 'data:')) { + img.crossOrigin = this.crossOriginKeyword; + } img.src = url; } }, From f8099e9ab10e60209f4bb739f25c204c10374947 Mon Sep 17 00:00:00 2001 From: fredj Date: Fri, 10 Feb 2012 13:46:13 +0100 Subject: [PATCH 7/7] Unset crossOrigin when setting blankImageUrl to the image. Tested with FF 10, Chrome 16 and 18. --- lib/OpenLayers/Tile/Image.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/OpenLayers/Tile/Image.js b/lib/OpenLayers/Tile/Image.js index 309976a22f..dfbf1bda43 100644 --- a/lib/OpenLayers/Tile/Image.js +++ b/lib/OpenLayers/Tile/Image.js @@ -315,7 +315,9 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, { } else { OpenLayers.Event.observe(img, "load", load); OpenLayers.Event.observe(img, "error", load); - delete img.crossOrigin; + if (img.crossOrigin) { + img.crossOrigin = null; + } img.src = this.blankImageUrl; } }