Canvas Improvements and Blob URL Fixes: HtmlUnit 5.3.0

July brings HtmlUnit 5.3.0 with Chrome/Edge 150 support and a release heavily focused on two critical areas: Canvas API correctness and proper Blob URL handling. These improvements address long-standing issues and bring HtmlUnit closer to real browser behavior.

🚀 Version 5.3.0 - July 15, 2026

Blob URL and XMLHttpRequest Overhaul

One of the most significant improvements in this release comes from Lai Quang Duong’s comprehensive rework of Blob URL handling. The changes are substantial:

Blob URL Architecture: I completely refactored URL storage to use a user-agent-wide blob URL store on WebClient, replacing the previous per-Document store. This matches the W3C specification where a blob: URL minted in one document is resolvable from any same-client browsing context. This is a critical correctness fix for applications using Blob URLs across multiple documents.

XMLHttpRequest Origin Checks: Fixed XMLHttpRequest to properly check blob URL origins instead of throwing “No permitted Access-Control-Allow-Origin header” errors. The implementation now correctly validates blob URL access and respects same-origin policies.

XMLHttpRequest Improvements:

  • responseXML() now checks the responseType as the first step, ensuring early validation
  • Fixed error handling when accessing local resources forbidden for security reasons
  • The upload property now correctly returns the same object for repeated calls
  • Improved handling of missing response headers and status text in error scenarios

Canvas API Enhancements

This release includes extensive Canvas improvements, likely the most comprehensive set of Canvas fixes we’ve done:

Path Management:

  • lineTo() now correctly becomes a moveTo() if the current path is empty
  • arc() and ellipse() start point handling has been fixed
  • rect() now correctly creates a separate subpath according to spec
  • close() properly creates a new subpath
  • stroke() only draws if the path is not empty

Rectangle Operations:

  • rect(), strokeRect(), fillRect(), and clearRect() now support negative width/height
  • strokeRect() now respects the lineWidth property
  • Both methods now use double coordinates for better precision

Gradient and Styling:

  • New lineCap and lineJoin properties are now fully supported
  • createLinearGradient() parameter handling has been fixed
  • lineWidth is now properly a float value
  • fill() now supports the winding rule parameter
  • Improved stroke handling with correct BasicStroke properties (lineCap, lineJoin, miterLimit)

Rendering Backend:

  • Proper RenderingHints.VALUE_STROKE_PURE setting for correct right/bottom edge drawing
  • putImageData() now uses BufferedImage for better performance
  • Coordinate precision improvements throughout (translate now uses float coordinates)
  • More robust clip handling in SaveState
  • Font is now properly part of SaveState

Important Fixes:

  • clip() no longer closes the current subpath
  • Consecutive moveTo() calls no longer accumulate orphan subpaths
  • Implicit subpath creation now does a moveTo to the start point

DOM and Range Improvements

Several important fixes improve DOM manipulation correctness:

  • DomElement.setAttributeNode(Attr) now correctly returns the previously set Attr with the same name
  • DomElement.ChildElementsIterator#remove() now works for the last element
  • DomNode.normalize() now recurses into the full subtree, not just direct children
  • Range.setEndBefore() now correctly updates the end
  • Range.getBoundingClientRect() now properly calculates x and y values
  • Range.getClientRects() now supports DomText nodes as well
  • SimpleRange.containedNodes() now works when startNode and endNode are the same

JavaScript Engine Progress

The Rhino team continues making progress with WeakRef support now available, enabling more sophisticated garbage collection patterns. Additionally, work has begun on a new faster interpreter implementation that should provide performance improvements in future releases.

HTML and Form Improvements

  • Option.index property is now fixed for selects using optgroups
  • Missing getter/setter for src and type properties of HTMLEmbedElement added
  • Initial support for the ‘plaintext-only’ value of the contentEditable attribute
  • Setting textarea/input elements to readonly now correctly sets the attribute to ‘’ instead of ‘readOnly’
  • Minor fixes for select option replacement

Security and Documentation

Security: Thanks to MatrixNeoKozak, TransformerFactory and DocumentBuilderFactory are now configured with FEATURE_SECURE_PROCESSING to restrict external DTD and stylesheet references, mitigating remote resource loading during XSLT transformation.

We’ve also added a new comprehensive documentation page: Details about HtmlUnit Security. This page covers important security considerations when using HtmlUnit, helping developers understand the security implications and best practices.

Documentation: Added comprehensive javadoc improvements with MDN links to all JavaScript classes, making it easier for developers to understand the available APIs.

XML Serialization

Ronny Shapiro’s contribution improved asXml() to emit formatting line breaks only where the document contains whitespace. Adjacent elements no longer gain fabricated line breaks that would render as a space—an important fix for proper XML output.

Other Improvements

  • WebSocket client (Jetty) updated to 12.1.11
  • All colors from recent CSS specs added to CssColors
  • Crypto methods now properly return the same object on repeated calls (crypto.subtle, randomUUID())
  • BrowserVersion.getPixelsPerChar() fixed (typo in method name)
  • Chrome/Edge: Screen colorDepth/pixelDepth are now 24
  • Improved PointerEvent simulation of altitudeAngle/azimuthAngle
  • Apache ECharts test case added

Version 5.3.0 is available on Maven Central. Check out the full changes report for the complete list of changes.

Special thanks to Lai Quang Duong for the Blob URL and XMLHttpRequest work, Ronny Shapiro for the XML serialization improvements, and MatrixNeoKozak for the security enhancements. Thanks also to the Rhino team for continued JavaScript engine progress.

Happy testing!

— RBRi


Resources: