On Mon, Feb 22, 2010 at 7:57 PM, Drew Wilson <span dir="ltr"><<a href="mailto:atwilson@google.com">atwilson@google.com</a>></span> wrote:<br><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">

<br><br><div class="gmail_quote"><div class="im">On Mon, Feb 22, 2010 at 11:13 AM, David Levin <span dir="ltr"><<a href="mailto:levin@google.com" target="_blank">levin@google.com</a>></span> wrote:<br></div><div><div>

</div><div class="h5"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><span style="font-family:Verdana;font-size:13px"><div><div>I've talked with some other folks on WebKit (Maciej and Oliver) about having a canvas that is available to workers. They suggested some nice modifications to make it an offscreen canvas, which may be used in the Document or in a Worker.</div>



<div><br></div><div>Proposal:</div><div>Introduce an OffscreenCanvas which may be created from a Document or a Worker context.</div></div><div><font face="'courier new', monospace"><br></font></div><div><span style="border-collapse:collapse"><div>



<font face="'courier new', monospace">interface OffscreenCanvas {</font></div><div><span style="border-collapse:collapse"><div><div><div style="margin-top:0px;margin-bottom:0px"><font face="'courier new', monospace">                 attribute unsigned long width;</font></div>



<div style="margin-top:0px;margin-bottom:0px"><font face="'courier new', monospace">                 attribute unsigned long height;</font></div></div><div style="margin-top:0px;margin-bottom:0px"><font face="'courier new', monospace">        DOMString toDataURL (in optional DOMString type, in any... args);</font></div>



<div style="margin-top:0px;margin-bottom:0px"><font face="'courier new', monospace">        object getContext(in DOMString contextId);      </font></div></div><div style="margin-top:0px;margin-bottom:0px">
<span style="border-collapse:separate"><font face="'courier new', monospace">};</font></span></div><div style="margin-top:0px;margin-bottom:0px"><font face="'courier new', monospace"><span style="border-collapse:separate"><br>



</span></font></div><div style="margin-top:0px;margin-bottom:0px"><span style="border-collapse:separate"><font face="arial, helvetica, sans-serif"><br></font></span></div><div style="margin-top:0px;margin-bottom:0px">
<span style="border-collapse:separate"><font face="arial, helvetica, sans-serif">When it is created in the Worker context, </font><span style="border-collapse:collapse"><font face="arial, helvetica, sans-serif">OffscreenCanvas.</font><span style="border-collapse:separate"><font face="arial, helvetica, sans-serif">getContext("2d") returns a CanvasWorkerContext2D. In the Document context, it returns a CanvasRenderingContext2D.</font></span></span></span></div>



<div style="margin-top:0px;margin-bottom:0px"><span style="border-collapse:separate"><span style="border-collapse:collapse"><span style="border-collapse:separate"><font face="arial, helvetica, sans-serif"><br>
</font></span></span></span></div><div style="margin-top:0px;margin-bottom:0px"><span style="border-collapse:separate"><font face="arial, helvetica, sans-serif">The base class for both CanvasWorkerContext2D and CanvasRenderingContext2D is CanvasContext2D. CanvasContext2D is just like a CanvasRenderingContext2D except for omitting the font methods and any method which uses HTML elements. It does have some replacement methods for createPattern/drawImage which take an OffscreenCanvas. The canvas object attribute is either a HTMLCanvasElement or an OffscreenCanvas depending on what the canvas context came from.</font></span></div>



<div style="margin-top:0px;margin-bottom:0px"><span style="border-collapse:separate"><font face="'courier new', monospace"><br></font></span></div><div style="margin-top:0px;margin-bottom:0px"><span style="border-collapse:separate"><font face="'courier new', monospace">interface CanvasContext2D<span style="font-family:arial"> {</span></font></span></div>



<div style="margin-top:0px;margin-bottom:0px"><span style="border-collapse:separate"><font face="'courier new', monospace">        readonly attribute object canvas;</font></span></div><span style="border-collapse:separate;font-family:Verdana;font-size:13px"><div style="margin-top:0px;margin-bottom:0px">



<font face="'Courier New'"><br></font></div><div style="margin-top:0px;margin-bottom:0px"><font face="'Courier New'"><div style="margin-top:0px;margin-bottom:0px">        void save();</div><div style="margin-top:0px;margin-bottom:0px">



        void restore();</div><div style="margin-top:0px;margin-bottom:0px"><br></div><div style="margin-top:0px;margin-bottom:0px">        void scale(in float sx, in float sy);</div><div><div style="margin-top:0px;margin-bottom:0px">



        void rotate(in float angle);</div></div><div style="margin-top:0px;margin-bottom:0px">        void translate(in float tx, in float ty);</div><div><div style="margin-top:0px;margin-bottom:0px">
        void transform(in float m11, in float m12, in float m21, in float m22, in float dx, in float dy);</div><div style="margin-top:0px;margin-bottom:0px">        void setTransform(in float m11, in float m12, in float m21, in float m22, in float dx, in float dy);</div>



<div style="margin-top:0px;margin-bottom:0px"><br></div></div><div style="margin-top:0px;margin-bottom:0px">                 attribute float globalAlpha;</div><div style="margin-top:0px;margin-bottom:0px">                 attribute [ConvertNullToNullString] DOMString globalCompositeOperation;</div>



<div><div style="margin-top:0px;margin-bottom:0px"><br></div><div style="margin-top:0px;margin-bottom:0px">        CanvasGradient createLinearGradient(in float x0, in float y0, in float x1, in float y1)</div>
</div><div style="margin-top:0px;margin-bottom:0px">            raises (DOMException);</div><div><div style="margin-top:0px;margin-bottom:0px">        CanvasGradient createRadialGradient(in float x0, in float y0, in float r0, in float x1, in float y1, in float r1)</div>



</div><div style="margin-top:0px;margin-bottom:0px">            raises (DOMException);</div><div style="margin-top:0px;margin-bottom:0px"><span style="font-family:Verdana"><div style="margin-top:0px;margin-bottom:0px">
<font face="'Courier New'">        CanvasPattern createPattern(in <span style="font-family:'courier new', monospace;font-size:small;border-collapse:collapse">OffscreenCanvas</span> image, in DOMString repetition);</font></div>



<div><font face="'Courier New'"><br></font></div></span></div><div style="margin-top:0px;margin-bottom:0px">                 attribute float lineWidth;</div><div style="margin-top:0px;margin-bottom:0px">
                 attribute [ConvertNullToNullString] DOMString lineCap;</div><div style="margin-top:0px;margin-bottom:0px">                 attribute [ConvertNullToNullString] DOMString lineJoin;</div><div style="margin-top:0px;margin-bottom:0px">



                 attribute float miterLimit;</div><div style="margin-top:0px;margin-bottom:0px"><br></div><div style="margin-top:0px;margin-bottom:0px">                 attribute float shadowOffsetX;</div><div style="margin-top:0px;margin-bottom:0px">



                 attribute float shadowOffsetY;</div><div style="margin-top:0px;margin-bottom:0px">                 attribute float shadowBlur;</div><div style="margin-top:0px;margin-bottom:0px">                 attribute [ConvertNullToNullString] DOMString shadowColor;</div>



<div style="margin-top:0px;margin-bottom:0px"><br></div><div style="margin-top:0px;margin-bottom:0px">        void clearRect(in float x, in float y, in float width, in float height);</div><div style="margin-top:0px;margin-bottom:0px">



        void fillRect(in float x, in float y, in float width, in float height);</div><div><div style="margin-top:0px;margin-bottom:0px">        void strokeRect(in float x, in float y, in float w, in float h);</div>
<div style="margin-top:0px;margin-bottom:0px"><br></div></div><div><div style="margin-top:0px;margin-bottom:0px">        void beginPath();</div><div style="margin-top:0px;margin-bottom:0px">        void closePath();</div>



<div style="margin-top:0px;margin-bottom:0px">        void moveTo(in float x, in float y);</div><div style="margin-top:0px;margin-bottom:0px">        void lineTo(in float x, in float y);</div><div style="margin-top:0px;margin-bottom:0px">



        void quadraticCurveTo(in float cpx, in float cpy, in float x, in float y);</div><div style="margin-top:0px;margin-bottom:0px">        void bezierCurveTo(in float cp1x, in float cp1y, in float cp2x, in float cp2y, in float x, in float y);</div>



<div style="margin-top:0px;margin-bottom:0px">        void arcTo(in float x1, in float y1, in float x2, in float y2, in float radius);</div></div><div style="margin-top:0px;margin-bottom:0px">        void rect(in float x, in float y, in float width, in float height);</div>



<div><div style="margin-top:0px;margin-bottom:0px">        void arc(in float x, in float y, in float radius, in float startAngle, in float endAngle, in boolean anticlockwise);</div><div style="margin-top:0px;margin-bottom:0px">



        void fill();</div><div style="margin-top:0px;margin-bottom:0px">        void stroke();</div><div style="margin-top:0px;margin-bottom:0px">        void clip();</div><div style="margin-top:0px;margin-bottom:0px">
        boolean isPointInPath(in float x, in float y);</div><div style="margin-top:0px;margin-bottom:0px"><br></div></div><div style="margin-top:0px;margin-bottom:0px"><span style="font-family:'courier new', monospace;font-size:small"><div style="margin-top:0px;margin-bottom:0px">



        void drawImage(in <span style="border-collapse:collapse">OffscreenCanvas</span> image, in float dx, in float dy, in optional float dw, in optional float dh);</div><div style="margin-top:0px;margin-bottom:0px">
        void drawImage(in <span style="border-collapse:collapse">OffscreenCanvas</span> image, in float sx, in float sy, in float sw, in float sh, in float dx, in float dy, in float dw, in float dh);</div><div><br></div>



</span></div><div><div style="margin-top:0px;margin-bottom:0px">        // pixel manipulation</div><div style="margin-top:0px;margin-bottom:0px">        ImageData createImageData(in float sw, in float sh)</div>
</div><div style="margin-top:0px;margin-bottom:0px">            raises (DOMException);</div><div><div style="margin-top:0px;margin-bottom:0px">        ImageData getImageData(in float sx, in float sy, in float sw, in float sh)</div>



</div><div style="margin-top:0px;margin-bottom:0px">            raises(DOMException);</div><div style="margin-top:0px;margin-bottom:0px">        void putImageData(in ImageData imagedata, in float dx, in float dy, in optional float dirtyX, in optional float dirtyY, in optional float dirtyWidth, in optional float dirtyHeight]);</div>



</font></div><div style="margin-top:0px;margin-bottom:0px"><span style="font-family:'Courier New'">};</span></div><div style="margin-top:0px;margin-bottom:0px"><font face="'Courier New'"><br></font></div>



<div style="margin-top:0px;margin-bottom:0px"><font face="'Courier New'">interface <span style="font-family:'courier new', monospace;font-size:small">CanvasWorkerContext2D : CanvasContext2D {</span></font></div>



<div style="margin-top:0px;margin-bottom:0px"><font face="'Courier New'"><span style="font-family:'courier new', monospace;font-size:small">};</span></font></div><div style="margin-top:0px;margin-bottom:0px">



<font face="'Courier New'"><span style="font-family:'courier new', monospace;font-size:small"><br></span></font></div><div style="margin-top:0px;margin-bottom:0px"><span style="font-family:'courier new', monospace;font-size:small">interface CanvasRenderingContext2D <span style="font-family:arial">: <span style="font-family:'courier new', monospace">CanvasContext2D <span style="font-family:arial">{</span></span></span></span></div>



<div style="margin-top:0px;margin-bottom:0px"><font face="'Courier New'"><span style="font-family:'courier new', monospace;font-size:small"><span style="font-family:arial"><div style="margin-top:0px;margin-bottom:0px">



<font face="'courier new', monospace"><div style="margin-top:0px;margin-bottom:0px">         CanvasPattern createPattern(in HTMLImageElement image, in DOMString repetition);</div><div style="margin-top:0px;margin-bottom:0px">



         CanvasPattern createPattern(in HTMLCanvasElement image, in DOMString repetition);</div><div style="margin-top:0px;margin-bottom:0px">         CanvasPattern createPattern(in HTMLVideoElement image, in DOMString repetition);</div>



<div><br></div></font></div><div style="margin-top:0px;margin-bottom:0px"><font face="'courier new', monospace">         // focus management</font></div><div style="margin-top:0px;margin-bottom:0px"><font face="'courier new', monospace">         boolean drawFocusRing(in Element element, in float xCaret, in float yCaret, in optional boolean canDrawCustom);</font></div>



<div style="margin-top:0px;margin-bottom:0px"><font face="'courier new', monospace"><br></font></div><div style="margin-top:0px;margin-bottom:0px"><font face="'courier new', monospace">        // text</font></div>



<div style="margin-top:0px;margin-bottom:0px"><font face="'courier new', monospace"><span style="font-family:'Courier New';font-size:13px">     </span><span style="font-family:'Courier New'">    </span>        attribute DOMString font;</font></div>



<div style="margin-top:0px;margin-bottom:0px"><font face="'courier new', monospace"><span style="font-family:'Courier New'">         </span>        attribute DOMString textAlign;</font></div><div style="margin-top:0px;margin-bottom:0px">



<font face="'courier new', monospace"><span style="font-family:'Courier New'">         </span>        attribute DOMString textBaseline;</font></div><div style="margin-top:0px;margin-bottom:0px"><font face="'courier new', monospace">        void fillText(</font><span style="line-height:21px;white-space:pre-wrap"><font face="'courier new', monospace">in DOMString text, in float x, in float y, in optional float maxWidth</font><span style="line-height:normal;white-space:normal"><font face="'courier new', monospace">);</font></span></span></div>



<div style="margin-top:0px;margin-bottom:0px"><font face="'courier new', monospace">        void strokeText(</font><span style="line-height:21px;white-space:pre-wrap"><font face="'courier new', monospace">in DOMString text, in float x, in float y, in optional float maxWidth</font><span style="line-height:normal;white-space:normal"><font face="'courier new', monospace">);</font></span></span></div>



<div style="margin-top:0px;margin-bottom:0px"><font face="'courier new', monospace">        TextMetrics measureText(in DOMString text);</font></div><div style="margin-top:0px;margin-bottom:0px"><font face="'courier new', monospace"><br>



</font></div><div style="margin-top:0px;margin-bottom:0px"><font face="'courier new', monospace"><div style="margin-top:0px;margin-bottom:0px">        // drawing images</div><div style="margin-top:0px;margin-bottom:0px">



        void drawImage(in HTMLImageElement image, in float dx, in float dy, in optional float dw, in float dh);</div><div style="margin-top:0px;margin-bottom:0px">        void drawImage(in HTMLImageElement image, in float sx, in float sy, in float sw, in float sh, in float dx, in float dy, in float dw, in float dh);</div>



<div style="margin-top:0px;margin-bottom:0px">        void drawImage(in HTMLVideoElement image, in float dx, in float dy, in optional float dw, in optional float dh);</div><div style="margin-top:0px;margin-bottom:0px">
        void drawImage(in HTMLVideoElement image, in float sx, in float sy, in float sw, in float sh, in float dx, in float dy, in float dw, in float dh);</div></font></div></span></span></font></div><span style="font-family:'courier new', monospace;font-size:small"><div style="margin-top:0px;margin-bottom:0px">



        </div></span><div style="margin-top:0px;margin-bottom:0px"><span style="font-size:small"><font face="'courier new', monospace"><div style="margin-top:0px;margin-bottom:0px">        void drawImage(in HTMLCanvasElement image, in float dx, in float dy, in optional float dw, in float dh);</div>



<div style="margin-top:0px;margin-bottom:0px">        void drawImage(in HTMLCanvasElement image, in float sx, in float sy, in float sw, in float sh, in float dx, in float dy, in float dw, in float dh);</div></font></span></div>



<span style="font-family:arial;font-size:small"><div><span style="border-collapse:collapse"><div><span style="border-collapse:collapse"><div style="margin-top:0px;margin-bottom:0px"><span style="border-collapse:separate"><font face="'courier new', monospace"><span style="font-family:arial"><br>



</span></font></span></div></span></div></span></div><font face="'courier new', monospace"></font></span><font face="'courier new', monospace"></font><font face="'courier new', monospace"></font><div style="margin-top:0px;margin-bottom:0px">



<span style="font-size:small"><font face="'courier new', monospace">};</font></span></div><div style="margin-top:0px;margin-bottom:0px"><font face="'Courier New'"><span style="font-family:'courier new', monospace;font-size:small"><span style="font-family:arial"><br>



</span></span></font></div><div style="margin-top:0px;margin-bottom:0px"><font face="'Courier New'"><span style="font-family:'courier new', monospace;font-size:small"><span style="font-family:arial"><div>



Questions and comments are welcome.</div><div><br></div><div>Note that something similar did come up in December and this proposal avoids doing any text related items in the offscreen canvas which was a concern brought up by Robert O'Callahan at the time  (<a href="http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2009-December/024478.html" target="_blank">http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2009-December/024478.html</a>).</div>


</span></span></font></div></span></span></div></span></div></span></div></blockquote><div><br></div></div></div><div>Do we feel that text APIs are, in general, difficult to implement in a multi-thread safe manner? Or would we be limiting this API primarily because of the specifics of a single current implementation? Because if it's the latter, I would argue against omitting the text APIs, since they seem fundamental to many use cases. It seems like there are a range of solutions for retrofitting multi-thread support to non-multi-thread-safe operations, ranging from the use of global mutexes to changing the code itself to be safely re-entrant.</div>

</div></blockquote><div><br></div><div>It does indeed seem pretty short sighted.</div><div><br></div><div>Why can't implementations that aren't able to render text (or whatever) on a worker thread simply schedule such work on their main thread?  I know it defeats the parallelism, but it's better than _some_ implementations are single threaded when doing things like rendering text rather than _all_ implementations (not to mention that it's easier from the web developer's perspective).</div>

</div>