From 9e01c5701eca8c5f2570ac8e380520bdd5a661b1 Mon Sep 17 00:00:00 2001 From: Joel Martin Date: Sat, 6 Nov 2010 12:23:23 -0500 Subject: [PATCH] canvas.js: workaround WebKit bug, issue #28. This is WebKit bug https://bugs.webkit.org/show_bug.cgi?id=46319 The workaround is to wrap Canvas render functions with a function that sets a flush timer. The flush function sets the right margin and then 1ms later sets it back. This triggers the canvas to redraw with the correct contents. Two downsides: - rendering is slower, but only on the busted versions of webkit. Correct and useful is better than fast and useless. - There is a barely perceptible jitter of the control buttons because the canvas size is changing by one pixel. To support this functionality, we also have to read out the exact webkit version from the user agent in the render engine detection code in include/util.js. --- include/canvas.js | 38 ++++++++++++++++++++++++++++++++++++-- include/util.js | 8 ++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/include/canvas.js b/include/canvas.js index baa2fd5..34d9da3 100644 --- a/include/canvas.js +++ b/include/canvas.js @@ -25,8 +25,10 @@ var that = {}, // Public API interface c_keyPress = null, c_mouseButton = null, - c_mouseMove = null; + c_mouseMove = null, + c_webkit_bug = false, + c_flush_timer = null; // Configuration settings function cdef(v, type, defval, desc) { @@ -91,7 +93,7 @@ that.get_height = function() { function constructor() { Util.Debug(">> Canvas.init"); - var c, ctx, imgTest, tval, i, curDat, curSave, + var c, ctx, func, origfunc, imgTest, tval, i, curDat, curSave, has_imageData = false, UE = Util.Engine; if (! conf.target) { throw("target must be set"); } @@ -159,6 +161,26 @@ function constructor() { that.cmapImage = that.cmapImageFill; } + if (UE.webkit && UE.webkit >= 534.7 && UE.webkit <= 534.9) { + // Workaround WebKit canvas rendering bug #46319 + conf.render_mode += ", webkit bug workaround"; + Util.Debug("Working around WebKit bug #46319"); + c_webkit_bug = true; + for (func in {"fillRect":1, "copyImage":1, "rgbxImage":1, + "cmapImage":1, "blitStringImage":1}) { + that[func] = (function() { + var myfunc = that[func]; // Save original function + //Util.Debug("Wrapping " + func); + return function() { + myfunc.apply(this, arguments); + if (!c_flush_timer) { + c_flush_timer = setTimeout(that.flush, 100); + } + }; + })(); + } + } + /* * Determine browser support for setting the cursor via data URI * scheme @@ -483,6 +505,18 @@ that.stop = function() { } }; +that.flush = function() { + var old_val; + //Util.Debug(">> flush"); + // Force canvas redraw (for webkit bug #46319 workaround) + old_val = conf.target.style.marginRight; + conf.target.style.marginRight = "1"; + c_flush_timer = null; + setTimeout(function () { + conf.target.style.marginRight = old_val; + }, 1); +}; + that.setFillColor = function(color) { var rgb, newStyle; if (conf.true_color) { diff --git a/include/util.js b/include/util.js index 726486b..af83b8a 100644 --- a/include/util.js +++ b/include/util.js @@ -208,6 +208,14 @@ Util.Engine = { 'gecko': (function() { return (!document.getBoxObjectFor && window.mozInnerScreenX == null) ? false : ((document.getElementsByClassName) ? 19 : 18); }()) }; +if (Util.Engine.webkit) { + // Extract actual webkit version if available + Util.Engine.webkit = (function(v) { + var re = new RegExp('WebKit/([0-9\.]*) '); + v = (navigator.userAgent.match(re) || ['', v])[1]; + return parseFloat(v, 10); + })(Util.Engine.webkit); +} Util.Flash = (function(){ var v, version;