         false
       else
         true
+    @dom
+  useDOM: ->
+    @makeDOM()
+    ## Clone if content is static, to enable later re-use
+    if @isStatic
+      @dom.documentElement.cloneNode true
+    else
+      @dom.documentElement
+
+class SVGTopLevel extends SVGContent
+  ###
+  Abstract base class for `SVGSymbol` and `SVGSVG` which have support for
+  `viewBox`, `overflowBox`, and `z-index`.
+  Subclass should define `wrapper` of 'symbol' or 'svg'.
+  Parser will enforce that the content is wrapped in this element.
+  ###
+  makeDOM: ->
+    super()
+    ## Wrap XML in <wrapper>.
+    symbol = @dom.createElementNS SVGNS, @wrapper
+    ## Force `id` to be first attribute.
+    symbol.setAttribute 'id', @id if @id?
+    ## Avoid a layer of indirection for <symbol>/<svg> at top level
+    if @dom.documentElement.nodeName in ['symbol', 'svg'] and
+       not @dom.documentElement.nextSibling?
+      for attribute in @dom.documentElement.attributes
+        unless attribute.name in ['version', 'id'] or attribute.name.startsWith 'xmlns'
+          symbol.setAttribute attribute.name, attribute.value
+      @dom.removeChild doc = @dom.documentElement
+    else
+      doc = @dom
+      ## Allow top-level object to specify <symbol> data.
+      for attribute in ['z-index', 'viewBox', 'overflowBox']
+        if doc.documentElement.hasAttribute attribute
+          symbol.setAttribute attribute,
+            doc.documentElement.getAttribute attribute
+          doc.documentElement.removeAttribute attribute
+    for child in (node for node in doc.childNodes)
+      symbol.appendChild child
+    @dom.appendChild symbol
 
     ## Compute viewBox attribute if absent and wrapping in <symbol>.
-    @viewBox = svgBBox @dom, wrapper == 'symbol'
+    @viewBox = svgBBox @dom, @wrapper == 'symbol'
 
     ## Overflow behavior
     overflow = attributeOrStyle @dom.documentElement, 'overflow'

        if @height == 0
          @viewBox[3] = zeroSizeReplacement
      ## Reset viewBox attribute in case either absent (and computed via
      ## svgBBox) or changed to avoid zeroes.
      @dom.documentElement.setAttribute 'viewBox', @viewBox.join ' '
    @overflowBox = extractOverflowBox @dom
    if wrapper == 'symbol'
      @width = forceWidth if (forceWidth = @getSetting 'forceWidth')?
      @height = forceHeight if (forceHeight = @getSetting 'forceHeight')?
      warnings = []
      unless @width?
        warnings.push 'width'
        @width = 0
      unless @height?
        warnings.push 'height'
        @height = 0
      if warnings.length > 0
        console.warn "Failed to detect #{warnings.join ' and '} of SVG for tile '#{@key}'"
    ## Detect special `width="auto"` and/or `height="auto"` fields for future
    ## processing, and remove them to ensure valid SVG.
    @autoWidth = isAuto @dom, 'width'
    @autoHeight = isAuto @dom, 'height'
    @dom.documentElement.removeAttribute 'width' if @autoWidth
    @dom.documentElement.removeAttribute 'height' if @autoHeight
    @zIndex = extractZIndex @dom.documentElement
    ## Optionally extract <text> nodes for LaTeX output
    if @getSetting 'texText'
      @text = []
      domRecurse @dom.documentElement, (node, parent) =>
        if node.nodeName == 'text'
          @text.push node
          parent.removeChild node
          false # don't recurse into <text>'s children
        else
          true

  doBeforeRender: (render, onResult) ->
    for callback in @beforeRenderQueue
      result = callback.call render, render
      onResult? result, @
  doAfterRender: (render, onResult) ->
    for callback in @afterRenderQueue
      result = callback.call render, render
      onResult? result, @

beforeRender = (fn) ->
  unless currentMapping?
