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

Side by Side Diff: third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp

Issue 1739553002: Pull up a subset of CanvasRenderingContext2D into BaseRenderingContext2D. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 10 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
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 19 matching lines...) Expand all
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */ 31 */
32 32
33 #include "modules/canvas2d/CanvasRenderingContext2D.h" 33 #include "modules/canvas2d/CanvasRenderingContext2D.h"
34 34
35 #include "bindings/core/v8/ExceptionMessages.h" 35 #include "bindings/core/v8/ExceptionMessages.h"
36 #include "bindings/core/v8/ExceptionState.h" 36 #include "bindings/core/v8/ExceptionState.h"
37 #include "bindings/core/v8/ExceptionStatePlaceholder.h" 37 #include "bindings/core/v8/ExceptionStatePlaceholder.h"
38 #include "core/CSSPropertyNames.h" 38 #include "core/CSSPropertyNames.h"
39 #include "core/css/StylePropertySet.h" 39 #include "core/css/StylePropertySet.h"
40 #include "core/css/parser/CSSParser.h"
41 #include "core/css/resolver/StyleResolver.h" 40 #include "core/css/resolver/StyleResolver.h"
42 #include "core/dom/AXObjectCache.h" 41 #include "core/dom/AXObjectCache.h"
43 #include "core/dom/StyleEngine.h" 42 #include "core/dom/StyleEngine.h"
44 #include "core/events/Event.h" 43 #include "core/events/Event.h"
45 #include "core/frame/ImageBitmap.h"
46 #include "core/frame/Settings.h" 44 #include "core/frame/Settings.h"
47 #include "core/html/HTMLVideoElement.h"
48 #include "core/html/ImageData.h"
49 #include "core/html/TextMetrics.h" 45 #include "core/html/TextMetrics.h"
50 #include "core/html/canvas/CanvasFontCache.h" 46 #include "core/html/canvas/CanvasFontCache.h"
51 #include "core/layout/LayoutBox.h" 47 #include "core/layout/LayoutBox.h"
52 #include "core/layout/LayoutTheme.h" 48 #include "core/layout/LayoutTheme.h"
53 #include "modules/canvas2d/CanvasGradient.h"
54 #include "modules/canvas2d/CanvasPattern.h"
55 #include "modules/canvas2d/CanvasRenderingContext2DState.h"
56 #include "modules/canvas2d/CanvasStyle.h" 49 #include "modules/canvas2d/CanvasStyle.h"
57 #include "modules/canvas2d/HitRegion.h" 50 #include "modules/canvas2d/HitRegion.h"
58 #include "modules/canvas2d/Path2D.h" 51 #include "modules/canvas2d/Path2D.h"
59 #include "platform/fonts/FontCache.h" 52 #include "platform/fonts/FontCache.h"
60 #include "platform/geometry/FloatQuad.h"
61 #include "platform/graphics/DrawLooperBuilder.h" 53 #include "platform/graphics/DrawLooperBuilder.h"
62 #include "platform/graphics/ExpensiveCanvasHeuristicParameters.h" 54 #include "platform/graphics/ExpensiveCanvasHeuristicParameters.h"
63 #include "platform/graphics/ImageBuffer.h" 55 #include "platform/graphics/ImageBuffer.h"
64 #include "platform/graphics/StrokeData.h" 56 #include "platform/graphics/StrokeData.h"
65 #include "platform/graphics/skia/SkiaUtils.h" 57 #include "platform/graphics/skia/SkiaUtils.h"
66 #include "platform/text/BidiTextRun.h" 58 #include "platform/text/BidiTextRun.h"
67 #include "public/platform/Platform.h" 59 #include "public/platform/Platform.h"
68 #include "third_party/skia/include/core/SkCanvas.h" 60 #include "third_party/skia/include/core/SkCanvas.h"
69 #include "third_party/skia/include/core/SkImageFilter.h" 61 #include "third_party/skia/include/core/SkImageFilter.h"
70 #include "wtf/ArrayBufferContents.h" 62 #include "wtf/ArrayBufferContents.h"
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
111 c->restoreToCount(m_saveCount); 103 c->restoreToCount(m_saveCount);
112 m_context->validateStateStack(); 104 m_context->validateStateStack();
113 } 105 }
114 private: 106 private:
115 RawPtrWillBeMember<CanvasRenderingContext2D> m_context; 107 RawPtrWillBeMember<CanvasRenderingContext2D> m_context;
116 int m_saveCount; 108 int m_saveCount;
117 }; 109 };
118 110
119 CanvasRenderingContext2D::CanvasRenderingContext2D(HTMLCanvasElement* canvas, co nst CanvasContextCreationAttributes& attrs, Document& document) 111 CanvasRenderingContext2D::CanvasRenderingContext2D(HTMLCanvasElement* canvas, co nst CanvasContextCreationAttributes& attrs, Document& document)
120 : CanvasRenderingContext(canvas) 112 : CanvasRenderingContext(canvas)
121 , m_clipAntialiasing(NotAntiAliased)
122 , m_hasAlpha(attrs.alpha()) 113 , m_hasAlpha(attrs.alpha())
123 , m_contextLostMode(NotLostContext) 114 , m_contextLostMode(NotLostContext)
124 , m_contextRestorable(true) 115 , m_contextRestorable(true)
125 , m_tryRestoreContextAttemptCount(0) 116 , m_tryRestoreContextAttemptCount(0)
126 , m_dispatchContextLostEventTimer(this, &CanvasRenderingContext2D::dispatchC ontextLostEvent) 117 , m_dispatchContextLostEventTimer(this, &CanvasRenderingContext2D::dispatchC ontextLostEvent)
127 , m_dispatchContextRestoredEventTimer(this, &CanvasRenderingContext2D::dispa tchContextRestoredEvent) 118 , m_dispatchContextRestoredEventTimer(this, &CanvasRenderingContext2D::dispa tchContextRestoredEvent)
128 , m_tryRestoreContextEventTimer(this, &CanvasRenderingContext2D::tryRestoreC ontextEvent) 119 , m_tryRestoreContextEventTimer(this, &CanvasRenderingContext2D::tryRestoreC ontextEvent)
129 , m_pruneLocalFontCacheScheduled(false) 120 , m_pruneLocalFontCacheScheduled(false)
130 { 121 {
131 if (document.settings() && document.settings()->antialiasedClips2dCanvasEnab led()) 122 if (document.settings() && document.settings()->antialiasedClips2dCanvasEnab led())
132 m_clipAntialiasing = AntiAliased; 123 m_clipAntialiasing = AntiAliased;
133 m_stateStack.append(CanvasRenderingContext2DState::create());
134 setShouldAntialias(true); 124 setShouldAntialias(true);
135 #if ENABLE(OILPAN) 125 #if ENABLE(OILPAN)
136 ThreadState::current()->registerPreFinalizer(this); 126 ThreadState::current()->registerPreFinalizer(this);
137 #endif 127 #endif
138 } 128 }
139 129
140 void CanvasRenderingContext2D::unwindStateStack() 130 void CanvasRenderingContext2D::unwindStateStack()
141 { 131 {
142 if (size_t stackSize = m_stateStack.size()) { 132 if (size_t stackSize = m_stateStack.size()) {
143 if (SkCanvas* skCanvas = canvas()->existingDrawingCanvas()) { 133 if (SkCanvas* skCanvas = canvas()->existingDrawingCanvas()) {
(...skipping 21 matching lines...) Expand all
165 void CanvasRenderingContext2D::validateStateStack() 155 void CanvasRenderingContext2D::validateStateStack()
166 { 156 {
167 #if ENABLE(ASSERT) 157 #if ENABLE(ASSERT)
168 SkCanvas* skCanvas = canvas()->existingDrawingCanvas(); 158 SkCanvas* skCanvas = canvas()->existingDrawingCanvas();
169 if (skCanvas && m_contextLostMode == NotLostContext) { 159 if (skCanvas && m_contextLostMode == NotLostContext) {
170 ASSERT(static_cast<size_t>(skCanvas->getSaveCount()) == m_stateStack.siz e()); 160 ASSERT(static_cast<size_t>(skCanvas->getSaveCount()) == m_stateStack.siz e());
171 } 161 }
172 #endif 162 #endif
173 } 163 }
174 164
175 CanvasRenderingContext2DState& CanvasRenderingContext2D::modifiableState()
176 {
177 realizeSaves();
178 return *m_stateStack.last();
179 }
180
181 bool CanvasRenderingContext2D::isAccelerated() const 165 bool CanvasRenderingContext2D::isAccelerated() const
182 { 166 {
183 if (!canvas()->hasImageBuffer()) 167 if (!canvas()->hasImageBuffer())
184 return false; 168 return false;
185 return canvas()->buffer()->isAccelerated(); 169 return canvas()->buffer()->isAccelerated();
186 } 170 }
187 171
188 void CanvasRenderingContext2D::stop() 172 void CanvasRenderingContext2D::stop()
189 { 173 {
190 if (!isContextLost()) { 174 if (!isContextLost()) {
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
223 } else { 207 } else {
224 // legacy synchronous context restoration. 208 // legacy synchronous context restoration.
225 reset(); 209 reset();
226 m_contextLostMode = NotLostContext; 210 m_contextLostMode = NotLostContext;
227 } 211 }
228 } 212 }
229 } 213 }
230 214
231 DEFINE_TRACE(CanvasRenderingContext2D) 215 DEFINE_TRACE(CanvasRenderingContext2D)
232 { 216 {
233 visitor->trace(m_stateStack);
234 visitor->trace(m_hitRegionManager); 217 visitor->trace(m_hitRegionManager);
235 CanvasRenderingContext::trace(visitor); 218 CanvasRenderingContext::trace(visitor);
219 BaseRenderingContext2D::trace(visitor);
236 } 220 }
237 221
238 void CanvasRenderingContext2D::dispatchContextLostEvent(Timer<CanvasRenderingCon text2D>*) 222 void CanvasRenderingContext2D::dispatchContextLostEvent(Timer<CanvasRenderingCon text2D>*)
239 { 223 {
240 if (contextLostRestoredEventsEnabled()) { 224 if (contextLostRestoredEventsEnabled()) {
241 RefPtrWillBeRawPtr<Event> event = Event::createCancelable(EventTypeNames ::contextlost); 225 RefPtrWillBeRawPtr<Event> event = Event::createCancelable(EventTypeNames ::contextlost);
242 canvas()->dispatchEvent(event); 226 canvas()->dispatchEvent(event);
243 if (event->defaultPrevented()) { 227 if (event->defaultPrevented()) {
244 m_contextRestorable = false; 228 m_contextRestorable = false;
245 } 229 }
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
311 ASSERT(m_stateStack.begin() < m_stateStack.end()); 295 ASSERT(m_stateStack.begin() < m_stateStack.end());
312 for (currState = m_stateStack.begin(); currState < m_stateStack.end(); currS tate++) { 296 for (currState = m_stateStack.begin(); currState < m_stateStack.end(); currS tate++) {
313 c->setMatrix(SkMatrix::I()); 297 c->setMatrix(SkMatrix::I());
314 currState->get()->playbackClips(c); 298 currState->get()->playbackClips(c);
315 c->setMatrix(affineTransformToSkMatrix(currState->get()->transform())); 299 c->setMatrix(affineTransformToSkMatrix(currState->get()->transform()));
316 c->save(); 300 c->save();
317 } 301 }
318 c->restore(); 302 c->restore();
319 } 303 }
320 304
321 void CanvasRenderingContext2D::realizeSaves()
322 {
323 validateStateStack();
324 if (state().hasUnrealizedSaves()) {
325 ASSERT(m_stateStack.size() >= 1);
326 // Reduce the current state's unrealized count by one now,
327 // to reflect the fact we are saving one state.
328 m_stateStack.last()->restore();
329 m_stateStack.append(CanvasRenderingContext2DState::create(state(), Canva sRenderingContext2DState::DontCopyClipList));
330 // Set the new state's unrealized count to 0, because it has no outstand ing saves.
331 // We need to do this explicitly because the copy constructor and operat or= used
332 // by the Vector operations copy the unrealized count from the previous state (in
333 // turn necessary to support correct resizing and unwinding of the stack ).
334 m_stateStack.last()->resetUnrealizedSaveCount();
335 SkCanvas* canvas = drawingCanvas();
336 if (canvas)
337 canvas->save();
338 validateStateStack();
339 }
340 }
341
342 void CanvasRenderingContext2D::save()
343 {
344 m_stateStack.last()->save();
345 }
346
347 void CanvasRenderingContext2D::restore()
348 {
349 validateStateStack();
350 if (state().hasUnrealizedSaves()) {
351 // We never realized the save, so just record that it was unnecessary.
352 m_stateStack.last()->restore();
353 return;
354 }
355 ASSERT(m_stateStack.size() >= 1);
356 if (m_stateStack.size() <= 1)
357 return;
358 m_path.transform(state().transform());
359 m_stateStack.removeLast();
360 m_stateStack.last()->clearResolvedFilter();
361 m_path.transform(state().transform().inverse());
362 SkCanvas* c = drawingCanvas();
363 if (c)
364 c->restore();
365
366 validateStateStack();
367 }
368
369 static inline void convertCanvasStyleToUnionType(CanvasStyle* style, StringOrCan vasGradientOrCanvasPattern& returnValue)
370 {
371 if (CanvasGradient* gradient = style->canvasGradient()) {
372 returnValue.setCanvasGradient(gradient);
373 return;
374 }
375 if (CanvasPattern* pattern = style->canvasPattern()) {
376 returnValue.setCanvasPattern(pattern);
377 return;
378 }
379 returnValue.setString(style->color());
380 }
381
382 void CanvasRenderingContext2D::strokeStyle(StringOrCanvasGradientOrCanvasPattern & returnValue) const
383 {
384 convertCanvasStyleToUnionType(state().strokeStyle(), returnValue);
385 }
386
387 void CanvasRenderingContext2D::setStrokeStyle(const StringOrCanvasGradientOrCanv asPattern& style)
388 {
389 ASSERT(!style.isNull());
390
391 String colorString;
392 CanvasStyle* canvasStyle = nullptr;
393 if (style.isString()) {
394 colorString = style.getAsString();
395 if (colorString == state().unparsedStrokeColor())
396 return;
397 Color parsedColor = 0;
398 if (!parseColorOrCurrentColor(parsedColor, colorString, canvas()))
399 return;
400 if (state().strokeStyle()->isEquivalentRGBA(parsedColor.rgb())) {
401 modifiableState().setUnparsedStrokeColor(colorString);
402 return;
403 }
404 canvasStyle = CanvasStyle::createFromRGBA(parsedColor.rgb());
405 } else if (style.isCanvasGradient()) {
406 canvasStyle = CanvasStyle::createFromGradient(style.getAsCanvasGradient( ));
407 } else if (style.isCanvasPattern()) {
408 CanvasPattern* canvasPattern = style.getAsCanvasPattern();
409
410 if (canvas()->originClean() && !canvasPattern->originClean())
411 canvas()->setOriginTainted();
412
413 canvasStyle = CanvasStyle::createFromPattern(canvasPattern);
414 }
415
416 ASSERT(canvasStyle);
417
418 modifiableState().setStrokeStyle(canvasStyle);
419 modifiableState().setUnparsedStrokeColor(colorString);
420 modifiableState().clearResolvedFilter();
421 }
422
423 void CanvasRenderingContext2D::fillStyle(StringOrCanvasGradientOrCanvasPattern& returnValue) const
424 {
425 convertCanvasStyleToUnionType(state().fillStyle(), returnValue);
426 }
427
428 void CanvasRenderingContext2D::setFillStyle(const StringOrCanvasGradientOrCanvas Pattern& style)
429 {
430 ASSERT(!style.isNull());
431 validateStateStack();
432 String colorString;
433 CanvasStyle* canvasStyle = nullptr;
434 if (style.isString()) {
435 colorString = style.getAsString();
436 if (colorString == state().unparsedFillColor())
437 return;
438 Color parsedColor = 0;
439 if (!parseColorOrCurrentColor(parsedColor, colorString, canvas()))
440 return;
441 if (state().fillStyle()->isEquivalentRGBA(parsedColor.rgb())) {
442 modifiableState().setUnparsedFillColor(colorString);
443 return;
444 }
445 canvasStyle = CanvasStyle::createFromRGBA(parsedColor.rgb());
446 } else if (style.isCanvasGradient()) {
447 canvasStyle = CanvasStyle::createFromGradient(style.getAsCanvasGradient( ));
448 } else if (style.isCanvasPattern()) {
449 CanvasPattern* canvasPattern = style.getAsCanvasPattern();
450
451 if (canvas()->originClean() && !canvasPattern->originClean())
452 canvas()->setOriginTainted();
453 if (canvasPattern->pattern()->isTextureBacked())
454 canvas()->disableDeferral(DisableDeferralReasonUsingTextureBackedPat tern);
455 canvasStyle = CanvasStyle::createFromPattern(canvasPattern);
456 }
457
458 ASSERT(canvasStyle);
459 modifiableState().setFillStyle(canvasStyle);
460 modifiableState().setUnparsedFillColor(colorString);
461 modifiableState().clearResolvedFilter();
462 }
463
464 double CanvasRenderingContext2D::lineWidth() const
465 {
466 return state().lineWidth();
467 }
468
469 void CanvasRenderingContext2D::setLineWidth(double width)
470 {
471 if (!std::isfinite(width) || width <= 0)
472 return;
473 if (state().lineWidth() == width)
474 return;
475 modifiableState().setLineWidth(width);
476 }
477
478 String CanvasRenderingContext2D::lineCap() const
479 {
480 return lineCapName(state().lineCap());
481 }
482
483 void CanvasRenderingContext2D::setLineCap(const String& s)
484 {
485 LineCap cap;
486 if (!parseLineCap(s, cap))
487 return;
488 if (state().lineCap() == cap)
489 return;
490 modifiableState().setLineCap(cap);
491 }
492
493 String CanvasRenderingContext2D::lineJoin() const
494 {
495 return lineJoinName(state().lineJoin());
496 }
497
498 void CanvasRenderingContext2D::setLineJoin(const String& s)
499 {
500 LineJoin join;
501 if (!parseLineJoin(s, join))
502 return;
503 if (state().lineJoin() == join)
504 return;
505 modifiableState().setLineJoin(join);
506 }
507
508 double CanvasRenderingContext2D::miterLimit() const
509 {
510 return state().miterLimit();
511 }
512
513 void CanvasRenderingContext2D::setMiterLimit(double limit)
514 {
515 if (!std::isfinite(limit) || limit <= 0)
516 return;
517 if (state().miterLimit() == limit)
518 return;
519 modifiableState().setMiterLimit(limit);
520 }
521
522 double CanvasRenderingContext2D::shadowOffsetX() const
523 {
524 return state().shadowOffset().width();
525 }
526
527 void CanvasRenderingContext2D::setShadowOffsetX(double x)
528 {
529 if (!std::isfinite(x))
530 return;
531 if (state().shadowOffset().width() == x)
532 return;
533 modifiableState().setShadowOffsetX(x);
534 }
535
536 double CanvasRenderingContext2D::shadowOffsetY() const
537 {
538 return state().shadowOffset().height();
539 }
540
541 void CanvasRenderingContext2D::setShadowOffsetY(double y)
542 {
543 if (!std::isfinite(y))
544 return;
545 if (state().shadowOffset().height() == y)
546 return;
547 modifiableState().setShadowOffsetY(y);
548 }
549
550 double CanvasRenderingContext2D::shadowBlur() const
551 {
552 return state().shadowBlur();
553 }
554
555 void CanvasRenderingContext2D::setShadowBlur(double blur)
556 {
557 if (!std::isfinite(blur) || blur < 0)
558 return;
559 if (state().shadowBlur() == blur)
560 return;
561 modifiableState().setShadowBlur(blur);
562 }
563
564 String CanvasRenderingContext2D::shadowColor() const
565 {
566 return Color(state().shadowColor()).serialized();
567 }
568
569 void CanvasRenderingContext2D::setShadowColor(const String& colorString)
570 {
571 Color color;
572 if (!parseColorOrCurrentColor(color, colorString, canvas()))
573 return;
574 if (state().shadowColor() == color)
575 return;
576 modifiableState().setShadowColor(color.rgb());
577 }
578
579 const Vector<double>& CanvasRenderingContext2D::getLineDash() const
580 {
581 return state().lineDash();
582 }
583
584 static bool lineDashSequenceIsValid(const Vector<double>& dash)
585 {
586 for (size_t i = 0; i < dash.size(); i++) {
587 if (!std::isfinite(dash[i]) || dash[i] < 0)
588 return false;
589 }
590 return true;
591 }
592
593 void CanvasRenderingContext2D::setLineDash(const Vector<double>& dash)
594 {
595 if (!lineDashSequenceIsValid(dash))
596 return;
597 modifiableState().setLineDash(dash);
598 }
599
600 double CanvasRenderingContext2D::lineDashOffset() const
601 {
602 return state().lineDashOffset();
603 }
604
605 void CanvasRenderingContext2D::setLineDashOffset(double offset)
606 {
607 if (!std::isfinite(offset) || state().lineDashOffset() == offset)
608 return;
609 modifiableState().setLineDashOffset(offset);
610 }
611
612 double CanvasRenderingContext2D::globalAlpha() const
613 {
614 return state().globalAlpha();
615 }
616
617 void CanvasRenderingContext2D::setGlobalAlpha(double alpha)
618 {
619 if (!(alpha >= 0 && alpha <= 1))
620 return;
621 if (state().globalAlpha() == alpha)
622 return;
623 modifiableState().setGlobalAlpha(alpha);
624 }
625
626 bool CanvasRenderingContext2D::shouldAntialias() const
627 {
628 return state().shouldAntialias();
629 }
630
631 void CanvasRenderingContext2D::setShouldAntialias(bool doAA) 305 void CanvasRenderingContext2D::setShouldAntialias(bool doAA)
632 { 306 {
633 modifiableState().setShouldAntialias(doAA); 307 modifiableState().setShouldAntialias(doAA);
634 } 308 }
635 309
636 String CanvasRenderingContext2D::globalCompositeOperation() const
637 {
638 return compositeOperatorName(compositeOperatorFromSkia(state().globalComposi te()), blendModeFromSkia(state().globalComposite()));
639 }
640
641 void CanvasRenderingContext2D::setGlobalCompositeOperation(const String& operati on)
642 {
643 CompositeOperator op = CompositeSourceOver;
644 WebBlendMode blendMode = WebBlendModeNormal;
645 if (!parseCompositeAndBlendOperator(operation, op, blendMode))
646 return;
647 SkXfermode::Mode xfermode = WebCoreCompositeToSkiaComposite(op, blendMode);
648 if (state().globalComposite() == xfermode)
649 return;
650 modifiableState().setGlobalComposite(xfermode);
651 }
652
653 String CanvasRenderingContext2D::filter() const
654 {
655 return state().unparsedFilter();
656 }
657
658 void CanvasRenderingContext2D::setFilter(const String& filterString)
659 {
660 if (filterString == state().unparsedFilter())
661 return;
662
663 RefPtrWillBeRawPtr<CSSValue> filterValue = CSSParser::parseSingleValue(CSSPr opertyWebkitFilter, filterString, CSSParserContext(HTMLStandardMode, 0));
664
665 if (!filterValue || filterValue->isInitialValue() || filterValue->isInherite dValue())
666 return;
667
668 modifiableState().setUnparsedFilter(filterString);
669 modifiableState().setFilter(filterValue.release());
670 }
671
672 PassRefPtrWillBeRawPtr<SVGMatrixTearOff> CanvasRenderingContext2D::currentTransf orm() const
673 {
674 return SVGMatrixTearOff::create(state().transform());
675 }
676
677 void CanvasRenderingContext2D::setCurrentTransform(PassRefPtrWillBeRawPtr<SVGMat rixTearOff> passMatrixTearOff)
678 {
679 RefPtrWillBeRawPtr<SVGMatrixTearOff> matrixTearOff = passMatrixTearOff;
680 const AffineTransform& transform = matrixTearOff->value();
681 setTransform(transform.a(), transform.b(), transform.c(), transform.d(), tra nsform.e(), transform.f());
682 }
683
684 void CanvasRenderingContext2D::scale(double sx, double sy)
685 {
686 SkCanvas* c = drawingCanvas();
687 if (!c)
688 return;
689
690 if (!std::isfinite(sx) || !std::isfinite(sy))
691 return;
692
693 AffineTransform newTransform = state().transform();
694 newTransform.scaleNonUniform(sx, sy);
695 if (state().transform() == newTransform)
696 return;
697
698 modifiableState().setTransform(newTransform);
699 if (!state().isTransformInvertible())
700 return;
701
702 c->scale(sx, sy);
703 m_path.transform(AffineTransform().scaleNonUniform(1.0 / sx, 1.0 / sy));
704 }
705
706 void CanvasRenderingContext2D::rotate(double angleInRadians)
707 {
708 SkCanvas* c = drawingCanvas();
709 if (!c)
710 return;
711
712 if (!std::isfinite(angleInRadians))
713 return;
714
715 AffineTransform newTransform = state().transform();
716 newTransform.rotateRadians(angleInRadians);
717 if (state().transform() == newTransform)
718 return;
719
720 modifiableState().setTransform(newTransform);
721 if (!state().isTransformInvertible())
722 return;
723 c->rotate(angleInRadians * (180.0 / piFloat));
724 m_path.transform(AffineTransform().rotateRadians(-angleInRadians));
725 }
726
727 void CanvasRenderingContext2D::translate(double tx, double ty)
728 {
729 SkCanvas* c = drawingCanvas();
730 if (!c)
731 return;
732 if (!state().isTransformInvertible())
733 return;
734
735 if (!std::isfinite(tx) || !std::isfinite(ty))
736 return;
737
738 AffineTransform newTransform = state().transform();
739 newTransform.translate(tx, ty);
740 if (state().transform() == newTransform)
741 return;
742
743 modifiableState().setTransform(newTransform);
744 if (!state().isTransformInvertible())
745 return;
746 c->translate(tx, ty);
747 m_path.transform(AffineTransform().translate(-tx, -ty));
748 }
749
750 void CanvasRenderingContext2D::transform(double m11, double m12, double m21, dou ble m22, double dx, double dy)
751 {
752 SkCanvas* c = drawingCanvas();
753 if (!c)
754 return;
755
756 if (!std::isfinite(m11) || !std::isfinite(m21) || !std::isfinite(dx) || !std ::isfinite(m12) || !std::isfinite(m22) || !std::isfinite(dy))
757 return;
758
759 AffineTransform transform(m11, m12, m21, m22, dx, dy);
760 AffineTransform newTransform = state().transform() * transform;
761 if (state().transform() == newTransform)
762 return;
763
764 modifiableState().setTransform(newTransform);
765 if (!state().isTransformInvertible())
766 return;
767
768 c->concat(affineTransformToSkMatrix(transform));
769 m_path.transform(transform.inverse());
770 }
771
772 void CanvasRenderingContext2D::resetTransform()
773 {
774 SkCanvas* c = drawingCanvas();
775 if (!c)
776 return;
777
778 AffineTransform ctm = state().transform();
779 bool invertibleCTM = state().isTransformInvertible();
780 // It is possible that CTM is identity while CTM is not invertible.
781 // When CTM becomes non-invertible, realizeSaves() can make CTM identity.
782 if (ctm.isIdentity() && invertibleCTM)
783 return;
784
785 // resetTransform() resolves the non-invertible CTM state.
786 modifiableState().resetTransform();
787 c->setMatrix(affineTransformToSkMatrix(canvas()->baseTransform()));
788
789 if (invertibleCTM)
790 m_path.transform(ctm);
791 // When else, do nothing because all transform methods didn't update m_path when CTM became non-invertible.
792 // It means that resetTransform() restores m_path just before CTM became non -invertible.
793 }
794
795 void CanvasRenderingContext2D::setTransform(double m11, double m12, double m21, double m22, double dx, double dy)
796 {
797 SkCanvas* c = drawingCanvas();
798 if (!c)
799 return;
800
801 if (!std::isfinite(m11) || !std::isfinite(m21) || !std::isfinite(dx) || !std ::isfinite(m12) || !std::isfinite(m22) || !std::isfinite(dy))
802 return;
803
804 resetTransform();
805 transform(m11, m12, m21, m22, dx, dy);
806 }
807
808 void CanvasRenderingContext2D::beginPath()
809 {
810 m_path.clear();
811 }
812
813 static bool validateRectForCanvas(double& x, double& y, double& width, double& h eight)
814 {
815 if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(width) || !std: :isfinite(height))
816 return false;
817
818 if (!width && !height)
819 return false;
820
821 if (width < 0) {
822 width = -width;
823 x -= width;
824 }
825
826 if (height < 0) {
827 height = -height;
828 y -= height;
829 }
830
831 return true;
832 }
833
834 static bool isFullCanvasCompositeMode(SkXfermode::Mode op)
835 {
836 // See 4.8.11.1.3 Compositing
837 // CompositeSourceAtop and CompositeDestinationOut are not listed here as th e platforms already
838 // implement the specification's behavior.
839 return op == SkXfermode::kSrcIn_Mode || op == SkXfermode::kSrcOut_Mode || op == SkXfermode::kDstIn_Mode || op == SkXfermode::kDstATop_Mode;
840 }
841
842 template<typename DrawFunc>
843 void CanvasRenderingContext2D::compositedDraw(const DrawFunc& drawFunc, SkCanvas * c, CanvasRenderingContext2DState::PaintType paintType, CanvasRenderingContext2 DState::ImageType imageType)
844 {
845 SkImageFilter* filter = state().getFilter(canvas(), accessFont(), canvas()-> size(), this);
846 ASSERT(isFullCanvasCompositeMode(state().globalComposite()) || filter);
847 SkMatrix ctm = c->getTotalMatrix();
848 c->resetMatrix();
849 SkPaint compositePaint;
850 compositePaint.setXfermodeMode(state().globalComposite());
851 if (state().shouldDrawShadows()) {
852 // unroll into two independently composited passes if drawing shadows
853 SkPaint shadowPaint = *state().getPaint(paintType, DrawShadowOnly, image Type);
854 int saveCount = c->getSaveCount();
855 if (filter) {
856 SkPaint filterPaint;
857 filterPaint.setImageFilter(filter);
858 // TODO(junov): crbug.com/502921 We could use primitive bounds if we knew that the filter
859 // does not affect transparent black regions.
860 c->saveLayer(nullptr, &shadowPaint);
861 c->saveLayer(nullptr, &filterPaint);
862 SkPaint foregroundPaint = *state().getPaint(paintType, DrawForegroun dOnly, imageType);
863 c->setMatrix(ctm);
864 drawFunc(c, &foregroundPaint);
865 } else {
866 ASSERT(isFullCanvasCompositeMode(state().globalComposite()));
867 c->saveLayer(nullptr, &compositePaint);
868 shadowPaint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
869 c->setMatrix(ctm);
870 drawFunc(c, &shadowPaint);
871 }
872 c->restoreToCount(saveCount);
873 }
874
875 compositePaint.setImageFilter(filter);
876 // TODO(junov): crbug.com/502921 We could use primitive bounds if we knew th at the filter
877 // does not affect transparent black regions *and* !isFullCanvasCompositeMod e
878 c->saveLayer(nullptr, &compositePaint);
879 SkPaint foregroundPaint = *state().getPaint(paintType, DrawForegroundOnly, i mageType);
880 foregroundPaint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
881 c->setMatrix(ctm);
882 drawFunc(c, &foregroundPaint);
883 c->restore();
884 c->setMatrix(ctm);
885 }
886
887 template<typename DrawFunc, typename ContainsFunc>
888 bool CanvasRenderingContext2D::draw(const DrawFunc& drawFunc, const ContainsFunc & drawCoversClipBounds, const SkRect& bounds, CanvasRenderingContext2DState::Pai ntType paintType, CanvasRenderingContext2DState::ImageType imageType)
889 {
890 if (!state().isTransformInvertible())
891 return false;
892
893 SkIRect clipBounds;
894 if (!drawingCanvas() || !drawingCanvas()->getClipDeviceBounds(&clipBounds))
895 return false;
896
897 // If gradient size is zero, then paint nothing.
898 CanvasStyle* style = state().style(paintType);
899 if (style) {
900 CanvasGradient* gradient = style->canvasGradient();
901 if (gradient && gradient->gradient()->isZeroSize())
902 return false;
903 }
904
905 if (isFullCanvasCompositeMode(state().globalComposite()) || state().hasFilte r(canvas(), accessFont(), canvas()->size(), this)) {
906 compositedDraw(drawFunc, drawingCanvas(), paintType, imageType);
907 didDraw(clipBounds);
908 } else if (state().globalComposite() == SkXfermode::kSrc_Mode) {
909 clearCanvas(); // takes care of checkOverdraw()
910 const SkPaint* paint = state().getPaint(paintType, DrawForegroundOnly, i mageType);
911 drawFunc(drawingCanvas(), paint);
912 didDraw(clipBounds);
913 } else {
914 SkIRect dirtyRect;
915 if (computeDirtyRect(bounds, clipBounds, &dirtyRect)) {
916 const SkPaint* paint = state().getPaint(paintType, DrawShadowAndFore ground, imageType);
917 if (paintType != CanvasRenderingContext2DState::StrokePaintType && d rawCoversClipBounds(clipBounds))
918 checkOverdraw(bounds, paint, imageType, ClipFill);
919 drawFunc(drawingCanvas(), paint);
920 didDraw(dirtyRect);
921 }
922 }
923 return true;
924 }
925
926 static bool isPathExpensive(const Path& path)
927 {
928 const SkPath& skPath = path.skPath();
929 if (ExpensiveCanvasHeuristicParameters::ConcavePathsAreExpensive && !skPath. isConvex())
930 return true;
931
932 if (skPath.countPoints() > ExpensiveCanvasHeuristicParameters::ExpensivePath PointCount)
933 return true;
934
935 return false;
936 }
937
938 void CanvasRenderingContext2D::drawPathInternal(const Path& path, CanvasRenderin gContext2DState::PaintType paintType, SkPath::FillType fillType)
939 {
940 if (path.isEmpty())
941 return;
942
943 SkPath skPath = path.skPath();
944 FloatRect bounds = path.boundingRect();
945 skPath.setFillType(fillType);
946
947 if (paintType == CanvasRenderingContext2DState::StrokePaintType)
948 inflateStrokeRect(bounds);
949
950 if (!drawingCanvas())
951 return;
952
953 if (draw(
954 [&skPath, this](SkCanvas* c, const SkPaint* paint) // draw lambda
955 {
956 c->drawPath(skPath, *paint);
957 },
958 [](const SkIRect& rect) // overdraw test lambda
959 {
960 return false;
961 }, bounds, paintType)) {
962 if (isPathExpensive(path)) {
963 ImageBuffer* buffer = canvas()->buffer();
964 if (buffer)
965 buffer->setHasExpensiveOp();
966 }
967 }
968 }
969
970 static SkPath::FillType parseWinding(const String& windingRuleString)
971 {
972 if (windingRuleString == "nonzero")
973 return SkPath::kWinding_FillType;
974 if (windingRuleString == "evenodd")
975 return SkPath::kEvenOdd_FillType;
976
977 ASSERT_NOT_REACHED();
978 return SkPath::kEvenOdd_FillType;
979 }
980
981 void CanvasRenderingContext2D::fill(const String& windingRuleString)
982 {
983 drawPathInternal(m_path, CanvasRenderingContext2DState::FillPaintType, parse Winding(windingRuleString));
984 }
985
986 void CanvasRenderingContext2D::fill(Path2D* domPath, const String& windingRuleSt ring)
987 {
988 drawPathInternal(domPath->path(), CanvasRenderingContext2DState::FillPaintTy pe, parseWinding(windingRuleString));
989 }
990
991 void CanvasRenderingContext2D::stroke()
992 {
993 drawPathInternal(m_path, CanvasRenderingContext2DState::StrokePaintType);
994 }
995
996 void CanvasRenderingContext2D::stroke(Path2D* domPath)
997 {
998 drawPathInternal(domPath->path(), CanvasRenderingContext2DState::StrokePaint Type);
999 }
1000
1001 void CanvasRenderingContext2D::fillRect(double x, double y, double width, double height)
1002 {
1003 if (!validateRectForCanvas(x, y, width, height))
1004 return;
1005
1006 if (!drawingCanvas())
1007 return;
1008
1009 SkRect rect = SkRect::MakeXYWH(x, y, width, height);
1010 draw(
1011 [&rect, this](SkCanvas* c, const SkPaint* paint) // draw lambda
1012 {
1013 c->drawRect(rect, *paint);
1014 },
1015 [&rect, this](const SkIRect& clipBounds) // overdraw test lambda
1016 {
1017 return rectContainsTransformedRect(rect, clipBounds);
1018 }, rect, CanvasRenderingContext2DState::FillPaintType);
1019 }
1020
1021 static void strokeRectOnCanvas(const FloatRect& rect, SkCanvas* canvas, const Sk Paint* paint)
1022 {
1023 ASSERT(paint->getStyle() == SkPaint::kStroke_Style);
1024 if ((rect.width() > 0) != (rect.height() > 0)) {
1025 // When stroking, we must skip the zero-dimension segments
1026 SkPath path;
1027 path.moveTo(rect.x(), rect.y());
1028 path.lineTo(rect.maxX(), rect.maxY());
1029 path.close();
1030 canvas->drawPath(path, *paint);
1031 return;
1032 }
1033 canvas->drawRect(rect, *paint);
1034 }
1035
1036 void CanvasRenderingContext2D::strokeRect(double x, double y, double width, doub le height)
1037 {
1038 if (!validateRectForCanvas(x, y, width, height))
1039 return;
1040
1041 if (!drawingCanvas())
1042 return;
1043
1044 SkRect rect = SkRect::MakeXYWH(x, y, width, height);
1045 FloatRect bounds = rect;
1046 inflateStrokeRect(bounds);
1047 draw(
1048 [&rect, this](SkCanvas* c, const SkPaint* paint) // draw lambda
1049 {
1050 strokeRectOnCanvas(rect, c, paint);
1051 },
1052 [](const SkIRect& clipBounds) // overdraw test lambda
1053 {
1054 return false;
1055 }, bounds, CanvasRenderingContext2DState::StrokePaintType);
1056 }
1057
1058 void CanvasRenderingContext2D::clipInternal(const Path& path, const String& wind ingRuleString)
1059 {
1060 SkCanvas* c = drawingCanvas();
1061 if (!c) {
1062 return;
1063 }
1064 if (!state().isTransformInvertible()) {
1065 return;
1066 }
1067
1068 SkPath skPath = path.skPath();
1069 skPath.setFillType(parseWinding(windingRuleString));
1070 modifiableState().clipPath(skPath, m_clipAntialiasing);
1071 c->clipPath(skPath, SkRegion::kIntersect_Op, m_clipAntialiasing == AntiAlias ed);
1072 if (ExpensiveCanvasHeuristicParameters::ComplexClipsAreExpensive && !skPath. isRect(0) && canvas()->hasImageBuffer()) {
1073 canvas()->buffer()->setHasExpensiveOp();
1074 }
1075 }
1076
1077 void CanvasRenderingContext2D::clip(const String& windingRuleString)
1078 {
1079 clipInternal(m_path, windingRuleString);
1080 }
1081
1082 void CanvasRenderingContext2D::clip(Path2D* domPath, const String& windingRuleSt ring)
1083 {
1084 clipInternal(domPath->path(), windingRuleString);
1085 }
1086
1087 bool CanvasRenderingContext2D::isPointInPath(const double x, const double y, con st String& windingRuleString)
1088 {
1089 return isPointInPathInternal(m_path, x, y, windingRuleString);
1090 }
1091
1092 bool CanvasRenderingContext2D::isPointInPath(Path2D* domPath, const double x, co nst double y, const String& windingRuleString)
1093 {
1094 return isPointInPathInternal(domPath->path(), x, y, windingRuleString);
1095 }
1096
1097 bool CanvasRenderingContext2D::isPointInPathInternal(const Path& path, const dou ble x, const double y, const String& windingRuleString)
1098 {
1099 SkCanvas* c = drawingCanvas();
1100 if (!c)
1101 return false;
1102 if (!state().isTransformInvertible())
1103 return false;
1104
1105 FloatPoint point(x, y);
1106 if (!std::isfinite(point.x()) || !std::isfinite(point.y()))
1107 return false;
1108 AffineTransform ctm = state().transform();
1109 FloatPoint transformedPoint = ctm.inverse().mapPoint(point);
1110
1111 return path.contains(transformedPoint, SkFillTypeToWindRule(parseWinding(win dingRuleString)));
1112 }
1113
1114 bool CanvasRenderingContext2D::isPointInStroke(const double x, const double y)
1115 {
1116 return isPointInStrokeInternal(m_path, x, y);
1117 }
1118
1119 bool CanvasRenderingContext2D::isPointInStroke(Path2D* domPath, const double x, const double y)
1120 {
1121 return isPointInStrokeInternal(domPath->path(), x, y);
1122 }
1123
1124 bool CanvasRenderingContext2D::isPointInStrokeInternal(const Path& path, const d ouble x, const double y)
1125 {
1126 SkCanvas* c = drawingCanvas();
1127 if (!c)
1128 return false;
1129 if (!state().isTransformInvertible())
1130 return false;
1131
1132 FloatPoint point(x, y);
1133 if (!std::isfinite(point.x()) || !std::isfinite(point.y()))
1134 return false;
1135 AffineTransform ctm = state().transform();
1136 FloatPoint transformedPoint = ctm.inverse().mapPoint(point);
1137
1138 StrokeData strokeData;
1139 strokeData.setThickness(state().lineWidth());
1140 strokeData.setLineCap(state().lineCap());
1141 strokeData.setLineJoin(state().lineJoin());
1142 strokeData.setMiterLimit(state().miterLimit());
1143 Vector<float> lineDash(state().lineDash().size());
1144 std::copy(state().lineDash().begin(), state().lineDash().end(), lineDash.beg in());
1145 strokeData.setLineDash(lineDash, state().lineDashOffset());
1146 return path.strokeContains(transformedPoint, strokeData);
1147 }
1148
1149 void CanvasRenderingContext2D::scrollPathIntoView() 310 void CanvasRenderingContext2D::scrollPathIntoView()
1150 { 311 {
1151 scrollPathIntoViewInternal(m_path); 312 scrollPathIntoViewInternal(m_path);
1152 } 313 }
1153 314
1154 void CanvasRenderingContext2D::scrollPathIntoView(Path2D* path2d) 315 void CanvasRenderingContext2D::scrollPathIntoView(Path2D* path2d)
1155 { 316 {
1156 scrollPathIntoViewInternal(path2d->path()); 317 scrollPathIntoViewInternal(path2d->path());
1157 } 318 }
1158 319
(...skipping 21 matching lines...) Expand all
1180 341
1181 renderer->scrollRectToVisible( 342 renderer->scrollRectToVisible(
1182 pathRect, ScrollAlignment::alignCenterAlways, ScrollAlignment::alignTopA lways); 343 pathRect, ScrollAlignment::alignCenterAlways, ScrollAlignment::alignTopA lways);
1183 344
1184 // TODO: should implement "inform the user" that the caret and/or 345 // TODO: should implement "inform the user" that the caret and/or
1185 // selection the specified rectangle of the canvas. See http://crbug.com/357 987 346 // selection the specified rectangle of the canvas. See http://crbug.com/357 987
1186 } 347 }
1187 348
1188 void CanvasRenderingContext2D::clearRect(double x, double y, double width, doubl e height) 349 void CanvasRenderingContext2D::clearRect(double x, double y, double width, doubl e height)
1189 { 350 {
1190 if (!validateRectForCanvas(x, y, width, height)) 351 BaseRenderingContext2D::clearRect(x, y, width, height);
1191 return;
1192
1193 SkCanvas* c = drawingCanvas();
1194 if (!c)
1195 return;
1196 if (!state().isTransformInvertible())
1197 return;
1198
1199 SkIRect clipBounds;
1200 if (!c->getClipDeviceBounds(&clipBounds))
1201 return;
1202
1203 SkPaint clearPaint;
1204 clearPaint.setXfermodeMode(SkXfermode::kClear_Mode);
1205 clearPaint.setStyle(SkPaint::kFill_Style);
1206 FloatRect rect(x, y, width, height); 352 FloatRect rect(x, y, width, height);
1207 353
1208 if (rectContainsTransformedRect(rect, clipBounds)) {
1209 checkOverdraw(rect, &clearPaint, CanvasRenderingContext2DState::NoImage, ClipFill);
1210 if (drawingCanvas())
1211 drawingCanvas()->drawRect(rect, clearPaint);
1212 didDraw(clipBounds);
1213 } else {
1214 SkIRect dirtyRect;
1215 if (computeDirtyRect(rect, clipBounds, &dirtyRect)) {
1216 c->drawRect(rect, clearPaint);
1217 didDraw(dirtyRect);
1218 }
1219 }
1220
1221 if (m_hitRegionManager) { 354 if (m_hitRegionManager) {
1222 m_hitRegionManager->removeHitRegionsInRect(rect, state().transform()); 355 m_hitRegionManager->removeHitRegionsInRect(rect, state().transform());
1223 } 356 }
1224 } 357 }
1225 358
1226 static inline FloatRect normalizeRect(const FloatRect& rect)
1227 {
1228 return FloatRect(std::min(rect.x(), rect.maxX()),
1229 std::min(rect.y(), rect.maxY()),
1230 std::max(rect.width(), -rect.width()),
1231 std::max(rect.height(), -rect.height()));
1232 }
1233
1234 static inline void clipRectsToImageRect(const FloatRect& imageRect, FloatRect* s rcRect, FloatRect* dstRect)
1235 {
1236 if (imageRect.contains(*srcRect))
1237 return;
1238
1239 // Compute the src to dst transform
1240 FloatSize scale(dstRect->size().width() / srcRect->size().width(), dstRect-> size().height() / srcRect->size().height());
1241 FloatPoint scaledSrcLocation = srcRect->location();
1242 scaledSrcLocation.scale(scale.width(), scale.height());
1243 FloatSize offset = dstRect->location() - scaledSrcLocation;
1244
1245 srcRect->intersect(imageRect);
1246
1247 // To clip the destination rectangle in the same proportion, transform the c lipped src rect
1248 *dstRect = *srcRect;
1249 dstRect->scale(scale.width(), scale.height());
1250 dstRect->move(offset);
1251 }
1252
1253 static inline CanvasImageSource* toImageSourceInternal(const CanvasImageSourceUn ion& value)
1254 {
1255 if (value.isHTMLImageElement())
1256 return value.getAsHTMLImageElement().get();
1257 if (value.isHTMLVideoElement())
1258 return value.getAsHTMLVideoElement().get();
1259 if (value.isHTMLCanvasElement())
1260 return value.getAsHTMLCanvasElement().get();
1261 if (value.isImageBitmap())
1262 return value.getAsImageBitmap().get();
1263 ASSERT_NOT_REACHED();
1264 return nullptr;
1265 }
1266
1267 void CanvasRenderingContext2D::drawImage(const CanvasImageSourceUnion& imageSour ce, double x, double y, ExceptionState& exceptionState)
1268 {
1269 CanvasImageSource* imageSourceInternal = toImageSourceInternal(imageSource);
1270 FloatSize sourceRectSize = imageSourceInternal->elementSize();
1271 FloatSize destRectSize = imageSourceInternal->defaultDestinationSize();
1272 drawImage(imageSourceInternal, 0, 0, sourceRectSize.width(), sourceRectSize. height(), x, y, destRectSize.width(), destRectSize.height(), exceptionState);
1273 }
1274
1275 void CanvasRenderingContext2D::drawImage(const CanvasImageSourceUnion& imageSour ce,
1276 double x, double y, double width, double height, ExceptionState& exceptionSt ate)
1277 {
1278 CanvasImageSource* imageSourceInternal = toImageSourceInternal(imageSource);
1279 FloatSize sourceRectSize = imageSourceInternal->elementSize();
1280 drawImage(imageSourceInternal, 0, 0, sourceRectSize.width(), sourceRectSize. height(), x, y, width, height, exceptionState);
1281 }
1282
1283 void CanvasRenderingContext2D::drawImage(const CanvasImageSourceUnion& imageSour ce,
1284 double sx, double sy, double sw, double sh,
1285 double dx, double dy, double dw, double dh, ExceptionState& exceptionState)
1286 {
1287 CanvasImageSource* imageSourceInternal = toImageSourceInternal(imageSource);
1288 drawImage(imageSourceInternal, sx, sy, sw, sh, dx, dy, dw, dh, exceptionStat e);
1289 }
1290
1291 bool CanvasRenderingContext2D::shouldDrawImageAntialiased(const FloatRect& destR ect) const
1292 {
1293 if (!shouldAntialias())
1294 return false;
1295 SkCanvas* c = drawingCanvas();
1296 ASSERT(c);
1297
1298 const SkMatrix &ctm = c->getTotalMatrix();
1299 // Don't disable anti-aliasing if we're rotated or skewed.
1300 if (!ctm.rectStaysRect())
1301 return true;
1302 // Check if the dimensions of the destination are "small" (less than one
1303 // device pixel). To prevent sudden drop-outs. Since we know that
1304 // kRectStaysRect_Mask is set, the matrix either has scale and no skew or
1305 // vice versa. We can query the kAffine_Mask flag to determine which case
1306 // it is.
1307 // FIXME: This queries the CTM while drawing, which is generally
1308 // discouraged. Always drawing with AA can negatively impact performance
1309 // though - that's why it's not always on.
1310 SkScalar widthExpansion, heightExpansion;
1311 if (ctm.getType() & SkMatrix::kAffine_Mask)
1312 widthExpansion = ctm[SkMatrix::kMSkewY], heightExpansion = ctm[SkMatrix: :kMSkewX];
1313 else
1314 widthExpansion = ctm[SkMatrix::kMScaleX], heightExpansion = ctm[SkMatrix ::kMScaleY];
1315 return destRect.width() * fabs(widthExpansion) < 1 || destRect.height() * fa bs(heightExpansion) < 1;
1316 }
1317
1318 void CanvasRenderingContext2D::drawImageInternal(SkCanvas* c, CanvasImageSource* imageSource, Image* image, const FloatRect& srcRect, const FloatRect& dstRect, const SkPaint* paint)
1319 {
1320 int initialSaveCount = c->getSaveCount();
1321 SkPaint imagePaint = *paint;
1322
1323 if (paint->getImageFilter()) {
1324 SkMatrix invCtm;
1325 if (!c->getTotalMatrix().invert(&invCtm)) {
1326 // There is an earlier check for invertibility, but the arithmetic
1327 // in AffineTransform is not exactly identical, so it is possible
1328 // for SkMatrix to find the transform to be non-invertible at this s tage.
1329 // crbug.com/504687
1330 return;
1331 }
1332 SkRect bounds = dstRect;
1333 SkPaint layerPaint;
1334 layerPaint.setXfermode(paint->getXfermode());
1335 SkAutoTUnref<SkImageFilter> localFilter(paint->getImageFilter()->newWith LocalMatrix(invCtm));
1336 layerPaint.setImageFilter(localFilter);
1337 c->saveLayer(&bounds, &layerPaint);
1338 imagePaint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
1339 imagePaint.setImageFilter(nullptr);
1340 }
1341
1342 if (!imageSource->isVideoElement()) {
1343 imagePaint.setAntiAlias(shouldDrawImageAntialiased(dstRect));
1344 image->draw(c, imagePaint, dstRect, srcRect, DoNotRespectImageOrientatio n, Image::DoNotClampImageToSourceRect);
1345 } else {
1346 c->save();
1347 c->clipRect(dstRect);
1348 c->translate(dstRect.x(), dstRect.y());
1349 c->scale(dstRect.width() / srcRect.width(), dstRect.height() / srcRect.h eight());
1350 c->translate(-srcRect.x(), -srcRect.y());
1351 HTMLVideoElement* video = static_cast<HTMLVideoElement*>(imageSource);
1352 video->paintCurrentFrame(c, IntRect(IntPoint(), IntSize(video->videoWidt h(), video->videoHeight())), &imagePaint);
1353 }
1354
1355 c->restoreToCount(initialSaveCount);
1356 }
1357
1358 bool shouldDisableDeferral(CanvasImageSource* imageSource, DisableDeferralReason * reason)
1359 {
1360 ASSERT(reason);
1361 ASSERT(*reason == DisableDeferralReasonUnknown);
1362
1363 if (imageSource->isVideoElement()) {
1364 *reason = DisableDeferralReasonDrawImageOfVideo;
1365 return true;
1366 }
1367 if (imageSource->isCanvasElement()) {
1368 HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(imageSource) ;
1369 if (canvas->isAnimated2D()) {
1370 *reason = DisableDeferralReasonDrawImageOfAnimated2dCanvas;
1371 return true;
1372 }
1373 }
1374 return false;
1375 }
1376
1377 void CanvasRenderingContext2D::drawImage(CanvasImageSource* imageSource,
1378 double sx, double sy, double sw, double sh,
1379 double dx, double dy, double dw, double dh, ExceptionState& exceptionState)
1380 {
1381 if (!drawingCanvas())
1382 return;
1383
1384 RefPtr<Image> image;
1385 SourceImageStatus sourceImageStatus = InvalidSourceImageStatus;
1386 if (!imageSource->isVideoElement()) {
1387 AccelerationHint hint = canvas()->buffer()->isAccelerated() ? PreferAcce leration : PreferNoAcceleration;
1388 image = imageSource->getSourceImageForCanvas(&sourceImageStatus, hint, S napshotReasonDrawImage);
1389 if (sourceImageStatus == UndecodableSourceImageStatus)
1390 exceptionState.throwDOMException(InvalidStateError, "The HTMLImageEl ement provided is in the 'broken' state.");
1391 if (!image || !image->width() || !image->height())
1392 return;
1393 } else {
1394 if (!static_cast<HTMLVideoElement*>(imageSource)->hasAvailableVideoFrame ())
1395 return;
1396 }
1397
1398 if (!std::isfinite(dx) || !std::isfinite(dy) || !std::isfinite(dw) || !std:: isfinite(dh)
1399 || !std::isfinite(sx) || !std::isfinite(sy) || !std::isfinite(sw) || !st d::isfinite(sh)
1400 || !dw || !dh || !sw || !sh)
1401 return;
1402
1403 FloatRect srcRect = normalizeRect(FloatRect(sx, sy, sw, sh));
1404 FloatRect dstRect = normalizeRect(FloatRect(dx, dy, dw, dh));
1405
1406 clipRectsToImageRect(FloatRect(FloatPoint(), imageSource->elementSize()), &s rcRect, &dstRect);
1407
1408 imageSource->adjustDrawRects(&srcRect, &dstRect);
1409
1410 if (srcRect.isEmpty())
1411 return;
1412
1413 DisableDeferralReason reason = DisableDeferralReasonUnknown;
1414 if (shouldDisableDeferral(imageSource, &reason) || image->isTextureBacked())
1415 canvas()->disableDeferral(reason);
1416
1417 validateStateStack();
1418
1419 draw(
1420 [this, &imageSource, &image, &srcRect, dstRect](SkCanvas* c, const SkPai nt* paint) // draw lambda
1421 {
1422 drawImageInternal(c, imageSource, image.get(), srcRect, dstRect, pai nt);
1423 },
1424 [this, &dstRect](const SkIRect& clipBounds) // overdraw test lambda
1425 {
1426 return rectContainsTransformedRect(dstRect, clipBounds);
1427 }, dstRect, CanvasRenderingContext2DState::ImagePaintType,
1428 imageSource->isOpaque() ? CanvasRenderingContext2DState::OpaqueImage : C anvasRenderingContext2DState::NonOpaqueImage);
1429
1430 validateStateStack();
1431
1432 bool isExpensive = false;
1433
1434 if (ExpensiveCanvasHeuristicParameters::SVGImageSourcesAreExpensive && image Source->isSVGSource())
1435 isExpensive = true;
1436
1437 if (imageSource->elementSize().width() * imageSource->elementSize().height() > canvas()->width() * canvas()->height() * ExpensiveCanvasHeuristicParameters:: ExpensiveImageSizeRatio)
1438 isExpensive = true;
1439
1440 if (isExpensive) {
1441 ImageBuffer* buffer = canvas()->buffer();
1442 if (buffer)
1443 buffer->setHasExpensiveOp();
1444 }
1445
1446 if (imageSource->isCanvasElement() && static_cast<HTMLCanvasElement*>(imageS ource)->is3D()) {
1447 // WebGL to 2D canvas: must flush graphics context to prevent a race
1448 // FIXME: crbug.com/516331 Fix the underlying synchronization issue so t his flush can be eliminated.
1449 canvas()->buffer()->flushGpu(FlushReasonDrawImageOfWebGL);
1450 }
1451
1452 if (canvas()->originClean() && wouldTaintOrigin(imageSource))
1453 canvas()->setOriginTainted();
1454 }
1455
1456 void CanvasRenderingContext2D::clearCanvas()
1457 {
1458 FloatRect canvasRect(0, 0, canvas()->width(), canvas()->height());
1459 checkOverdraw(canvasRect, 0, CanvasRenderingContext2DState::NoImage, ClipFil l);
1460 SkCanvas* c = drawingCanvas();
1461 if (c)
1462 c->clear(m_hasAlpha ? SK_ColorTRANSPARENT : SK_ColorBLACK);
1463 }
1464
1465 bool CanvasRenderingContext2D::rectContainsTransformedRect(const FloatRect& rect , const SkIRect& transformedRect) const
1466 {
1467 FloatQuad quad(rect);
1468 FloatQuad transformedQuad(FloatRect(transformedRect.x(), transformedRect.y() , transformedRect.width(), transformedRect.height()));
1469 return state().transform().mapQuad(quad).containsQuad(transformedQuad);
1470 }
1471
1472 CanvasGradient* CanvasRenderingContext2D::createLinearGradient(double x0, double y0, double x1, double y1)
1473 {
1474 CanvasGradient* gradient = CanvasGradient::create(FloatPoint(x0, y0), FloatP oint(x1, y1));
1475 return gradient;
1476 }
1477
1478 CanvasGradient* CanvasRenderingContext2D::createRadialGradient(double x0, double y0, double r0, double x1, double y1, double r1, ExceptionState& exceptionState)
1479 {
1480 if (r0 < 0 || r1 < 0) {
1481 exceptionState.throwDOMException(IndexSizeError, String::format("The %s provided is less than 0.", r0 < 0 ? "r0" : "r1"));
1482 return nullptr;
1483 }
1484
1485 CanvasGradient* gradient = CanvasGradient::create(FloatPoint(x0, y0), r0, Fl oatPoint(x1, y1), r1);
1486 return gradient;
1487 }
1488
1489 CanvasPattern* CanvasRenderingContext2D::createPattern(const CanvasImageSourceUn ion& imageSource, const String& repetitionType, ExceptionState& exceptionState)
1490 {
1491 Pattern::RepeatMode repeatMode = CanvasPattern::parseRepetitionType(repetiti onType, exceptionState);
1492 if (exceptionState.hadException())
1493 return nullptr;
1494
1495 SourceImageStatus status;
1496 CanvasImageSource* imageSourceInternal = toImageSourceInternal(imageSource);
1497 RefPtr<Image> imageForRendering = imageSourceInternal->getSourceImageForCanv as(&status, PreferNoAcceleration, SnapshotReasonCreatePattern);
1498
1499 switch (status) {
1500 case NormalSourceImageStatus:
1501 break;
1502 case ZeroSizeCanvasSourceImageStatus:
1503 exceptionState.throwDOMException(InvalidStateError, String::format("The canvas %s is 0.", imageSourceInternal->elementSize().width() ? "height" : "width "));
1504 return nullptr;
1505 case UndecodableSourceImageStatus:
1506 exceptionState.throwDOMException(InvalidStateError, "Source image is in the 'broken' state.");
1507 return nullptr;
1508 case InvalidSourceImageStatus:
1509 imageForRendering = Image::nullImage();
1510 break;
1511 case IncompleteSourceImageStatus:
1512 return nullptr;
1513 default:
1514 ASSERT_NOT_REACHED();
1515 return nullptr;
1516 }
1517 ASSERT(imageForRendering);
1518
1519 bool originClean = !wouldTaintOrigin(imageSourceInternal);
1520
1521 return CanvasPattern::create(imageForRendering.release(), repeatMode, origin Clean);
1522 }
1523
1524 bool CanvasRenderingContext2D::computeDirtyRect(const FloatRect& localRect, SkIR ect* dirtyRect)
1525 {
1526 SkIRect clipBounds;
1527 if (!drawingCanvas()->getClipDeviceBounds(&clipBounds))
1528 return false;
1529 return computeDirtyRect(localRect, clipBounds, dirtyRect);
1530 }
1531
1532 bool CanvasRenderingContext2D::computeDirtyRect(const FloatRect& localRect, cons t SkIRect& transformedClipBounds, SkIRect* dirtyRect)
1533 {
1534 FloatRect canvasRect = state().transform().mapRect(localRect);
1535
1536 if (alphaChannel(state().shadowColor())) {
1537 FloatRect shadowRect(canvasRect);
1538 shadowRect.move(state().shadowOffset());
1539 shadowRect.inflate(state().shadowBlur());
1540 canvasRect.unite(shadowRect);
1541 }
1542
1543 SkIRect canvasIRect;
1544 static_cast<SkRect>(canvasRect).roundOut(&canvasIRect);
1545 if (!canvasIRect.intersect(transformedClipBounds))
1546 return false;
1547
1548 if (dirtyRect)
1549 *dirtyRect = canvasIRect;
1550
1551 return true;
1552 }
1553
1554 void CanvasRenderingContext2D::didDraw(const SkIRect& dirtyRect) 359 void CanvasRenderingContext2D::didDraw(const SkIRect& dirtyRect)
1555 { 360 {
1556 if (dirtyRect.isEmpty()) 361 if (dirtyRect.isEmpty())
1557 return; 362 return;
1558 363
1559 if (ExpensiveCanvasHeuristicParameters::BlurredShadowsAreExpensive && state( ).shouldDrawShadows() && state().shadowBlur() > 0) { 364 if (ExpensiveCanvasHeuristicParameters::BlurredShadowsAreExpensive && state( ).shouldDrawShadows() && state().shadowBlur() > 0) {
1560 ImageBuffer* buffer = canvas()->buffer(); 365 ImageBuffer* buffer = canvas()->buffer();
1561 if (buffer) 366 if (buffer)
1562 buffer->setHasExpensiveOp(); 367 buffer->setHasExpensiveOp();
1563 } 368 }
1564 369
1565 canvas()->didDraw(SkRect::Make(dirtyRect)); 370 canvas()->didDraw(SkRect::Make(dirtyRect));
1566 } 371 }
1567 372
373 bool CanvasRenderingContext2D::stateHasFilter()
374 {
375 return state().hasFilter(canvas(), accessFont(), canvas()->size(), this);
376 }
377
378 SkImageFilter* CanvasRenderingContext2D::stateGetFilter()
379 {
380 return state().getFilter(canvas(), accessFont(), canvas()->size(), this);
381 }
382
1568 SkCanvas* CanvasRenderingContext2D::drawingCanvas() const 383 SkCanvas* CanvasRenderingContext2D::drawingCanvas() const
1569 { 384 {
1570 if (isContextLost()) 385 if (isContextLost())
1571 return nullptr; 386 return nullptr;
1572 return canvas()->drawingCanvas(); 387 return canvas()->drawingCanvas();
1573 } 388 }
1574 389
1575 ImageData* CanvasRenderingContext2D::createImageData(ImageData* imageData) const 390 SkCanvas* CanvasRenderingContext2D::existingDrawingCanvas() const
1576 { 391 {
1577 return ImageData::create(imageData->size()); 392 return canvas()->existingDrawingCanvas();
1578 } 393 }
1579 394
1580 ImageData* CanvasRenderingContext2D::createImageData(double sw, double sh, Excep tionState& exceptionState) const 395 void CanvasRenderingContext2D::disableDeferral(DisableDeferralReason reason)
1581 { 396 {
1582 if (!sw || !sh) { 397 canvas()->disableDeferral(reason);
1583 exceptionState.throwDOMException(IndexSizeError, String::format("The sou rce %s is 0.", sw ? "height" : "width"));
1584 return nullptr;
1585 }
1586
1587 FloatSize logicalSize(fabs(sw), fabs(sh));
1588 if (!logicalSize.isExpressibleAsIntSize())
1589 return nullptr;
1590
1591 IntSize size = expandedIntSize(logicalSize);
1592 if (size.width() < 1)
1593 size.setWidth(1);
1594 if (size.height() < 1)
1595 size.setHeight(1);
1596
1597 return ImageData::create(size);
1598 } 398 }
1599 399
1600 ImageData* CanvasRenderingContext2D::getImageData(double sx, double sy, double s w, double sh, ExceptionState& exceptionState) const 400 AffineTransform CanvasRenderingContext2D::baseTransform() const
1601 { 401 {
1602 if (!canvas()->originClean()) 402 return canvas()->baseTransform();
1603 exceptionState.throwSecurityError("The canvas has been tainted by cross- origin data.");
1604 else if (!sw || !sh)
1605 exceptionState.throwDOMException(IndexSizeError, String::format("The sou rce %s is 0.", sw ? "height" : "width"));
1606
1607 if (exceptionState.hadException())
1608 return nullptr;
1609
1610 if (sw < 0) {
1611 sx += sw;
1612 sw = -sw;
1613 }
1614 if (sh < 0) {
1615 sy += sh;
1616 sh = -sh;
1617 }
1618
1619 FloatRect logicalRect(sx, sy, sw, sh);
1620 if (logicalRect.width() < 1)
1621 logicalRect.setWidth(1);
1622 if (logicalRect.height() < 1)
1623 logicalRect.setHeight(1);
1624 if (!logicalRect.isExpressibleAsIntRect())
1625 return nullptr;
1626
1627 IntRect imageDataRect = enclosingIntRect(logicalRect);
1628 ImageBuffer* buffer = canvas()->buffer();
1629 if (!buffer || isContextLost())
1630 return ImageData::create(imageDataRect.size());
1631
1632 WTF::ArrayBufferContents contents;
1633 if (!buffer->getImageData(Unmultiplied, imageDataRect, contents))
1634 return nullptr;
1635
1636 RefPtr<DOMArrayBuffer> arrayBuffer = DOMArrayBuffer::create(contents);
1637 return ImageData::create(
1638 imageDataRect.size(),
1639 DOMUint8ClampedArray::create(arrayBuffer, 0, arrayBuffer->byteLength())) ;
1640 }
1641
1642 void CanvasRenderingContext2D::putImageData(ImageData* data, double dx, double d y, ExceptionState& exceptionState)
1643 {
1644 putImageData(data, dx, dy, 0, 0, data->width(), data->height(), exceptionSta te);
1645 }
1646
1647 void CanvasRenderingContext2D::putImageData(ImageData* data, double dx, double d y, double dirtyX, double dirtyY, double dirtyWidth, double dirtyHeight, Exceptio nState& exceptionState)
1648 {
1649 if (data->data()->bufferBase()->isNeutered()) {
1650 exceptionState.throwDOMException(InvalidStateError, "The source data has been neutered.");
1651 return;
1652 }
1653 ImageBuffer* buffer = canvas()->buffer();
1654 if (!buffer)
1655 return;
1656
1657 if (dirtyWidth < 0) {
1658 dirtyX += dirtyWidth;
1659 dirtyWidth = -dirtyWidth;
1660 }
1661
1662 if (dirtyHeight < 0) {
1663 dirtyY += dirtyHeight;
1664 dirtyHeight = -dirtyHeight;
1665 }
1666
1667 FloatRect clipRect(dirtyX, dirtyY, dirtyWidth, dirtyHeight);
1668 clipRect.intersect(IntRect(0, 0, data->width(), data->height()));
1669 IntSize destOffset(static_cast<int>(dx), static_cast<int>(dy));
1670 IntRect destRect = enclosingIntRect(clipRect);
1671 destRect.move(destOffset);
1672 destRect.intersect(IntRect(IntPoint(), buffer->size()));
1673 if (destRect.isEmpty())
1674 return;
1675 IntRect sourceRect(destRect);
1676 sourceRect.move(-destOffset);
1677
1678 checkOverdraw(destRect, 0, CanvasRenderingContext2DState::NoImage, Untransfo rmedUnclippedFill);
1679
1680 buffer->putByteArray(Unmultiplied, data->data()->data(), IntSize(data->width (), data->height()), sourceRect, IntPoint(destOffset));
1681
1682 didDraw(destRect);
1683 } 403 }
1684 404
1685 String CanvasRenderingContext2D::font() const 405 String CanvasRenderingContext2D::font() const
1686 { 406 {
1687 if (!state().hasRealizedFont()) 407 if (!state().hasRealizedFont())
1688 return defaultFont; 408 return defaultFont;
1689 409
1690 canvas()->document().canvasFontCache()->willUseCurrentFont(); 410 canvas()->document().canvasFontCache()->willUseCurrentFont();
1691 StringBuilder serializedFont; 411 StringBuilder serializedFont;
1692 const FontDescription& fontDescription = state().font().fontDescription(); 412 const FontDescription& fontDescription = state().font().fontDescription();
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
1816 if (oldStyle && oldStyle->font() == newStyle.font()) 536 if (oldStyle && oldStyle->font() == newStyle.font())
1817 return; 537 return;
1818 pruneLocalFontCache(0); 538 pruneLocalFontCache(0);
1819 } 539 }
1820 540
1821 void CanvasRenderingContext2D::filterNeedsInvalidation() 541 void CanvasRenderingContext2D::filterNeedsInvalidation()
1822 { 542 {
1823 state().clearResolvedFilter(); 543 state().clearResolvedFilter();
1824 } 544 }
1825 545
546 bool CanvasRenderingContext2D::originClean() const
547 {
548 return canvas()->originClean();
549 }
550
551 void CanvasRenderingContext2D::setOriginTainted()
552 {
553 return canvas()->setOriginTainted();
554 }
555
556 int CanvasRenderingContext2D::width() const
557 {
558 return canvas()->width();
559 }
560
561 int CanvasRenderingContext2D::height() const
562 {
563 return canvas()->height();
564 }
565
566 bool CanvasRenderingContext2D::hasImageBuffer() const
567 {
568 return canvas()->hasImageBuffer();
569 }
570
571 ImageBuffer* CanvasRenderingContext2D::imageBuffer() const
572 {
573 return canvas()->buffer();
574 }
575
576 bool CanvasRenderingContext2D::parseColorOrCurrentColor(Color& color, const Stri ng& colorString) const
577 {
578 return ::blink::parseColorOrCurrentColor(color, colorString, canvas());
579 }
580
1826 String CanvasRenderingContext2D::textAlign() const 581 String CanvasRenderingContext2D::textAlign() const
1827 { 582 {
1828 return textAlignName(state().textAlign()); 583 return textAlignName(state().textAlign());
1829 } 584 }
1830 585
1831 void CanvasRenderingContext2D::setTextAlign(const String& s) 586 void CanvasRenderingContext2D::setTextAlign(const String& s)
1832 { 587 {
1833 TextAlign align; 588 TextAlign align;
1834 if (!parseTextAlign(s, align)) 589 if (!parseTextAlign(s, align))
1835 return; 590 return;
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after
2051 { 806 {
2052 font.drawBidiText(c, textRunPaintInfo, location, Font::UseFallbackIf FontNotReady, cDeviceScaleFactor, *paint); 807 font.drawBidiText(c, textRunPaintInfo, location, Font::UseFallbackIf FontNotReady, cDeviceScaleFactor, *paint);
2053 }, 808 },
2054 [](const SkIRect& rect) // overdraw test lambda 809 [](const SkIRect& rect) // overdraw test lambda
2055 { 810 {
2056 return false; 811 return false;
2057 }, 812 },
2058 textRunPaintInfo.bounds, paintType); 813 textRunPaintInfo.bounds, paintType);
2059 } 814 }
2060 815
2061 void CanvasRenderingContext2D::inflateStrokeRect(FloatRect& rect) const
2062 {
2063 // Fast approximation of the stroke's bounding rect.
2064 // This yields a slightly oversized rect but is very fast
2065 // compared to Path::strokeBoundingRect().
2066 static const double root2 = sqrtf(2);
2067 double delta = state().lineWidth() / 2;
2068 if (state().lineJoin() == MiterJoin)
2069 delta *= state().miterLimit();
2070 else if (state().lineCap() == SquareCap)
2071 delta *= root2;
2072
2073 rect.inflate(delta);
2074 }
2075
2076 const Font& CanvasRenderingContext2D::accessFont() 816 const Font& CanvasRenderingContext2D::accessFont()
2077 { 817 {
2078 if (!state().hasRealizedFont()) 818 if (!state().hasRealizedFont())
2079 setFont(state().unparsedFont()); 819 setFont(state().unparsedFont());
2080 canvas()->document().canvasFontCache()->willUseCurrentFont(); 820 canvas()->document().canvasFontCache()->willUseCurrentFont();
2081 return state().font(); 821 return state().font();
2082 } 822 }
2083 823
2084 int CanvasRenderingContext2D::getFontBaseline(const FontMetrics& fontMetrics) co nst 824 int CanvasRenderingContext2D::getFontBaseline(const FontMetrics& fontMetrics) co nst
2085 { 825 {
(...skipping 29 matching lines...) Expand all
2115 bool CanvasRenderingContext2D::isTransformInvertible() const 855 bool CanvasRenderingContext2D::isTransformInvertible() const
2116 { 856 {
2117 return state().isTransformInvertible(); 857 return state().isTransformInvertible();
2118 } 858 }
2119 859
2120 WebLayer* CanvasRenderingContext2D::platformLayer() const 860 WebLayer* CanvasRenderingContext2D::platformLayer() const
2121 { 861 {
2122 return canvas()->buffer() ? canvas()->buffer()->platformLayer() : 0; 862 return canvas()->buffer() ? canvas()->buffer()->platformLayer() : 0;
2123 } 863 }
2124 864
2125 bool CanvasRenderingContext2D::imageSmoothingEnabled() const
2126 {
2127 return state().imageSmoothingEnabled();
2128 }
2129
2130 void CanvasRenderingContext2D::setImageSmoothingEnabled(bool enabled)
2131 {
2132 if (enabled == state().imageSmoothingEnabled())
2133 return;
2134
2135 modifiableState().setImageSmoothingEnabled(enabled);
2136 }
2137
2138 String CanvasRenderingContext2D::imageSmoothingQuality() const
2139 {
2140 return state().imageSmoothingQuality();
2141 }
2142
2143 void CanvasRenderingContext2D::setImageSmoothingQuality(const String& quality)
2144 {
2145 if (quality == state().imageSmoothingQuality())
2146 return;
2147
2148 modifiableState().setImageSmoothingQuality(quality);
2149 }
2150
2151 void CanvasRenderingContext2D::getContextAttributes(Canvas2DContextAttributes& a ttrs) const 865 void CanvasRenderingContext2D::getContextAttributes(Canvas2DContextAttributes& a ttrs) const
2152 { 866 {
2153 attrs.setAlpha(m_hasAlpha); 867 attrs.setAlpha(m_hasAlpha);
2154 } 868 }
2155 869
2156 void CanvasRenderingContext2D::drawFocusIfNeeded(Element* element) 870 void CanvasRenderingContext2D::drawFocusIfNeeded(Element* element)
2157 { 871 {
2158 drawFocusIfNeededInternal(m_path, element); 872 drawFocusIfNeededInternal(m_path, element);
2159 } 873 }
2160 874
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
2300 } 1014 }
2301 1015
2302 unsigned CanvasRenderingContext2D::hitRegionsCount() const 1016 unsigned CanvasRenderingContext2D::hitRegionsCount() const
2303 { 1017 {
2304 if (m_hitRegionManager) 1018 if (m_hitRegionManager)
2305 return m_hitRegionManager->getHitRegionsCount(); 1019 return m_hitRegionManager->getHitRegionsCount();
2306 1020
2307 return 0; 1021 return 0;
2308 } 1022 }
2309 1023
2310 void CanvasRenderingContext2D::checkOverdraw(const SkRect& rect, const SkPaint* paint, CanvasRenderingContext2DState::ImageType imageType, DrawType drawType)
2311 {
2312 SkCanvas* c = drawingCanvas();
2313 if (!c || !canvas()->buffer()->isRecording())
2314 return;
2315
2316 SkRect deviceRect;
2317 if (drawType == UntransformedUnclippedFill) {
2318 deviceRect = rect;
2319 } else {
2320 ASSERT(drawType == ClipFill);
2321 if (state().hasComplexClip())
2322 return;
2323
2324 SkIRect skIBounds;
2325 if (!c->getClipDeviceBounds(&skIBounds))
2326 return;
2327 deviceRect = SkRect::Make(skIBounds);
2328 }
2329
2330 const SkImageInfo& imageInfo = c->imageInfo();
2331 if (!deviceRect.contains(SkRect::MakeWH(imageInfo.width(), imageInfo.height( ))))
2332 return;
2333
2334 bool isSourceOver = true;
2335 unsigned alpha = 0xFF;
2336 if (paint) {
2337 if (paint->getLooper() || paint->getImageFilter() || paint->getMaskFilte r())
2338 return;
2339
2340 SkXfermode* xfermode = paint->getXfermode();
2341 if (xfermode) {
2342 SkXfermode::Mode mode;
2343 if (xfermode->asMode(&mode)) {
2344 isSourceOver = mode == SkXfermode::kSrcOver_Mode;
2345 if (!isSourceOver && mode != SkXfermode::kSrc_Mode && mode != Sk Xfermode::kClear_Mode)
2346 return; // The code below only knows how to handle Src, SrcO ver, and Clear
2347 } else {
2348 // unknown xfermode
2349 ASSERT_NOT_REACHED();
2350 return;
2351 }
2352 }
2353
2354 alpha = paint->getAlpha();
2355
2356 if (isSourceOver && imageType == CanvasRenderingContext2DState::NoImage) {
2357 SkShader* shader = paint->getShader();
2358 if (shader) {
2359 if (shader->isOpaque() && alpha == 0xFF)
2360 canvas()->buffer()->willOverwriteCanvas();
2361 return;
2362 }
2363 }
2364 }
2365
2366 if (isSourceOver) {
2367 // With source over, we need to certify that alpha == 0xFF for all pixel s
2368 if (imageType == CanvasRenderingContext2DState::NonOpaqueImage)
2369 return;
2370 if (alpha < 0xFF)
2371 return;
2372 }
2373
2374 canvas()->buffer()->willOverwriteCanvas();
2375 }
2376
2377 } // namespace blink 1024 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698