diff --git a/src/CanvasRenderingContext2d.cc b/src/CanvasRenderingContext2d.cc index 911efeca1..8779e8557 100644 --- a/src/CanvasRenderingContext2d.cc +++ b/src/CanvasRenderingContext2d.cc @@ -1112,8 +1112,8 @@ NAN_METHOD(Context2d::DrawImage) { , dy = 0 , dw = 0 , dh = 0 - , fw = 0 - , fh = 0; + , source_w = 0 + , source_h = 0; cairo_surface_t *surface; @@ -1125,15 +1125,15 @@ NAN_METHOD(Context2d::DrawImage) { if (!img->isComplete()) { return Nan::ThrowError("Image given has not completed loading"); } - fw = sw = img->width; - fh = sh = img->height; + source_w = sw = img->width; + source_h = sh = img->height; surface = img->surface(); // Canvas } else if (Nan::New(Canvas::constructor)->HasInstance(obj)) { Canvas *canvas = Nan::ObjectWrap::Unwrap(obj); - fw = sw = canvas->getWidth(); - fh = sh = canvas->getHeight(); + source_w = sw = canvas->getWidth(); + source_h = sh = canvas->getHeight(); surface = canvas->surface(); // Invalid @@ -1183,10 +1183,11 @@ NAN_METHOD(Context2d::DrawImage) { float fx = (float) dw / sw; float fy = (float) dh / sh; bool needScale = dw != sw || dh != sh; - bool needCut = sw != fw || sh != fh; + bool needCut = sw != source_w || sh != source_h || sx < 0 || sy < 0; + bool needCairoClip = sx < 0 || sy < 0 || sw > source_w || sh > source_h; bool sameCanvas = surface == context->canvas()->surface(); - bool needsExtraSurface = sameCanvas || needCut || needScale; + bool needsExtraSurface = sameCanvas || needCut || needScale || needCairoClip; cairo_surface_t *surfTemp = NULL; cairo_t *ctxTemp = NULL; @@ -1194,6 +1195,18 @@ NAN_METHOD(Context2d::DrawImage) { surfTemp = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, dw, dh); ctxTemp = cairo_create(surfTemp); cairo_scale(ctxTemp, fx, fy); + if (needCairoClip) { + float clip_w = (std::min)(sw, source_w); + float clip_h = (std::min)(sh, source_h); + if (sx > 0) { + clip_w -= sx; + } + if (sy > 0) { + clip_h -= sy; + } + cairo_rectangle(ctxTemp, -sx , -sy , clip_w, clip_h); + cairo_clip(ctxTemp); + } cairo_set_source_surface(ctxTemp, surface, -sx, -sy); cairo_pattern_set_filter(cairo_get_source(ctxTemp), context->state->imageSmoothingEnabled ? context->state->patternQuality : CAIRO_FILTER_NEAREST); cairo_pattern_set_extend(cairo_get_source(ctxTemp), CAIRO_EXTEND_REFLECT); diff --git a/test/public/tests.js b/test/public/tests.js index bed0dde55..1ecb077e6 100644 --- a/test/public/tests.js +++ b/test/public/tests.js @@ -1199,6 +1199,7 @@ gco.forEach(op => { var img2 = new Image() img1.onload = function () { img2.onload = function () { + ctx.globalAlpha = 0.7 ctx.drawImage(img1, 0, 0) ctx.globalCompositeOperation = op ctx.drawImage(img2, 0, 0) @@ -1210,6 +1211,42 @@ gco.forEach(op => { } }) +gco.forEach(op => { + tests['9 args, transform, globalCompositeOperator ' + op] = function (ctx, done) { + var img1 = new Image() + var img2 = new Image() + img1.onload = function () { + img2.onload = function () { + ctx.globalAlpha = 0.7 + ctx.drawImage(img1, 0, 0) + ctx.globalCompositeOperation = op + ctx.rotate(0.1) + ctx.scale(0.8, 1.2) + ctx.translate(5, -5) + ctx.drawImage(img2, -80, -50, 400, 400, 10, 10, 180, 180) + done() + } + img2.src = imageSrc('newcontent.png') + } + img1.src = imageSrc('existing.png') + } +}) + +tests['drawImage issue #1249'] = function (ctx, done) { + var img1 = new Image() + var img2 = new Image() + img1.onload = function () { + img2.onload = function () { + ctx.drawImage(img1, 0, 0, 200, 200) + ctx.drawImage(img2, -8, -8, 18, 18, 0, 0, 200, 200) + ctx.restore() + done() + } + img2.src = imageSrc('checkers.png') + } + img1.src = imageSrc('chrome.jpg') +} + tests['known bug #416'] = function (ctx, done) { var img1 = new Image() var img2 = new Image()