HTML Standard Tracker

Diff (omit for latest revision)
Filter

Short URL: http://html5.org/r/6125

File a bug

SVNBugCommentTime (UTC)
6125[Gecko] [Internet Explorer] [Opera] [Webkit] updated drawFocusRing to take recent feedback into account2011-05-11 00:08
Index: source
===================================================================
--- source	(revision 6124)
+++ source	(revision 6125)
@@ -176,6 +176,14 @@
    <li><a href="#crossDocumentMessages">Cross-document messaging</a> (also known as Communications)<!--POSTMSG-->
    <li><a href="#channel-messaging">Channel messaging</a> (also known as Communications)<!--POSTMSG-->
   </ul>
+  
+  <p>The specification that covers the Canvas 2D Graphics Context at
+  the W3C does not include all the advice included in the equivalent
+  section in this document, because of <a
+  href="http://lists.w3.org/Archives/Public/public-html/2011Apr/0712.html">the
+  discussion</a> that followed <a
+  href="http://lists.w3.org/Archives/Public/public-html/2011Apr/0271.html">a
+  working gorup decision from April 2011</a>.</p>
 
   <p>The <a href="#forms">forms</a> part of this specification was
   previously published separately in a specification known as Web
@@ -37675,7 +37683,7 @@
 
   <h5 id="2dcontext">The 2D context</h5>
 
-  <!-- v2: we're on v4. suggestions for next version are marked v5. -->
+  <!-- v2: we're on v4.1. suggestions for next version are marked v5. -->
 
   <!--START 2dcontext-->
 
@@ -37776,12 +37784,12 @@
   void <span title="dom-context-2d-arc">arc</span>(in double x, in double y, in double radius, in double startAngle, in double endAngle, in optional boolean anticlockwise);
   void <span title="dom-context-2d-fill">fill</span>();
   void <span title="dom-context-2d-stroke">stroke</span>();
+  void <span title="dom-context-2d-drawOSFocusRing">drawOSFocusRing</span>(in <span>Element</span> element);
+  boolean <span title="dom-context-2d-drawCustomFocusRing">drawCustomFocusRing</span>(in <span>Element</span> element);
+  void <span title="dom-context-2d-scrollPathIntoView">scrollPathIntoView</span>();
   void <span title="dom-context-2d-clip">clip</span>();
   boolean <span title="dom-context-2d-isPointInPath">isPointInPath</span>(in double x, in double y);
 
-  // focus management
-  boolean <span title="dom-context-2d-drawFocusRing">drawFocusRing</span>(in <span>Element</span> element, in double xCaret, in double yCaret, in optional boolean canDrawCustom);
-
   // text
            attribute DOMString <span title="dom-context-2d-font">font</span>; // (default 10px sans-serif)
            attribute DOMString <span title="dom-context-2d-textAlign">textAlign</span>; // "start", "end", "left", "right", "center" (default: "start")
@@ -39346,6 +39354,42 @@
 
    </dd>
 
+   <dt><var title="">context</var> . <code title="dom-context-2d-drawOSFocusRing">drawOSFocusRing</code>(<var title="">element</var>)</dt>
+
+   <dd>
+
+    <p>If the given element is focused, draws a focus ring around the
+    current path, following the platform conventions for focus
+    rings.</p>
+
+   </dd>
+
+   <dt><var title="">shouldDraw</var> = <var title="">context</var> . <code title="dom-context-2d-drawCustomFocusRing">drawCustomFocusRing</code>(<var title="">element</var>)</dt>
+
+   <dd>
+
+    <p>If the given element is focused, and the user has configured
+    his system to draw focus rings in a particular manner (for
+    example, high contrast focus rings), draws a focus ring around the
+    current path and returns false.</p>
+
+    <p>Otherwise, returns true if the given element is focused, and
+    false otherwise. This can thus be used to determine when to draw a
+    focus ring (see <a href="#drawCustomFocusRingExample">the
+    example</a> below).</p>
+
+   </dd>
+
+   <dt><var title="">context</var> . <code title="dom-context-2d-scrollPathIntoView">scrollPathIntoView</code>()</dt>
+
+   <dd>
+
+    <p>Scrolls the current path into view. This is especially useful
+    on devices with small screens, where the whole canvas might not be
+    visible at once.</p>
+
+   </dd>
+
    <dt><var title="">context</var> . <code title="dom-context-2d-clip">clip</code>()</dt>
 
    <dd>
@@ -39611,95 +39655,58 @@
   <p>Zero-length line segments must be pruned before stroking a
   path. Empty subpaths must be ignored.</p>
 
+  <hr>
 
-  <p>The <dfn title="dom-context-2d-clip"><code>clip()</code></dfn>
-  method must create a new <dfn>clipping region</dfn> by calculating
-  the intersection of the current clipping region and the area
-  described by the current path, using the non-zero winding number
-  rule. Open subpaths must be implicitly closed when computing the
-  clipping region, without affecting the actual subpaths. The new
-  clipping region replaces the current clipping region.</p>
-
-  <p>When the context is initialized, the clipping region must be set
-  to the rectangle with the top left corner at (0,0) and the width and
-  height of the coordinate space.</p>
-
-  <!-- v5
-   Jordan OSETE suggests:
-    * support ways of extending the clipping region (union instead of intersection)
-       - also "add", "subtract", "replace", "intersect" and "xor"
-    * support ways of resetting the clipping region without save/restore
-  -->
-
-
   <p>The <dfn
-  title="dom-context-2d-isPointInPath"><code>isPointInPath(<var
-  title="">x</var>, <var title="">y</var>)</code></dfn> method must
-  return true if the point given by the <var title="">x</var> and <var
-  title="">y</var> coordinates passed to the method, when treated as
-  coordinates in the canvas coordinate space unaffected by the current
-  transformation, is inside the current path as determined by the
-  non-zero winding number rule; and must return false
-  otherwise. Points on the path itself are considered to be inside the
-  path. If either of the arguments is infinite or NaN, then the method
-  must return false.</p>
+  title="dom-context-2d-drawOSFocusRing"><code>drawOSFocusRing(<var
+  title="">element</var>)</code></dfn> method, when invoked,
+  must run the following steps:</p>
 
-  </div>
+  <ol>
 
+   <li><p>If <var title="">element</var> is not focused or is not a
+   descendant of the element with whose context the method is
+   associated, then abort these steps.</p></li>
 
-  <h6>Focus management</h6> <!-- a v4 feature -->
+   <li>
 
-  <p>When a canvas is interactive, authors should include focusable
-  elements in the element's fallback content corresponding to each
-  focusable part of the canvas.</p>
+    <p>If the user has requested the use of particular focus rings
+    (e.g. high-contrast focus rings), or if the <var
+    title="">element</var> would have a focus ring drawn around it,
+    then draw a focus ring of the appropriate style along the path,
+    following platform conventions, and abort these steps.</p>
 
-  <p>To indicate which focusable part of the canvas is currently
-  focused, authors should use the <code
-  title="dom-context-2d-drawFocusRing">drawFocusRing()</code> method,
-  passing it the element for which a ring is being drawn. This method
-  only draws the focus ring if the element is focused, so that it can
-  simply be called whenever drawing the element, without checking
-  whether the element is focused or not first. The position of the
-  center of the control, or of the editing caret if the control has
-  one, should be given in the <var title="">x</var> and <var
-  title="">y</var> arguments.</p>
+    <p class="note">Some platforms only draw focus rings around
+    elements that have been focused from the keyboard, and not those
+    focused from the mouse. Other platforms simply don't draw focus
+    rings around some elements at all unless relevant accessibility
+    features are enabled. This API is intended to follow these
+    conventions.</p>
 
-  <dl class="domintro">
+    <p>The focus ring should not be subject to the <span
+    title="shadows">shadow effects</span>, the <span
+    title="dom-context-2d-globalAlpha">global alpha</span>, or the <span
+    title="dom-context-2d-globalCompositeOperation">global composition
+    operators</span>, but <em>should</em> be subject to the <span
+    title="clipping region">clipping region</span>.</p>
 
-   <dt><var title="">shouldDraw</var> = <var title="">context</var> . <code title="dom-context-2d-drawFocusRing">drawFocusRing</code>(<var title="">element</var>, <var title="">x</var>, <var title="">y</var>, [ <var title="">canDrawCustom</var> ])</dt>
+   </li>
 
-   <dd>
+   <li>
 
-    <p>If the given element is focused, draws a focus ring around the
-    current path, following the platform conventions for focus
-    rings. The given coordinate is used if the user's attention needs
-    to be brought to a particular position (e.g. if a magnifier is
-    following the editing caret in a text field).</p>
+    <p>Optionally, <a href="#inform">inform the user</a> that the
+    focus is at the location given by the path. User agents may wait
+    until the next time the <span>event loop</span> reaches its
+    "update the rendering" step to optionally inform the user.</p>
 
-    <p>If the <var title="">canDrawCustom</var> argument is true, then
-    the focus ring is only drawn if the user has configured his system
-    to draw focus rings in a particular manner. (For example, high
-    contrast focus rings.)</p>
+   </li>
 
-    <p>Returns true if the given element is focused, the <var
-    title="">canDrawCustom</var> argument is true, and the user has
-    not configured his system to draw focus rings in a particular
-    manner. Otherwise, returns false.</p>
+  </ol>
 
-    <p>When the method returns true, the author is expected to
-    manually draw a focus ring.</p>
-
-   </dd>
-
-  </dl>
-
-  <div class="impl">
-
   <p>The <dfn
-  title="dom-context-2d-drawFocusRing"><code>drawFocusRing(<var
-  title="">element</var>, <var title="">x</var>, <var
-  title="">y</var>, [<var title="">canDrawCustom</var>])</code></dfn>
-  method, when invoked, must run the following steps:</p>
+  title="dom-context-2d-drawCustomFocusRing"><code>drawCustomFocusRing(<var
+  title="">element</var>)</code></dfn> method, when invoked, must run
+  the following steps:</p>
 
   <ol>
 
@@ -39707,22 +39714,11 @@
    descendant of the element with whose context the method is
    associated, then return false and abort these steps.</p></li>
 
-   <li><p>Transform the given point (<var title="">x</var>, <var
-   title="">y</var>) according to the <span
-   title="dom-context-2d-transformation">current transformation
-   matrix</span>.</p></li>
-
-   <li><p>Optionally, inform the user that the focus is at the given
-   (transformed) coordinate on the canvas. (For example, this could
-   involve moving the user's magnification tool.)</p></li>
-
    <li>
 
     <p>If the user has requested the use of particular focus rings
-    (e.g. high-contrast focus rings), or if the <var
-    title="">canDrawCustom</var> argument is absent or false, then
-    draw a focus ring of the appropriate style along the path,
-    following platform conventions, return false, and abort these
+    (e.g. high-contrast focus rings), then draw a focus ring of the
+    appropriate style along the path, return false, and abort these
     steps.</p>
 
     <p>The focus ring should not be subject to the <span
@@ -39734,44 +39730,128 @@
 
    </li>
 
+   <li>
+
+    <p>Optionally, <a href="#inform">inform the user</a> that the
+    focus is at the location given by the path. User agents may wait
+    until the next time the <span>event loop</span> reaches its
+    "update the rendering" step to optionally inform the user.</p>
+
+   </li>
+
    <li><p>Return true.</p></li>
 
   </ol>
 
+  <p>The <dfn
+  title="dom-context-2d-scrollPathIntoView"><code>scrollPathIntoView()</code></dfn>
+  method, when invoked, must run the following steps:</p>
+
+  <ol>
+
+   <li><p>Let <var title="">notional child</var> be a hypothetical
+   element that is a rendered child of the <code>canvas</code> element
+   whose dimensions are exactly the rectangle of the bounding box of
+   the current path.</p></li>
+
+   <li><p><span title="scroll an element into view">Scroll <var
+   title="">notional child</var> into view</span> with the <var
+   title="">align to top flag</var> set.</p>
+
+   <li><p>Optionally, <a href="#inform">inform the user</a> that the
+   caret and/or selection cover <var title="">the specified
+   rectangle</var> of the canvas. User agents may wait until the next
+   time the <span>event loop</span> reaches its "update the rendering"
+   step to optionally inform the user.</p></li>
+
+  </ol>
+
+  <p class="note" id="inform">"Inform the user", as used in this
+  section, could mean calling a system accessibility API, which would
+  notify assistive technologies such as magnification tools. To
+  properly drive magnification based on a focus change, a system
+  accessibility API driving a screen magnifier needs the bounds for
+  the newly focused object. The methods above are intended to enable
+  this by allowing the user agent to report the bounding box of the
+  path used to render the focus ring as the bounds of the <var
+  title="">element</var> element passed as an argument, if that
+  element is focused, and the bounding box of the area to which the
+  user agent is scrolling as the bounding box of the current
+  selection.</p>
+
+  <hr>
+
+  <p>The <dfn title="dom-context-2d-clip"><code>clip()</code></dfn>
+  method must create a new <dfn>clipping region</dfn> by calculating
+  the intersection of the current clipping region and the area
+  described by the current path, using the non-zero winding number
+  rule. Open subpaths must be implicitly closed when computing the
+  clipping region, without affecting the actual subpaths. The new
+  clipping region replaces the current clipping region.</p>
+
+  <p>When the context is initialized, the clipping region must be set
+  to the rectangle with the top left corner at (0,0) and the width and
+  height of the coordinate space.</p>
+
+  <!-- v5
+   Jordan OSETE suggests:
+    * support ways of extending the clipping region (union instead of intersection)
+       - also "add", "subtract", "replace", "intersect" and "xor"
+    * support ways of resetting the clipping region without save/restore
+  -->
+
+  <hr>
+
+  <p>The <dfn
+  title="dom-context-2d-isPointInPath"><code>isPointInPath(<var
+  title="">x</var>, <var title="">y</var>)</code></dfn> method must
+  return true if the point given by the <var title="">x</var> and <var
+  title="">y</var> coordinates passed to the method, when treated as
+  coordinates in the canvas coordinate space unaffected by the current
+  transformation, is inside the current path as determined by the
+  non-zero winding number rule; and must return false
+  otherwise. Points on the path itself are considered to be inside the
+  path. If either of the arguments is infinite or NaN, then the method
+  must return false.</p>
+
   </div>
 
-  <div class="example">
 
-   <p>This <code>canvas</code> element has a couple of checkboxes:</p>
+  <div class="example" id="drawCustomFocusRingExample">
 
+   <p>This <code>canvas</code> element has a couple of checkboxes. The
+   path-related commands are highlighted:</p>
+
    <pre>&lt;canvas height=400 width=750>
  &lt;label>&lt;input type=checkbox id=showA> Show As&lt;/label>
  &lt;label>&lt;input type=checkbox id=showB> Show Bs&lt;/label>
  &lt;!-- ... -->
 &lt;/canvas>
 &lt;script>
- function drawCheckbox(context, element, x, y) {
+ function drawCheckbox(context, element, x, y, paint) {
    context.save();
    context.font = '10px sans-serif';
    context.textAlign = 'left';
    context.textBaseline = 'middle';
    var metrics = context.measureText(element.labels[0].textContent);
-   context.beginPath();
-   context.strokeStyle = 'black';
-   context.rect(x-5, y-5, 10, 10);
-   context.stroke();
-   if (element.checked) {
-     context.fillStyle = 'black';
-     context.fill();
+   if (paint) {
+<strong>     context.beginPath();
+     context.strokeStyle = 'black';
+     context.rect(x-5, y-5, 10, 10);
+     context.stroke();
+</strong>     if (element.checked) {
+<strong>       context.fillStyle = 'black';
+       context.fill();
+</strong>     }
+     context.fillText(element.labels[0].textContent, x+5, y);
    }
-   context.fillText(element.labels[0].textContent, x+5, y);
-   context.beginPath();
+<strong>   context.beginPath();
    context.rect(x-7, y-7, 12 + metrics.width+2, 14);
-   if (context.drawFocusRing(element, x, y, true)) {
+   if (paint && context.drawCustomFocusRing(element)) {
      context.strokeStyle = 'silver';
      context.stroke();
    }
-   context.restore();
+</strong>   context.restore();
  }
  function drawBase() { /* ... */ }
  function drawAs() { /* ... */ }
@@ -39780,8 +39860,8 @@
    var canvas = document.getElementsByTagName('canvas')[0];
    var context = canvas.getContext('2d');
    context.clearRect(0, 0, canvas.width, canvas.height);
-   drawCheckbox(context, document.getElementById('showA'), 20, 40);
-   drawCheckbox(context, document.getElementById('showB'), 20, 60);
+   drawCheckbox(context, document.getElementById('showA'), 20, 40, true);
+   drawCheckbox(context, document.getElementById('showB'), 20, 60, true);
    drawBase();
    if (document.getElementById('showA').checked)
      drawAs();
@@ -39791,12 +39871,17 @@
  function processClick(event) {
    var canvas = document.getElementsByTagName('canvas')[0];
    var context = canvas.getContext('2d');
-   var x = event.clientX - canvas.offsetLeft;
-   var y = event.clientY - canvas.offsetTop;
-   drawCheckbox(context, document.getElementById('showA'), 20, 40);
+   var x = event.clientX;
+   var y = event.clientY;
+   while (node) {
+     x -= node.offsetLeft - node.scrollLeft;
+     y -= node.offsetTop - node.scrollTop;
+     node = node.offsetParent;
+   }
+   drawCheckbox(context, document.getElementById('showA'), 20, 40, false);
    if (context.isPointInPath(x, y))
      document.getElementById('showA').checked = !(document.getElementById('showA').checked);
-   drawCheckbox(context, document.getElementById('showB'), 20, 60);
+   drawCheckbox(context, document.getElementById('showB'), 20, 60, false);
    if (context.isPointInPath(x, y))
      document.getElementById('showB').checked = !(document.getElementById('showB').checked);
    redraw();
@@ -39812,6 +39897,8 @@
   </div>
 
 
+
+
   <h6>Text</h6> <!-- a v3 feature -->
 
   <dl class="domintro">
@@ -41074,6 +41161,74 @@
   </div>
 
 
+  <h6>Best practices</h6>
+
+  <!--END dev-html--><p><i>This section is non-normative.</i></p><!--START dev-html-->
+
+  <p>When a canvas is interactive, authors should include focusable
+  elements in the element's fallback content corresponding to each
+  focusable part of the canvas, as in the <a
+  href="#drawCustomFocusRingExample">example above</a>.</p>
+
+  <p>To indicate which focusable part of the canvas is currently
+  focused, authors should use the <code
+  title="dom-context-2d-drawOSFocusRing">drawOSFocusRing()</code> method,
+  passing it the element for which a ring is being drawn. This method
+  only draws the focus ring if the element is focused, so that it can
+  simply be called whenever drawing the element, without checking
+  whether the element is focused or not first.</p>
+
+  <p>Authors should avoid implementing text editing controls using the
+  <code>canvas</code> element. Doing so has a large number of
+  disadvantages:</p>
+
+  <ul>
+
+   <li>Mouse placement of the caret has to be reimplemented.</li>
+
+   <li>Keyboard movement of the caret has to be reimplemented (possibly across lines, for multiline text input).</li>
+
+   <li>Scrolling of the text field has to be implemented (horizontally for long lines, vertically for multiline input).</li>
+
+   <li>Native features such as copy-and-paste have to be reimplemented.</li>
+
+   <li>Native features such as spell-checking have to be reimplemented.</li>
+
+   <li>Native features such as drag-and-drop have to be reimplemented.</li>
+
+   <li>Native features such as page-wide text search have to be reimplemented.</li>
+
+   <li>Native features specific to the user, for example custom text
+   services, have to be reimplemented. This is close to impossible
+   since each user might have different services installed, and there
+   is an unbounded set of possible such services.</li>
+
+   <li>Bidirectional text editing has to be reimplemented.</li>
+
+   <li>For multiline text editing, line wrapping has to be implemented for all relevant languages.</li>
+
+   <li>Text selection has to be reimplemented.</li>
+
+   <li>Dragging of bidirectional text selections has to be reimplemented.</li>
+
+   <li>Platform-native keyboard shortcuts have to be reimplemented.</li>
+
+   <li>Platform-native input method editors (IMEs) have to be reimplemented.</li>
+
+   <li>Undo and redo functionality has to be reimplemented.</li>
+
+   <li>Accessibility features such as magnification following the
+   caret or selection have to be reimplemented.</li>
+
+  </ul>
+
+  <p>This is a huge amount of work, and authors are most strongly
+  encouraged to avoid doing any of it by instead using the
+  <code>input</code> element, the <code>textarea</code> element, or
+  the <code title="attr-contenteditable">contenteditable</code>
+  attribute.</p>
+
+
   <h6>Examples</h6>
 
   <!--END dev-html--><p><i>This section is non-normative.</i></p><!--START dev-html-->

|