Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(118)

Side by Side Diff: Source/core/html/canvas/CanvasRenderingContext2D.cpp

Issue 181693006: Refactoring source image usage in CanvasRenderingContext2D (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: moar goodness Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved. 2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
3 * Copyright (C) 2008, 2010 Nokia Corporation and/or its subsidiary(-ies) 3 * Copyright (C) 2008, 2010 Nokia Corporation and/or its subsidiary(-ies)
4 * Copyright (C) 2007 Alp Toker <alp@atoker.com> 4 * Copyright (C) 2007 Alp Toker <alp@atoker.com>
5 * Copyright (C) 2008 Eric Seidel <eric@webkit.org> 5 * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
6 * Copyright (C) 2008 Dirk Schulze <krit@webkit.org> 6 * Copyright (C) 2008 Dirk Schulze <krit@webkit.org>
7 * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved. 7 * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
8 * Copyright (C) 2012, 2013 Intel Corporation. All rights reserved. 8 * Copyright (C) 2012, 2013 Intel Corporation. All rights reserved.
9 * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved. 9 * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved.
10 * 10 *
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
56 #include "core/html/canvas/DOMPath.h" 56 #include "core/html/canvas/DOMPath.h"
57 #include "core/frame/ImageBitmap.h" 57 #include "core/frame/ImageBitmap.h"
58 #include "core/rendering/RenderImage.h" 58 #include "core/rendering/RenderImage.h"
59 #include "core/rendering/RenderLayer.h" 59 #include "core/rendering/RenderLayer.h"
60 #include "core/rendering/RenderTheme.h" 60 #include "core/rendering/RenderTheme.h"
61 #include "platform/fonts/FontCache.h" 61 #include "platform/fonts/FontCache.h"
62 #include "platform/geometry/FloatQuad.h" 62 #include "platform/geometry/FloatQuad.h"
63 #include "platform/graphics/GraphicsContextStateSaver.h" 63 #include "platform/graphics/GraphicsContextStateSaver.h"
64 #include "platform/graphics/DrawLooper.h" 64 #include "platform/graphics/DrawLooper.h"
65 #include "platform/text/TextRun.h" 65 #include "platform/text/TextRun.h"
66 #include "platform/weborigin/SecurityOrigin.h"
67 #include "wtf/CheckedArithmetic.h" 66 #include "wtf/CheckedArithmetic.h"
68 #include "wtf/MathExtras.h" 67 #include "wtf/MathExtras.h"
69 #include "wtf/OwnPtr.h" 68 #include "wtf/OwnPtr.h"
70 #include "wtf/Uint8ClampedArray.h" 69 #include "wtf/Uint8ClampedArray.h"
71 #include "wtf/text/StringBuilder.h" 70 #include "wtf/text/StringBuilder.h"
72 71
73 using namespace std; 72 using namespace std;
74 73
75 namespace WebCore { 74 namespace WebCore {
76 75
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after
283 return; 282 return;
284 283
285 if (state().m_strokeStyle && state().m_strokeStyle->isEquivalentColor(*style )) 284 if (state().m_strokeStyle && state().m_strokeStyle->isEquivalentColor(*style ))
286 return; 285 return;
287 286
288 if (style->isCurrentColor()) { 287 if (style->isCurrentColor()) {
289 if (style->hasOverrideAlpha()) 288 if (style->hasOverrideAlpha())
290 style = CanvasStyle::createFromRGBA(colorWithOverrideAlpha(currentCo lor(canvas()), style->overrideAlpha())); 289 style = CanvasStyle::createFromRGBA(colorWithOverrideAlpha(currentCo lor(canvas()), style->overrideAlpha()));
291 else 290 else
292 style = CanvasStyle::createFromRGBA(currentColor(canvas())); 291 style = CanvasStyle::createFromRGBA(currentColor(canvas()));
293 } else 292 } else if (canvas()->originClean() && style->canvasPattern() && !style->canv asPattern()->originClean()) {
294 checkOrigin(style->canvasPattern()); 293 canvas()->setOriginTainted();
Stephen White 2014/03/10 15:27:03 Do we have tests for pattern tainting (or tainting
294 }
295 295
296 realizeSaves(); 296 realizeSaves();
297 modifiableState().m_strokeStyle = style.release(); 297 modifiableState().m_strokeStyle = style.release();
298 GraphicsContext* c = drawingContext(); 298 GraphicsContext* c = drawingContext();
299 if (!c) 299 if (!c)
300 return; 300 return;
301 state().m_strokeStyle->applyStrokeColor(c); 301 state().m_strokeStyle->applyStrokeColor(c);
302 modifiableState().m_unparsedStrokeColor = String(); 302 modifiableState().m_unparsedStrokeColor = String();
303 } 303 }
304 304
(...skipping 10 matching lines...) Expand all
315 return; 315 return;
316 316
317 if (state().m_fillStyle && state().m_fillStyle->isEquivalentColor(*style)) 317 if (state().m_fillStyle && state().m_fillStyle->isEquivalentColor(*style))
318 return; 318 return;
319 319
320 if (style->isCurrentColor()) { 320 if (style->isCurrentColor()) {
321 if (style->hasOverrideAlpha()) 321 if (style->hasOverrideAlpha())
322 style = CanvasStyle::createFromRGBA(colorWithOverrideAlpha(currentCo lor(canvas()), style->overrideAlpha())); 322 style = CanvasStyle::createFromRGBA(colorWithOverrideAlpha(currentCo lor(canvas()), style->overrideAlpha()));
323 else 323 else
324 style = CanvasStyle::createFromRGBA(currentColor(canvas())); 324 style = CanvasStyle::createFromRGBA(currentColor(canvas()));
325 } else 325 } else if (canvas()->originClean() && style->canvasPattern() && !style->canv asPattern()->originClean()) {
326 checkOrigin(style->canvasPattern()); 326 canvas()->setOriginTainted();
327 }
327 328
328 realizeSaves(); 329 realizeSaves();
329 modifiableState().m_fillStyle = style.release(); 330 modifiableState().m_fillStyle = style.release();
330 GraphicsContext* c = drawingContext(); 331 GraphicsContext* c = drawingContext();
331 if (!c) 332 if (!c)
332 return; 333 return;
333 state().m_fillStyle->applyFillColor(c); 334 state().m_fillStyle->applyFillColor(c);
334 modifiableState().m_unparsedFillColor = String(); 335 modifiableState().m_unparsedFillColor = String();
335 } 336 }
336 337
(...skipping 961 matching lines...) Expand 10 before | Expand all | Expand 10 after
1298 bool CanvasRenderingContext2D::shouldDrawShadows() const 1299 bool CanvasRenderingContext2D::shouldDrawShadows() const
1299 { 1300 {
1300 return alphaChannel(state().m_shadowColor) && (state().m_shadowBlur || !stat e().m_shadowOffset.isZero()); 1301 return alphaChannel(state().m_shadowColor) && (state().m_shadowBlur || !stat e().m_shadowOffset.isZero());
1301 } 1302 }
1302 1303
1303 enum ImageSizeType { 1304 enum ImageSizeType {
1304 ImageSizeAfterDevicePixelRatio, 1305 ImageSizeAfterDevicePixelRatio,
1305 ImageSizeBeforeDevicePixelRatio 1306 ImageSizeBeforeDevicePixelRatio
1306 }; 1307 };
1307 1308
1308 static LayoutSize sizeFor(HTMLImageElement* image, ImageSizeType sizeType)
1309 {
1310 LayoutSize size;
1311 ImageResource* cachedImage = image->cachedImage();
1312 if (cachedImage) {
1313 size = cachedImage->imageSizeForRenderer(image->renderer(), 1.0f); // FI XME: Not sure about this.
1314
1315 if (sizeType == ImageSizeAfterDevicePixelRatio && image->renderer() && i mage->renderer()->isRenderImage() && cachedImage->image() && !cachedImage->image ()->hasRelativeWidth())
1316 size.scale(toRenderImage(image->renderer())->imageDevicePixelRatio() );
1317 }
1318 return size;
1319 }
1320
1321 static IntSize sizeFor(HTMLVideoElement* video)
1322 {
1323 if (MediaPlayer* player = video->player())
1324 return player->naturalSize();
1325 return IntSize();
1326 }
1327
1328 static inline FloatRect normalizeRect(const FloatRect& rect) 1309 static inline FloatRect normalizeRect(const FloatRect& rect)
1329 { 1310 {
1330 return FloatRect(min(rect.x(), rect.maxX()), 1311 return FloatRect(min(rect.x(), rect.maxX()),
1331 min(rect.y(), rect.maxY()), 1312 min(rect.y(), rect.maxY()),
1332 max(rect.width(), -rect.width()), 1313 max(rect.width(), -rect.width()),
1333 max(rect.height(), -rect.height())); 1314 max(rect.height(), -rect.height()));
1334 } 1315 }
1335 1316
1336 static inline void clipRectsToImageRect(const FloatRect& imageRect, FloatRect* s rcRect, FloatRect* dstRect) 1317 static inline void clipRectsToImageRect(const FloatRect& imageRect, FloatRect* s rcRect, FloatRect* dstRect)
1337 { 1318 {
1338 if (imageRect.contains(*srcRect)) 1319 if (imageRect.contains(*srcRect))
1339 return; 1320 return;
1340 1321
1341 // Compute the src to dst transform 1322 // Compute the src to dst transform
1342 FloatSize scale(dstRect->size().width() / srcRect->size().width(), dstRect-> size().height() / srcRect->size().height()); 1323 FloatSize scale(dstRect->size().width() / srcRect->size().width(), dstRect-> size().height() / srcRect->size().height());
1343 FloatPoint scaledSrcLocation = srcRect->location(); 1324 FloatPoint scaledSrcLocation = srcRect->location();
1344 scaledSrcLocation.scale(scale.width(), scale.height()); 1325 scaledSrcLocation.scale(scale.width(), scale.height());
1345 FloatSize offset = dstRect->location() - scaledSrcLocation; 1326 FloatSize offset = dstRect->location() - scaledSrcLocation;
1346 1327
1347 srcRect->intersect(imageRect); 1328 srcRect->intersect(imageRect);
1348 1329
1349 // To clip the destination rectangle in the same proportion, transform the c lipped src rect 1330 // To clip the destination rectangle in the same proportion, transform the c lipped src rect
1350 *dstRect = *srcRect; 1331 *dstRect = *srcRect;
1351 dstRect->scale(scale.width(), scale.height()); 1332 dstRect->scale(scale.width(), scale.height());
1352 dstRect->move(offset); 1333 dstRect->move(offset);
1353 } 1334 }
1354 1335
1355 void CanvasRenderingContext2D::drawImageInternal(Image* image, const FloatRect& srcRect, const FloatRect& dstRect, const CompositeOperator& op, const blink::Web BlendMode& blendMode) 1336 static bool checkImageSource(CanvasImageSource* imageSource, ExceptionState& exc eptionState)
1356 { 1337 {
1357 if (!image) 1338 if (!imageSource) {
1358 return; 1339 // FIXME: Message should mention ImageBitmap once that feature ships.
1359 1340 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::a rgumentNullOrIncorrectType(1, String("HTMLImageElement, HTMLCanvasElement or HTM LVideoElement")));
1360 GraphicsContext* c = drawingContext(); 1341 return false;
1361 if (!c)
1362 return;
1363 if (!state().m_invertibleCTM)
1364 return;
1365 FloatRect clipBounds;
1366 if (!drawingContext()->getTransformedClipBounds(&clipBounds))
1367 return;
1368
1369 if (rectContainsTransformedRect(dstRect, clipBounds)) {
1370 c->drawImage(image, dstRect, srcRect, op, blendMode);
1371 didDraw(clipBounds);
1372 } else if (isFullCanvasCompositeMode(op)) {
1373 fullCanvasCompositedDrawImage(image, dstRect, srcRect, op);
1374 didDraw(clipBounds);
1375 } else if (op == CompositeCopy) {
1376 clearCanvas();
1377 c->drawImage(image, dstRect, srcRect, op, blendMode);
1378 didDraw(clipBounds);
1379 } else {
1380 FloatRect dirtyRect;
1381 if (computeDirtyRect(dstRect, &dirtyRect)) {
1382 c->drawImage(image, dstRect, srcRect, op, blendMode);
1383 didDraw(dirtyRect);
1384 }
1385 } 1342 }
1343 return true;
1386 } 1344 }
1387 1345
1388 void CanvasRenderingContext2D::drawImage(ImageBitmap* bitmap, float x, float y, ExceptionState& exceptionState) 1346 void CanvasRenderingContext2D::drawImage(CanvasImageSource* imageSource, float x , float y, ExceptionState& exceptionState)
1389 { 1347 {
1390 if (!bitmap) { 1348 if (!checkImageSource(imageSource, exceptionState))
1391 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::a rgumentNullOrIncorrectType(1, "ImageBitmap"));
1392 return; 1349 return;
1393 } 1350 FloatSize destRectSize = imageSource->defaultDestinationSize();
1394 drawImage(bitmap, x, y, bitmap->width(), bitmap->height(), exceptionState); 1351 drawImage(imageSource, x, y, destRectSize.width(), destRectSize.height(), ex ceptionState);
1395 } 1352 }
1396 1353
1397 void CanvasRenderingContext2D::drawImage(ImageBitmap* bitmap, 1354 void CanvasRenderingContext2D::drawImage(CanvasImageSource* imageSource,
1398 float x, float y, float width, float height, ExceptionState& exceptionState) 1355 float x, float y, float width, float height, ExceptionState& exceptionState)
1399 { 1356 {
1400 if (!bitmap) { 1357 if (!checkImageSource(imageSource, exceptionState))
1401 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::a rgumentNullOrIncorrectType(1, "ImageBitmap"));
1402 return; 1358 return;
1403 } 1359 FloatSize sourceRectSize = imageSource->sourceSize();
1404 if (!bitmap->bitmapRect().width() || !bitmap->bitmapRect().height()) 1360 drawImage(imageSource, 0, 0, sourceRectSize.width(), sourceRectSize.height() , x, y, width, height, exceptionState);
1405 return;
1406
1407 drawImage(bitmap, 0, 0, bitmap->width(), bitmap->height(), x, y, width, heig ht, exceptionState);
1408 } 1361 }
1409 1362
1410 void CanvasRenderingContext2D::drawImage(ImageBitmap* bitmap, 1363 void CanvasRenderingContext2D::drawImage(CanvasImageSource* imageSource,
1411 float sx, float sy, float sw, float sh, 1364 float sx, float sy, float sw, float sh,
1412 float dx, float dy, float dw, float dh, ExceptionState& exceptionState) 1365 float dx, float dy, float dw, float dh, ExceptionState& exceptionState)
1413 { 1366 {
1414 if (!bitmap) { 1367 GraphicsContext* c = drawingContext(); // Do not exit yet if !c because we m ay need to throw exceptions first
1415 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::a rgumentNullOrIncorrectType(1, "ImageBitmap")); 1368 CompositeOperator op = c ? c->compositeOperation() : CompositeSourceOver;
1369 blink::WebBlendMode blendMode = c ? c->blendModeOperation() : blink::WebBlen dModeNormal;
1370 drawImageInternal(imageSource, sx, sy, sw, sh, dx, dy, dw, dh, exceptionStat e, op, blendMode);
1371 }
1372
1373 void CanvasRenderingContext2D::drawImageInternal(CanvasImageSource* imageSource,
1374 float sx, float sy, float sw, float sh,
1375 float dx, float dy, float dw, float dh, ExceptionState& exceptionState,
1376 CompositeOperator op, blink::WebBlendMode blendMode)
1377 {
1378 if (!checkImageSource(imageSource, exceptionState))
1416 return; 1379 return;
1380
1381 RefPtr<Image> image;
1382 SourceImageStatus sourceImageStatus;
1383 if (!imageSource->isVideoElement()) {
1384 SourceImageMode mode = canvas()->asCanvasImageSource() == imageSource ? CopySourceImageIfVolatile : DontCopySourceImage;
Stephen White 2014/03/10 15:27:03 As discussed, this could just be canvas() == image
1385 image = imageSource->getSourceImageForCanvas(mode, &sourceImageStatus);
1386 if (sourceImageStatus == UndecodableSourceImageStatus)
1387 exceptionState.throwDOMException(InvalidStateError, "The HTMLImageEl ement provided is in the 'broken' state.");
1388 if (!image || !image->width() || !image->height())
1389 return;
1417 } 1390 }
1418 1391
1419 FloatRect srcRect(sx, sy, sw, sh);
1420 FloatRect dstRect(dx, dy, dw, dh);
1421 FloatRect bitmapRect = bitmap->bitmapRect();
1422
1423 if (!std::isfinite(dstRect.x()) || !std::isfinite(dstRect.y()) || !std::isfi nite(dstRect.width()) || !std::isfinite(dstRect.height())
1424 || !std::isfinite(srcRect.x()) || !std::isfinite(srcRect.y()) || !std::i sfinite(srcRect.width()) || !std::isfinite(srcRect.height()))
1425 return;
1426
1427 if (!dstRect.width() || !dstRect.height() || !srcRect.width() || !srcRect.he ight())
1428 return;
1429
1430 ASSERT(bitmap->height() && bitmap->width());
1431 FloatRect normalizedSrcRect = normalizeRect(srcRect);
1432 FloatRect normalizedDstRect = normalizeRect(dstRect);
1433
1434 // Clip the rects to where the user thinks that the image is situated.
1435 clipRectsToImageRect(IntRect(IntPoint(), bitmap->size()), &normalizedSrcRect , &normalizedDstRect);
1436
1437 FloatRect intersectRect = intersection(bitmapRect, normalizedSrcRect);
1438 FloatRect actualSrcRect(intersectRect);
1439
1440 IntPoint bitmapOffset = bitmap->bitmapOffset();
1441 actualSrcRect.move(bitmapOffset - bitmapRect.location());
1442 FloatRect imageRect = FloatRect(bitmapOffset, bitmapRect.size());
1443
1444 FloatRect actualDstRect(FloatPoint(intersectRect.location() - normalizedSrcR ect.location()), bitmapRect.size());
1445 actualDstRect.scale(normalizedDstRect.width() / normalizedSrcRect.width() * intersectRect.width() / bitmapRect.width(),
1446 normalizedDstRect.height() / normalizedSrcRect.height() * intersectRect. height() / bitmapRect.height());
1447 actualDstRect.moveBy(normalizedDstRect.location());
1448
1449 if (!imageRect.intersects(actualSrcRect))
1450 return;
1451
1452 RefPtr<Image> imageForRendering = bitmap->bitmapImage();
1453 if (!imageForRendering)
1454 return;
1455
1456 drawImageInternal(imageForRendering.get(), actualSrcRect, actualDstRect, sta te().m_globalComposite, state().m_globalBlend);
1457 }
1458
1459 void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, float x, float y, ExceptionState& exceptionState)
1460 {
1461 if (!image) {
1462 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::a rgumentNullOrIncorrectType(1, "HTMLImageElement"));
1463 return;
1464 }
1465 LayoutSize destRectSize = sizeFor(image, ImageSizeAfterDevicePixelRatio);
1466 drawImage(image, x, y, destRectSize.width(), destRectSize.height(), exceptio nState);
1467 }
1468
1469 void CanvasRenderingContext2D::drawImage(HTMLImageElement* image,
1470 float x, float y, float width, float height, ExceptionState& exceptionState)
1471 {
1472 if (!image) {
1473 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::a rgumentNullOrIncorrectType(1, "HTMLImageElement"));
1474 return;
1475 }
1476 LayoutSize sourceRectSize = sizeFor(image, ImageSizeBeforeDevicePixelRatio);
1477 drawImage(image, FloatRect(0, 0, sourceRectSize.width(), sourceRectSize.heig ht()), FloatRect(x, y, width, height), exceptionState);
1478 }
1479
1480 void CanvasRenderingContext2D::drawImage(HTMLImageElement* image,
1481 float sx, float sy, float sw, float sh,
1482 float dx, float dy, float dw, float dh, ExceptionState& exceptionState)
1483 {
1484 drawImage(image, FloatRect(sx, sy, sw, sh), FloatRect(dx, dy, dw, dh), excep tionState);
1485 }
1486
1487 void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, const FloatRec t& srcRect, const FloatRect& dstRect, ExceptionState& exceptionState)
1488 {
1489 drawImage(image, srcRect, dstRect, state().m_globalComposite, state().m_glob alBlend, exceptionState);
1490 }
1491
1492 void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, const FloatRec t& srcRect, const FloatRect& dstRect, const CompositeOperator& op, const blink:: WebBlendMode& blendMode, ExceptionState& exceptionState)
1493 {
1494 if (!image) {
1495 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::a rgumentNullOrIncorrectType(1, "HTMLImageElement"));
1496 return;
1497 }
1498
1499 if (!std::isfinite(dstRect.x()) || !std::isfinite(dstRect.y()) || !std::isfi nite(dstRect.width()) || !std::isfinite(dstRect.height())
1500 || !std::isfinite(srcRect.x()) || !std::isfinite(srcRect.y()) || !std::i sfinite(srcRect.width()) || !std::isfinite(srcRect.height()))
1501 return;
1502
1503 ImageResource* cachedImage = image->cachedImage();
1504 if (!cachedImage || !image->complete())
1505 return;
1506
1507 LayoutSize size = sizeFor(image, ImageSizeBeforeDevicePixelRatio);
1508 if (!size.width() || !size.height() || !dstRect.width() || !dstRect.height() || !srcRect.width() || !srcRect.height())
1509 return;
1510
1511 FloatRect normalizedSrcRect = normalizeRect(srcRect);
1512 FloatRect normalizedDstRect = normalizeRect(dstRect);
1513
1514 FloatRect imageRect = FloatRect(FloatPoint(), size);
1515 if (!imageRect.intersects(normalizedSrcRect))
1516 return;
1517
1518 clipRectsToImageRect(imageRect, &normalizedSrcRect, &normalizedDstRect);
1519
1520 checkOrigin(image);
1521
1522 Image* imageForRendering = cachedImage->imageForRenderer(image->renderer());
1523
1524 // For images that depend on an unavailable container size, we need to fall back to the intrinsic
1525 // object size. http://www.w3.org/TR/2dcontext2/#dom-context-2d-drawimage
1526 // FIXME: Without a specified image size this should resolve against the can vas element's size, see: crbug.com/230163.
1527 if (!image->renderer() && imageForRendering->usesContainerSize())
1528 imageForRendering->setContainerSize(imageForRendering->size());
1529
1530 drawImageInternal(imageForRendering, normalizedSrcRect, normalizedDstRect, o p, blendMode);
1531 }
1532
1533 void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* sourceCanvas, float x, float y, ExceptionState& exceptionState)
1534 {
1535 drawImage(sourceCanvas, 0, 0, sourceCanvas->width(), sourceCanvas->height(), x, y, sourceCanvas->width(), sourceCanvas->height(), exceptionState);
1536 }
1537
1538 void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* sourceCanvas,
1539 float x, float y, float width, float height, ExceptionState& exceptionState)
1540 {
1541 drawImage(sourceCanvas, FloatRect(0, 0, sourceCanvas->width(), sourceCanvas- >height()), FloatRect(x, y, width, height), exceptionState);
1542 }
1543
1544 void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* sourceCanvas,
1545 float sx, float sy, float sw, float sh,
1546 float dx, float dy, float dw, float dh, ExceptionState& exceptionState)
1547 {
1548 drawImage(sourceCanvas, FloatRect(sx, sy, sw, sh), FloatRect(dx, dy, dw, dh) , exceptionState);
1549 }
1550
1551 void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* sourceCanvas, const FloatRect& srcRect,
1552 const FloatRect& dstRect, ExceptionState& exceptionState)
1553 {
1554 if (!sourceCanvas) {
1555 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::a rgumentNullOrIncorrectType(1, "HTMLCanvasElement"));
1556 return;
1557 }
1558
1559 FloatRect srcCanvasRect = FloatRect(FloatPoint(), sourceCanvas->size());
1560
1561 if (!srcCanvasRect.width() || !srcCanvasRect.height() || !srcRect.width() || !srcRect.height())
1562 return;
1563
1564 FloatRect normalizedSrcRect = normalizeRect(srcRect);
1565 FloatRect normalizedDstRect = normalizeRect(dstRect);
1566
1567 if (!srcCanvasRect.intersects(normalizedSrcRect) || !normalizedDstRect.width () || !normalizedDstRect.height())
1568 return;
1569
1570 clipRectsToImageRect(srcCanvasRect, &normalizedSrcRect, &normalizedDstRect);
1571
1572 GraphicsContext* c = drawingContext();
1573 if (!c)
1574 return;
1575 if (!state().m_invertibleCTM) 1392 if (!state().m_invertibleCTM)
1576 return; 1393 return;
1577 1394
1578 // FIXME: Do this through platform-independent GraphicsContext API. 1395 if (!std::isfinite(dx) || !std::isfinite(dy) || !std::isfinite(dw) || !std:: isfinite(dh)
1579 ImageBuffer* buffer = sourceCanvas->buffer(); 1396 || !std::isfinite(sx) || !std::isfinite(sy) || !std::isfinite(sw) || !st d::isfinite(sh)
1580 if (!buffer) 1397 || !dw || !dh || !sw || !sh)
1581 return; 1398 return;
1582 1399
1583 FloatRect clipBounds; 1400 FloatRect clipBounds;
1584 if (!drawingContext()->getTransformedClipBounds(&clipBounds)) 1401 if (!drawingContext()->getTransformedClipBounds(&clipBounds))
1585 return; 1402 return;
1586 1403
1587 checkOrigin(sourceCanvas); 1404 FloatRect srcRect = normalizeRect(FloatRect(sx, sy, sw, sh));
1405 FloatRect dstRect = normalizeRect(FloatRect(dx, dy, dw, dh));
1588 1406
1589 // If we're drawing from one accelerated canvas 2d to another, avoid calling sourceCanvas->makeRenderingResultsAvailable() 1407 clipRectsToImageRect(FloatRect(FloatPoint(), imageSource->sourceSize()), &sr cRect, &dstRect);
1590 // as that will do a readback to software.
1591 CanvasRenderingContext* sourceContext = sourceCanvas->renderingContext();
1592 // FIXME: Implement an accelerated path for drawing from a WebGL canvas to a 2d canvas when possible.
1593 if (sourceContext && sourceContext->is3d())
1594 sourceContext->paintRenderingResultsToCanvas();
1595 1408
1596 if (rectContainsTransformedRect(normalizedDstRect, clipBounds)) { 1409 imageSource->adjustDrawRects(&srcRect, &dstRect);
1597 c->drawImageBuffer(buffer, normalizedDstRect, normalizedSrcRect, state() .m_globalComposite, state().m_globalBlend);
1598 didDraw(clipBounds);
1599 } else if (isFullCanvasCompositeMode(state().m_globalComposite)) {
1600 fullCanvasCompositedDrawImage(buffer, normalizedDstRect, normalizedSrcRe ct, state().m_globalComposite);
1601 didDraw(clipBounds);
1602 } else if (state().m_globalComposite == CompositeCopy) {
1603 clearCanvas();
1604 c->drawImageBuffer(buffer, normalizedDstRect, normalizedSrcRect, state() .m_globalComposite, state().m_globalBlend);
1605 didDraw(clipBounds);
1606 } else {
1607 FloatRect dirtyRect;
1608 if (computeDirtyRect(normalizedDstRect, clipBounds, &dirtyRect)) {
1609 c->drawImageBuffer(buffer, normalizedDstRect, normalizedSrcRect, sta te().m_globalComposite, state().m_globalBlend);
1610 didDraw(dirtyRect);
1611 }
1612 }
1613 1410
1614 // Flush canvas's ImageBuffer when drawImage from WebGL to HW accelerated 2d canvas 1411 if (srcRect.isEmpty())
1615 if (sourceContext && sourceContext->is3d() && is2d() && isAccelerated() && c anvas()->buffer())
1616 canvas()->buffer()->flush();
1617 }
1618
1619 void CanvasRenderingContext2D::drawImage(HTMLVideoElement* video, float x, float y, ExceptionState& exceptionState)
1620 {
1621 if (!video) {
1622 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::a rgumentNullOrIncorrectType(1, "HTMLVideoElement"));
1623 return; 1412 return;
1624 }
1625 IntSize size = sizeFor(video);
1626 drawImage(video, x, y, size.width(), size.height(), exceptionState);
1627 }
1628
1629 void CanvasRenderingContext2D::drawImage(HTMLVideoElement* video,
1630 float x, float y, float width, float height, ExceptionState& exceptionState)
1631 {
1632 if (!video) {
1633 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::a rgumentNullOrIncorrectType(1, "HTMLVideoElement"));
1634 return;
1635 }
1636 IntSize size = sizeFor(video);
1637 drawImage(video, FloatRect(0, 0, size.width(), size.height()), FloatRect(x, y, width, height), exceptionState);
1638 }
1639
1640 void CanvasRenderingContext2D::drawImage(HTMLVideoElement* video,
1641 float sx, float sy, float sw, float sh,
1642 float dx, float dy, float dw, float dh, ExceptionState& exceptionState)
1643 {
1644 drawImage(video, FloatRect(sx, sy, sw, sh), FloatRect(dx, dy, dw, dh), excep tionState);
1645 }
1646
1647 void CanvasRenderingContext2D::drawImage(HTMLVideoElement* video, const FloatRec t& srcRect, const FloatRect& dstRect, ExceptionState& exceptionState)
1648 {
1649 if (!video) {
1650 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::a rgumentNullOrIncorrectType(1, "HTMLVideoElement"));
1651 return;
1652 }
1653
1654 if (video->readyState() == HTMLMediaElement::HAVE_NOTHING || video->readySta te() == HTMLMediaElement::HAVE_METADATA)
1655 return;
1656 if (!srcRect.width() || !srcRect.height())
1657 return;
1658
1659 FloatRect videoRect = FloatRect(FloatPoint(), sizeFor(video));
1660
1661 FloatRect normalizedSrcRect = normalizeRect(srcRect);
1662 FloatRect normalizedDstRect = normalizeRect(dstRect);
1663
1664 if (!videoRect.intersects(normalizedSrcRect) || !normalizedDstRect.width() | | !normalizedDstRect.height())
1665 return;
1666
1667 clipRectsToImageRect(videoRect, &normalizedSrcRect, &normalizedDstRect);
1668 1413
1669 GraphicsContext* c = drawingContext(); 1414 GraphicsContext* c = drawingContext();
1670 if (!c) 1415 if (!c)
1671 return; 1416 return;
1672 if (!state().m_invertibleCTM)
1673 return;
1674 1417
1675 checkOrigin(video); 1418 FloatRect dirtyRect = clipBounds;
1419 if (imageSource->isVideoElement()) {
1420 drawVideo(static_cast<HTMLVideoElement*>(imageSource), srcRect, dstRect) ;
1421 computeDirtyRect(dstRect, clipBounds, &dirtyRect);
1422 } else {
1423 if (rectContainsTransformedRect(dstRect, clipBounds)) {
1424 c->drawImage(image.get(), dstRect, srcRect, op, blendMode);
1425 } else if (isFullCanvasCompositeMode(op)) {
1426 fullCanvasCompositedDrawImage(image.get(), dstRect, srcRect, op);
1427 } else if (op == CompositeCopy) {
1428 clearCanvas();
1429 c->drawImage(image.get(), dstRect, srcRect, op, blendMode);
1430 } else {
1431 FloatRect dirtyRect;
1432 computeDirtyRect(dstRect, clipBounds, &dirtyRect);
1433 c->drawImage(image.get(), dstRect, srcRect, op, blendMode);
1434 }
1676 1435
1677 FloatRect dirtyRect; 1436 if (sourceImageStatus == ExternalSourceImageStatus && is2d() && isAccele rated() && canvas()->buffer())
Stephen White 2014/03/10 15:27:03 <philosoraptor>I wonder if we'd ever get in here i
1678 if (!computeDirtyRect(normalizedDstRect, &dirtyRect)) 1437 canvas()->buffer()->flush();
1679 return; 1438 }
1680 1439
1681 GraphicsContextStateSaver stateSaver(*c); 1440 if (canvas()->originClean() && imageSource->wouldTaintOrigin(canvas()->secur ityOrigin()))
1682 c->clip(normalizedDstRect); 1441 canvas()->setOriginTainted();
1683 c->translate(normalizedDstRect.x(), normalizedDstRect.y());
1684 c->scale(FloatSize(normalizedDstRect.width() / normalizedSrcRect.width(), no rmalizedDstRect.height() / normalizedSrcRect.height()));
1685 c->translate(-normalizedSrcRect.x(), -normalizedSrcRect.y());
1686 video->paintCurrentFrameInContext(c, IntRect(IntPoint(), sizeFor(video)));
1687 stateSaver.restore();
1688 1442
1689 didDraw(dirtyRect); 1443 didDraw(dirtyRect);
1690 } 1444 }
1691 1445
1446 void CanvasRenderingContext2D::drawVideo(HTMLVideoElement* video, FloatRect srcR ect, FloatRect dstRect)
1447 {
1448 GraphicsContext* c = drawingContext();
1449 GraphicsContextStateSaver stateSaver(*c);
1450 c->clip(dstRect);
1451 c->translate(dstRect.x(), dstRect.y());
1452 c->scale(FloatSize(dstRect.width() / srcRect.width(), dstRect.height() / src Rect.height()));
1453 c->translate(-srcRect.x(), -srcRect.y());
1454 video->paintCurrentFrameInContext(c, IntRect(IntPoint(), IntSize(video->vide oWidth(), video->videoHeight())));
1455 stateSaver.restore();
1456 }
1457
1692 void CanvasRenderingContext2D::drawImageFromRect(HTMLImageElement* image, 1458 void CanvasRenderingContext2D::drawImageFromRect(HTMLImageElement* image,
1693 float sx, float sy, float sw, float sh, 1459 float sx, float sy, float sw, float sh,
1694 float dx, float dy, float dw, float dh, 1460 float dx, float dy, float dw, float dh,
1695 const String& compositeOperation) 1461 const String& compositeOperation)
1696 { 1462 {
1697 CompositeOperator op; 1463 CompositeOperator op;
1698 blink::WebBlendMode blendOp = blink::WebBlendModeNormal; 1464 blink::WebBlendMode blendOp = blink::WebBlendModeNormal;
1699 if (!parseCompositeAndBlendOperator(compositeOperation, op, blendOp) || blen dOp != blink::WebBlendModeNormal) 1465 if (!parseCompositeAndBlendOperator(compositeOperation, op, blendOp) || blen dOp != blink::WebBlendModeNormal)
1700 op = CompositeSourceOver; 1466 op = CompositeSourceOver;
1701 1467
1702 drawImage(image, FloatRect(sx, sy, sw, sh), FloatRect(dx, dy, dw, dh), op, b link::WebBlendModeNormal, IGNORE_EXCEPTION); 1468 drawImageInternal(image, sx, sy, sw, sh, dx, dy, dw, dh, IGNORE_EXCEPTION, o p, blendOp);
1703 } 1469 }
1704 1470
1705 void CanvasRenderingContext2D::setAlpha(float alpha) 1471 void CanvasRenderingContext2D::setAlpha(float alpha)
1706 { 1472 {
1707 setGlobalAlpha(alpha); 1473 setGlobalAlpha(alpha);
1708 } 1474 }
1709 1475
1710 void CanvasRenderingContext2D::setCompositeOperation(const String& operation) 1476 void CanvasRenderingContext2D::setCompositeOperation(const String& operation)
1711 { 1477 {
1712 setGlobalCompositeOperation(operation); 1478 setGlobalCompositeOperation(operation);
(...skipping 17 matching lines...) Expand all
1730 FloatQuad quad(rect); 1496 FloatQuad quad(rect);
1731 FloatQuad transformedQuad(transformedRect); 1497 FloatQuad transformedQuad(transformedRect);
1732 return state().m_transform.mapQuad(quad).containsQuad(transformedQuad); 1498 return state().m_transform.mapQuad(quad).containsQuad(transformedQuad);
1733 } 1499 }
1734 1500
1735 static void drawImageToContext(Image* image, GraphicsContext* context, const Flo atRect& dest, const FloatRect& src, CompositeOperator op) 1501 static void drawImageToContext(Image* image, GraphicsContext* context, const Flo atRect& dest, const FloatRect& src, CompositeOperator op)
1736 { 1502 {
1737 context->drawImage(image, dest, src, op); 1503 context->drawImage(image, dest, src, op);
1738 } 1504 }
1739 1505
1740 static void drawImageToContext(ImageBuffer* imageBuffer, GraphicsContext* contex t, const FloatRect& dest, const FloatRect& src, CompositeOperator op)
1741 {
1742 context->drawImageBuffer(imageBuffer, dest, src, op);
1743 }
1744
1745 template<class T> void CanvasRenderingContext2D::fullCanvasCompositedDrawImage( T* image, const FloatRect& dest, const FloatRect& src, CompositeOperator op) 1506 template<class T> void CanvasRenderingContext2D::fullCanvasCompositedDrawImage( T* image, const FloatRect& dest, const FloatRect& src, CompositeOperator op)
1746 { 1507 {
1747 ASSERT(isFullCanvasCompositeMode(op)); 1508 ASSERT(isFullCanvasCompositeMode(op));
1748 1509
1749 drawingContext()->beginLayer(1, op); 1510 drawingContext()->beginLayer(1, op);
1750 drawImageToContext(image, drawingContext(), dest, src, CompositeSourceOver); 1511 drawImageToContext(image, drawingContext(), dest, src, CompositeSourceOver);
1751 drawingContext()->endLayer(); 1512 drawingContext()->endLayer();
1752 } 1513 }
1753 1514
1754 static void fillPrimitive(const FloatRect& rect, GraphicsContext* context) 1515 static void fillPrimitive(const FloatRect& rect, GraphicsContext* context)
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
1810 else if (r0 < 0 || r1 < 0) 1571 else if (r0 < 0 || r1 < 0)
1811 exceptionState.throwDOMException(IndexSizeError, String::format("The %s provided is less than 0.", r0 < 0 ? "r0" : "r1")); 1572 exceptionState.throwDOMException(IndexSizeError, String::format("The %s provided is less than 0.", r0 < 0 ? "r0" : "r1"));
1812 1573
1813 if (exceptionState.hadException()) 1574 if (exceptionState.hadException())
1814 return nullptr; 1575 return nullptr;
1815 1576
1816 RefPtr<CanvasGradient> gradient = CanvasGradient::create(FloatPoint(x0, y0), r0, FloatPoint(x1, y1), r1); 1577 RefPtr<CanvasGradient> gradient = CanvasGradient::create(FloatPoint(x0, y0), r0, FloatPoint(x1, y1), r1);
1817 return gradient.release(); 1578 return gradient.release();
1818 } 1579 }
1819 1580
1820 PassRefPtr<CanvasPattern> CanvasRenderingContext2D::createPattern(HTMLImageEleme nt* image, 1581 PassRefPtr<CanvasPattern> CanvasRenderingContext2D::createPattern(CanvasImageSou rce* imageSource,
1821 const String& repetitionType, ExceptionState& exceptionState) 1582 const String& repetitionType, ExceptionState& exceptionState)
1822 { 1583 {
1823 if (!image) { 1584 if (!checkImageSource(imageSource, exceptionState))
1824 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::a rgumentNullOrIncorrectType(1, "HTMLImageElement"));
1825 return nullptr; 1585 return nullptr;
1826 }
1827 bool repeatX, repeatY; 1586 bool repeatX, repeatY;
1828 CanvasPattern::parseRepetitionType(repetitionType, repeatX, repeatY, excepti onState); 1587 CanvasPattern::parseRepetitionType(repetitionType, repeatX, repeatY, excepti onState);
1829 if (exceptionState.hadException()) 1588 if (exceptionState.hadException())
1830 return nullptr; 1589 return nullptr;
1831 1590
1832 if (!image->complete()) 1591 SourceImageStatus status;
1592 RefPtr<Image> imageForRendering = imageSource->getSourceImageForCanvas(CopyS ourceImageIfVolatile, &status);
1593
1594 switch (status) {
1595 case NormalSourceImageStatus:
1596 break;
1597 case ZeroSizeCanvasSourceImageStatus:
1598 exceptionState.throwDOMException(InvalidStateError, String::format("The canvas %s is 0.", imageSource->sourceSize().width() ? "height" : "width"));
1833 return nullptr; 1599 return nullptr;
1600 case UndecodableSourceImageStatus:
1601 exceptionState.throwDOMException(InvalidStateError, "Source image is in the 'broken' state.");
1602 return nullptr;
1603 case InvalidSourceImageStatus:
1604 imageForRendering = Image::nullImage();
1605 break;
1606 case IncompleteSourceImageStatus:
1607 return nullptr;
1608 default:
1609 case ExternalSourceImageStatus: // should not happen when mode is CopySource ImageIfVolatile
1610 ASSERT_NOT_REACHED();
1611 return nullptr;
1612 }
1613 ASSERT(imageForRendering);
1834 1614
1835 ImageResource* cachedImage = image->cachedImage(); 1615 return CanvasPattern::create(imageForRendering.release(), repeatX, repeatY, !imageSource->wouldTaintOrigin(canvas()->securityOrigin()));
1836 Image* imageForRendering = cachedImage ? cachedImage->imageForRenderer(image ->renderer()) : 0;
1837 if (!imageForRendering)
1838 return CanvasPattern::create(Image::nullImage(), repeatX, repeatY, true) ;
1839
1840 // We need to synthesize a container size if a renderer is not available to provide one.
1841 if (!image->renderer() && imageForRendering->usesContainerSize())
1842 imageForRendering->setContainerSize(imageForRendering->size());
1843
1844 bool originClean = cachedImage->isAccessAllowed(canvas()->securityOrigin());
1845 return CanvasPattern::create(imageForRendering, repeatX, repeatY, originClea n);
1846 }
1847
1848 PassRefPtr<CanvasPattern> CanvasRenderingContext2D::createPattern(HTMLCanvasElem ent* canvas,
1849 const String& repetitionType, ExceptionState& exceptionState)
1850 {
1851 if (!canvas)
1852 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::a rgumentNullOrIncorrectType(1, "HTMLCanvasElement"));
1853 else if (!canvas->width() || !canvas->height())
1854 exceptionState.throwDOMException(InvalidStateError, String::format("The canvas %s is 0.", canvas->width() ? "height" : "width"));
1855
1856 if (exceptionState.hadException())
1857 return nullptr;
1858
1859 bool repeatX, repeatY;
1860 CanvasPattern::parseRepetitionType(repetitionType, repeatX, repeatY, excepti onState);
1861 if (exceptionState.hadException())
1862 return nullptr;
1863 return CanvasPattern::create(canvas->copiedImage(), repeatX, repeatY, canvas ->originClean());
1864 } 1616 }
1865 1617
1866 bool CanvasRenderingContext2D::computeDirtyRect(const FloatRect& localRect, Floa tRect* dirtyRect) 1618 bool CanvasRenderingContext2D::computeDirtyRect(const FloatRect& localRect, Floa tRect* dirtyRect)
1867 { 1619 {
1868 FloatRect clipBounds; 1620 FloatRect clipBounds;
1869 if (!drawingContext()->getTransformedClipBounds(&clipBounds)) 1621 if (!drawingContext()->getTransformedClipBounds(&clipBounds))
1870 return false; 1622 return false;
1871 return computeDirtyRect(localRect, clipBounds, dirtyRect); 1623 return computeDirtyRect(localRect, clipBounds, dirtyRect);
1872 } 1624 }
1873 1625
(...skipping 674 matching lines...) Expand 10 before | Expand all | Expand 10 after
2548 const int focusRingWidth = 5; 2300 const int focusRingWidth = 5;
2549 const int focusRingOutline = 0; 2301 const int focusRingOutline = 0;
2550 c->drawFocusRing(path, focusRingWidth, focusRingOutline, focusRingColor); 2302 c->drawFocusRing(path, focusRingWidth, focusRingOutline, focusRingColor);
2551 2303
2552 c->restore(); 2304 c->restore();
2553 2305
2554 didDraw(dirtyRect); 2306 didDraw(dirtyRect);
2555 } 2307 }
2556 2308
2557 } // namespace WebCore 2309 } // namespace WebCore
OLDNEW
« no previous file with comments | « Source/core/html/canvas/CanvasRenderingContext2D.h ('k') | Source/core/html/canvas/CanvasRenderingContext2D.idl » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698