Removed getStrokeBBox() and extended getBBox() with its functionality (plus more). (ACTION-3581)
authorCameron McCormack <cam@mcc.id.au>
Tue, 04 Feb 2014 15:03:33 +1100
changeset 599 c144d4186eeb
parent 598 8699c4121a13
child 600 bd73dcb53208
Removed getStrokeBBox() and extended getBBox() with its functionality (plus more). (ACTION-3581)
master/changes.html
master/coords.html
master/style/default_svg.css
master/types.html
--- a/master/changes.html	Tue Feb 04 11:30:05 2014 +1100
+++ b/master/changes.html	Tue Feb 04 15:03:33 2014 +1100
@@ -77,7 +77,7 @@
 
   <li>Added constructors to <a>SVGNumber</a>, <a>SVGLength</a>, <a>SVGAngle</a> and <a>SVGRect</a>.</li>
 
-  <li>Added <a href="types.html#__svg__SVGGraphicsElement__getStrokeBBox">getStrokeBBox</a> to get the tight stroke bounding box.</li>
+  <li>Added getStrokeBBox on <a>SVGGraphicsElement</a> to get the tight stroke bounding box.</li>
 
   <li>Added base value accessors on <a>SVGAnimatedLength</a> and <a>SVGAnimatedLengthList</a> for each of the CSS length units supported.</li>
 
@@ -90,6 +90,8 @@
   <li class='added-since-last-wd'>Added <a href="types.html#__svg__SVGDocument__activeElement">activeElement</a> attribute to <a>Document</a>.</li>
 
   <li class='added-since-last-wd'>Made <a>SVGElement</a> implement the <a>GlobalEventHandlers</a> interface from HTML.</li>
+
+  <li class='added-since-last-wd'>Removed getStrokeBBox from <a>SVGGraphicsElement</a> and extended <a href="types.html#__svg__SVGGraphicsElement__getBBox">getBBox</a> with a dictionary argument that controls which parts of the element are included in the returned bounding box.</li>
 </ul>
 
 <h3 id="structure">Document Structure chapter</h3>
@@ -129,6 +131,7 @@
 <ul>
   <li>Added constructors to <a>SVGPoint</a>, <a>SVGMatrix</a> and <a>SVGTransform</a>.</li>
   <li>Make <a>SVGMatrix</a>.skew{X,Y} throw an exception on bad values.</li>
+  <li class='added-since-last-wd'>Added an algorithm which can compute a bounding box for an element.</li>
 </ul>
 
 <h3 id="paths">Paths chapter</h3>
--- a/master/coords.html	Tue Feb 04 11:30:05 2014 +1100
+++ b/master/coords.html	Tue Feb 04 15:03:33 2014 +1100
@@ -1029,6 +1029,114 @@
 bottom rectangle of the group illustrates what happens when
 values specified in percentage units are scaled.</p>
 
+<div class="ready-for-wg-review">
+
+<h2 id="BoundingBoxes">Bounding boxes</h2>
+
+<p>The bounding box of an element is an axis-aligned rectangle in a given
+coordinate system that tightly contains certain parts of the element.
+The following algorithm describes how to compute the bounding box for a
+given element.  The inputs to the algorithm are:</p>
+
+<ul>
+  <li><var>element</var>, the element we are computing a bounding box for;</li>
+  <li><var>space</var>, a coordinate space in which the bounding box will be computed;</li>
+  <li><var>fill</var>, a boolean indicating whether the bounding box includes the geometry of the element and its descendants;</li>
+  <li><var>stroke</var>, a boolean indicating whether the bounding box includes the stroke of the element and its descendants;</li>
+  <li><var>markers</var>, a boolean indicating whether the bounding box includes the markers of the element and its descendants; and</li>
+  <li><var>clipped</var>, a boolean indicating whether the bounding box is affected by any clipping paths applied to the element and its descendants.</li>
+</ul>
+
+<p class='issue'>Need to define what the union of rectangles with no area means.</p>
+
+<p>The algorithm to compute the bounding box is as follows, depending on the type of <var>element</var>:</p>
+
+<dl class="switch">
+  <dt>a <a>shape</a></dt>
+  <dt>a <a>text content element</a></dt>
+  <dt>an <a>'a'</a> element within a <a>text content element</a></dt>
+  <dd>
+    <ol class="algorithm">
+      <li>Let <var>box</var> be a rectangle initialized to (0, 0, 0, 0).</li>
+      <li>Let <var>fill-shape</var> be the <a>equivalent path</a> of <var>element</var>
+      if it is a <a>shape</a>, or a shape that includes each of the glyph cells corresponding
+      to the text within the elements otherwise.</li>
+      <li>If <var>fill</var> is true, then set <var>box</var> to the tightest rectangle
+      in the coordinate system <var>space</var> that contains <var>fill-shape</var>.
+      <p class='issue'>We should say something about allowed approximations such as using the bounding
+      box of a B├ęzier segment's control points.</p></li>
+      <li>If <var>stroke</var> is true and the element's <a>'stroke'</a> is anything other than
+      <span class='prop-value'>none</span>, then set <var>box</var> to be the union of <var>box</var> and the
+      tightest rectangle in coordinate system <var>space</var> that contains the <a href="painting.html#StrokeShape">stroke shape</a> of the
+      element, with the assumption that the element has no dash pattern.</li>
+      <li>If <var>markers</var> is true, then for each marker <var>marker</var> rendered on the element:
+        <ol>
+          <li>For each descendant <a>graphics element</a> <var>child</var> of the <a>'marker element'</a> element
+          that defines <var>marker</var>'s content:
+            <ol>
+              <li>If <var>child</var> has an ancestor element within the <a>'marker element'</a> that is
+              <span class='prop-value'>'display: none'</span>, has a failing <a>conditional processing attribute</a>,
+              or is not an <a>'a'</a>, <a>'g'</a>, <a>'svg'</a> or <a>'switch'</a> element, then
+              continue to the next descendant <a>graphics element</a>.</li>
+              <li>Otherwise, set <var>box</var> to be the union of <var>box</var> and the result of invoking the
+              algorithm to compute a bounding box with <var>child</var> as the element,
+              <var>space</var> as the target coordinate space, true for <var>fill</var>,
+              <var>stroke</var> and <var>markers</var>, and <var>clipped</var> for <var>clipped</var>.
+              <p class='issue'>Need to determine whether <span class='prop-value'>'display: none'</span> on the
+              <a>'marker element'</a> element itself has any effect here.</p></li>
+            </ol>
+          </li>
+        </ol>
+      </li>
+      <li>If <var>clipped</var> is true and the value of <a>'clip-path'</a> on <var>element</var> is not
+      <span class='prop-value'>none</span>, then set <var>box</var> to be the tighest rectangle
+      in coordinate system <var>space</var> that contains the intersection of <var>box</var> and the clipping path.</li>
+      <li>Return <var>box</var>.</li>
+    </ol>
+  </dd>
+  <dt>a <a>container element</a></dt>
+  <dt><a>'use'</a></dt>
+  <dd>
+    <ol class="algorithm">
+      <li>Let <var>box</var> be a rectangle initialized to (0, 0, 0, 0).</li>
+      <li>Let <var>parent</var> be the <a>container element</a> if it is one, or the
+      root of the <a>'use'</a> element's shadow tree otherwise.</li>
+      <li>For each descendant <a>graphics element</a> <var>child</var> of <var>parent</var>:
+        <ol>
+          <li>If <var>child</var> has an ancestor element within <var>parent</var> that is
+          <span class='prop-value'>'display: none'</span>, has a failing <a>conditional processing attribute</a>,
+          or is not an <a>'a'</a>, <a>'g'</a>, <a>'svg'</a> or <a>'switch'</a> element, then
+          continue to the next descendant <a>graphics element</a>.</li>
+          <li>Otherwise, set <var>box</var> to be the union of <var>box</var> and the result of invoking the
+          algorithm to compute a bounding box with <var>child</var> as the element
+          and the same values for <var>space</var>, <var>fill</var>, <var>stroke</var>,
+          <var>markers</var> and <var>clipped</var> as the corresponding algorithm input values.</li>
+        </ol>
+      </li>
+      <li>Return <var>box</var>.</li>
+    </ol>
+  </dd>
+  <dt><a>'canvas'</a></dt>
+  <dt><a>'foreignObject'</a></dt>
+  <dt><a>'iframe'</a></dt>
+  <dt><a>'image'</a></dt>
+  <dt><a>'video'</a></dt>
+  <dd>
+    <ol class="algorithm">
+      <li>Return the tightest rectangle in coordinate space <var>space</var> that
+      contains the rectangle defined by the 
+      <span class='attr-name'>'x'</span>,
+      <span class='attr-name'>'y'</span>,
+      <span class='attr-name'>'width'</span> and
+      <span class='attr-name'>'height'</span> attributes of the element.
+      <p class='issue'>This returns a bounding box even if <var>fill</var> is false. Is this what we want?</p>
+      </li>
+    </ol>
+  </dd>
+</dl>
+
+</div>
+
 <h2 id="ObjectBoundingBoxUnits">Object bounding box units</h2>
 
 <p id="ObjectBoundingBox">The following elements offer the option of expressing
@@ -1039,6 +1147,9 @@
 
 <p class="issue">Need a line for <a>'meshGradient'</a>.</p>
 
+<p class="issue">Need to invoke the bounding box computation algorithm from the previous
+section with <var>fill</var> = true and the other options false.</p>
+
 <table class='vert'>
   <tr>
     <th>Element</th>
--- a/master/style/default_svg.css	Tue Feb 04 11:30:05 2014 +1100
+++ b/master/style/default_svg.css	Tue Feb 04 15:03:33 2014 +1100
@@ -379,6 +379,15 @@
 table.propdef.attrdef th:first-child + th + th + th,
 table.propdef.attrdef td:first-child + td + td + td { width: 6em; padding-right: 0 !important }
 
+ol.algorithm ol {
+  border-left: 1px solid #90b8de;
+  margin-left: 1em;
+}
+ol.algorithm ol.algorithm {
+  border-left: none;
+  margin-left: 0;
+}
+
 /* HTML5-like switch statements. */
 dl.switch > dd > ol.only {
   margin-left: 0;
--- a/master/types.html	Tue Feb 04 11:30:05 2014 +1100
+++ b/master/types.html	Tue Feb 04 15:03:33 2014 +1100
@@ -4017,14 +4017,20 @@
 <a>'transform'</a> property applies to all <a>SVGGraphicsElement</a>. All <a>SVGGraphicsElement</a>
 have a bounding box in current user space.</p>
 
-<pre class="idl">interface <b>SVGGraphicsElement</b> : <a>SVGElement</a> {
+<pre class="idl">dictionary <b id="SVGBoundingBoxOptions">SVGBoundingBoxOptions</b> {
+  bool fill = true;
+  bool stroke = false;
+  bool markers = false;
+  bool clipped = false;
+};
+
+interface <b>SVGGraphicsElement</b> : <a>SVGElement</a> {
   readonly attribute <a class="idlinterface" href="coords.html#InterfaceSVGAnimatedTransformList">SVGAnimatedTransformList</a> <a href="types.html#__svg__SVGGraphicsElement__transform">transform</a>;
 
   readonly attribute <a class="idlinterface" href="types.html#InterfaceSVGElement">SVGElement</a>? <a href="types.html#__svg__SVGGraphicsElement__nearestViewportElement">nearestViewportElement</a>;
   readonly attribute <a class="idlinterface" href="types.html#InterfaceSVGElement">SVGElement</a>? <a href="types.html#__svg__SVGGraphicsElement__farthestViewportElement">farthestViewportElement</a>;
 
-  <a class="idlinterface" href="types.html#InterfaceSVGRect">SVGRect</a> <a href="types.html#__svg__SVGGraphicsElement__getBBox">getBBox</a>();
-  <a class="idlinterface" href="types.html#InterfaceSVGRect">SVGRect</a> <a href="types.html#__svg__SVGGraphicsElement__getStrokeBBox">getStrokeBBox</a>();
+  <a class="idlinterface" href="types.html#InterfaceSVGRect">SVGRect</a> <a href="types.html#__svg__SVGGraphicsElement__getBBox">getBBox</a>(optional <a href="#SVGBoundingBoxOptions">SVGBoundingBoxOptions</a> options);
   <a class="idlinterface" href="coords.html#InterfaceSVGMatrix">SVGMatrix</a>? <a href="types.html#__svg__SVGGraphicsElement__getCTM">getCTM</a>();
   <a class="idlinterface" href="coords.html#InterfaceSVGMatrix">SVGMatrix</a>? <a href="types.html#__svg__SVGGraphicsElement__getScreenCTM">getScreenCTM</a>();
   <a class="idlinterface" href="coords.html#InterfaceSVGMatrix">SVGMatrix</a> <a href="types.html#__svg__SVGGraphicsElement__getTransformToElement">getTransformToElement</a>(<a class="idlinterface" href="types.html#InterfaceSVGGraphicsElement">SVGGraphicsElement</a> element);
@@ -4063,16 +4069,17 @@
   </dd>
   <dt class="operations-header">Operations:</dt>
   <dd>
+    <div class="ready-for-wg-review">
     <dl class="attributes">
-      <dt id="__svg__SVGGraphicsElement__getBBox" class="operation first-child"><a class="idlinterface" href="types.html#InterfaceSVGRect">SVGRect</a> <b>getBBox</b>()</dt>
+      <dt id="__svg__SVGGraphicsElement__getBBox" class="operation first-child"><a class="idlinterface" href="types.html#InterfaceSVGRect">SVGRect</a> <b>getBBox</b>(optional <a href="#SVGBoundingBoxOptions">SVGBoundingBoxOptions</a> <var>options</var>)</dt>
       <dd class="operation">
         <div>
-          Returns the tight bounding box in current user space (i.e., after
-          application of the <a>'transform'</a> property) on the
-          geometry of all contained graphics elements, exclusive of stroking, clipping, masking and
-          filter effects. Note that getBBox must return the actual bounding box
-          at the time the method was called, even in case the element has not
-          yet been rendered.
+          <p>Returns the result of invoking the <a href="coords.html#BoundingBoxes">bounding box algorithm</a>
+          for the element, with <var>fill</var>, <var>stroke</var>, <var>markers</var>
+          and <var>clipped</var> members of the <var>options</var> dictionary argument
+          used to control which parts of the element are included in the bounding box,
+	  using the element's user space as the coordinate system to return the
+	  bounding box in.</p>
         </div>
         <dl class="operation">
           <dt class="returns-header">Returns</dt>
@@ -4083,29 +4090,9 @@
           </dd>
         </dl>
       </dd>
-      <dt id="__svg__SVGGraphicsElement__getStrokeBBox" class="operation"><a class="idlinterface" href="types.html#InterfaceSVGRect">SVGRect</a> <b>getStrokeBBox</b>()</dt>
-      <dd class="operation">
-        <div>
-          Returns the union of the tight bounding box (see <a>getBBox</a>), the stroke
-          bounding box and the stroke bounding box of applied markers in current user space
-          (i.e., after application of the <a>'transform'</a> property) on the
-          geometry of all contained graphics elements, exclusive of clipping, masking and
-          filter effects. The stroke bounding box takes the stroke style
-          properties <a>'stroke-width'</a>, <a>'stroke-linecap'</a>, <a>'stroke-linejoin'</a>,
-          <a>'stroke-miterlimit'</a>, <a>'stroke-dasharray'</a> and <a>'stroke-dashoffset'</a>
-          into account. Note that getStrokeBBox must
-          return the actual union of the bounding box at the time the method was called,
-          even in case the element has not yet been rendered.
-        </div>
-        <dl class="operation">
-          <dt class="returns-header">Returns</dt>
-          <dd>
-            <div>
-              An <a>SVGRect</a> object that defines the stroke bounding box.
-            </div>
-          </dd>
-        </dl>
-      </dd>
+    </dl>
+    </div>
+    <dl class="attributes">
       <dt id="__svg__SVGGraphicsElement__getCTM" class="operation"><a class="idlinterface" href="coords.html#InterfaceSVGMatrix">SVGMatrix</a>? <b>getCTM</b>()</dt>
       <dd class="operation">
         <div>