Skip to content

feat: [#241] Add canvas adapter pattern for pluggable rendering support (vol.2)#2069

Open
RAprogramm wants to merge 40 commits intocapricorn86:masterfrom
RAprogramm:master
Open

feat: [#241] Add canvas adapter pattern for pluggable rendering support (vol.2)#2069
RAprogramm wants to merge 40 commits intocapricorn86:masterfrom
RAprogramm:master

Conversation

@RAprogramm
Copy link
Copy Markdown

@RAprogramm RAprogramm commented Feb 20, 2026

the part 2 of this accidentally closed PR

Message from previous PR
#2043 (review)


Closes #241

capricorn86 and others added 26 commits January 23, 2026 01:19
…ering support

Adds ICanvasAdapter interface and static setCanvasAdapter() method to HTMLCanvasElement,
allowing users to plug in real canvas implementations like node-canvas.

Changes:
- Add ICanvasAdapter interface with getContext(), toDataURL(), toBlob() methods
- Add HTMLCanvasElement.setCanvasAdapter() and getCanvasAdapter() static methods
- Delegate canvas operations to adapter when set
- Add NodeCanvasAdapter implementation using node-canvas library
- Add comprehensive tests (44 new tests)

This enables real canvas rendering in Happy-DOM when node-canvas is installed:

```typescript
import { HTMLCanvasElement } from 'happy-dom';
import { NodeCanvasAdapter } from 'happy-dom/lib/nodes/html-canvas-element/adapters/NodeCanvasAdapter.js';

HTMLCanvasElement.setCanvasAdapter(new NodeCanvasAdapter());
// Now canvas.getContext('2d') returns real CanvasRenderingContext2D
```

Closes capricorn86#241
- Fix member ordering in HTMLCanvasElement class
- Add curly braces to all if statements
- Add public access modifiers to methods
- Add JSDoc comments for all parameters
- Use angle bracket type assertions in tests
- Fix code formatting per project standards
…ning incorrect values (capricorn86#1953)

- Fixed focusNode getter to return the correct focus boundary point
based on selection direction
- Fixed focusOffset getter to return the correct focus offset based on
selection direction
…f EcmaScript modules (capricorn86#2050)

* feat: [capricorn86#2049] Adds support for caching the compiled code of EcmaScript modules

* feat: [capricorn86#2049] Adds support for caching the compiled code of EcmaScript modules

* feat: [capricorn86#2049] Adds support for caching the compiled code of EcmaScript modules
… according to spec (capricorn86#1960)

* fix: [capricorn86#1955] Conforming stepUp and stepDown on HTMLInputElement to spec for number inputs

* chore: [capricorn86#1960] Fixes implementation to follow the spec and the project coding style

* chore: [capricorn86#1960] Fixes implementation to follow the spec and the project coding style

---------
…coding (capricorn86#2016)

- Replace decodeHTMLAttributeValue with entities.decodeHTMLAttribute
- Replace decodeHTMLEntities with entities.decodeHTML
- Replace decodeXMLAttributeValue with entities.decodeXML
- Replace decodeXMLEntities with entities.decodeXML
- Replace encodeTextContent with entities.escapeText
- Add entities@6 as dependency
- Remove unused regex patterns and lookup tables
- Add test for numeric character reference decoding in attributes

This fixes issue capricorn86#1947 where numeric character references like &capricorn86#34;
and " were not being decoded in HTML attribute values.
… character references in attr values (capricorn86#1948)

- attribute values can contain named and numeric character references
  per https://html.spec.whatwg.org/multipage/syntax.html#syntax-attribute-value
- add decoding for all numeric character references
- add decoding for ', this could probably appear in single-quoted
  attribute values
- ignore other named character references, the list is huge
* fix: Node.replaceWith does not throw w/o parent

```js
let div = document.createElement("div");
let span = document.createElement("span");

div.parentNode; // null
span.parentNode; // null

div.replaceWith(span); // ok
```

* chore: remove unused DOMException import

* chore: [#0] Adds unit test

---------
…6#2027)

* fix: [capricorn86#1959] Implement Text.wholeText property

* fix: [capricorn86#1959] Implement Text.wholeText property

---------
…w flow content (capricorn86#2058)

Fixes capricorn86#2052

## Problem

The caption element was incorrectly configured with contentModel: textOrComments,
which only allowed text nodes and comments. Per the HTML spec, caption elements
should contain flow content (inline and block elements), except table elements.

This caused elements like <b>, <em>, <span>, etc. to be incorrectly moved
outside the caption during parsing.

## Changes

### packages/happy-dom/src/config/HTMLElementConfig.ts

Updated caption element configuration to match the HTML spec and follow the
same pattern as td/th elements:

- Changed contentModel from textOrComments to noForbiddenFirstLevelDescendants
- Added forbiddenDescendants: table structure elements (table, tbody, thead,
  tfoot, tr, td, th, col, colgroup)
- Added permittedParents: ['table'] to ensure caption only appears in tables

### packages/happy-dom/test/html-parser/HTMLParser.malformedHTML.test.ts

Added comprehensive test coverage for caption element content model:
- Inline elements preservation (b, strong, em, span, a)
- Nested inline elements
- Block-level elements (p, div)
- Table element prohibition
- Content serialization
- permittedParents validation (wrong parent, standalone, correct parent)

## Implementation Details

This fix follows the same pattern as PR capricorn86#2007 for paragraph elements, using
the existing noForbiddenFirstLevelDescendants content model. While this
doesn't recursively check deeply nested table elements, it matches the
existing codebase patterns and handles the vast majority of real-world cases.
…SS spec (capricorn86#2062)

* fix: [capricorn86#2057] Support Unicode characters in selectors per CSS spec

The CSS specification allows identifiers (class names, IDs, element names)
to contain ISO 10646 characters U+00A0 and higher. The regex patterns in
SelectorParser.ts were only allowing ASCII characters plus a hardcoded
workaround for guillemets.

This change updates both SELECTOR_REGEXP and SIMPLE_SELECTOR_REGEXP to
accept characters in the range \u00A0-\uFFFF, which covers Greek letters,
CJK characters, Cyrillic, Arabic, Hebrew, and other Unicode scripts.

* chore: [capricorn86#2057] Adds unit tests

* chore: [capricorn86#2057] Adds unit tests

---------
…ricorn86#2059)

* fix: [capricorn86#2042] Support CSS gradients with rgba() colors

This fix resolves an issue where CSS background properties containing
linear gradients with rgba() color values would return empty strings.

Root Cause:
- GRADIENT_REGEXP pattern used [^)]+ which stopped at the first closing
  parenthesis, failing to match gradients with nested rgba() functions
- String splitting logic didn't respect nested parentheses, incorrectly
  splitting rgba(0, 0, 0, 0) into multiple invalid parts

Solution:
- Updated GRADIENT_REGEXP to handle one level of nested parentheses
- Improved getGradient() to split commas while respecting parentheses depth
- Added splitByComma() and splitBySpace() helper functions to properly
  handle nested parentheses when parsing CSS values
- Updated getBackground() and getBackgroundImage() to use new helpers

Tests:
- Added 15 comprehensive test cases covering rgba(), hsla(), rgb(), hsl()
- Tests include repeating gradients, conic gradients, multiple gradients
- Tests verify edge cases: many color stops, decimal values, whitespace
- All 7,184 tests pass

chore: [capricorn86#2042] Format test file

* fix: [capricorn86#2042] Improves performance on splitting

* fix: [capricorn86#2042] Improves performance on splitting

* fix: [capricorn86#2042] Improves performance on splitting

---------
…or with has expression (capricorn86#2068)

* fix: [capricorn86#1910] Fixes issue when parsing complex CSS has expression

* fix: [capricorn86#1910] Fixes issue when parsing complex CSS has expression

* fix: [capricorn86#1910] Fixes issue when parsing complex CSS has expression
…dapter

- Add 13 comprehensive tests for CanvasAdapter
- Add .gitignore and .npmignore files
- Enhance README.md with usage examples and API documentation
- Update package.json with scripts, keywords and complete metadata
- Update tsconfig.json with additional compiler options
- Add canvas documentation to happy-dom README
@RAprogramm
Copy link
Copy Markdown
Author

RAprogramm commented Feb 20, 2026

@capricorn86, CI is failing because of tests in @happy-dom/node-canvas-adapter — it requires the native canvas library, which isn't available in the CI environment.

Since the canvas adapter is an optional dependency, what's the best approach:

  1. Skip these tests in CI?
  2. Add canvas dependencies installation to the workflow?
  3. Use mocks for tests in CI?

Could you advise on the right way to handle this?

Thanks!

@capricorn86
Copy link
Copy Markdown
Owner

capricorn86 commented Feb 20, 2026

@capricorn86, CI is failing because of tests in @happy-dom/node-canvas-adapter — it requires the native canvas library, which isn't available in the CI environment.

Since the canvas adapter is an optional dependency, what's the best approach:

  1. Skip these tests in CI?
  2. Add canvas dependencies installation to the workflow?
  3. Use mocks for tests in CI?

Could you advise on the right way to handle this?

Thanks!

@RAprogramm It looks really good! I will soon look into this more closely and see if something is missing, but I don't think so.

I think that the library can be added as dev dependency (in addition to be an optional dependency). It should solve the problem as it will only be available in the dev environment and not in the published package.

@capricorn86
Copy link
Copy Markdown
Owner

Update: I've been working on adding types and make sure that functions such as drawImage() will work with various types.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add support for Canvas