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

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

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

Powered by Google App Engine
This is Rietveld 408576698