Skip to content

Commit c6a1546

Browse files
calvinsomethingzbjornson
authored andcommitted
fix repeat-x/y support in createPattern()
1 parent f8d4949 commit c6a1546

File tree

3 files changed

+50
-1
lines changed

3 files changed

+50
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ project adheres to [Semantic Versioning](http://semver.org/).
1313
### Fixed
1414
* `rgba(r,g,b)` with no alpha should parse as opaque, not transparent. ([#2029](https://github.com/Automattic/node-canvas/issues/2029))
1515
* Typo in `PngConfig.filters` types. ([#2072](https://github.com/Automattic/node-canvas/issues/2072))
16+
* `createPattern()` always used "repeat" mode; now supports "repeat-x" and "repeat-y". ([#2066](https://github.com/Automattic/node-canvas/issues/2066))
1617

1718
2.9.3
1819
==================

src/CanvasRenderingContext2d.cc

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,7 @@ Context2d::setFillRule(v8::Local<v8::Value> value) {
367367
void
368368
Context2d::fill(bool preserve) {
369369
cairo_pattern_t *new_pattern;
370+
bool needsRestore = false;
370371
if (state->fillPattern) {
371372
if (state->globalAlpha < 1) {
372373
new_pattern = create_transparent_pattern(state->fillPattern, state->globalAlpha);
@@ -381,10 +382,36 @@ Context2d::fill(bool preserve) {
381382
cairo_set_source(_context, state->fillPattern);
382383
}
383384
repeat_type_t repeat = Pattern::get_repeat_type_for_cairo_pattern(state->fillPattern);
384-
if (NO_REPEAT == repeat) {
385+
if (repeat == NO_REPEAT) {
385386
cairo_pattern_set_extend(cairo_get_source(_context), CAIRO_EXTEND_NONE);
387+
} else if (repeat == REPEAT) {
388+
cairo_pattern_set_extend(cairo_get_source(_context), CAIRO_EXTEND_REPEAT);
386389
} else {
390+
cairo_save(_context);
391+
cairo_path_t *savedPath = cairo_copy_path(_context);
392+
cairo_surface_t *patternSurface = nullptr;
393+
cairo_pattern_get_surface(cairo_get_source(_context), &patternSurface);
394+
395+
double width, height;
396+
if (repeat == REPEAT_X) {
397+
double x1, x2;
398+
cairo_path_extents(_context, &x1, nullptr, &x2, nullptr);
399+
width = x2 - x1;
400+
height = cairo_image_surface_get_height(patternSurface);
401+
} else {
402+
double y1, y2;
403+
cairo_path_extents(_context, nullptr, &y1, nullptr, &y2);
404+
width = cairo_image_surface_get_width(patternSurface);
405+
height = y2 - y1;
406+
}
407+
408+
cairo_new_path(_context);
409+
cairo_rectangle(_context, 0, 0, width, height);
410+
cairo_clip(_context);
411+
cairo_append_path(_context, savedPath);
412+
cairo_path_destroy(savedPath);
387413
cairo_pattern_set_extend(cairo_get_source(_context), CAIRO_EXTEND_REPEAT);
414+
needsRestore = true;
388415
}
389416
} else if (state->fillGradient) {
390417
if (state->globalAlpha < 1) {
@@ -412,6 +439,9 @@ Context2d::fill(bool preserve) {
412439
? shadow(cairo_fill)
413440
: cairo_fill(_context);
414441
}
442+
if (needsRestore) {
443+
cairo_restore(_context);
444+
}
415445
}
416446

417447
/*

test/public/tests.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,24 @@ tests['createPattern() with globalAlpha'] = function (ctx, done) {
471471
img.src = imageSrc('face.jpeg')
472472
}
473473

474+
tests['createPattern() repeat-x and repeat-y'] = function (ctx, done) {
475+
const img = new Image()
476+
img.onload = function () {
477+
ctx.scale(0.1, 0.1)
478+
ctx.lineStyle = 'black'
479+
ctx.lineWidth = 10
480+
ctx.fillStyle = ctx.createPattern(img, 'repeat-x')
481+
ctx.fillRect(0, 0, 900, 900)
482+
ctx.strokeRect(0, 0, 900, 900)
483+
ctx.translate(1000, 1000)
484+
ctx.fillStyle = ctx.createPattern(img, 'repeat-y')
485+
ctx.fillRect(0, 0, 900, 900)
486+
ctx.strokeRect(0, 0, 900, 900)
487+
done()
488+
}
489+
img.src = imageSrc('face.jpeg')
490+
}
491+
474492
tests['createPattern() no-repeat'] = function (ctx, done) {
475493
const img = new Image()
476494
img.onload = function () {

0 commit comments

Comments
 (0)