androidsvg icon indicating copy to clipboard operation
androidsvg copied to clipboard

Support "inherit" in CSS rules

Open alpha0010 opened this issue 4 years ago • 10 comments
trafficstars

The top half of all symbols from a score generated with Verovio are cut off.

Expected: expected render

Actual: actual render

SVG file: thesvg.svg.zip

alpha0010 avatar Jun 07 '21 18:06 alpha0010

Thanks for the report.

I remember seeing you post this recently on Stack Overflow, and I was hoping that my library didn't have this bug. : Oh well :0

I'll take a look.

BigBadaboom avatar Jun 09 '21 05:06 BigBadaboom

If helpful to you, I determined text alignment issue appears to be related to nested tspan elements. Flattening the hierarchy resolved the issue for me. (Not particularly sure why the font size is larger though.)

    for (node in svgXml.xPath("//*[local-name()=\"text\"]")) {
      val textNodes = recurseGetTextNodes(node, emptyMap())
      if (textNodes.isEmpty()) {
        continue
      }

      for (tspan in node.elementsOfType("tspan")) {
        node.removeChild(tspan)
      }
      for (textNode in textNodes) {
        node.appendChild(textNode)
      }
    }

// [...]

  private fun recurseGetTextNodes(elem: Node, parentAttr: Map<String, String>): List<Element> {
    val children = elem.elementsOfType("tspan").toList()
    if (children.isEmpty()) {
      if (elem.textContent.isBlank()) {
        return emptyList()
      }
      val textNode = elem.ownerDocument.createElement("tspan")
      textNode.appendChild(elem.ownerDocument.createTextNode(elem.textContent))
      for ((attr, attrValue) in parentAttr) {
        textNode.setAttribute(attr, attrValue)
      }
      return listOf(textNode)
    }

    val output = mutableListOf<Element>()
    for (child in children) {
      val textNodes = recurseGetTextNodes(
        child,
        mergeTextAttributes(child, parentAttr)
      )
      output.addAll(textNodes)
    }
    return output
  }

  private fun mergeTextAttributes(
    node: Node,
    parentAttr: Map<String, String>
  ): Map<String, String> {
    val knownAttrs =
      arrayOf("x", "y", "font-family", "font-size", "font-style", "text-anchor", "class")
    val output = mutableMapOf<String, String>()
    for (attr in knownAttrs) {
      val attrValue = node.attributes.getNamedItem(attr)?.textContent ?: parentAttr[attr]
      if (attrValue != null) {
        output[attr] = attrValue
      }
    }
    return output
  }

alpha0010 avatar Jun 16 '21 15:06 alpha0010

Hi. Thanks for the research and the clues.

  • I assume by "text alignment issue", you mean the mis-aligned title text?

  • I'm pretty sure the font size issue is due to different fonts being used. Your SVG specifies font-family: Times;. However, Android SVG doesn't know what that font is, since Times isn't a standard Android system font. You can fix that by copying the Times font to your app's assets directory (as Times.ttf). Then add the following to your app before you render the SVG:

    SVG.registerExternalFileResolver(new SimpleAssetResolver(context.getAssets()));
    

    The test should render correctly then. Do the same for any other fonts one of your SVGs may need

  • Other than the clipped note shapes, is there anything else wrong that I am missing? I see there seems to be stuff missing from the bottom of the page. Is that actually missing, or is it just not included in your screenshot?

Paul

BigBadaboom avatar Jun 17 '21 16:06 BigBadaboom

Yes, alignment referred to the title text.

Adding the Times font did not change anything, best as I could tell. (I did add a symbolic font, which fixed the "symbol missing empty box" render issue I had with some other files.)

Oops, I just pulled it into GIMP to generate a png, without checking the results very well. Apparently this is a difficult SVG to render. Here is a better screenshot. Clipped note shapes and text alignment (and maybe font size? potentially something on my end?) are the issues I am having.

expected-render

alpha0010 avatar Jun 17 '21 20:06 alpha0010

Traced down the font issue. Appears CSS styles did not propagate the font-family to the main text. Creating an explicit rule renderOptions.css(".text { font-family: Times; }") fixed that.

alpha0010 avatar Jul 13 '21 17:07 alpha0010

Likely related: https://github.com/Kozea/CairoSVG/issues/300

alpha0010 avatar Jul 20 '21 20:07 alpha0010

Yes. You're right. AndroidSVG's CSS code doesn't support "inherit" yet. Mainly because - as that commenter said - it requires quite a bit of work,. And "inherit" is something that is rarely used.

Is that person's solution something that would work for you?

BigBadaboom avatar Jul 21 '21 04:07 BigBadaboom

A different renderer I was also using had no support for symbol elements. Scripting a conversion of symbols into multiple path defs, one for each different transform used of the specified symbol, resolved my issue (both for this library and the other renderer).

alpha0010 avatar Jul 21 '21 12:07 alpha0010

So, I am not dealing with the problems mentioned here anymore. (Up to you if you want to close this issue or not.)

alpha0010 avatar Jul 21 '21 12:07 alpha0010

Thanks for letting me know. I'll leave this around for now, and treat it as a feature request for "inherit" support.

BigBadaboom avatar Jul 21 '21 16:07 BigBadaboom