| OLD | NEW |
| 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 272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 283 return; | 283 return; |
| 284 | 284 |
| 285 if (state().m_strokeStyle && state().m_strokeStyle->isEquivalentColor(*style
)) | 285 if (state().m_strokeStyle && state().m_strokeStyle->isEquivalentColor(*style
)) |
| 286 return; | 286 return; |
| 287 | 287 |
| 288 if (style->isCurrentColor()) { | 288 if (style->isCurrentColor()) { |
| 289 if (style->hasOverrideAlpha()) | 289 if (style->hasOverrideAlpha()) |
| 290 style = CanvasStyle::createFromRGBA(colorWithOverrideAlpha(currentCo
lor(canvas()), style->overrideAlpha())); | 290 style = CanvasStyle::createFromRGBA(colorWithOverrideAlpha(currentCo
lor(canvas()), style->overrideAlpha())); |
| 291 else | 291 else |
| 292 style = CanvasStyle::createFromRGBA(currentColor(canvas())); | 292 style = CanvasStyle::createFromRGBA(currentColor(canvas())); |
| 293 } else | 293 } else if (canvas()->originClean() && style->canvasPattern() && !style->canv
asPattern()->originClean()) { |
| 294 checkOrigin(style->canvasPattern()); | 294 canvas()->setOriginTainted(); |
| 295 } |
| 295 | 296 |
| 296 realizeSaves(); | 297 realizeSaves(); |
| 297 modifiableState().m_strokeStyle = style.release(); | 298 modifiableState().m_strokeStyle = style.release(); |
| 298 GraphicsContext* c = drawingContext(); | 299 GraphicsContext* c = drawingContext(); |
| 299 if (!c) | 300 if (!c) |
| 300 return; | 301 return; |
| 301 state().m_strokeStyle->applyStrokeColor(c); | 302 state().m_strokeStyle->applyStrokeColor(c); |
| 302 modifiableState().m_unparsedStrokeColor = String(); | 303 modifiableState().m_unparsedStrokeColor = String(); |
| 303 } | 304 } |
| 304 | 305 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 315 return; | 316 return; |
| 316 | 317 |
| 317 if (state().m_fillStyle && state().m_fillStyle->isEquivalentColor(*style)) | 318 if (state().m_fillStyle && state().m_fillStyle->isEquivalentColor(*style)) |
| 318 return; | 319 return; |
| 319 | 320 |
| 320 if (style->isCurrentColor()) { | 321 if (style->isCurrentColor()) { |
| 321 if (style->hasOverrideAlpha()) | 322 if (style->hasOverrideAlpha()) |
| 322 style = CanvasStyle::createFromRGBA(colorWithOverrideAlpha(currentCo
lor(canvas()), style->overrideAlpha())); | 323 style = CanvasStyle::createFromRGBA(colorWithOverrideAlpha(currentCo
lor(canvas()), style->overrideAlpha())); |
| 323 else | 324 else |
| 324 style = CanvasStyle::createFromRGBA(currentColor(canvas())); | 325 style = CanvasStyle::createFromRGBA(currentColor(canvas())); |
| 325 } else | 326 } else if (canvas()->originClean() && style->canvasPattern() && !style->canv
asPattern()->originClean()) { |
| 326 checkOrigin(style->canvasPattern()); | 327 canvas()->setOriginTainted(); |
| 328 } |
| 327 | 329 |
| 328 realizeSaves(); | 330 realizeSaves(); |
| 329 modifiableState().m_fillStyle = style.release(); | 331 modifiableState().m_fillStyle = style.release(); |
| 330 GraphicsContext* c = drawingContext(); | 332 GraphicsContext* c = drawingContext(); |
| 331 if (!c) | 333 if (!c) |
| 332 return; | 334 return; |
| 333 state().m_fillStyle->applyFillColor(c); | 335 state().m_fillStyle->applyFillColor(c); |
| 334 modifiableState().m_unparsedFillColor = String(); | 336 modifiableState().m_unparsedFillColor = String(); |
| 335 } | 337 } |
| 336 | 338 |
| (...skipping 902 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1239 bool CanvasRenderingContext2D::shouldDrawShadows() const | 1241 bool CanvasRenderingContext2D::shouldDrawShadows() const |
| 1240 { | 1242 { |
| 1241 return alphaChannel(state().m_shadowColor) && (state().m_shadowBlur || !stat
e().m_shadowOffset.isZero()); | 1243 return alphaChannel(state().m_shadowColor) && (state().m_shadowBlur || !stat
e().m_shadowOffset.isZero()); |
| 1242 } | 1244 } |
| 1243 | 1245 |
| 1244 enum ImageSizeType { | 1246 enum ImageSizeType { |
| 1245 ImageSizeAfterDevicePixelRatio, | 1247 ImageSizeAfterDevicePixelRatio, |
| 1246 ImageSizeBeforeDevicePixelRatio | 1248 ImageSizeBeforeDevicePixelRatio |
| 1247 }; | 1249 }; |
| 1248 | 1250 |
| 1249 static LayoutSize sizeFor(HTMLImageElement* image, ImageSizeType sizeType) | |
| 1250 { | |
| 1251 LayoutSize size; | |
| 1252 ImageResource* cachedImage = image->cachedImage(); | |
| 1253 if (cachedImage) { | |
| 1254 size = cachedImage->imageSizeForRenderer(image->renderer(), 1.0f); // FI
XME: Not sure about this. | |
| 1255 | |
| 1256 if (sizeType == ImageSizeAfterDevicePixelRatio && image->renderer() && i
mage->renderer()->isRenderImage() && cachedImage->image() && !cachedImage->image
()->hasRelativeWidth()) | |
| 1257 size.scale(toRenderImage(image->renderer())->imageDevicePixelRatio()
); | |
| 1258 } | |
| 1259 return size; | |
| 1260 } | |
| 1261 | |
| 1262 static IntSize sizeFor(HTMLVideoElement* video) | |
| 1263 { | |
| 1264 if (MediaPlayer* player = video->player()) | |
| 1265 return player->naturalSize(); | |
| 1266 return IntSize(); | |
| 1267 } | |
| 1268 | |
| 1269 static inline FloatRect normalizeRect(const FloatRect& rect) | 1251 static inline FloatRect normalizeRect(const FloatRect& rect) |
| 1270 { | 1252 { |
| 1271 return FloatRect(min(rect.x(), rect.maxX()), | 1253 return FloatRect(min(rect.x(), rect.maxX()), |
| 1272 min(rect.y(), rect.maxY()), | 1254 min(rect.y(), rect.maxY()), |
| 1273 max(rect.width(), -rect.width()), | 1255 max(rect.width(), -rect.width()), |
| 1274 max(rect.height(), -rect.height())); | 1256 max(rect.height(), -rect.height())); |
| 1275 } | 1257 } |
| 1276 | 1258 |
| 1277 static inline void clipRectsToImageRect(const FloatRect& imageRect, FloatRect* s
rcRect, FloatRect* dstRect) | 1259 static inline void clipRectsToImageRect(const FloatRect& imageRect, FloatRect* s
rcRect, FloatRect* dstRect) |
| 1278 { | 1260 { |
| 1279 if (imageRect.contains(*srcRect)) | 1261 if (imageRect.contains(*srcRect)) |
| 1280 return; | 1262 return; |
| 1281 | 1263 |
| 1282 // Compute the src to dst transform | 1264 // Compute the src to dst transform |
| 1283 FloatSize scale(dstRect->size().width() / srcRect->size().width(), dstRect->
size().height() / srcRect->size().height()); | 1265 FloatSize scale(dstRect->size().width() / srcRect->size().width(), dstRect->
size().height() / srcRect->size().height()); |
| 1284 FloatPoint scaledSrcLocation = srcRect->location(); | 1266 FloatPoint scaledSrcLocation = srcRect->location(); |
| 1285 scaledSrcLocation.scale(scale.width(), scale.height()); | 1267 scaledSrcLocation.scale(scale.width(), scale.height()); |
| 1286 FloatSize offset = dstRect->location() - scaledSrcLocation; | 1268 FloatSize offset = dstRect->location() - scaledSrcLocation; |
| 1287 | 1269 |
| 1288 srcRect->intersect(imageRect); | 1270 srcRect->intersect(imageRect); |
| 1289 | 1271 |
| 1290 // To clip the destination rectangle in the same proportion, transform the c
lipped src rect | 1272 // To clip the destination rectangle in the same proportion, transform the c
lipped src rect |
| 1291 *dstRect = *srcRect; | 1273 *dstRect = *srcRect; |
| 1292 dstRect->scale(scale.width(), scale.height()); | 1274 dstRect->scale(scale.width(), scale.height()); |
| 1293 dstRect->move(offset); | 1275 dstRect->move(offset); |
| 1294 } | 1276 } |
| 1295 | 1277 |
| 1296 void CanvasRenderingContext2D::drawImageInternal(Image* image, const FloatRect&
srcRect, const FloatRect& dstRect, const CompositeOperator& op, const blink::Web
BlendMode& blendMode) | 1278 static bool checkImageSource(CanvasImageSource* imageSource, ExceptionState& exc
eptionState) |
| 1297 { | 1279 { |
| 1298 if (!image) | 1280 if (!imageSource) { |
| 1299 return; | 1281 // FIXME: Message should mention ImageBitmap once that feature ships. |
| 1300 | 1282 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::a
rgumentNullOrIncorrectType(1, String("HTMLImageElement, HTMLCanvasElement or HTM
LVideoElement"))); |
| 1301 GraphicsContext* c = drawingContext(); | 1283 return false; |
| 1302 if (!c) | |
| 1303 return; | |
| 1304 if (!state().m_invertibleCTM) | |
| 1305 return; | |
| 1306 FloatRect clipBounds; | |
| 1307 if (!drawingContext()->getTransformedClipBounds(&clipBounds)) | |
| 1308 return; | |
| 1309 | |
| 1310 if (rectContainsTransformedRect(dstRect, clipBounds)) { | |
| 1311 c->drawImage(image, dstRect, srcRect, op, blendMode); | |
| 1312 didDraw(clipBounds); | |
| 1313 } else if (isFullCanvasCompositeMode(op)) { | |
| 1314 fullCanvasCompositedDrawImage(image, dstRect, srcRect, op); | |
| 1315 didDraw(clipBounds); | |
| 1316 } else if (op == CompositeCopy) { | |
| 1317 clearCanvas(); | |
| 1318 c->drawImage(image, dstRect, srcRect, op, blendMode); | |
| 1319 didDraw(clipBounds); | |
| 1320 } else { | |
| 1321 FloatRect dirtyRect; | |
| 1322 if (computeDirtyRect(dstRect, &dirtyRect)) { | |
| 1323 c->drawImage(image, dstRect, srcRect, op, blendMode); | |
| 1324 didDraw(dirtyRect); | |
| 1325 } | |
| 1326 } | 1284 } |
| 1285 return true; |
| 1327 } | 1286 } |
| 1328 | 1287 |
| 1329 void CanvasRenderingContext2D::drawImage(ImageBitmap* bitmap, float x, float y,
ExceptionState& exceptionState) | 1288 void CanvasRenderingContext2D::drawImage(CanvasImageSource* imageSource, float x
, float y, ExceptionState& exceptionState) |
| 1330 { | 1289 { |
| 1331 if (!bitmap) { | 1290 if (!checkImageSource(imageSource, exceptionState)) |
| 1332 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::a
rgumentNullOrIncorrectType(1, "ImageBitmap")); | |
| 1333 return; | 1291 return; |
| 1334 } | 1292 FloatSize destRectSize = imageSource->defaultDestinationSize(); |
| 1335 drawImage(bitmap, x, y, bitmap->width(), bitmap->height(), exceptionState); | 1293 drawImage(imageSource, x, y, destRectSize.width(), destRectSize.height(), ex
ceptionState); |
| 1336 } | 1294 } |
| 1337 | 1295 |
| 1338 void CanvasRenderingContext2D::drawImage(ImageBitmap* bitmap, | 1296 void CanvasRenderingContext2D::drawImage(CanvasImageSource* imageSource, |
| 1339 float x, float y, float width, float height, ExceptionState& exceptionState) | 1297 float x, float y, float width, float height, ExceptionState& exceptionState) |
| 1340 { | 1298 { |
| 1341 if (!bitmap) { | 1299 if (!checkImageSource(imageSource, exceptionState)) |
| 1342 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::a
rgumentNullOrIncorrectType(1, "ImageBitmap")); | |
| 1343 return; | 1300 return; |
| 1344 } | 1301 FloatSize sourceRectSize = imageSource->sourceSize(); |
| 1345 if (!bitmap->bitmapRect().width() || !bitmap->bitmapRect().height()) | 1302 drawImage(imageSource, 0, 0, sourceRectSize.width(), sourceRectSize.height()
, x, y, width, height, exceptionState); |
| 1346 return; | |
| 1347 | |
| 1348 drawImage(bitmap, 0, 0, bitmap->width(), bitmap->height(), x, y, width, heig
ht, exceptionState); | |
| 1349 } | 1303 } |
| 1350 | 1304 |
| 1351 void CanvasRenderingContext2D::drawImage(ImageBitmap* bitmap, | 1305 void CanvasRenderingContext2D::drawImage(CanvasImageSource* imageSource, |
| 1352 float sx, float sy, float sw, float sh, | 1306 float sx, float sy, float sw, float sh, |
| 1353 float dx, float dy, float dw, float dh, ExceptionState& exceptionState) | 1307 float dx, float dy, float dw, float dh, ExceptionState& exceptionState) |
| 1354 { | 1308 { |
| 1355 if (!bitmap) { | 1309 if (!checkImageSource(imageSource, exceptionState)) |
| 1356 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::a
rgumentNullOrIncorrectType(1, "ImageBitmap")); | |
| 1357 return; | |
| 1358 } | |
| 1359 | |
| 1360 FloatRect srcRect(sx, sy, sw, sh); | |
| 1361 FloatRect dstRect(dx, dy, dw, dh); | |
| 1362 FloatRect bitmapRect = bitmap->bitmapRect(); | |
| 1363 | |
| 1364 if (!std::isfinite(dstRect.x()) || !std::isfinite(dstRect.y()) || !std::isfi
nite(dstRect.width()) || !std::isfinite(dstRect.height()) | |
| 1365 || !std::isfinite(srcRect.x()) || !std::isfinite(srcRect.y()) || !std::i
sfinite(srcRect.width()) || !std::isfinite(srcRect.height())) | |
| 1366 return; | 1310 return; |
| 1367 | 1311 |
| 1368 if (!dstRect.width() || !dstRect.height() || !srcRect.width() || !srcRect.he
ight()) | |
| 1369 return; | |
| 1370 | |
| 1371 ASSERT(bitmap->height() && bitmap->width()); | |
| 1372 FloatRect normalizedSrcRect = normalizeRect(srcRect); | |
| 1373 FloatRect normalizedDstRect = normalizeRect(dstRect); | |
| 1374 | |
| 1375 // Clip the rects to where the user thinks that the image is situated. | |
| 1376 clipRectsToImageRect(IntRect(IntPoint(), bitmap->size()), &normalizedSrcRect
, &normalizedDstRect); | |
| 1377 | |
| 1378 FloatRect intersectRect = intersection(bitmapRect, normalizedSrcRect); | |
| 1379 FloatRect actualSrcRect(intersectRect); | |
| 1380 | |
| 1381 IntPoint bitmapOffset = bitmap->bitmapOffset(); | |
| 1382 actualSrcRect.move(bitmapOffset - bitmapRect.location()); | |
| 1383 FloatRect imageRect = FloatRect(bitmapOffset, bitmapRect.size()); | |
| 1384 | |
| 1385 FloatRect actualDstRect(FloatPoint(intersectRect.location() - normalizedSrcR
ect.location()), bitmapRect.size()); | |
| 1386 actualDstRect.scale(normalizedDstRect.width() / normalizedSrcRect.width() *
intersectRect.width() / bitmapRect.width(), | |
| 1387 normalizedDstRect.height() / normalizedSrcRect.height() * intersectRect.
height() / bitmapRect.height()); | |
| 1388 actualDstRect.moveBy(normalizedDstRect.location()); | |
| 1389 | |
| 1390 if (!imageRect.intersects(actualSrcRect)) | |
| 1391 return; | |
| 1392 | |
| 1393 RefPtr<Image> imageForRendering = bitmap->bitmapImage(); | |
| 1394 if (!imageForRendering) | |
| 1395 return; | |
| 1396 | |
| 1397 drawImageInternal(imageForRendering.get(), actualSrcRect, actualDstRect, sta
te().m_globalComposite, state().m_globalBlend); | |
| 1398 } | |
| 1399 | |
| 1400 void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, float x, float
y, ExceptionState& exceptionState) | |
| 1401 { | |
| 1402 if (!image) { | |
| 1403 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::a
rgumentNullOrIncorrectType(1, "HTMLImageElement")); | |
| 1404 return; | |
| 1405 } | |
| 1406 LayoutSize destRectSize = sizeFor(image, ImageSizeAfterDevicePixelRatio); | |
| 1407 drawImage(image, x, y, destRectSize.width(), destRectSize.height(), exceptio
nState); | |
| 1408 } | |
| 1409 | |
| 1410 void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, | |
| 1411 float x, float y, float width, float height, ExceptionState& exceptionState) | |
| 1412 { | |
| 1413 if (!image) { | |
| 1414 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::a
rgumentNullOrIncorrectType(1, "HTMLImageElement")); | |
| 1415 return; | |
| 1416 } | |
| 1417 LayoutSize sourceRectSize = sizeFor(image, ImageSizeBeforeDevicePixelRatio); | |
| 1418 drawImage(image, FloatRect(0, 0, sourceRectSize.width(), sourceRectSize.heig
ht()), FloatRect(x, y, width, height), exceptionState); | |
| 1419 } | |
| 1420 | |
| 1421 void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, | |
| 1422 float sx, float sy, float sw, float sh, | |
| 1423 float dx, float dy, float dw, float dh, ExceptionState& exceptionState) | |
| 1424 { | |
| 1425 drawImage(image, FloatRect(sx, sy, sw, sh), FloatRect(dx, dy, dw, dh), excep
tionState); | |
| 1426 } | |
| 1427 | |
| 1428 void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, const FloatRec
t& srcRect, const FloatRect& dstRect, ExceptionState& exceptionState) | |
| 1429 { | |
| 1430 drawImage(image, srcRect, dstRect, state().m_globalComposite, state().m_glob
alBlend, exceptionState); | |
| 1431 } | |
| 1432 | |
| 1433 void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, const FloatRec
t& srcRect, const FloatRect& dstRect, const CompositeOperator& op, const blink::
WebBlendMode& blendMode, ExceptionState& exceptionState) | |
| 1434 { | |
| 1435 if (!image) { | |
| 1436 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::a
rgumentNullOrIncorrectType(1, "HTMLImageElement")); | |
| 1437 return; | |
| 1438 } | |
| 1439 | |
| 1440 if (!std::isfinite(dstRect.x()) || !std::isfinite(dstRect.y()) || !std::isfi
nite(dstRect.width()) || !std::isfinite(dstRect.height()) | |
| 1441 || !std::isfinite(srcRect.x()) || !std::isfinite(srcRect.y()) || !std::i
sfinite(srcRect.width()) || !std::isfinite(srcRect.height())) | |
| 1442 return; | |
| 1443 | |
| 1444 ImageResource* cachedImage = image->cachedImage(); | |
| 1445 if (!cachedImage || !image->complete()) | |
| 1446 return; | |
| 1447 | |
| 1448 LayoutSize size = sizeFor(image, ImageSizeBeforeDevicePixelRatio); | |
| 1449 if (!size.width() || !size.height() || !dstRect.width() || !dstRect.height()
|| !srcRect.width() || !srcRect.height()) | |
| 1450 return; | |
| 1451 | |
| 1452 FloatRect normalizedSrcRect = normalizeRect(srcRect); | |
| 1453 FloatRect normalizedDstRect = normalizeRect(dstRect); | |
| 1454 | |
| 1455 FloatRect imageRect = FloatRect(FloatPoint(), size); | |
| 1456 if (!imageRect.intersects(normalizedSrcRect)) | |
| 1457 return; | |
| 1458 | |
| 1459 clipRectsToImageRect(imageRect, &normalizedSrcRect, &normalizedDstRect); | |
| 1460 | |
| 1461 checkOrigin(image); | |
| 1462 | |
| 1463 Image* imageForRendering = cachedImage->imageForRenderer(image->renderer()); | |
| 1464 | |
| 1465 // For images that depend on an unavailable container size, we need to fall
back to the intrinsic | |
| 1466 // object size. http://www.w3.org/TR/2dcontext2/#dom-context-2d-drawimage | |
| 1467 // FIXME: Without a specified image size this should resolve against the can
vas element's size, see: crbug.com/230163. | |
| 1468 if (!image->renderer() && imageForRendering->usesContainerSize()) | |
| 1469 imageForRendering->setContainerSize(imageForRendering->size()); | |
| 1470 | |
| 1471 drawImageInternal(imageForRendering, normalizedSrcRect, normalizedDstRect, o
p, blendMode); | |
| 1472 } | |
| 1473 | |
| 1474 void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* sourceCanvas, float
x, float y, ExceptionState& exceptionState) | |
| 1475 { | |
| 1476 drawImage(sourceCanvas, 0, 0, sourceCanvas->width(), sourceCanvas->height(),
x, y, sourceCanvas->width(), sourceCanvas->height(), exceptionState); | |
| 1477 } | |
| 1478 | |
| 1479 void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* sourceCanvas, | |
| 1480 float x, float y, float width, float height, ExceptionState& exceptionState) | |
| 1481 { | |
| 1482 drawImage(sourceCanvas, FloatRect(0, 0, sourceCanvas->width(), sourceCanvas-
>height()), FloatRect(x, y, width, height), exceptionState); | |
| 1483 } | |
| 1484 | |
| 1485 void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* sourceCanvas, | |
| 1486 float sx, float sy, float sw, float sh, | |
| 1487 float dx, float dy, float dw, float dh, ExceptionState& exceptionState) | |
| 1488 { | |
| 1489 drawImage(sourceCanvas, FloatRect(sx, sy, sw, sh), FloatRect(dx, dy, dw, dh)
, exceptionState); | |
| 1490 } | |
| 1491 | |
| 1492 void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* sourceCanvas, const
FloatRect& srcRect, | |
| 1493 const FloatRect& dstRect, ExceptionState& exceptionState) | |
| 1494 { | |
| 1495 if (!sourceCanvas) { | |
| 1496 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::a
rgumentNullOrIncorrectType(1, "HTMLCanvasElement")); | |
| 1497 return; | |
| 1498 } | |
| 1499 | |
| 1500 FloatRect srcCanvasRect = FloatRect(FloatPoint(), sourceCanvas->size()); | |
| 1501 | |
| 1502 if (!srcCanvasRect.width() || !srcCanvasRect.height() || !srcRect.width() ||
!srcRect.height()) | |
| 1503 return; | |
| 1504 | |
| 1505 FloatRect normalizedSrcRect = normalizeRect(srcRect); | |
| 1506 FloatRect normalizedDstRect = normalizeRect(dstRect); | |
| 1507 | |
| 1508 if (!srcCanvasRect.intersects(normalizedSrcRect) || !normalizedDstRect.width
() || !normalizedDstRect.height()) | |
| 1509 return; | |
| 1510 | |
| 1511 clipRectsToImageRect(srcCanvasRect, &normalizedSrcRect, &normalizedDstRect); | |
| 1512 | |
| 1513 GraphicsContext* c = drawingContext(); | |
| 1514 if (!c) | |
| 1515 return; | |
| 1516 if (!state().m_invertibleCTM) | 1312 if (!state().m_invertibleCTM) |
| 1517 return; | 1313 return; |
| 1518 | 1314 |
| 1519 // FIXME: Do this through platform-independent GraphicsContext API. | 1315 RefPtr<Image> image; |
| 1520 ImageBuffer* buffer = sourceCanvas->buffer(); | 1316 bool imageSourceIsVolatile = false; |
| 1521 if (!buffer) | 1317 if (!imageSource->isVideoElement()) { |
| 1318 image = imageSource->getSourceImageForCanvas(canvas(), exceptionState, D
rawCanvasImageSourceUsage, &imageSourceIsVolatile); |
| 1319 if (!image || !image->width() || !image->height()) |
| 1320 return; |
| 1321 } |
| 1322 |
| 1323 if (!std::isfinite(dx) || !std::isfinite(dy) || !std::isfinite(dw) || !std::
isfinite(dh) |
| 1324 || !std::isfinite(sx) || !std::isfinite(sy) || !std::isfinite(sw) || !st
d::isfinite(sh) |
| 1325 || !dw || !dh || !sw || !sh) |
| 1522 return; | 1326 return; |
| 1523 | 1327 |
| 1524 FloatRect clipBounds; | 1328 FloatRect clipBounds; |
| 1525 if (!drawingContext()->getTransformedClipBounds(&clipBounds)) | 1329 if (!drawingContext()->getTransformedClipBounds(&clipBounds)) |
| 1526 return; | 1330 return; |
| 1527 | 1331 |
| 1528 checkOrigin(sourceCanvas); | 1332 FloatRect srcRect = normalizeRect(FloatRect(sx, sy, sw, sh)); |
| 1333 FloatRect dstRect = normalizeRect(FloatRect(dx, dy, dw, dh)); |
| 1529 | 1334 |
| 1530 // If we're drawing from one accelerated canvas 2d to another, avoid calling
sourceCanvas->makeRenderingResultsAvailable() | 1335 clipRectsToImageRect(FloatRect(FloatPoint(), imageSource->sourceSize()), &sr
cRect, &dstRect); |
| 1531 // as that will do a readback to software. | |
| 1532 CanvasRenderingContext* sourceContext = sourceCanvas->renderingContext(); | |
| 1533 // FIXME: Implement an accelerated path for drawing from a WebGL canvas to a
2d canvas when possible. | |
| 1534 if (sourceContext && sourceContext->is3d()) | |
| 1535 sourceContext->paintRenderingResultsToCanvas(); | |
| 1536 | 1336 |
| 1537 if (rectContainsTransformedRect(normalizedDstRect, clipBounds)) { | 1337 imageSource->adjustDrawRects(&srcRect, &dstRect); |
| 1538 c->drawImageBuffer(buffer, normalizedDstRect, normalizedSrcRect, state()
.m_globalComposite, state().m_globalBlend); | |
| 1539 didDraw(clipBounds); | |
| 1540 } else if (isFullCanvasCompositeMode(state().m_globalComposite)) { | |
| 1541 fullCanvasCompositedDrawImage(buffer, normalizedDstRect, normalizedSrcRe
ct, state().m_globalComposite); | |
| 1542 didDraw(clipBounds); | |
| 1543 } else if (state().m_globalComposite == CompositeCopy) { | |
| 1544 clearCanvas(); | |
| 1545 c->drawImageBuffer(buffer, normalizedDstRect, normalizedSrcRect, state()
.m_globalComposite, state().m_globalBlend); | |
| 1546 didDraw(clipBounds); | |
| 1547 } else { | |
| 1548 FloatRect dirtyRect; | |
| 1549 if (computeDirtyRect(normalizedDstRect, clipBounds, &dirtyRect)) { | |
| 1550 c->drawImageBuffer(buffer, normalizedDstRect, normalizedSrcRect, sta
te().m_globalComposite, state().m_globalBlend); | |
| 1551 didDraw(dirtyRect); | |
| 1552 } | |
| 1553 } | |
| 1554 | 1338 |
| 1555 // Flush canvas's ImageBuffer when drawImage from WebGL to HW accelerated 2d
canvas | 1339 if (srcRect.isEmpty()) |
| 1556 if (sourceContext && sourceContext->is3d() && is2d() && isAccelerated() && c
anvas()->buffer()) | |
| 1557 canvas()->buffer()->flush(); | |
| 1558 } | |
| 1559 | |
| 1560 void CanvasRenderingContext2D::drawImage(HTMLVideoElement* video, float x, float
y, ExceptionState& exceptionState) | |
| 1561 { | |
| 1562 if (!video) { | |
| 1563 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::a
rgumentNullOrIncorrectType(1, "HTMLVideoElement")); | |
| 1564 return; | 1340 return; |
| 1565 } | |
| 1566 IntSize size = sizeFor(video); | |
| 1567 drawImage(video, x, y, size.width(), size.height(), exceptionState); | |
| 1568 } | |
| 1569 | |
| 1570 void CanvasRenderingContext2D::drawImage(HTMLVideoElement* video, | |
| 1571 float x, float y, float width, float height, ExceptionState& exceptionState) | |
| 1572 { | |
| 1573 if (!video) { | |
| 1574 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::a
rgumentNullOrIncorrectType(1, "HTMLVideoElement")); | |
| 1575 return; | |
| 1576 } | |
| 1577 IntSize size = sizeFor(video); | |
| 1578 drawImage(video, FloatRect(0, 0, size.width(), size.height()), FloatRect(x,
y, width, height), exceptionState); | |
| 1579 } | |
| 1580 | |
| 1581 void CanvasRenderingContext2D::drawImage(HTMLVideoElement* video, | |
| 1582 float sx, float sy, float sw, float sh, | |
| 1583 float dx, float dy, float dw, float dh, ExceptionState& exceptionState) | |
| 1584 { | |
| 1585 drawImage(video, FloatRect(sx, sy, sw, sh), FloatRect(dx, dy, dw, dh), excep
tionState); | |
| 1586 } | |
| 1587 | |
| 1588 void CanvasRenderingContext2D::drawImage(HTMLVideoElement* video, const FloatRec
t& srcRect, const FloatRect& dstRect, ExceptionState& exceptionState) | |
| 1589 { | |
| 1590 if (!video) { | |
| 1591 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::a
rgumentNullOrIncorrectType(1, "HTMLVideoElement")); | |
| 1592 return; | |
| 1593 } | |
| 1594 | |
| 1595 if (video->readyState() == HTMLMediaElement::HAVE_NOTHING || video->readySta
te() == HTMLMediaElement::HAVE_METADATA) | |
| 1596 return; | |
| 1597 if (!srcRect.width() || !srcRect.height()) | |
| 1598 return; | |
| 1599 | |
| 1600 FloatRect videoRect = FloatRect(FloatPoint(), sizeFor(video)); | |
| 1601 | |
| 1602 FloatRect normalizedSrcRect = normalizeRect(srcRect); | |
| 1603 FloatRect normalizedDstRect = normalizeRect(dstRect); | |
| 1604 | |
| 1605 if (!videoRect.intersects(normalizedSrcRect) || !normalizedDstRect.width() |
| !normalizedDstRect.height()) | |
| 1606 return; | |
| 1607 | |
| 1608 clipRectsToImageRect(videoRect, &normalizedSrcRect, &normalizedDstRect); | |
| 1609 | 1341 |
| 1610 GraphicsContext* c = drawingContext(); | 1342 GraphicsContext* c = drawingContext(); |
| 1611 if (!c) | 1343 if (!c) |
| 1612 return; | 1344 return; |
| 1613 if (!state().m_invertibleCTM) | |
| 1614 return; | |
| 1615 | 1345 |
| 1616 checkOrigin(video); | 1346 FloatRect dirtyRect = clipBounds; |
| 1347 if (imageSource->isVideoElement()) { |
| 1348 GraphicsContextStateSaver stateSaver(*c); |
| 1349 c->clip(dstRect); |
| 1350 c->translate(dstRect.x(), dstRect.y()); |
| 1351 c->scale(FloatSize(dstRect.width() / srcRect.width(), dstRect.height() /
srcRect.height())); |
| 1352 c->translate(-srcRect.x(), -srcRect.y()); |
| 1353 static_cast<HTMLVideoElement*>(imageSource)->paintCurrentFrameInContext(
c, IntRect(IntPoint(), roundedIntSize(imageSource->sourceSize()))); |
| 1354 stateSaver.restore(); |
| 1355 computeDirtyRect(dstRect, clipBounds, &dirtyRect); |
| 1356 } else { |
| 1357 CompositeOperator op = c->compositeOperation(); |
| 1358 blink::WebBlendMode blendMode = c->blendModeOperation(); |
| 1359 if (rectContainsTransformedRect(dstRect, clipBounds)) { |
| 1360 c->drawImage(image.get(), dstRect, srcRect, op, blendMode); |
| 1361 } else if (isFullCanvasCompositeMode(op)) { |
| 1362 fullCanvasCompositedDrawImage(image.get(), dstRect, srcRect, op); |
| 1363 } else if (op == CompositeCopy) { |
| 1364 clearCanvas(); |
| 1365 c->drawImage(image.get(), dstRect, srcRect, op, blendMode); |
| 1366 } else { |
| 1367 FloatRect dirtyRect; |
| 1368 computeDirtyRect(dstRect, clipBounds, &dirtyRect); |
| 1369 c->drawImage(image.get(), dstRect, srcRect, op, blendMode); |
| 1370 } |
| 1617 | 1371 |
| 1618 FloatRect dirtyRect; | 1372 if (imageSourceIsVolatile && is2d() && isAccelerated() && canvas()->buff
er()) |
| 1619 if (!computeDirtyRect(normalizedDstRect, &dirtyRect)) | 1373 canvas()->buffer()->flush(); |
| 1620 return; | 1374 } |
| 1621 | 1375 |
| 1622 GraphicsContextStateSaver stateSaver(*c); | 1376 if (canvas()->originClean() && imageSource->wouldTaintOrigin(this)) |
| 1623 c->clip(normalizedDstRect); | 1377 canvas()->setOriginTainted(); |
| 1624 c->translate(normalizedDstRect.x(), normalizedDstRect.y()); | |
| 1625 c->scale(FloatSize(normalizedDstRect.width() / normalizedSrcRect.width(), no
rmalizedDstRect.height() / normalizedSrcRect.height())); | |
| 1626 c->translate(-normalizedSrcRect.x(), -normalizedSrcRect.y()); | |
| 1627 video->paintCurrentFrameInContext(c, IntRect(IntPoint(), sizeFor(video))); | |
| 1628 stateSaver.restore(); | |
| 1629 | 1378 |
| 1630 didDraw(dirtyRect); | 1379 didDraw(dirtyRect); |
| 1631 } | 1380 } |
| 1632 | 1381 |
| 1382 |
| 1633 void CanvasRenderingContext2D::drawImageFromRect(HTMLImageElement* image, | 1383 void CanvasRenderingContext2D::drawImageFromRect(HTMLImageElement* image, |
| 1634 float sx, float sy, float sw, float sh, | 1384 float sx, float sy, float sw, float sh, |
| 1635 float dx, float dy, float dw, float dh, | 1385 float dx, float dy, float dw, float dh, |
| 1636 const String& compositeOperation) | 1386 const String& compositeOperation) |
| 1637 { | 1387 { |
| 1388 GraphicsContext* c = drawingContext(); |
| 1389 if (!c) |
| 1390 return; |
| 1638 CompositeOperator op; | 1391 CompositeOperator op; |
| 1639 blink::WebBlendMode blendOp = blink::WebBlendModeNormal; | 1392 blink::WebBlendMode blendOp = blink::WebBlendModeNormal; |
| 1640 if (!parseCompositeAndBlendOperator(compositeOperation, op, blendOp) || blen
dOp != blink::WebBlendModeNormal) | 1393 if (!parseCompositeAndBlendOperator(compositeOperation, op, blendOp) || blen
dOp != blink::WebBlendModeNormal) |
| 1641 op = CompositeSourceOver; | 1394 op = CompositeSourceOver; |
| 1642 | 1395 |
| 1643 drawImage(image, FloatRect(sx, sy, sw, sh), FloatRect(dx, dy, dw, dh), op, b
link::WebBlendModeNormal, IGNORE_EXCEPTION); | 1396 CompositeOperator savedOp = c->compositeOperation(); |
| 1397 blink::WebBlendMode savedBlendMode = c->blendModeOperation(); |
| 1398 c->setCompositeOperation(op, blink::WebBlendModeNormal); |
| 1399 drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh, IGNORE_EXCEPTION); |
| 1400 c->setCompositeOperation(savedOp, savedBlendMode); |
| 1644 } | 1401 } |
| 1645 | 1402 |
| 1646 void CanvasRenderingContext2D::setAlpha(float alpha) | 1403 void CanvasRenderingContext2D::setAlpha(float alpha) |
| 1647 { | 1404 { |
| 1648 setGlobalAlpha(alpha); | 1405 setGlobalAlpha(alpha); |
| 1649 } | 1406 } |
| 1650 | 1407 |
| 1651 void CanvasRenderingContext2D::setCompositeOperation(const String& operation) | 1408 void CanvasRenderingContext2D::setCompositeOperation(const String& operation) |
| 1652 { | 1409 { |
| 1653 setGlobalCompositeOperation(operation); | 1410 setGlobalCompositeOperation(operation); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1671 FloatQuad quad(rect); | 1428 FloatQuad quad(rect); |
| 1672 FloatQuad transformedQuad(transformedRect); | 1429 FloatQuad transformedQuad(transformedRect); |
| 1673 return state().m_transform.mapQuad(quad).containsQuad(transformedQuad); | 1430 return state().m_transform.mapQuad(quad).containsQuad(transformedQuad); |
| 1674 } | 1431 } |
| 1675 | 1432 |
| 1676 static void drawImageToContext(Image* image, GraphicsContext* context, const Flo
atRect& dest, const FloatRect& src, CompositeOperator op) | 1433 static void drawImageToContext(Image* image, GraphicsContext* context, const Flo
atRect& dest, const FloatRect& src, CompositeOperator op) |
| 1677 { | 1434 { |
| 1678 context->drawImage(image, dest, src, op); | 1435 context->drawImage(image, dest, src, op); |
| 1679 } | 1436 } |
| 1680 | 1437 |
| 1681 static void drawImageToContext(ImageBuffer* imageBuffer, GraphicsContext* contex
t, const FloatRect& dest, const FloatRect& src, CompositeOperator op) | |
| 1682 { | |
| 1683 context->drawImageBuffer(imageBuffer, dest, src, op); | |
| 1684 } | |
| 1685 | |
| 1686 template<class T> void CanvasRenderingContext2D::fullCanvasCompositedDrawImage(
T* image, const FloatRect& dest, const FloatRect& src, CompositeOperator op) | 1438 template<class T> void CanvasRenderingContext2D::fullCanvasCompositedDrawImage(
T* image, const FloatRect& dest, const FloatRect& src, CompositeOperator op) |
| 1687 { | 1439 { |
| 1688 ASSERT(isFullCanvasCompositeMode(op)); | 1440 ASSERT(isFullCanvasCompositeMode(op)); |
| 1689 | 1441 |
| 1690 drawingContext()->beginLayer(1, op); | 1442 drawingContext()->beginLayer(1, op); |
| 1691 drawImageToContext(image, drawingContext(), dest, src, CompositeSourceOver); | 1443 drawImageToContext(image, drawingContext(), dest, src, CompositeSourceOver); |
| 1692 drawingContext()->endLayer(); | 1444 drawingContext()->endLayer(); |
| 1693 } | 1445 } |
| 1694 | 1446 |
| 1695 static void fillPrimitive(const FloatRect& rect, GraphicsContext* context) | 1447 static void fillPrimitive(const FloatRect& rect, GraphicsContext* context) |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1751 else if (r0 < 0 || r1 < 0) | 1503 else if (r0 < 0 || r1 < 0) |
| 1752 exceptionState.throwDOMException(IndexSizeError, String::format("The %s
provided is less than 0.", r0 < 0 ? "r0" : "r1")); | 1504 exceptionState.throwDOMException(IndexSizeError, String::format("The %s
provided is less than 0.", r0 < 0 ? "r0" : "r1")); |
| 1753 | 1505 |
| 1754 if (exceptionState.hadException()) | 1506 if (exceptionState.hadException()) |
| 1755 return nullptr; | 1507 return nullptr; |
| 1756 | 1508 |
| 1757 RefPtr<CanvasGradient> gradient = CanvasGradient::create(FloatPoint(x0, y0),
r0, FloatPoint(x1, y1), r1); | 1509 RefPtr<CanvasGradient> gradient = CanvasGradient::create(FloatPoint(x0, y0),
r0, FloatPoint(x1, y1), r1); |
| 1758 return gradient.release(); | 1510 return gradient.release(); |
| 1759 } | 1511 } |
| 1760 | 1512 |
| 1761 PassRefPtr<CanvasPattern> CanvasRenderingContext2D::createPattern(HTMLImageEleme
nt* image, | 1513 PassRefPtr<CanvasPattern> CanvasRenderingContext2D::createPattern(CanvasImageSou
rce* imageSource, |
| 1762 const String& repetitionType, ExceptionState& exceptionState) | 1514 const String& repetitionType, ExceptionState& exceptionState) |
| 1763 { | 1515 { |
| 1764 if (!image) { | 1516 if (!checkImageSource(imageSource, exceptionState)) |
| 1765 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::a
rgumentNullOrIncorrectType(1, "HTMLImageElement")); | |
| 1766 return nullptr; | 1517 return nullptr; |
| 1767 } | |
| 1768 bool repeatX, repeatY; | 1518 bool repeatX, repeatY; |
| 1769 CanvasPattern::parseRepetitionType(repetitionType, repeatX, repeatY, excepti
onState); | 1519 CanvasPattern::parseRepetitionType(repetitionType, repeatX, repeatY, excepti
onState); |
| 1770 if (exceptionState.hadException()) | 1520 if (exceptionState.hadException()) |
| 1771 return nullptr; | 1521 return nullptr; |
| 1772 | 1522 |
| 1773 if (!image->complete()) | 1523 RefPtr<Image> imageForRendering = imageSource->getSourceImageForCanvas(canva
s(), exceptionState, PatternCanvasImageSourceUsage); |
| 1524 if (exceptionState.hadException() || !imageForRendering) |
| 1774 return nullptr; | 1525 return nullptr; |
| 1775 | 1526 |
| 1776 ImageResource* cachedImage = image->cachedImage(); | 1527 return CanvasPattern::create(imageForRendering.release(), repeatX, repeatY,
!imageSource->wouldTaintOrigin(this)); |
| 1777 Image* imageForRendering = cachedImage ? cachedImage->imageForRenderer(image
->renderer()) : 0; | |
| 1778 if (!imageForRendering) | |
| 1779 return CanvasPattern::create(Image::nullImage(), repeatX, repeatY, true)
; | |
| 1780 | |
| 1781 // We need to synthesize a container size if a renderer is not available to
provide one. | |
| 1782 if (!image->renderer() && imageForRendering->usesContainerSize()) | |
| 1783 imageForRendering->setContainerSize(imageForRendering->size()); | |
| 1784 | |
| 1785 bool originClean = cachedImage->isAccessAllowed(canvas()->securityOrigin()); | |
| 1786 return CanvasPattern::create(imageForRendering, repeatX, repeatY, originClea
n); | |
| 1787 } | |
| 1788 | |
| 1789 PassRefPtr<CanvasPattern> CanvasRenderingContext2D::createPattern(HTMLCanvasElem
ent* canvas, | |
| 1790 const String& repetitionType, ExceptionState& exceptionState) | |
| 1791 { | |
| 1792 if (!canvas) | |
| 1793 exceptionState.throwDOMException(TypeMismatchError, ExceptionMessages::a
rgumentNullOrIncorrectType(1, "HTMLCanvasElement")); | |
| 1794 else if (!canvas->width() || !canvas->height()) | |
| 1795 exceptionState.throwDOMException(InvalidStateError, String::format("The
canvas %s is 0.", canvas->width() ? "height" : "width")); | |
| 1796 | |
| 1797 if (exceptionState.hadException()) | |
| 1798 return nullptr; | |
| 1799 | |
| 1800 bool repeatX, repeatY; | |
| 1801 CanvasPattern::parseRepetitionType(repetitionType, repeatX, repeatY, excepti
onState); | |
| 1802 if (exceptionState.hadException()) | |
| 1803 return nullptr; | |
| 1804 return CanvasPattern::create(canvas->copiedImage(), repeatX, repeatY, canvas
->originClean()); | |
| 1805 } | 1528 } |
| 1806 | 1529 |
| 1807 bool CanvasRenderingContext2D::computeDirtyRect(const FloatRect& localRect, Floa
tRect* dirtyRect) | 1530 bool CanvasRenderingContext2D::computeDirtyRect(const FloatRect& localRect, Floa
tRect* dirtyRect) |
| 1808 { | 1531 { |
| 1809 FloatRect clipBounds; | 1532 FloatRect clipBounds; |
| 1810 if (!drawingContext()->getTransformedClipBounds(&clipBounds)) | 1533 if (!drawingContext()->getTransformedClipBounds(&clipBounds)) |
| 1811 return false; | 1534 return false; |
| 1812 return computeDirtyRect(localRect, clipBounds, dirtyRect); | 1535 return computeDirtyRect(localRect, clipBounds, dirtyRect); |
| 1813 } | 1536 } |
| 1814 | 1537 |
| (...skipping 629 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2444 const int focusRingWidth = 5; | 2167 const int focusRingWidth = 5; |
| 2445 const int focusRingOutline = 0; | 2168 const int focusRingOutline = 0; |
| 2446 c->drawFocusRing(path, focusRingWidth, focusRingOutline, focusRingColor); | 2169 c->drawFocusRing(path, focusRingWidth, focusRingOutline, focusRingColor); |
| 2447 | 2170 |
| 2448 c->restore(); | 2171 c->restore(); |
| 2449 | 2172 |
| 2450 didDraw(dirtyRect); | 2173 didDraw(dirtyRect); |
| 2451 } | 2174 } |
| 2452 | 2175 |
| 2453 } // namespace WebCore | 2176 } // namespace WebCore |
| OLD | NEW |