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

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

Powered by Google App Engine
This is Rietveld 408576698