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

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: Fix for mac build 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();
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 if (!checkImageSource(imageSource, exceptionState))
1415 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::a rgumentNullOrIncorrectType(1, "ImageBitmap"));
1416 return;
1417 }
1418
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; 1368 return;
1426 1369
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) 1370 if (!state().m_invertibleCTM)
1576 return; 1371 return;
1577 1372
1578 // FIXME: Do this through platform-independent GraphicsContext API. 1373 RefPtr<Image> image;
1579 ImageBuffer* buffer = sourceCanvas->buffer(); 1374 bool imageSourceIsVolatile = false;
1580 if (!buffer) 1375 if (!imageSource->isVideoElement()) {
1376 CanvasImageSourceUsage usage = canvas()->asCanvasImageSource() == imageS ource ? DrawToSelfCanvasImageSourceUsage : DrawCanvasImageSourceUsage;
1377 image = imageSource->getSourceImageForCanvas(exceptionState, usage, &ima geSourceIsVolatile);
1378 if (!image || !image->width() || !image->height())
1379 return;
1380 }
1381
1382 if (!std::isfinite(dx) || !std::isfinite(dy) || !std::isfinite(dw) || !std:: isfinite(dh)
1383 || !std::isfinite(sx) || !std::isfinite(sy) || !std::isfinite(sw) || !st d::isfinite(sh)
1384 || !dw || !dh || !sw || !sh)
1581 return; 1385 return;
1582 1386
1583 FloatRect clipBounds; 1387 FloatRect clipBounds;
1584 if (!drawingContext()->getTransformedClipBounds(&clipBounds)) 1388 if (!drawingContext()->getTransformedClipBounds(&clipBounds))
1585 return; 1389 return;
1586 1390
1587 checkOrigin(sourceCanvas); 1391 FloatRect srcRect = normalizeRect(FloatRect(sx, sy, sw, sh));
1392 FloatRect dstRect = normalizeRect(FloatRect(dx, dy, dw, dh));
1588 1393
1589 // If we're drawing from one accelerated canvas 2d to another, avoid calling sourceCanvas->makeRenderingResultsAvailable() 1394 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 1395
1596 if (rectContainsTransformedRect(normalizedDstRect, clipBounds)) { 1396 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 1397
1614 // Flush canvas's ImageBuffer when drawImage from WebGL to HW accelerated 2d canvas 1398 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; 1399 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 1400
1669 GraphicsContext* c = drawingContext(); 1401 GraphicsContext* c = drawingContext();
1670 if (!c) 1402 if (!c)
1671 return; 1403 return;
1672 if (!state().m_invertibleCTM)
1673 return;
1674 1404
1675 checkOrigin(video); 1405 FloatRect dirtyRect = clipBounds;
1406 if (imageSource->isVideoElement()) {
1407 GraphicsContextStateSaver stateSaver(*c);
Stephen White 2014/03/06 16:06:17 Nit: might consider refactoring the video-specific
1408 c->clip(dstRect);
1409 c->translate(dstRect.x(), dstRect.y());
1410 c->scale(FloatSize(dstRect.width() / srcRect.width(), dstRect.height() / srcRect.height()));
1411 c->translate(-srcRect.x(), -srcRect.y());
1412 static_cast<HTMLVideoElement*>(imageSource)->paintCurrentFrameInContext( c, IntRect(IntPoint(), roundedIntSize(imageSource->sourceSize())));
1413 stateSaver.restore();
1414 computeDirtyRect(dstRect, clipBounds, &dirtyRect);
1415 } else {
1416 CompositeOperator op = c->compositeOperation();
1417 blink::WebBlendMode blendMode = c->blendModeOperation();
1418 if (rectContainsTransformedRect(dstRect, clipBounds)) {
1419 c->drawImage(image.get(), dstRect, srcRect, op, blendMode);
1420 } else if (isFullCanvasCompositeMode(op)) {
1421 fullCanvasCompositedDrawImage(image.get(), dstRect, srcRect, op);
1422 } else if (op == CompositeCopy) {
1423 clearCanvas();
1424 c->drawImage(image.get(), dstRect, srcRect, op, blendMode);
1425 } else {
1426 FloatRect dirtyRect;
1427 computeDirtyRect(dstRect, clipBounds, &dirtyRect);
1428 c->drawImage(image.get(), dstRect, srcRect, op, blendMode);
1429 }
1676 1430
1677 FloatRect dirtyRect; 1431 if (imageSourceIsVolatile && is2d() && isAccelerated() && canvas()->buff er())
1678 if (!computeDirtyRect(normalizedDstRect, &dirtyRect)) 1432 canvas()->buffer()->flush();
1679 return; 1433 }
1680 1434
1681 GraphicsContextStateSaver stateSaver(*c); 1435 if (canvas()->originClean() && imageSource->wouldTaintOrigin(canvas()->secur ityOrigin()))
1682 c->clip(normalizedDstRect); 1436 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 1437
1689 didDraw(dirtyRect); 1438 didDraw(dirtyRect);
1690 } 1439 }
1691 1440
1441
1692 void CanvasRenderingContext2D::drawImageFromRect(HTMLImageElement* image, 1442 void CanvasRenderingContext2D::drawImageFromRect(HTMLImageElement* image,
1693 float sx, float sy, float sw, float sh, 1443 float sx, float sy, float sw, float sh,
1694 float dx, float dy, float dw, float dh, 1444 float dx, float dy, float dw, float dh,
1695 const String& compositeOperation) 1445 const String& compositeOperation)
1696 { 1446 {
1447 GraphicsContext* c = drawingContext();
1448 if (!c)
1449 return;
1697 CompositeOperator op; 1450 CompositeOperator op;
1698 blink::WebBlendMode blendOp = blink::WebBlendModeNormal; 1451 blink::WebBlendMode blendOp = blink::WebBlendModeNormal;
1699 if (!parseCompositeAndBlendOperator(compositeOperation, op, blendOp) || blen dOp != blink::WebBlendModeNormal) 1452 if (!parseCompositeAndBlendOperator(compositeOperation, op, blendOp) || blen dOp != blink::WebBlendModeNormal)
1700 op = CompositeSourceOver; 1453 op = CompositeSourceOver;
1701 1454
1702 drawImage(image, FloatRect(sx, sy, sw, sh), FloatRect(dx, dy, dw, dh), op, b link::WebBlendModeNormal, IGNORE_EXCEPTION); 1455 CompositeOperator savedOp = c->compositeOperation();
1456 blink::WebBlendMode savedBlendMode = c->blendModeOperation();
1457 c->setCompositeOperation(op, blink::WebBlendModeNormal);
Stephen White 2014/03/06 16:06:17 To me, this would be cleaner if we had a drawImage
1458 drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh, IGNORE_EXCEPTION);
1459 c->setCompositeOperation(savedOp, savedBlendMode);
1703 } 1460 }
1704 1461
1705 void CanvasRenderingContext2D::setAlpha(float alpha) 1462 void CanvasRenderingContext2D::setAlpha(float alpha)
1706 { 1463 {
1707 setGlobalAlpha(alpha); 1464 setGlobalAlpha(alpha);
1708 } 1465 }
1709 1466
1710 void CanvasRenderingContext2D::setCompositeOperation(const String& operation) 1467 void CanvasRenderingContext2D::setCompositeOperation(const String& operation)
1711 { 1468 {
1712 setGlobalCompositeOperation(operation); 1469 setGlobalCompositeOperation(operation);
(...skipping 17 matching lines...) Expand all
1730 FloatQuad quad(rect); 1487 FloatQuad quad(rect);
1731 FloatQuad transformedQuad(transformedRect); 1488 FloatQuad transformedQuad(transformedRect);
1732 return state().m_transform.mapQuad(quad).containsQuad(transformedQuad); 1489 return state().m_transform.mapQuad(quad).containsQuad(transformedQuad);
1733 } 1490 }
1734 1491
1735 static void drawImageToContext(Image* image, GraphicsContext* context, const Flo atRect& dest, const FloatRect& src, CompositeOperator op) 1492 static void drawImageToContext(Image* image, GraphicsContext* context, const Flo atRect& dest, const FloatRect& src, CompositeOperator op)
1736 { 1493 {
1737 context->drawImage(image, dest, src, op); 1494 context->drawImage(image, dest, src, op);
1738 } 1495 }
1739 1496
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) 1497 template<class T> void CanvasRenderingContext2D::fullCanvasCompositedDrawImage( T* image, const FloatRect& dest, const FloatRect& src, CompositeOperator op)
1746 { 1498 {
1747 ASSERT(isFullCanvasCompositeMode(op)); 1499 ASSERT(isFullCanvasCompositeMode(op));
1748 1500
1749 drawingContext()->beginLayer(1, op); 1501 drawingContext()->beginLayer(1, op);
1750 drawImageToContext(image, drawingContext(), dest, src, CompositeSourceOver); 1502 drawImageToContext(image, drawingContext(), dest, src, CompositeSourceOver);
1751 drawingContext()->endLayer(); 1503 drawingContext()->endLayer();
1752 } 1504 }
1753 1505
1754 static void fillPrimitive(const FloatRect& rect, GraphicsContext* context) 1506 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) 1562 else if (r0 < 0 || r1 < 0)
1811 exceptionState.throwDOMException(IndexSizeError, String::format("The %s provided is less than 0.", r0 < 0 ? "r0" : "r1")); 1563 exceptionState.throwDOMException(IndexSizeError, String::format("The %s provided is less than 0.", r0 < 0 ? "r0" : "r1"));
1812 1564
1813 if (exceptionState.hadException()) 1565 if (exceptionState.hadException())
1814 return nullptr; 1566 return nullptr;
1815 1567
1816 RefPtr<CanvasGradient> gradient = CanvasGradient::create(FloatPoint(x0, y0), r0, FloatPoint(x1, y1), r1); 1568 RefPtr<CanvasGradient> gradient = CanvasGradient::create(FloatPoint(x0, y0), r0, FloatPoint(x1, y1), r1);
1817 return gradient.release(); 1569 return gradient.release();
1818 } 1570 }
1819 1571
1820 PassRefPtr<CanvasPattern> CanvasRenderingContext2D::createPattern(HTMLImageEleme nt* image, 1572 PassRefPtr<CanvasPattern> CanvasRenderingContext2D::createPattern(CanvasImageSou rce* imageSource,
1821 const String& repetitionType, ExceptionState& exceptionState) 1573 const String& repetitionType, ExceptionState& exceptionState)
1822 { 1574 {
1823 if (!image) { 1575 if (!checkImageSource(imageSource, exceptionState))
1824 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::a rgumentNullOrIncorrectType(1, "HTMLImageElement"));
1825 return nullptr; 1576 return nullptr;
1826 }
1827 bool repeatX, repeatY; 1577 bool repeatX, repeatY;
1828 CanvasPattern::parseRepetitionType(repetitionType, repeatX, repeatY, excepti onState); 1578 CanvasPattern::parseRepetitionType(repetitionType, repeatX, repeatY, excepti onState);
1829 if (exceptionState.hadException()) 1579 if (exceptionState.hadException())
1830 return nullptr; 1580 return nullptr;
1831 1581
1832 if (!image->complete()) 1582 RefPtr<Image> imageForRendering = imageSource->getSourceImageForCanvas(excep tionState, PatternCanvasImageSourceUsage);
1583 if (exceptionState.hadException() || !imageForRendering)
1833 return nullptr; 1584 return nullptr;
1834 1585
1835 ImageResource* cachedImage = image->cachedImage(); 1586 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 } 1587 }
1865 1588
1866 bool CanvasRenderingContext2D::computeDirtyRect(const FloatRect& localRect, Floa tRect* dirtyRect) 1589 bool CanvasRenderingContext2D::computeDirtyRect(const FloatRect& localRect, Floa tRect* dirtyRect)
1867 { 1590 {
1868 FloatRect clipBounds; 1591 FloatRect clipBounds;
1869 if (!drawingContext()->getTransformedClipBounds(&clipBounds)) 1592 if (!drawingContext()->getTransformedClipBounds(&clipBounds))
1870 return false; 1593 return false;
1871 return computeDirtyRect(localRect, clipBounds, dirtyRect); 1594 return computeDirtyRect(localRect, clipBounds, dirtyRect);
1872 } 1595 }
1873 1596
(...skipping 642 matching lines...) Expand 10 before | Expand all | Expand 10 after
2516 const int focusRingWidth = 5; 2239 const int focusRingWidth = 5;
2517 const int focusRingOutline = 0; 2240 const int focusRingOutline = 0;
2518 c->drawFocusRing(path, focusRingWidth, focusRingOutline, focusRingColor); 2241 c->drawFocusRing(path, focusRingWidth, focusRingOutline, focusRingColor);
2519 2242
2520 c->restore(); 2243 c->restore();
2521 2244
2522 didDraw(dirtyRect); 2245 didDraw(dirtyRect);
2523 } 2246 }
2524 2247
2525 } // namespace WebCore 2248 } // namespace WebCore
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698