google / blockly

The web-based visual programming editor.
https://developers.google.com/blockly/
Apache License 2.0
12.52k stars 3.72k forks source link

fix: size text with computed styles even when hidden #8572

Closed gonfunko closed 2 months ago

gonfunko commented 2 months ago

The basics

The details

Resolves

Re-fixes #8277

Proposed Changes

Recently, code that was calling getFastTextWidth() was updated to call getTextWidth() instead, because getFastTextWidth() required knowledge of some styling attributes. Historically, these were derived from the theme/renderer, but with recent changes to move towards using CSS for this purpose, it was thought that we needed to use getTextWidth() instead, which relied on the getComputedTextLength() method of SVG text elements.

Unfortunately, getComputedTextLength() has a significant limitation: it doesn't work when the SVG text element (or any of its parents) has display: none or similar set. This could result in blocks being incorrectly sized when manipulated while not visible, e.g. https://github.com/gonfunko/scratch-blocks/issues/163.

This PR modifies the implementation of getTextWidth() to instead use getComputedStyle() to dynamically calculate the CSS styles applied to an SVG text element, whether through Blockly's built-in styles, injected styles, or user agent stylesheets. This method returns a live CSSStyleDeclaration object, which allows accessing the currently-applicable value of any CSS property. AIUI, this doesn't calculate anything up front, only determining the value of properties when they are accessed, so performance should be (and appears to be) quite good. Moreover, this appears to return e.g. the font size/weight/face applied to an element even if it is hidden at the moment, and resolves the aforementioned issues.

This PR additionally removes exception handling and size estimation code that was presumably present due to an IE 10 behavior that caused getComputedTextLength() to throw for hidden elements.