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 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
83 static const char ltr[] = "ltr"; | 83 static const char ltr[] = "ltr"; |
84 static const double TryRestoreContextInterval = 0.5; | 84 static const double TryRestoreContextInterval = 0.5; |
85 static const unsigned MaxTryRestoreContextAttempts = 4; | 85 static const unsigned MaxTryRestoreContextAttempts = 4; |
86 static const unsigned FetchedFontsCacheLimit = 50; | 86 static const unsigned FetchedFontsCacheLimit = 50; |
87 | 87 |
88 static bool contextLostRestoredEventsEnabled() | 88 static bool contextLostRestoredEventsEnabled() |
89 { | 89 { |
90 return RuntimeEnabledFeatures::experimentalCanvasFeaturesEnabled(); | 90 return RuntimeEnabledFeatures::experimentalCanvasFeaturesEnabled(); |
91 } | 91 } |
92 | 92 |
| 93 // Drawing methods need to use this instead of SkAutoCanvasRestore in case overd
raw |
| 94 // detection substitutes the recording canvas (to discard overdrawn draw calls). |
| 95 class CanvasRenderingContext2DAutoRestoreSkCanvas { |
| 96 public: |
| 97 CanvasRenderingContext2DAutoRestoreSkCanvas(CanvasRenderingContext2D* contex
t) |
| 98 : m_context(context) |
| 99 { |
| 100 ASSERT(m_context); |
| 101 SkCanvas* c = m_context->drawingCanvas(); |
| 102 if (c) { |
| 103 m_saveCount = c->getSaveCount(); |
| 104 } |
| 105 } |
| 106 |
| 107 ~CanvasRenderingContext2DAutoRestoreSkCanvas() |
| 108 { |
| 109 SkCanvas* c = m_context->drawingCanvas(); |
| 110 if (c) |
| 111 c->restoreToCount(m_saveCount); |
| 112 m_context->validateStateStack(); |
| 113 } |
| 114 private: |
| 115 CanvasRenderingContext2D* m_context; |
| 116 int m_saveCount; |
| 117 }; |
| 118 |
93 CanvasRenderingContext2D::CanvasRenderingContext2D(HTMLCanvasElement* canvas, co
nst CanvasContextCreationAttributes& attrs, Document& document) | 119 CanvasRenderingContext2D::CanvasRenderingContext2D(HTMLCanvasElement* canvas, co
nst CanvasContextCreationAttributes& attrs, Document& document) |
94 : CanvasRenderingContext(canvas) | 120 : CanvasRenderingContext(canvas) |
95 , m_usesCSSCompatibilityParseMode(document.inQuirksMode()) | 121 , m_usesCSSCompatibilityParseMode(document.inQuirksMode()) |
96 , m_clipAntialiasing(NotAntiAliased) | 122 , m_clipAntialiasing(NotAntiAliased) |
97 , m_hasAlpha(attrs.alpha()) | 123 , m_hasAlpha(attrs.alpha()) |
98 , m_isContextLost(false) | 124 , m_isContextLost(false) |
99 , m_contextRestorable(true) | 125 , m_contextRestorable(true) |
100 , m_tryRestoreContextAttemptCount(0) | 126 , m_tryRestoreContextAttemptCount(0) |
101 , m_dispatchContextLostEventTimer(this, &CanvasRenderingContext2D::dispatchC
ontextLostEvent) | 127 , m_dispatchContextLostEventTimer(this, &CanvasRenderingContext2D::dispatchC
ontextLostEvent) |
102 , m_dispatchContextRestoredEventTimer(this, &CanvasRenderingContext2D::dispa
tchContextRestoredEvent) | 128 , m_dispatchContextRestoredEventTimer(this, &CanvasRenderingContext2D::dispa
tchContextRestoredEvent) |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
276 , m_globalComposite(SkXfermode::kSrcOver_Mode) | 302 , m_globalComposite(SkXfermode::kSrcOver_Mode) |
277 , m_invertibleCTM(true) | 303 , m_invertibleCTM(true) |
278 , m_lineDashOffset(0) | 304 , m_lineDashOffset(0) |
279 , m_imageSmoothingEnabled(true) | 305 , m_imageSmoothingEnabled(true) |
280 , m_textAlign(StartTextAlign) | 306 , m_textAlign(StartTextAlign) |
281 , m_textBaseline(AlphabeticTextBaseline) | 307 , m_textBaseline(AlphabeticTextBaseline) |
282 , m_direction(DirectionInherit) | 308 , m_direction(DirectionInherit) |
283 , m_unparsedFont(defaultFont) | 309 , m_unparsedFont(defaultFont) |
284 , m_realizedFont(false) | 310 , m_realizedFont(false) |
285 , m_hasClip(false) | 311 , m_hasClip(false) |
| 312 , m_hasComplexClip(false) |
286 { | 313 { |
287 } | 314 } |
288 | 315 |
289 CanvasRenderingContext2D::State::State(const State& other, ClipListCopyMode mode
) | 316 CanvasRenderingContext2D::State::State(const State& other, ClipListCopyMode mode
) |
290 : CSSFontSelectorClient() | 317 : CSSFontSelectorClient() |
291 , m_unrealizedSaveCount(other.m_unrealizedSaveCount) | 318 , m_unrealizedSaveCount(other.m_unrealizedSaveCount) |
292 , m_unparsedStrokeColor(other.m_unparsedStrokeColor) | 319 , m_unparsedStrokeColor(other.m_unparsedStrokeColor) |
293 , m_unparsedFillColor(other.m_unparsedFillColor) | 320 , m_unparsedFillColor(other.m_unparsedFillColor) |
294 , m_strokeStyle(other.m_strokeStyle) | 321 , m_strokeStyle(other.m_strokeStyle) |
295 , m_fillStyle(other.m_fillStyle) | 322 , m_fillStyle(other.m_fillStyle) |
(...skipping 10 matching lines...) Expand all Loading... |
306 , m_invertibleCTM(other.m_invertibleCTM) | 333 , m_invertibleCTM(other.m_invertibleCTM) |
307 , m_lineDashOffset(other.m_lineDashOffset) | 334 , m_lineDashOffset(other.m_lineDashOffset) |
308 , m_imageSmoothingEnabled(other.m_imageSmoothingEnabled) | 335 , m_imageSmoothingEnabled(other.m_imageSmoothingEnabled) |
309 , m_textAlign(other.m_textAlign) | 336 , m_textAlign(other.m_textAlign) |
310 , m_textBaseline(other.m_textBaseline) | 337 , m_textBaseline(other.m_textBaseline) |
311 , m_direction(other.m_direction) | 338 , m_direction(other.m_direction) |
312 , m_unparsedFont(other.m_unparsedFont) | 339 , m_unparsedFont(other.m_unparsedFont) |
313 , m_font(other.m_font) | 340 , m_font(other.m_font) |
314 , m_realizedFont(other.m_realizedFont) | 341 , m_realizedFont(other.m_realizedFont) |
315 , m_hasClip(other.m_hasClip) | 342 , m_hasClip(other.m_hasClip) |
| 343 , m_hasComplexClip(other.m_hasComplexClip) |
316 { | 344 { |
317 if (mode == CopyClipList) { | 345 if (mode == CopyClipList) { |
318 m_clipList = other.m_clipList; | 346 m_clipList = other.m_clipList; |
319 } | 347 } |
320 if (m_realizedFont) | 348 if (m_realizedFont) |
321 static_cast<CSSFontSelector*>(m_font.fontSelector())->registerForInvalid
ationCallbacks(this); | 349 static_cast<CSSFontSelector*>(m_font.fontSelector())->registerForInvalid
ationCallbacks(this); |
322 } | 350 } |
323 | 351 |
324 CanvasRenderingContext2D::State& CanvasRenderingContext2D::State::operator=(cons
t State& other) | 352 CanvasRenderingContext2D::State& CanvasRenderingContext2D::State::operator=(cons
t State& other) |
325 { | 353 { |
(...skipping 22 matching lines...) Expand all Loading... |
348 m_transform = other.m_transform; | 376 m_transform = other.m_transform; |
349 m_invertibleCTM = other.m_invertibleCTM; | 377 m_invertibleCTM = other.m_invertibleCTM; |
350 m_imageSmoothingEnabled = other.m_imageSmoothingEnabled; | 378 m_imageSmoothingEnabled = other.m_imageSmoothingEnabled; |
351 m_textAlign = other.m_textAlign; | 379 m_textAlign = other.m_textAlign; |
352 m_textBaseline = other.m_textBaseline; | 380 m_textBaseline = other.m_textBaseline; |
353 m_direction = other.m_direction; | 381 m_direction = other.m_direction; |
354 m_unparsedFont = other.m_unparsedFont; | 382 m_unparsedFont = other.m_unparsedFont; |
355 m_font = other.m_font; | 383 m_font = other.m_font; |
356 m_realizedFont = other.m_realizedFont; | 384 m_realizedFont = other.m_realizedFont; |
357 m_hasClip = other.m_hasClip; | 385 m_hasClip = other.m_hasClip; |
| 386 m_hasComplexClip = other.m_hasComplexClip; |
358 m_clipList = other.m_clipList; | 387 m_clipList = other.m_clipList; |
359 | 388 |
360 if (m_realizedFont) | 389 if (m_realizedFont) |
361 static_cast<CSSFontSelector*>(m_font.fontSelector())->registerForInvalid
ationCallbacks(this); | 390 static_cast<CSSFontSelector*>(m_font.fontSelector())->registerForInvalid
ationCallbacks(this); |
362 | 391 |
363 return *this; | 392 return *this; |
364 } | 393 } |
365 | 394 |
366 CanvasRenderingContext2D::State::~State() | 395 CanvasRenderingContext2D::State::~State() |
367 { | 396 { |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
535 } else if (style.isCanvasPattern()) { | 564 } else if (style.isCanvasPattern()) { |
536 RefPtrWillBeRawPtr<CanvasPattern> canvasPattern = style.getAsCanvasPatte
rn(); | 565 RefPtrWillBeRawPtr<CanvasPattern> canvasPattern = style.getAsCanvasPatte
rn(); |
537 | 566 |
538 if (canvas()->originClean() && !canvasPattern->originClean()) | 567 if (canvas()->originClean() && !canvasPattern->originClean()) |
539 canvas()->setOriginTainted(); | 568 canvas()->setOriginTainted(); |
540 | 569 |
541 canvasStyle = CanvasStyle::createFromPattern(canvasPattern); | 570 canvasStyle = CanvasStyle::createFromPattern(canvasPattern); |
542 } | 571 } |
543 | 572 |
544 ASSERT(canvasStyle); | 573 ASSERT(canvasStyle); |
545 | |
546 SkCanvas* c = drawingCanvas(); | 574 SkCanvas* c = drawingCanvas(); |
547 realizeSaves(c); | |
548 modifiableState().m_fillStyle = canvasStyle.release(); | |
549 if (!c) | 575 if (!c) |
550 return; | 576 return; |
| 577 realizeSaves(c); |
| 578 |
| 579 modifiableState().m_fillStyle = canvasStyle.release(); |
| 580 modifiableState().m_unparsedFillColor = colorString; |
551 state().m_fillStyle->applyFillColor(drawingContext()); | 581 state().m_fillStyle->applyFillColor(drawingContext()); |
552 modifiableState().m_unparsedFillColor = colorString; | |
553 } | 582 } |
554 | 583 |
555 float CanvasRenderingContext2D::lineWidth() const | 584 float CanvasRenderingContext2D::lineWidth() const |
556 { | 585 { |
557 return state().m_lineWidth; | 586 return state().m_lineWidth; |
558 } | 587 } |
559 | 588 |
560 void CanvasRenderingContext2D::setLineWidth(float width) | 589 void CanvasRenderingContext2D::setLineWidth(float width) |
561 { | 590 { |
562 if (!std::isfinite(width) || width <= 0) | 591 if (!std::isfinite(width) || width <= 0) |
(...skipping 552 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1115 | 1144 |
1116 SkPath skPath = path.skPath(); | 1145 SkPath skPath = path.skPath(); |
1117 skPath.setFillType(parseWinding(windingRuleString)); | 1146 skPath.setFillType(parseWinding(windingRuleString)); |
1118 ImageBuffer* buffer = canvas()->buffer(); | 1147 ImageBuffer* buffer = canvas()->buffer(); |
1119 if (buffer && buffer->needsClipTracking()) { | 1148 if (buffer && buffer->needsClipTracking()) { |
1120 modifiableState().m_clipList.clipPath(skPath, m_clipAntialiasing, affine
TransformToSkMatrix(state().m_transform)); | 1149 modifiableState().m_clipList.clipPath(skPath, m_clipAntialiasing, affine
TransformToSkMatrix(state().m_transform)); |
1121 } | 1150 } |
1122 | 1151 |
1123 c->clipPath(skPath, SkRegion::kIntersect_Op, m_clipAntialiasing == AntiAlias
ed); | 1152 c->clipPath(skPath, SkRegion::kIntersect_Op, m_clipAntialiasing == AntiAlias
ed); |
1124 if (!skPath.isRect(0)) | 1153 if (!skPath.isRect(0)) |
1125 drawingContext()->setHasComplexClip(); | 1154 modifiableState().m_hasComplexClip = true; |
1126 modifiableState().m_hasClip = true; | 1155 modifiableState().m_hasClip = true; |
1127 } | 1156 } |
1128 | 1157 |
1129 void CanvasRenderingContext2D::clip(const String& windingRuleString) | 1158 void CanvasRenderingContext2D::clip(const String& windingRuleString) |
1130 { | 1159 { |
1131 clipInternal(m_path, windingRuleString); | 1160 clipInternal(m_path, windingRuleString); |
1132 } | 1161 } |
1133 | 1162 |
1134 void CanvasRenderingContext2D::clip(Path2D* domPath, const String& windingRuleSt
ring) | 1163 void CanvasRenderingContext2D::clip(Path2D* domPath, const String& windingRuleSt
ring) |
1135 { | 1164 { |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1229 pathRect, ScrollAlignment::alignCenterAlways, ScrollAlignment::alignTopA
lways); | 1258 pathRect, ScrollAlignment::alignCenterAlways, ScrollAlignment::alignTopA
lways); |
1230 | 1259 |
1231 // TODO: should implement "inform the user" that the caret and/or | 1260 // TODO: should implement "inform the user" that the caret and/or |
1232 // selection the specified rectangle of the canvas. See http://crbug.com/357
987 | 1261 // selection the specified rectangle of the canvas. See http://crbug.com/357
987 |
1233 } | 1262 } |
1234 | 1263 |
1235 void CanvasRenderingContext2D::clearRect(float x, float y, float width, float he
ight) | 1264 void CanvasRenderingContext2D::clearRect(float x, float y, float width, float he
ight) |
1236 { | 1265 { |
1237 if (!validateRectForCanvas(x, y, width, height)) | 1266 if (!validateRectForCanvas(x, y, width, height)) |
1238 return; | 1267 return; |
1239 GraphicsContext* context = drawingContext(); | 1268 |
1240 if (!context) | 1269 GraphicsContext* c = drawingContext(); |
| 1270 if (!c) |
1241 return; | 1271 return; |
1242 if (!state().m_invertibleCTM) | 1272 if (!state().m_invertibleCTM) |
1243 return; | 1273 return; |
1244 FloatRect rect(x, y, width, height); | |
1245 | 1274 |
1246 FloatRect dirtyRect; | 1275 c->clearShadow(); |
1247 if (!computeDirtyRect(rect, &dirtyRect)) | 1276 c->setAlphaAsFloat(1); |
1248 return; | 1277 c->setCompositeOperation(SkXfermode::kClear_Mode); |
1249 | 1278 |
1250 context->clearShadow(); | 1279 // call to didDraw is taken care of in fillRect |
1251 context->setAlphaAsFloat(1); | 1280 fillRect(x, y, width, height); |
1252 context->setCompositeOperation(SkXfermode::kSrcOver_Mode); | |
1253 | |
1254 context->clearRect(rect); | |
1255 if (m_hitRegionManager) | |
1256 m_hitRegionManager->removeHitRegionsInRect(rect, state().m_transform); | |
1257 | 1281 |
1258 applyShadow(DrawShadowAndForeground); | 1282 applyShadow(DrawShadowAndForeground); |
1259 context->setAlphaAsFloat(state().m_globalAlpha); | 1283 c->setAlphaAsFloat(state().m_globalAlpha); |
1260 context->setCompositeOperation(state().m_globalComposite); | 1284 c->setCompositeOperation(state().m_globalComposite); |
1261 | 1285 |
1262 validateStateStack(); | 1286 if (m_hitRegionManager) { |
1263 didDraw(dirtyRect); | 1287 FloatRect rect(x, y, width, height); |
| 1288 m_hitRegionManager->removeHitRegionsInRect(rect, state().m_transform); |
| 1289 } |
1264 } | 1290 } |
1265 | 1291 |
1266 // FIXME(crbug.com/425531): Funtional.h cannot handle override function signatur
e. | 1292 // FIXME(crbug.com/425531): Funtional.h cannot handle override function signatur
e. |
1267 static void fillRectOnContext(GraphicsContext* context, const FloatRect& rect) | 1293 static void fillRectOnContext(GraphicsContext* context, const FloatRect& rect) |
1268 { | 1294 { |
1269 context->fillRect(rect); | 1295 context->fillRect(rect); |
1270 } | 1296 } |
1271 | 1297 |
1272 static void strokeRectOnContext(GraphicsContext* context, const FloatRect& rect) | 1298 static void strokeRectOnContext(GraphicsContext* context, const FloatRect& rect) |
1273 { | 1299 { |
(...skipping 16 matching lines...) Expand all Loading... |
1290 | 1316 |
1291 // from the HTML5 Canvas spec: | 1317 // from the HTML5 Canvas spec: |
1292 // If x0 = x1 and y0 = y1, then the linear gradient must paint nothing | 1318 // If x0 = x1 and y0 = y1, then the linear gradient must paint nothing |
1293 // If x0 = x1 and y0 = y1 and r0 = r1, then the radial gradient must paint n
othing | 1319 // If x0 = x1 and y0 = y1 and r0 = r1, then the radial gradient must paint n
othing |
1294 Gradient* gradient = c->fillGradient(); | 1320 Gradient* gradient = c->fillGradient(); |
1295 if (gradient && gradient->isZeroSize()) | 1321 if (gradient && gradient->isZeroSize()) |
1296 return; | 1322 return; |
1297 | 1323 |
1298 FloatRect rect(x, y, width, height); | 1324 FloatRect rect(x, y, width, height); |
1299 if (rectContainsTransformedRect(rect, clipBounds)) { | 1325 if (rectContainsTransformedRect(rect, clipBounds)) { |
| 1326 checkOverdraw(rect, &c->fillPaint(), NoImage, ClipFill); |
1300 c->fillRect(rect); | 1327 c->fillRect(rect); |
1301 didDraw(clipBounds); | 1328 didDraw(clipBounds); |
1302 } else if (isFullCanvasCompositeMode(state().m_globalComposite)) { | 1329 } else if (isFullCanvasCompositeMode(state().m_globalComposite)) { |
1303 fullCanvasCompositedDraw(bind(&fillRectOnContext, c, rect)); | 1330 fullCanvasCompositedDraw(bind(&fillRectOnContext, c, rect)); |
1304 didDraw(clipBounds); | 1331 didDraw(clipBounds); |
1305 } else if (state().m_globalComposite == SkXfermode::kSrc_Mode) { | 1332 } else if (state().m_globalComposite == SkXfermode::kSrc_Mode) { |
1306 clearCanvas(); | 1333 clearCanvas(); |
1307 c->clearShadow(); | 1334 c->clearShadow(); // Takes care of signaling the overdraw |
1308 c->fillRect(rect); | 1335 c->fillRect(rect); |
1309 applyShadow(DrawShadowAndForeground); | 1336 applyShadow(DrawShadowAndForeground); |
1310 didDraw(clipBounds); | 1337 didDraw(clipBounds); |
1311 } else { | 1338 } else { |
1312 FloatRect dirtyRect; | 1339 FloatRect dirtyRect; |
1313 if (computeDirtyRect(rect, clipBounds, &dirtyRect)) { | 1340 if (computeDirtyRect(rect, clipBounds, &dirtyRect)) { |
1314 c->fillRect(rect); | 1341 c->fillRect(rect); |
1315 didDraw(dirtyRect); | 1342 didDraw(dirtyRect); |
1316 } | 1343 } |
1317 } | 1344 } |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1418 return value.getAsImageBitmap().get(); | 1445 return value.getAsImageBitmap().get(); |
1419 ASSERT_NOT_REACHED(); | 1446 ASSERT_NOT_REACHED(); |
1420 return nullptr; | 1447 return nullptr; |
1421 } | 1448 } |
1422 | 1449 |
1423 void CanvasRenderingContext2D::drawImage(const CanvasImageSourceUnion& imageSour
ce, float x, float y, ExceptionState& exceptionState) | 1450 void CanvasRenderingContext2D::drawImage(const CanvasImageSourceUnion& imageSour
ce, float x, float y, ExceptionState& exceptionState) |
1424 { | 1451 { |
1425 CanvasImageSource* imageSourceInternal = toImageSourceInternal(imageSource); | 1452 CanvasImageSource* imageSourceInternal = toImageSourceInternal(imageSource); |
1426 FloatSize sourceRectSize = imageSourceInternal->sourceSize(); | 1453 FloatSize sourceRectSize = imageSourceInternal->sourceSize(); |
1427 FloatSize destRectSize = imageSourceInternal->defaultDestinationSize(); | 1454 FloatSize destRectSize = imageSourceInternal->defaultDestinationSize(); |
1428 drawImageInternal(imageSourceInternal, 0, 0, sourceRectSize.width(), sourceR
ectSize.height(), x, y, destRectSize.width(), destRectSize.height(), exceptionSt
ate); | 1455 drawImage(imageSourceInternal, 0, 0, sourceRectSize.width(), sourceRectSize.
height(), x, y, destRectSize.width(), destRectSize.height(), exceptionState); |
1429 } | 1456 } |
1430 | 1457 |
1431 void CanvasRenderingContext2D::drawImage(const CanvasImageSourceUnion& imageSour
ce, | 1458 void CanvasRenderingContext2D::drawImage(const CanvasImageSourceUnion& imageSour
ce, |
1432 float x, float y, float width, float height, ExceptionState& exceptionState) | 1459 float x, float y, float width, float height, ExceptionState& exceptionState) |
1433 { | 1460 { |
1434 CanvasImageSource* imageSourceInternal = toImageSourceInternal(imageSource); | 1461 CanvasImageSource* imageSourceInternal = toImageSourceInternal(imageSource); |
1435 FloatSize sourceRectSize = imageSourceInternal->sourceSize(); | 1462 FloatSize sourceRectSize = imageSourceInternal->sourceSize(); |
1436 drawImageInternal(imageSourceInternal, 0, 0, sourceRectSize.width(), sourceR
ectSize.height(), x, y, width, height, exceptionState); | 1463 drawImage(imageSourceInternal, 0, 0, sourceRectSize.width(), sourceRectSize.
height(), x, y, width, height, exceptionState); |
1437 } | 1464 } |
1438 | 1465 |
1439 void CanvasRenderingContext2D::drawImage(const CanvasImageSourceUnion& imageSour
ce, | 1466 void CanvasRenderingContext2D::drawImage(const CanvasImageSourceUnion& imageSour
ce, |
1440 float sx, float sy, float sw, float sh, | 1467 float sx, float sy, float sw, float sh, |
1441 float dx, float dy, float dw, float dh, ExceptionState& exceptionState) | 1468 float dx, float dy, float dw, float dh, ExceptionState& exceptionState) |
1442 { | 1469 { |
1443 CanvasImageSource* imageSourceInternal = toImageSourceInternal(imageSource); | 1470 CanvasImageSource* imageSourceInternal = toImageSourceInternal(imageSource); |
1444 drawImageInternal(imageSourceInternal, sx, sy, sw, sh, dx, dy, dw, dh, excep
tionState); | 1471 drawImage(imageSourceInternal, sx, sy, sw, sh, dx, dy, dw, dh, exceptionStat
e); |
1445 } | 1472 } |
1446 | 1473 |
1447 static void drawVideo(SkCanvas* c, GraphicsContext* gc, CanvasImageSource* image
Source, FloatRect srcRect, FloatRect dstRect) | 1474 static void drawVideo(SkCanvas* c, GraphicsContext* gc, CanvasImageSource* image
Source, FloatRect srcRect, FloatRect dstRect) |
1448 { | 1475 { |
1449 HTMLVideoElement* video = static_cast<HTMLVideoElement*>(imageSource); | 1476 HTMLVideoElement* video = static_cast<HTMLVideoElement*>(imageSource); |
1450 c->save(); | 1477 c->save(); |
1451 c->clipRect(WebCoreFloatRectToSKRect(dstRect)); | 1478 c->clipRect(WebCoreFloatRectToSKRect(dstRect)); |
1452 c->translate(dstRect.x(), dstRect.y()); | 1479 c->translate(dstRect.x(), dstRect.y()); |
1453 c->scale(dstRect.width() / srcRect.width(), dstRect.height() / srcRect.heigh
t()); | 1480 c->scale(dstRect.width() / srcRect.width(), dstRect.height() / srcRect.heigh
t()); |
1454 c->translate(-srcRect.x(), -srcRect.y()); | 1481 c->translate(-srcRect.x(), -srcRect.y()); |
1455 video->paintCurrentFrameInContext(gc, IntRect(IntPoint(), IntSize(video->vid
eoWidth(), video->videoHeight()))); | 1482 video->paintCurrentFrameInContext(gc, IntRect(IntPoint(), IntSize(video->vid
eoWidth(), video->videoHeight()))); |
1456 c->restore(); | 1483 c->restore(); |
1457 } | 1484 } |
1458 | 1485 |
1459 static void drawImageOnContext(SkCanvas* c, GraphicsContext* gc, CanvasImageSour
ce* imageSource, Image* image, const FloatRect& srcRect, const FloatRect& dstRec
t) | 1486 static void drawImageOnContext(SkCanvas* c, GraphicsContext* gc, CanvasImageSour
ce* imageSource, Image* image, const FloatRect& srcRect, const FloatRect& dstRec
t) |
1460 { | 1487 { |
1461 if (!imageSource->isVideoElement()) { | 1488 if (!imageSource->isVideoElement()) { |
1462 gc->drawImage(image, dstRect, srcRect, gc->compositeOperation()); | 1489 gc->drawImage(image, dstRect, srcRect, gc->compositeOperation()); |
1463 } else { | 1490 } else { |
1464 drawVideo(c, gc, static_cast<HTMLVideoElement*>(imageSource), srcRect, d
stRect); | 1491 drawVideo(c, gc, static_cast<HTMLVideoElement*>(imageSource), srcRect, d
stRect); |
1465 } | 1492 } |
1466 } | 1493 } |
1467 | 1494 |
1468 void CanvasRenderingContext2D::drawImageInternal(CanvasImageSource* imageSource, | 1495 void CanvasRenderingContext2D::drawImage(CanvasImageSource* imageSource, |
1469 float sx, float sy, float sw, float sh, | 1496 float sx, float sy, float sw, float sh, |
1470 float dx, float dy, float dw, float dh, ExceptionState& exceptionState) | 1497 float dx, float dy, float dw, float dh, ExceptionState& exceptionState) |
1471 { | 1498 { |
1472 RefPtr<Image> image; | 1499 RefPtr<Image> image; |
1473 SourceImageStatus sourceImageStatus = InvalidSourceImageStatus; | 1500 SourceImageStatus sourceImageStatus = InvalidSourceImageStatus; |
1474 if (!imageSource->isVideoElement()) { | 1501 if (!imageSource->isVideoElement()) { |
1475 SourceImageMode mode = canvas() == imageSource ? CopySourceImageIfVolati
le : DontCopySourceImage; // Thunking for == | 1502 SourceImageMode mode = canvas() == imageSource ? CopySourceImageIfVolati
le : DontCopySourceImage; // Thunking for == |
1476 image = imageSource->getSourceImageForCanvas(mode, &sourceImageStatus); | 1503 image = imageSource->getSourceImageForCanvas(mode, &sourceImageStatus); |
1477 if (sourceImageStatus == UndecodableSourceImageStatus) | 1504 if (sourceImageStatus == UndecodableSourceImageStatus) |
1478 exceptionState.throwDOMException(InvalidStateError, "The HTMLImageEl
ement provided is in the 'broken' state."); | 1505 exceptionState.throwDOMException(InvalidStateError, "The HTMLImageEl
ement provided is in the 'broken' state."); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1511 | 1538 |
1512 // FIXME: crbug.com/447218 | 1539 // FIXME: crbug.com/447218 |
1513 // We make the destination canvas fall out of display list mode by calling | 1540 // We make the destination canvas fall out of display list mode by calling |
1514 // willAccessPixels. This is to prevent run-away memory consumption caused b
y SkSurface | 1541 // willAccessPixels. This is to prevent run-away memory consumption caused b
y SkSurface |
1515 // copyOnWrite when the source canvas is animated and consumed at a rate hig
her than the | 1542 // copyOnWrite when the source canvas is animated and consumed at a rate hig
her than the |
1516 // presentation frame rate of the destination canvas. | 1543 // presentation frame rate of the destination canvas. |
1517 if (imageSource->isCanvasElement()) | 1544 if (imageSource->isCanvasElement()) |
1518 canvas()->buffer()->willAccessPixels(); | 1545 canvas()->buffer()->willAccessPixels(); |
1519 | 1546 |
1520 if (rectContainsTransformedRect(dstRect, clipBounds)) { | 1547 if (rectContainsTransformedRect(dstRect, clipBounds)) { |
| 1548 checkOverdraw(dstRect, &c->fillPaint(), imageSource->isOpaque() ? Opaque
Image : NonOpaqueImage, ClipFill); |
1521 drawImageOnContext(drawingCanvas(), c, imageSource, image.get(), srcRect
, dstRect); | 1549 drawImageOnContext(drawingCanvas(), c, imageSource, image.get(), srcRect
, dstRect); |
1522 didDraw(clipBounds); | 1550 didDraw(clipBounds); |
1523 } else if (isFullCanvasCompositeMode(state().m_globalComposite)) { | 1551 } else if (isFullCanvasCompositeMode(state().m_globalComposite)) { |
1524 fullCanvasCompositedDraw(bind(&drawImageOnContext, drawingCanvas(), c, i
mageSource, image.get(), srcRect, dstRect)); | 1552 fullCanvasCompositedDraw(bind(&drawImageOnContext, drawingCanvas(), c, i
mageSource, image.get(), srcRect, dstRect)); |
1525 didDraw(clipBounds); | 1553 didDraw(clipBounds); |
1526 } else if (state().m_globalComposite == SkXfermode::kSrc_Mode) { | 1554 } else if (state().m_globalComposite == SkXfermode::kSrc_Mode) { |
1527 clearCanvas(); | 1555 clearCanvas(); // takes care of signaling an overdraw |
1528 drawImageOnContext(drawingCanvas(), c, imageSource, image.get(), srcRect
, dstRect); | 1556 drawImageOnContext(drawingCanvas(), c, imageSource, image.get(), srcRect
, dstRect); |
1529 didDraw(clipBounds); | 1557 didDraw(clipBounds); |
1530 } else { | 1558 } else { |
1531 FloatRect dirtyRect; | 1559 FloatRect dirtyRect; |
1532 if (computeDirtyRect(dstRect, clipBounds, &dirtyRect)) { | 1560 if (computeDirtyRect(dstRect, clipBounds, &dirtyRect)) { |
1533 drawImageOnContext(drawingCanvas(), c, imageSource, image.get(), src
Rect, dstRect); | 1561 drawImageOnContext(drawingCanvas(), c, imageSource, image.get(), src
Rect, dstRect); |
1534 didDraw(dirtyRect); | 1562 didDraw(dirtyRect); |
1535 } | 1563 } |
1536 } | 1564 } |
1537 | 1565 |
1538 validateStateStack(); | 1566 validateStateStack(); |
1539 | 1567 |
1540 if (sourceImageStatus == ExternalSourceImageStatus && isAccelerated() && can
vas()->buffer()) | 1568 if (sourceImageStatus == ExternalSourceImageStatus && isAccelerated() && can
vas()->buffer()) |
1541 canvas()->buffer()->flush(); | 1569 canvas()->buffer()->flush(); |
1542 | 1570 |
1543 if (canvas()->originClean() && wouldTaintOrigin(imageSource)) | 1571 if (canvas()->originClean() && wouldTaintOrigin(imageSource)) |
1544 canvas()->setOriginTainted(); | 1572 canvas()->setOriginTainted(); |
1545 } | 1573 } |
1546 | 1574 |
1547 void CanvasRenderingContext2D::clearCanvas() | 1575 void CanvasRenderingContext2D::clearCanvas() |
1548 { | 1576 { |
1549 FloatRect canvasRect(0, 0, canvas()->width(), canvas()->height()); | 1577 FloatRect canvasRect(0, 0, canvas()->width(), canvas()->height()); |
1550 SkCanvas* c = drawingCanvas(); | 1578 SkCanvas* c = drawingCanvas(); |
1551 if (!c) | 1579 if (!c) |
1552 return; | 1580 return; |
1553 | 1581 |
1554 c->clear(m_hasAlpha ? SK_ColorTRANSPARENT : SK_ColorBLACK); | 1582 checkOverdraw(canvasRect, 0, NoImage, ClipFill); |
| 1583 // Must not use 'c' beyond this point in case checkOverdraw substitutes the
recording |
| 1584 // canvas in order to clear a draw command backlog. |
| 1585 drawingCanvas()->clear(m_hasAlpha ? SK_ColorTRANSPARENT : SK_ColorBLACK); |
1555 } | 1586 } |
1556 | 1587 |
1557 bool CanvasRenderingContext2D::rectContainsTransformedRect(const FloatRect& rect
, const FloatRect& transformedRect) const | 1588 bool CanvasRenderingContext2D::rectContainsTransformedRect(const FloatRect& rect
, const FloatRect& transformedRect) const |
1558 { | 1589 { |
1559 FloatQuad quad(rect); | 1590 FloatQuad quad(rect); |
1560 FloatQuad transformedQuad(transformedRect); | 1591 FloatQuad transformedQuad(transformedRect); |
1561 return state().m_transform.mapQuad(quad).containsQuad(transformedQuad); | 1592 return state().m_transform.mapQuad(quad).containsQuad(transformedQuad); |
1562 } | 1593 } |
1563 | 1594 |
1564 void CanvasRenderingContext2D::fullCanvasCompositedDraw(PassOwnPtr<Closure> draw
) | 1595 void CanvasRenderingContext2D::fullCanvasCompositedDraw(PassOwnPtr<Closure> draw
) |
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1784 clipRect.intersect(IntRect(0, 0, data->width(), data->height())); | 1815 clipRect.intersect(IntRect(0, 0, data->width(), data->height())); |
1785 IntSize destOffset(static_cast<int>(dx), static_cast<int>(dy)); | 1816 IntSize destOffset(static_cast<int>(dx), static_cast<int>(dy)); |
1786 IntRect destRect = enclosingIntRect(clipRect); | 1817 IntRect destRect = enclosingIntRect(clipRect); |
1787 destRect.move(destOffset); | 1818 destRect.move(destOffset); |
1788 destRect.intersect(IntRect(IntPoint(), buffer->size())); | 1819 destRect.intersect(IntRect(IntPoint(), buffer->size())); |
1789 if (destRect.isEmpty()) | 1820 if (destRect.isEmpty()) |
1790 return; | 1821 return; |
1791 IntRect sourceRect(destRect); | 1822 IntRect sourceRect(destRect); |
1792 sourceRect.move(-destOffset); | 1823 sourceRect.move(-destOffset); |
1793 | 1824 |
| 1825 checkOverdraw(destRect, 0, NoImage, UntransformedUnclippedFill); |
| 1826 |
1794 buffer->putByteArray(Unmultiplied, data->data()->data(), IntSize(data->width
(), data->height()), sourceRect, IntPoint(destOffset)); | 1827 buffer->putByteArray(Unmultiplied, data->data()->data(), IntSize(data->width
(), data->height()), sourceRect, IntPoint(destOffset)); |
1795 | 1828 |
1796 didDraw(destRect); | 1829 didDraw(destRect); |
1797 } | 1830 } |
1798 | 1831 |
1799 String CanvasRenderingContext2D::font() const | 1832 String CanvasRenderingContext2D::font() const |
1800 { | 1833 { |
1801 if (!state().m_realizedFont) | 1834 if (!state().m_realizedFont) |
1802 return defaultFont; | 1835 return defaultFont; |
1803 | 1836 |
(...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2130 TextRunPaintInfo textRunPaintInfo(textRun); | 2163 TextRunPaintInfo textRunPaintInfo(textRun); |
2131 textRunPaintInfo.bounds = FloatRect(location.x() - fontMetrics.height() / 2, | 2164 textRunPaintInfo.bounds = FloatRect(location.x() - fontMetrics.height() / 2, |
2132 location.y() - fontMetrics.ascent() - fo
ntMetrics.lineGap(), | 2165 location.y() - fontMetrics.ascent() - fo
ntMetrics.lineGap(), |
2133 width + fontMetrics.height(), | 2166 width + fontMetrics.height(), |
2134 fontMetrics.lineSpacing()); | 2167 fontMetrics.lineSpacing()); |
2135 if (!fill) | 2168 if (!fill) |
2136 inflateStrokeRect(textRunPaintInfo.bounds); | 2169 inflateStrokeRect(textRunPaintInfo.bounds); |
2137 | 2170 |
2138 c->setTextDrawingMode(fill ? TextModeFill : TextModeStroke); | 2171 c->setTextDrawingMode(fill ? TextModeFill : TextModeStroke); |
2139 | 2172 |
2140 GraphicsContextStateSaver stateSaver(*c); | 2173 CanvasRenderingContext2DAutoRestoreSkCanvas stateRestorer(this); |
2141 if (useMaxWidth) { | 2174 if (useMaxWidth) { |
2142 c->translate(location.x(), location.y()); | 2175 SkCanvas* canvas = drawingCanvas(); |
| 2176 canvas->save(); |
| 2177 canvas->translate(location.x(), location.y()); |
2143 // We draw when fontWidth is 0 so compositing operations (eg, a "copy" o
p) still work. | 2178 // We draw when fontWidth is 0 so compositing operations (eg, a "copy" o
p) still work. |
2144 c->scale((fontWidth > 0 ? (width / fontWidth) : 0), 1); | 2179 canvas->scale((fontWidth > 0 ? (width / fontWidth) : 0), 1); |
2145 location = FloatPoint(); | 2180 location = FloatPoint(); |
2146 } | 2181 } |
2147 | 2182 |
2148 FloatRect clipBounds; | 2183 FloatRect clipBounds; |
2149 if (!c->getTransformedClipBounds(&clipBounds)) { | 2184 if (!c->getTransformedClipBounds(&clipBounds)) { |
2150 return; | 2185 return; |
2151 } | 2186 } |
2152 | 2187 |
2153 if (isFullCanvasCompositeMode(state().m_globalComposite)) { | 2188 if (isFullCanvasCompositeMode(state().m_globalComposite)) { |
2154 fullCanvasCompositedDraw(bind(&GraphicsContext::drawBidiText, c, font, t
extRunPaintInfo, location, Font::UseFallbackIfFontNotReady)); | 2189 fullCanvasCompositedDraw(bind(&GraphicsContext::drawBidiText, c, font, t
extRunPaintInfo, location, Font::UseFallbackIfFontNotReady)); |
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2375 } | 2410 } |
2376 | 2411 |
2377 unsigned CanvasRenderingContext2D::hitRegionsCount() const | 2412 unsigned CanvasRenderingContext2D::hitRegionsCount() const |
2378 { | 2413 { |
2379 if (m_hitRegionManager) | 2414 if (m_hitRegionManager) |
2380 return m_hitRegionManager->getHitRegionsCount(); | 2415 return m_hitRegionManager->getHitRegionsCount(); |
2381 | 2416 |
2382 return 0; | 2417 return 0; |
2383 } | 2418 } |
2384 | 2419 |
| 2420 void CanvasRenderingContext2D::checkOverdraw(const SkRect& rect, const SkPaint*
paint, ImageType imageType, DrawType drawType) |
| 2421 { |
| 2422 SkCanvas* c = drawingCanvas(); |
| 2423 if (!c || !canvas()->buffer()->isRecording()) |
| 2424 return; |
| 2425 |
| 2426 SkRect deviceRect; |
| 2427 if (drawType == UntransformedUnclippedFill) { |
| 2428 deviceRect = rect; |
| 2429 } else { |
| 2430 ASSERT(drawType == ClipFill); |
| 2431 if (state().m_hasComplexClip) |
| 2432 return; |
| 2433 |
| 2434 SkIRect skIBounds; |
| 2435 if (!c->getClipDeviceBounds(&skIBounds)) |
| 2436 return; |
| 2437 deviceRect = SkRect::Make(skIBounds); |
| 2438 } |
| 2439 |
| 2440 const SkImageInfo& imageInfo = c->imageInfo(); |
| 2441 if (!deviceRect.contains(SkRect::MakeWH(imageInfo.width(), imageInfo.height(
)))) |
| 2442 return; |
| 2443 |
| 2444 bool isSourceOver = true; |
| 2445 unsigned alpha = 0xFF; |
| 2446 if (paint) { |
| 2447 if (paint->getLooper() || paint->getImageFilter() || paint->getMaskFilte
r()) |
| 2448 return; |
| 2449 |
| 2450 SkXfermode* xfermode = paint->getXfermode(); |
| 2451 if (xfermode) { |
| 2452 SkXfermode::Mode mode; |
| 2453 if (xfermode->asMode(&mode)) { |
| 2454 isSourceOver = mode == SkXfermode::kSrcOver_Mode; |
| 2455 if (!isSourceOver && mode != SkXfermode::kSrc_Mode && mode != Sk
Xfermode::kClear_Mode) |
| 2456 return; // The code below only knows how to handle Src, SrcO
ver, and Clear |
| 2457 } else { |
| 2458 // unknown xfermode |
| 2459 ASSERT_NOT_REACHED(); |
| 2460 return; |
| 2461 } |
| 2462 } |
| 2463 |
| 2464 alpha = paint->getAlpha(); |
| 2465 |
| 2466 if (isSourceOver && imageType == NoImage) { |
| 2467 SkShader* shader = paint->getShader(); |
| 2468 if (shader) { |
| 2469 if (shader->isOpaque() && alpha == 0xFF) |
| 2470 canvas()->buffer()->willOverwriteCanvas(); |
| 2471 return; |
| 2472 } |
| 2473 } |
| 2474 } |
| 2475 |
| 2476 if (isSourceOver) { |
| 2477 // With source over, we need to certify that alpha == 0xFF for all pixel
s |
| 2478 if (imageType == NonOpaqueImage) |
| 2479 return; |
| 2480 if (alpha < 0xFF) |
| 2481 return; |
| 2482 } |
| 2483 |
| 2484 canvas()->buffer()->willOverwriteCanvas(); |
| 2485 } |
| 2486 |
2385 } // namespace blink | 2487 } // namespace blink |
OLD | NEW |