IE9 Tries to Implement HTML5 - Hilarity Ensues

6 min read

Deviation Actions

dt's avatar
dt
By
Published:
16K Views
What Can Be Done About 3 Gotchas in IE9 Beta


I just spent the past couple of days porting and debugging DeviantArt muro in Internet Explorer 9 beta.  Microsoft announced with much fanfare that they included support for <canvas> in IE9.  Unfortunately I took their word at face value and assumed that my existing HTML5 code would seamlessly start working once I changed X-UA-Compatible.  Alas, I instead stared in horror at my application that appeared to be possessed by some insane daemon.

I remember taking a C class when I was 14 years old, and the teacher went on about how great C was because it was portable.  I spent a week doing my first assignment on my PC in Turbo C++, and then showed up at the computer lab full of NeXT workstations the morning the assignment was due expecting it to just work.  One would think I would have learned from the ensuing traumatic experience, but here I am 20 years later still believing vendors when they say their implementations fit a standard.  In my defense, Chrome, Firefox, Opera, and Safari did an amazing job of coding to the HTML5 spec.  I don’t know why Microsoft couldn’t as well.

The following is a list of several IE9 gotchas that I ran into.  I am sure that there are more - this is only the result of kicking the tires.  It is also just the stuff that I ran into with DeviantArt muro, other applications will care more about other parts of the canvas feature set.


globalCompositeOperation

The Problem
IE ignores changes to context.globalCompositeOperation, always behaving like it is set to “source-over.”

Why This Matters
This is the biggest problem I have run into.  A canvas implementation without globalCompositeOperation is like having a salad bar with no lettuce.  There must be a million uses for globalCompositeOperation.  Set it to “destination-out” and you have an eraser.  You can use it to mask out shapes, or combine it with a pattern to create textured lines.  I would hope that Microsoft plans to implement it by the time they make a final release, to claim to have support for canvas without it would truly be an embarrassment.

Test Case

ctx.strokeStyle = 'rgba(255, 0, 0, 1)';                                                                                        
    ctx.lineWidth = 10;
    ctx.globalCompositeOperation = 'source-over';                                                                                  
            
    ctx.beginPath();                                                                                                               
        ctx.moveTo(0, 0);
        ctx.lineTo(100, 100);
    ctx.stroke();                                                                                                                  
                                                                                                                                   
    ctx.strokeStyle = 'rgba(0, 255, 0, 1)';                                                                                        
    ctx.globalCompositeOperation = 'destination-out';      
                                                                             
    ctx.beginPath();                                                                                                               
        ctx.moveTo(0, 100);                                                                                                        
        ctx.lineTo(100, 0);
    ctx.stroke();



Workaround
There is not a good workaround for this.




Canvas Resizing

The Problem
When a canvas is resized by changing the style.width or style.height, IE9 clears the canvas and resets the context.  Note that style.width is not the same as the width attribute of the canvas.  Having <canvas width=”50” height=”50” style=”width: 100px; height:100px”></canvas> would be equivalent to having a 50x50 pixel image that you stretch to 100x100px in a browser.  All browsers reset the canvas when you change the width or height attribute, but only IE resets the canvas when style.width or style.height is changed.

Why This Matters
Applications can zoom in and out of certain areas of a canvas by leaving the drawing as is and changing the style.width and/or style.height.

Test Case

// Start with a canvas that is 100x100px
ctx.strokeStyle = 'rgba(255, 0, 0, 1)';                                                                                        
ctx.lineWidth = 10;
                
ctx.beginPath();
    ctx.moveTo(0, 0);
    ctx.lineTo(100, 100);
ctx.stroke();
                
jQuery('#testCanv').width(101).height(101);
                    
ctx.strokeStyle = 'rgba(0, 255, 0, 1)';                                                                                        
ctx.beginPath();                                                                                                               
    ctx.moveTo(0, 100);                                                                                                        
    ctx.lineTo(100, 0);
ctx.stroke();



Workaround
Grab a copy of all the data in your canvas before you change its size, and paste it after you are done resizing.  All context settings must also be saved and reset.  We would have to change our test case code to:

// ... snip
ctx.stroke();
           
var tmpData = ctx.getImageData(0, 0, 100, 100);     
jQuery('#testCanv').width(101).height(101);
ctx.putImageData(tmpData, 0, 0);
ctx.lineWidth = 10;
                    
ctx.strokeStyle = 'rgba(0, 255, 0, 1)';
// snip ...





Limited Shadow Offset

The Problem
IE9 places an arbitrary limit on how high you can set shadow offsets using shadowOffsetX and shadowOffsetY.  Brief testing shows that the limit seems to be dependent on various random factors.  I have not yet reverse engineered the algorithm for how the limit is determined, but so far I have usually seen it to be a couple thousand pixels.

Why This Matters
I am sure that many people reading this think that I am complaining about an inconsequential implementation detail, but it actually does matter.  For all of the great things that canvas has to offer, it lacks in its ability to create soft lines.  Fortunately though, it can do a lot of fancy stuff with shadows, so you can draw with soft lines by drawing out of the canvas’ viewport and casting a shadow over to where you need the soft lines.  If you plan to make complex drawings on a large canvas, and you do not want to worry about your fake lines that are casting shadows coming into view when you pan and zoom, it is helpful to be able to set the shadow offset to a really large number.

Test Case

ctx.lineWidth = 10;                                                                                                            
    
ctx.shadowColor = 'rgba(255, 0, 0, 1)';
ctx.shadowBlur = 40;
ctx.shadowOffsetX = 10000;
ctx.shadowOffsetY = 0;                                                                                                         
    
ctx.beginPath();                                                                                                               
   ctx.moveTo(-10000, 0);                                                                                                     
   ctx.lineTo(-9900, 100);
ctx.stroke();



Workaround
You can use smaller versions of shadowOffset (though until the algorithm for how the limit is determined is discovered, you will never know for certain if you are safe).  At times you might have to change the offset and split up your strokes to make sure that things that are supposed to remain offscreen stay offscreen.

Edit:
Please see this blog article for further discussion between the author and a Microsoft Technical Evangelist: blogs.msdn.com/b/giorgio/archi…

© 2011 - 2024 dt
Comments72
Join the community to add your comment. Already a deviant? Log In
Hmm.. I just tried all the test cases in IE9 RC with the the IE Test Drive canvas test pad
[link]
The first two are now working as expected.
The third was is pretty close but looks like the blur effect levels are a bit different.
ctx.shadowBlur =8; instead of ctx.shadowBlur =40;