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

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

Issue 1710633002: Pull up a subset of CanvasRenderingContext2D into BaseRenderingContext2D. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase 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 // Copyright 2016 The Chromium Authors. All rights reserved.
2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be
3 * Copyright (C) 2008, 2010 Nokia Corporation and/or its subsidiary(-ies) 3 // found in the LICENSE file.
4 * Copyright (C) 2007 Alp Toker <alp@atoker.com>
5 * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
6 * Copyright (C) 2008 Dirk Schulze <krit@webkit.org>
7 * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
8 * Copyright (C) 2012, 2013 Intel Corporation. All rights reserved.
9 * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
21 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
28 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 4
33 #include "modules/canvas2d/CanvasRenderingContext2D.h" 5 #include "modules/canvas2d/BaseRenderingContext2D.h"
34 6
35 #include "bindings/core/v8/ExceptionMessages.h" 7 #include "bindings/core/v8/ExceptionMessages.h"
36 #include "bindings/core/v8/ExceptionState.h" 8 #include "bindings/core/v8/ExceptionState.h"
37 #include "bindings/core/v8/ExceptionStatePlaceholder.h" 9 #include "bindings/core/v8/ExceptionStatePlaceholder.h"
38 #include "core/CSSPropertyNames.h"
39 #include "core/css/StylePropertySet.h"
40 #include "core/css/parser/CSSParser.h" 10 #include "core/css/parser/CSSParser.h"
41 #include "core/css/resolver/StyleResolver.h"
42 #include "core/dom/AXObjectCache.h"
43 #include "core/dom/StyleEngine.h"
44 #include "core/events/Event.h"
45 #include "core/frame/ImageBitmap.h" 11 #include "core/frame/ImageBitmap.h"
46 #include "core/frame/Settings.h" 12 #include "core/html/HTMLCanvasElement.h"
13 #include "core/html/HTMLImageElement.h"
47 #include "core/html/HTMLVideoElement.h" 14 #include "core/html/HTMLVideoElement.h"
48 #include "core/html/ImageData.h" 15 #include "core/html/ImageData.h"
49 #include "core/html/TextMetrics.h"
50 #include "core/html/canvas/CanvasFontCache.h"
51 #include "core/layout/LayoutBox.h"
52 #include "core/layout/LayoutTheme.h"
53 #include "modules/canvas2d/CanvasGradient.h" 16 #include "modules/canvas2d/CanvasGradient.h"
54 #include "modules/canvas2d/CanvasPattern.h" 17 #include "modules/canvas2d/CanvasPattern.h"
55 #include "modules/canvas2d/CanvasRenderingContext2DState.h"
56 #include "modules/canvas2d/CanvasStyle.h" 18 #include "modules/canvas2d/CanvasStyle.h"
57 #include "modules/canvas2d/HitRegion.h"
58 #include "modules/canvas2d/Path2D.h" 19 #include "modules/canvas2d/Path2D.h"
59 #include "platform/fonts/FontCache.h"
60 #include "platform/geometry/FloatQuad.h" 20 #include "platform/geometry/FloatQuad.h"
61 #include "platform/graphics/DrawLooperBuilder.h" 21 #include "platform/graphics/Color.h"
62 #include "platform/graphics/ExpensiveCanvasHeuristicParameters.h" 22 #include "platform/graphics/ExpensiveCanvasHeuristicParameters.h"
23 #include "platform/graphics/Image.h"
63 #include "platform/graphics/ImageBuffer.h" 24 #include "platform/graphics/ImageBuffer.h"
64 #include "platform/graphics/StrokeData.h" 25 #include "platform/graphics/StrokeData.h"
65 #include "platform/graphics/skia/SkiaUtils.h" 26 #include "platform/graphics/skia/SkiaUtils.h"
66 #include "platform/text/BidiTextRun.h"
67 #include "public/platform/Platform.h"
68 #include "third_party/skia/include/core/SkCanvas.h"
69 #include "third_party/skia/include/core/SkImageFilter.h" 27 #include "third_party/skia/include/core/SkImageFilter.h"
70 #include "wtf/ArrayBufferContents.h"
71 #include "wtf/CheckedArithmetic.h"
72 #include "wtf/MathExtras.h"
73 #include "wtf/OwnPtr.h"
74 #include "wtf/text/StringBuilder.h"
75 28
76 namespace blink { 29 namespace blink {
77 30
78 static const char defaultFont[] = "10px sans-serif"; 31 BaseRenderingContext2D::BaseRenderingContext2D()
79 static const char inherit[] = "inherit"; 32 : m_clipAntialiasing(NotAntiAliased)
80 static const char rtl[] = "rtl";
81 static const char ltr[] = "ltr";
82 static const double TryRestoreContextInterval = 0.5;
83 static const unsigned MaxTryRestoreContextAttempts = 4;
84 static const double cDeviceScaleFactor = 1.0; // Canvas is device independent
85
86 static bool contextLostRestoredEventsEnabled()
87 { 33 {
88 return RuntimeEnabledFeatures::experimentalCanvasFeaturesEnabled(); 34 m_stateStack.append(CanvasRenderingContext2DState::create());
89 } 35 }
90 36
91 // Drawing methods need to use this instead of SkAutoCanvasRestore in case overd raw 37 BaseRenderingContext2D::~BaseRenderingContext2D()
92 // detection substitutes the recording canvas (to discard overdrawn draw calls).
93 class CanvasRenderingContext2DAutoRestoreSkCanvas {
94 STACK_ALLOCATED();
95 public:
96 explicit CanvasRenderingContext2DAutoRestoreSkCanvas(CanvasRenderingContext2 D* context)
97 : m_context(context)
98 , m_saveCount(0)
99 {
100 ASSERT(m_context);
101 SkCanvas* c = m_context->drawingCanvas();
102 if (c) {
103 m_saveCount = c->getSaveCount();
104 }
105 }
106
107 ~CanvasRenderingContext2DAutoRestoreSkCanvas()
108 {
109 SkCanvas* c = m_context->drawingCanvas();
110 if (c)
111 c->restoreToCount(m_saveCount);
112 m_context->validateStateStack();
113 }
114 private:
115 RawPtrWillBeMember<CanvasRenderingContext2D> m_context;
116 int m_saveCount;
117 };
118
119 CanvasRenderingContext2D::CanvasRenderingContext2D(HTMLCanvasElement* canvas, co nst CanvasContextCreationAttributes& attrs, Document& document)
120 : CanvasRenderingContext(canvas)
121 , m_clipAntialiasing(NotAntiAliased)
122 , m_hasAlpha(attrs.alpha())
123 , m_contextLostMode(NotLostContext)
124 , m_contextRestorable(true)
125 , m_tryRestoreContextAttemptCount(0)
126 , m_dispatchContextLostEventTimer(this, &CanvasRenderingContext2D::dispatchC ontextLostEvent)
127 , m_dispatchContextRestoredEventTimer(this, &CanvasRenderingContext2D::dispa tchContextRestoredEvent)
128 , m_tryRestoreContextEventTimer(this, &CanvasRenderingContext2D::tryRestoreC ontextEvent)
129 , m_pruneLocalFontCacheScheduled(false)
130 { 38 {
131 if (document.settings() && document.settings()->antialiasedClips2dCanvasEnab led())
132 m_clipAntialiasing = AntiAliased;
133 m_stateStack.append(CanvasRenderingContext2DState::create());
134 setShouldAntialias(true);
135 #if ENABLE(OILPAN)
136 ThreadState::current()->registerPreFinalizer(this);
137 #endif
138 } 39 }
139 40
140 void CanvasRenderingContext2D::unwindStateStack() 41 CanvasRenderingContext2DState& BaseRenderingContext2D::modifiableState()
141 {
142 if (size_t stackSize = m_stateStack.size()) {
143 if (SkCanvas* skCanvas = canvas()->existingDrawingCanvas()) {
144 while (--stackSize)
145 skCanvas->restore();
146 }
147 }
148 }
149
150 CanvasRenderingContext2D::~CanvasRenderingContext2D()
151 {
152 if (m_pruneLocalFontCacheScheduled) {
153 Platform::current()->currentThread()->removeTaskObserver(this);
154 }
155 #if !ENABLE(OILPAN)
156 dispose();
157 #endif
158 }
159
160 void CanvasRenderingContext2D::dispose()
161 {
162 clearFilterReferences();
163 }
164
165 void CanvasRenderingContext2D::validateStateStack()
166 {
167 #if ENABLE(ASSERT)
168 SkCanvas* skCanvas = canvas()->existingDrawingCanvas();
169 if (skCanvas && m_contextLostMode == NotLostContext) {
170 ASSERT(static_cast<size_t>(skCanvas->getSaveCount()) == m_stateStack.siz e());
171 }
172 #endif
173 }
174
175 CanvasRenderingContext2DState& CanvasRenderingContext2D::modifiableState()
176 { 42 {
177 realizeSaves(); 43 realizeSaves();
178 return *m_stateStack.last(); 44 return *m_stateStack.last();
179 } 45 }
180 46
181 bool CanvasRenderingContext2D::isAccelerated() const 47 void BaseRenderingContext2D::realizeSaves()
182 {
183 if (!canvas()->hasImageBuffer())
184 return false;
185 return canvas()->buffer()->isAccelerated();
186 }
187
188 void CanvasRenderingContext2D::stop()
189 {
190 if (!isContextLost()) {
191 // Never attempt to restore the context because the page is being torn d own.
192 loseContext(SyntheticLostContext);
193 }
194 }
195
196 bool CanvasRenderingContext2D::isContextLost() const
197 {
198 return m_contextLostMode != NotLostContext;
199 }
200
201 void CanvasRenderingContext2D::loseContext(LostContextMode lostMode)
202 {
203 if (m_contextLostMode != NotLostContext)
204 return;
205 m_contextLostMode = lostMode;
206 if (m_contextLostMode == SyntheticLostContext) {
207 canvas()->discardImageBuffer();
208 }
209 m_dispatchContextLostEventTimer.startOneShot(0, BLINK_FROM_HERE);
210 }
211
212 void CanvasRenderingContext2D::didSetSurfaceSize()
213 {
214 if (!m_contextRestorable)
215 return;
216 // This code path is for restoring from an eviction
217 // Restoring from surface failure is handled internally
218 ASSERT(m_contextLostMode != NotLostContext && !canvas()->hasImageBuffer());
219
220 if (canvas()->buffer()) {
221 if (contextLostRestoredEventsEnabled()) {
222 m_dispatchContextRestoredEventTimer.startOneShot(0, BLINK_FROM_HERE) ;
223 } else {
224 // legacy synchronous context restoration.
225 reset();
226 m_contextLostMode = NotLostContext;
227 }
228 }
229 }
230
231 DEFINE_TRACE(CanvasRenderingContext2D)
232 {
233 visitor->trace(m_stateStack);
234 visitor->trace(m_hitRegionManager);
235 CanvasRenderingContext::trace(visitor);
236 }
237
238 void CanvasRenderingContext2D::dispatchContextLostEvent(Timer<CanvasRenderingCon text2D>*)
239 {
240 if (contextLostRestoredEventsEnabled()) {
241 RefPtrWillBeRawPtr<Event> event = Event::createCancelable(EventTypeNames ::contextlost);
242 canvas()->dispatchEvent(event);
243 if (event->defaultPrevented()) {
244 m_contextRestorable = false;
245 }
246 }
247
248 // If RealLostContext, it means the context was not lost due to surface fail ure
249 // but rather due to a an eviction, which means image buffer exists.
250 if (m_contextRestorable && m_contextLostMode == RealLostContext) {
251 m_tryRestoreContextAttemptCount = 0;
252 m_tryRestoreContextEventTimer.startRepeating(TryRestoreContextInterval, BLINK_FROM_HERE);
253 }
254 }
255
256 void CanvasRenderingContext2D::tryRestoreContextEvent(Timer<CanvasRenderingConte xt2D>* timer)
257 {
258 if (m_contextLostMode == NotLostContext) {
259 // Canvas was already restored (possibly thanks to a resize), so stop tr ying.
260 m_tryRestoreContextEventTimer.stop();
261 return;
262 }
263
264 ASSERT(m_contextLostMode == RealLostContext);
265 if (canvas()->hasImageBuffer() && canvas()->buffer()->restoreSurface()) {
266 m_tryRestoreContextEventTimer.stop();
267 dispatchContextRestoredEvent(nullptr);
268 }
269
270 if (++m_tryRestoreContextAttemptCount > MaxTryRestoreContextAttempts) {
271 // final attempt: allocate a brand new image buffer instead of restoring
272 canvas()->discardImageBuffer();
273 m_tryRestoreContextEventTimer.stop();
274 if (canvas()->buffer())
275 dispatchContextRestoredEvent(nullptr);
276 }
277 }
278
279 void CanvasRenderingContext2D::dispatchContextRestoredEvent(Timer<CanvasRenderin gContext2D>*)
280 {
281 if (m_contextLostMode == NotLostContext)
282 return;
283 reset();
284 m_contextLostMode = NotLostContext;
285 if (contextLostRestoredEventsEnabled()) {
286 RefPtrWillBeRawPtr<Event> event(Event::create(EventTypeNames::contextres tored));
287 canvas()->dispatchEvent(event);
288 }
289 }
290
291 void CanvasRenderingContext2D::reset()
292 {
293 validateStateStack();
294 unwindStateStack();
295 m_stateStack.resize(1);
296 m_stateStack.first() = CanvasRenderingContext2DState::create();
297 m_path.clear();
298 SkCanvas* c = canvas()->existingDrawingCanvas();
299 if (c) {
300 c->resetMatrix();
301 c->clipRect(SkRect::MakeWH(canvas()->width(), canvas()->height()), SkReg ion::kReplace_Op);
302 }
303 validateStateStack();
304 }
305
306 void CanvasRenderingContext2D::restoreCanvasMatrixClipStack(SkCanvas* c) const
307 {
308 if (!c)
309 return;
310 WillBeHeapVector<OwnPtrWillBeMember<CanvasRenderingContext2DState>>::const_i terator currState;
311 ASSERT(m_stateStack.begin() < m_stateStack.end());
312 for (currState = m_stateStack.begin(); currState < m_stateStack.end(); currS tate++) {
313 c->setMatrix(SkMatrix::I());
314 currState->get()->playbackClips(c);
315 c->setMatrix(affineTransformToSkMatrix(currState->get()->transform()));
316 c->save();
317 }
318 c->restore();
319 }
320
321 void CanvasRenderingContext2D::realizeSaves()
322 { 48 {
323 validateStateStack(); 49 validateStateStack();
324 if (state().hasUnrealizedSaves()) { 50 if (state().hasUnrealizedSaves()) {
325 ASSERT(m_stateStack.size() >= 1); 51 ASSERT(m_stateStack.size() >= 1);
326 // Reduce the current state's unrealized count by one now, 52 // Reduce the current state's unrealized count by one now,
327 // to reflect the fact we are saving one state. 53 // to reflect the fact we are saving one state.
328 m_stateStack.last()->restore(); 54 m_stateStack.last()->restore();
329 m_stateStack.append(CanvasRenderingContext2DState::create(state(), Canva sRenderingContext2DState::DontCopyClipList)); 55 m_stateStack.append(CanvasRenderingContext2DState::create(state(), Canva sRenderingContext2DState::DontCopyClipList));
330 // Set the new state's unrealized count to 0, because it has no outstand ing saves. 56 // Set the new state's unrealized count to 0, because it has no outstand ing saves.
331 // We need to do this explicitly because the copy constructor and operat or= used 57 // We need to do this explicitly because the copy constructor and operat or= used
332 // by the Vector operations copy the unrealized count from the previous state (in 58 // by the Vector operations copy the unrealized count from the previous state (in
333 // turn necessary to support correct resizing and unwinding of the stack ). 59 // turn necessary to support correct resizing and unwinding of the stack ).
334 m_stateStack.last()->resetUnrealizedSaveCount(); 60 m_stateStack.last()->resetUnrealizedSaveCount();
335 SkCanvas* canvas = drawingCanvas(); 61 SkCanvas* canvas = drawingCanvas();
336 if (canvas) 62 if (canvas)
337 canvas->save(); 63 canvas->save();
338 validateStateStack(); 64 validateStateStack();
339 } 65 }
340 } 66 }
341 67
342 void CanvasRenderingContext2D::save() 68 void BaseRenderingContext2D::save()
343 { 69 {
344 m_stateStack.last()->save(); 70 m_stateStack.last()->save();
345 } 71 }
346 72
347 void CanvasRenderingContext2D::restore() 73 void BaseRenderingContext2D::restore()
348 { 74 {
349 validateStateStack(); 75 validateStateStack();
350 if (state().hasUnrealizedSaves()) { 76 if (state().hasUnrealizedSaves()) {
351 // We never realized the save, so just record that it was unnecessary. 77 // We never realized the save, so just record that it was unnecessary.
352 m_stateStack.last()->restore(); 78 m_stateStack.last()->restore();
353 return; 79 return;
354 } 80 }
355 ASSERT(m_stateStack.size() >= 1); 81 ASSERT(m_stateStack.size() >= 1);
356 if (m_stateStack.size() <= 1) 82 if (m_stateStack.size() <= 1)
357 return; 83 return;
(...skipping 14 matching lines...) Expand all
372 returnValue.setCanvasGradient(gradient); 98 returnValue.setCanvasGradient(gradient);
373 return; 99 return;
374 } 100 }
375 if (CanvasPattern* pattern = style->canvasPattern()) { 101 if (CanvasPattern* pattern = style->canvasPattern()) {
376 returnValue.setCanvasPattern(pattern); 102 returnValue.setCanvasPattern(pattern);
377 return; 103 return;
378 } 104 }
379 returnValue.setString(style->color()); 105 returnValue.setString(style->color());
380 } 106 }
381 107
382 void CanvasRenderingContext2D::strokeStyle(StringOrCanvasGradientOrCanvasPattern & returnValue) const 108 void BaseRenderingContext2D::strokeStyle(StringOrCanvasGradientOrCanvasPattern& returnValue) const
383 { 109 {
384 convertCanvasStyleToUnionType(state().strokeStyle(), returnValue); 110 convertCanvasStyleToUnionType(state().strokeStyle(), returnValue);
385 } 111 }
386 112
387 void CanvasRenderingContext2D::setStrokeStyle(const StringOrCanvasGradientOrCanv asPattern& style) 113 void BaseRenderingContext2D::setStrokeStyle(const StringOrCanvasGradientOrCanvas Pattern& style)
388 { 114 {
389 ASSERT(!style.isNull()); 115 ASSERT(!style.isNull());
390 116
391 String colorString; 117 String colorString;
392 CanvasStyle* canvasStyle = nullptr; 118 CanvasStyle* canvasStyle = nullptr;
393 if (style.isString()) { 119 if (style.isString()) {
394 colorString = style.getAsString(); 120 colorString = style.getAsString();
395 if (colorString == state().unparsedStrokeColor()) 121 if (colorString == state().unparsedStrokeColor())
396 return; 122 return;
397 Color parsedColor = 0; 123 Color parsedColor = 0;
398 if (!parseColorOrCurrentColor(parsedColor, colorString, canvas())) 124 if (!parseColorOrCurrentColor(parsedColor, colorString))
399 return; 125 return;
400 if (state().strokeStyle()->isEquivalentRGBA(parsedColor.rgb())) { 126 if (state().strokeStyle()->isEquivalentRGBA(parsedColor.rgb())) {
401 modifiableState().setUnparsedStrokeColor(colorString); 127 modifiableState().setUnparsedStrokeColor(colorString);
402 return; 128 return;
403 } 129 }
404 canvasStyle = CanvasStyle::createFromRGBA(parsedColor.rgb()); 130 canvasStyle = CanvasStyle::createFromRGBA(parsedColor.rgb());
405 } else if (style.isCanvasGradient()) { 131 } else if (style.isCanvasGradient()) {
406 canvasStyle = CanvasStyle::createFromGradient(style.getAsCanvasGradient( )); 132 canvasStyle = CanvasStyle::createFromGradient(style.getAsCanvasGradient( ));
407 } else if (style.isCanvasPattern()) { 133 } else if (style.isCanvasPattern()) {
408 CanvasPattern* canvasPattern = style.getAsCanvasPattern(); 134 CanvasPattern* canvasPattern = style.getAsCanvasPattern();
409 135
410 if (canvas()->originClean() && !canvasPattern->originClean()) 136 if (originClean() && !canvasPattern->originClean())
411 canvas()->setOriginTainted(); 137 setOriginTainted();
412 138
413 canvasStyle = CanvasStyle::createFromPattern(canvasPattern); 139 canvasStyle = CanvasStyle::createFromPattern(canvasPattern);
414 } 140 }
415 141
416 ASSERT(canvasStyle); 142 ASSERT(canvasStyle);
417 143
418 modifiableState().setStrokeStyle(canvasStyle); 144 modifiableState().setStrokeStyle(canvasStyle);
419 modifiableState().setUnparsedStrokeColor(colorString); 145 modifiableState().setUnparsedStrokeColor(colorString);
420 modifiableState().clearResolvedFilter(); 146 modifiableState().clearResolvedFilter();
421 } 147 }
422 148
423 void CanvasRenderingContext2D::fillStyle(StringOrCanvasGradientOrCanvasPattern& returnValue) const 149 void BaseRenderingContext2D::fillStyle(StringOrCanvasGradientOrCanvasPattern& re turnValue) const
424 { 150 {
425 convertCanvasStyleToUnionType(state().fillStyle(), returnValue); 151 convertCanvasStyleToUnionType(state().fillStyle(), returnValue);
426 } 152 }
427 153
428 void CanvasRenderingContext2D::setFillStyle(const StringOrCanvasGradientOrCanvas Pattern& style) 154 void BaseRenderingContext2D::setFillStyle(const StringOrCanvasGradientOrCanvasPa ttern& style)
429 { 155 {
430 ASSERT(!style.isNull()); 156 ASSERT(!style.isNull());
431 validateStateStack(); 157 validateStateStack();
432 String colorString; 158 String colorString;
433 CanvasStyle* canvasStyle = nullptr; 159 CanvasStyle* canvasStyle = nullptr;
434 if (style.isString()) { 160 if (style.isString()) {
435 colorString = style.getAsString(); 161 colorString = style.getAsString();
436 if (colorString == state().unparsedFillColor()) 162 if (colorString == state().unparsedFillColor())
437 return; 163 return;
438 Color parsedColor = 0; 164 Color parsedColor = 0;
439 if (!parseColorOrCurrentColor(parsedColor, colorString, canvas())) 165 if (!parseColorOrCurrentColor(parsedColor, colorString))
440 return; 166 return;
441 if (state().fillStyle()->isEquivalentRGBA(parsedColor.rgb())) { 167 if (state().fillStyle()->isEquivalentRGBA(parsedColor.rgb())) {
442 modifiableState().setUnparsedFillColor(colorString); 168 modifiableState().setUnparsedFillColor(colorString);
443 return; 169 return;
444 } 170 }
445 canvasStyle = CanvasStyle::createFromRGBA(parsedColor.rgb()); 171 canvasStyle = CanvasStyle::createFromRGBA(parsedColor.rgb());
446 } else if (style.isCanvasGradient()) { 172 } else if (style.isCanvasGradient()) {
447 canvasStyle = CanvasStyle::createFromGradient(style.getAsCanvasGradient( )); 173 canvasStyle = CanvasStyle::createFromGradient(style.getAsCanvasGradient( ));
448 } else if (style.isCanvasPattern()) { 174 } else if (style.isCanvasPattern()) {
449 CanvasPattern* canvasPattern = style.getAsCanvasPattern(); 175 CanvasPattern* canvasPattern = style.getAsCanvasPattern();
450 176
451 if (canvas()->originClean() && !canvasPattern->originClean()) 177 if (originClean() && !canvasPattern->originClean())
452 canvas()->setOriginTainted(); 178 setOriginTainted();
453 if (canvasPattern->pattern()->isTextureBacked()) 179 if (canvasPattern->pattern()->isTextureBacked())
454 canvas()->disableDeferral(DisableDeferralReasonUsingTextureBackedPat tern); 180 disableDeferral(DisableDeferralReasonUsingTextureBackedPattern);
455 canvasStyle = CanvasStyle::createFromPattern(canvasPattern); 181 canvasStyle = CanvasStyle::createFromPattern(canvasPattern);
456 } 182 }
457 183
458 ASSERT(canvasStyle); 184 ASSERT(canvasStyle);
459 modifiableState().setFillStyle(canvasStyle); 185 modifiableState().setFillStyle(canvasStyle);
460 modifiableState().setUnparsedFillColor(colorString); 186 modifiableState().setUnparsedFillColor(colorString);
461 modifiableState().clearResolvedFilter(); 187 modifiableState().clearResolvedFilter();
462 } 188 }
463 189
464 double CanvasRenderingContext2D::lineWidth() const 190 double BaseRenderingContext2D::lineWidth() const
465 { 191 {
466 return state().lineWidth(); 192 return state().lineWidth();
467 } 193 }
468 194
469 void CanvasRenderingContext2D::setLineWidth(double width) 195 void BaseRenderingContext2D::setLineWidth(double width)
470 { 196 {
471 if (!std::isfinite(width) || width <= 0) 197 if (!std::isfinite(width) || width <= 0)
472 return; 198 return;
473 if (state().lineWidth() == width) 199 if (state().lineWidth() == width)
474 return; 200 return;
475 modifiableState().setLineWidth(width); 201 modifiableState().setLineWidth(width);
476 } 202 }
477 203
478 String CanvasRenderingContext2D::lineCap() const 204 String BaseRenderingContext2D::lineCap() const
479 { 205 {
480 return lineCapName(state().lineCap()); 206 return lineCapName(state().lineCap());
481 } 207 }
482 208
483 void CanvasRenderingContext2D::setLineCap(const String& s) 209 void BaseRenderingContext2D::setLineCap(const String& s)
484 { 210 {
485 LineCap cap; 211 LineCap cap;
486 if (!parseLineCap(s, cap)) 212 if (!parseLineCap(s, cap))
487 return; 213 return;
488 if (state().lineCap() == cap) 214 if (state().lineCap() == cap)
489 return; 215 return;
490 modifiableState().setLineCap(cap); 216 modifiableState().setLineCap(cap);
491 } 217 }
492 218
493 String CanvasRenderingContext2D::lineJoin() const 219 String BaseRenderingContext2D::lineJoin() const
494 { 220 {
495 return lineJoinName(state().lineJoin()); 221 return lineJoinName(state().lineJoin());
496 } 222 }
497 223
498 void CanvasRenderingContext2D::setLineJoin(const String& s) 224 void BaseRenderingContext2D::setLineJoin(const String& s)
499 { 225 {
500 LineJoin join; 226 LineJoin join;
501 if (!parseLineJoin(s, join)) 227 if (!parseLineJoin(s, join))
502 return; 228 return;
503 if (state().lineJoin() == join) 229 if (state().lineJoin() == join)
504 return; 230 return;
505 modifiableState().setLineJoin(join); 231 modifiableState().setLineJoin(join);
506 } 232 }
507 233
508 double CanvasRenderingContext2D::miterLimit() const 234 double BaseRenderingContext2D::miterLimit() const
509 { 235 {
510 return state().miterLimit(); 236 return state().miterLimit();
511 } 237 }
512 238
513 void CanvasRenderingContext2D::setMiterLimit(double limit) 239 void BaseRenderingContext2D::setMiterLimit(double limit)
514 { 240 {
515 if (!std::isfinite(limit) || limit <= 0) 241 if (!std::isfinite(limit) || limit <= 0)
516 return; 242 return;
517 if (state().miterLimit() == limit) 243 if (state().miterLimit() == limit)
518 return; 244 return;
519 modifiableState().setMiterLimit(limit); 245 modifiableState().setMiterLimit(limit);
520 } 246 }
521 247
522 double CanvasRenderingContext2D::shadowOffsetX() const 248 double BaseRenderingContext2D::shadowOffsetX() const
523 { 249 {
524 return state().shadowOffset().width(); 250 return state().shadowOffset().width();
525 } 251 }
526 252
527 void CanvasRenderingContext2D::setShadowOffsetX(double x) 253 void BaseRenderingContext2D::setShadowOffsetX(double x)
528 { 254 {
529 if (!std::isfinite(x)) 255 if (!std::isfinite(x))
530 return; 256 return;
531 if (state().shadowOffset().width() == x) 257 if (state().shadowOffset().width() == x)
532 return; 258 return;
533 modifiableState().setShadowOffsetX(x); 259 modifiableState().setShadowOffsetX(x);
534 } 260 }
535 261
536 double CanvasRenderingContext2D::shadowOffsetY() const 262 double BaseRenderingContext2D::shadowOffsetY() const
537 { 263 {
538 return state().shadowOffset().height(); 264 return state().shadowOffset().height();
539 } 265 }
540 266
541 void CanvasRenderingContext2D::setShadowOffsetY(double y) 267 void BaseRenderingContext2D::setShadowOffsetY(double y)
542 { 268 {
543 if (!std::isfinite(y)) 269 if (!std::isfinite(y))
544 return; 270 return;
545 if (state().shadowOffset().height() == y) 271 if (state().shadowOffset().height() == y)
546 return; 272 return;
547 modifiableState().setShadowOffsetY(y); 273 modifiableState().setShadowOffsetY(y);
548 } 274 }
549 275
550 double CanvasRenderingContext2D::shadowBlur() const 276 double BaseRenderingContext2D::shadowBlur() const
551 { 277 {
552 return state().shadowBlur(); 278 return state().shadowBlur();
553 } 279 }
554 280
555 void CanvasRenderingContext2D::setShadowBlur(double blur) 281 void BaseRenderingContext2D::setShadowBlur(double blur)
556 { 282 {
557 if (!std::isfinite(blur) || blur < 0) 283 if (!std::isfinite(blur) || blur < 0)
558 return; 284 return;
559 if (state().shadowBlur() == blur) 285 if (state().shadowBlur() == blur)
560 return; 286 return;
561 modifiableState().setShadowBlur(blur); 287 modifiableState().setShadowBlur(blur);
562 } 288 }
563 289
564 String CanvasRenderingContext2D::shadowColor() const 290 String BaseRenderingContext2D::shadowColor() const
565 { 291 {
566 return Color(state().shadowColor()).serialized(); 292 return Color(state().shadowColor()).serialized();
567 } 293 }
568 294
569 void CanvasRenderingContext2D::setShadowColor(const String& colorString) 295 void BaseRenderingContext2D::setShadowColor(const String& colorString)
570 { 296 {
571 Color color; 297 Color color;
572 if (!parseColorOrCurrentColor(color, colorString, canvas())) 298 if (!parseColorOrCurrentColor(color, colorString))
573 return; 299 return;
574 if (state().shadowColor() == color) 300 if (state().shadowColor() == color)
575 return; 301 return;
576 modifiableState().setShadowColor(color.rgb()); 302 modifiableState().setShadowColor(color.rgb());
577 } 303 }
578 304
579 const Vector<double>& CanvasRenderingContext2D::getLineDash() const 305 const Vector<double>& BaseRenderingContext2D::getLineDash() const
580 { 306 {
581 return state().lineDash(); 307 return state().lineDash();
582 } 308 }
583 309
584 static bool lineDashSequenceIsValid(const Vector<double>& dash) 310 static bool lineDashSequenceIsValid(const Vector<double>& dash)
585 { 311 {
586 for (size_t i = 0; i < dash.size(); i++) { 312 for (size_t i = 0; i < dash.size(); i++) {
587 if (!std::isfinite(dash[i]) || dash[i] < 0) 313 if (!std::isfinite(dash[i]) || dash[i] < 0)
588 return false; 314 return false;
589 } 315 }
590 return true; 316 return true;
591 } 317 }
592 318
593 void CanvasRenderingContext2D::setLineDash(const Vector<double>& dash) 319 void BaseRenderingContext2D::setLineDash(const Vector<double>& dash)
594 { 320 {
595 if (!lineDashSequenceIsValid(dash)) 321 if (!lineDashSequenceIsValid(dash))
596 return; 322 return;
597 modifiableState().setLineDash(dash); 323 modifiableState().setLineDash(dash);
598 } 324 }
599 325
600 double CanvasRenderingContext2D::lineDashOffset() const 326 double BaseRenderingContext2D::lineDashOffset() const
601 { 327 {
602 return state().lineDashOffset(); 328 return state().lineDashOffset();
603 } 329 }
604 330
605 void CanvasRenderingContext2D::setLineDashOffset(double offset) 331 void BaseRenderingContext2D::setLineDashOffset(double offset)
606 { 332 {
607 if (!std::isfinite(offset) || state().lineDashOffset() == offset) 333 if (!std::isfinite(offset) || state().lineDashOffset() == offset)
608 return; 334 return;
609 modifiableState().setLineDashOffset(offset); 335 modifiableState().setLineDashOffset(offset);
610 } 336 }
611 337
612 double CanvasRenderingContext2D::globalAlpha() const 338 double BaseRenderingContext2D::globalAlpha() const
613 { 339 {
614 return state().globalAlpha(); 340 return state().globalAlpha();
615 } 341 }
616 342
617 void CanvasRenderingContext2D::setGlobalAlpha(double alpha) 343 void BaseRenderingContext2D::setGlobalAlpha(double alpha)
618 { 344 {
619 if (!(alpha >= 0 && alpha <= 1)) 345 if (!(alpha >= 0 && alpha <= 1))
620 return; 346 return;
621 if (state().globalAlpha() == alpha) 347 if (state().globalAlpha() == alpha)
622 return; 348 return;
623 modifiableState().setGlobalAlpha(alpha); 349 modifiableState().setGlobalAlpha(alpha);
624 } 350 }
625 351
626 bool CanvasRenderingContext2D::shouldAntialias() const 352 String BaseRenderingContext2D::globalCompositeOperation() const
627 {
628 return state().shouldAntialias();
629 }
630
631 void CanvasRenderingContext2D::setShouldAntialias(bool doAA)
632 {
633 modifiableState().setShouldAntialias(doAA);
634 }
635
636 String CanvasRenderingContext2D::globalCompositeOperation() const
637 { 353 {
638 return compositeOperatorName(compositeOperatorFromSkia(state().globalComposi te()), blendModeFromSkia(state().globalComposite())); 354 return compositeOperatorName(compositeOperatorFromSkia(state().globalComposi te()), blendModeFromSkia(state().globalComposite()));
639 } 355 }
640 356
641 void CanvasRenderingContext2D::setGlobalCompositeOperation(const String& operati on) 357 void BaseRenderingContext2D::setGlobalCompositeOperation(const String& operation )
642 { 358 {
643 CompositeOperator op = CompositeSourceOver; 359 CompositeOperator op = CompositeSourceOver;
644 WebBlendMode blendMode = WebBlendModeNormal; 360 WebBlendMode blendMode = WebBlendModeNormal;
645 if (!parseCompositeAndBlendOperator(operation, op, blendMode)) 361 if (!parseCompositeAndBlendOperator(operation, op, blendMode))
646 return; 362 return;
647 SkXfermode::Mode xfermode = WebCoreCompositeToSkiaComposite(op, blendMode); 363 SkXfermode::Mode xfermode = WebCoreCompositeToSkiaComposite(op, blendMode);
648 if (state().globalComposite() == xfermode) 364 if (state().globalComposite() == xfermode)
649 return; 365 return;
650 modifiableState().setGlobalComposite(xfermode); 366 modifiableState().setGlobalComposite(xfermode);
651 } 367 }
652 368
653 String CanvasRenderingContext2D::filter() const 369 String BaseRenderingContext2D::filter() const
654 { 370 {
655 return state().unparsedFilter(); 371 return state().unparsedFilter();
656 } 372 }
657 373
658 void CanvasRenderingContext2D::setFilter(const String& filterString) 374 void BaseRenderingContext2D::setFilter(const String& filterString)
659 { 375 {
660 if (filterString == state().unparsedFilter()) 376 if (filterString == state().unparsedFilter())
661 return; 377 return;
662 378
663 RefPtrWillBeRawPtr<CSSValue> filterValue = CSSParser::parseSingleValue(CSSPr opertyWebkitFilter, filterString, CSSParserContext(HTMLStandardMode, 0)); 379 RefPtrWillBeRawPtr<CSSValue> filterValue = CSSParser::parseSingleValue(CSSPr opertyWebkitFilter, filterString, CSSParserContext(HTMLStandardMode, 0));
664 380
665 if (!filterValue || filterValue->isInitialValue() || filterValue->isInherite dValue()) 381 if (!filterValue || filterValue->isInitialValue() || filterValue->isInherite dValue())
666 return; 382 return;
667 383
668 modifiableState().setUnparsedFilter(filterString); 384 modifiableState().setUnparsedFilter(filterString);
669 modifiableState().setFilter(filterValue.release()); 385 modifiableState().setFilter(filterValue.release());
670 } 386 }
671 387
672 PassRefPtrWillBeRawPtr<SVGMatrixTearOff> CanvasRenderingContext2D::currentTransf orm() const 388 PassRefPtrWillBeRawPtr<SVGMatrixTearOff> BaseRenderingContext2D::currentTransfor m() const
673 { 389 {
674 return SVGMatrixTearOff::create(state().transform()); 390 return SVGMatrixTearOff::create(state().transform());
675 } 391 }
676 392
677 void CanvasRenderingContext2D::setCurrentTransform(PassRefPtrWillBeRawPtr<SVGMat rixTearOff> passMatrixTearOff) 393 void BaseRenderingContext2D::setCurrentTransform(PassRefPtrWillBeRawPtr<SVGMatri xTearOff> passMatrixTearOff)
678 { 394 {
679 RefPtrWillBeRawPtr<SVGMatrixTearOff> matrixTearOff = passMatrixTearOff; 395 RefPtrWillBeRawPtr<SVGMatrixTearOff> matrixTearOff = passMatrixTearOff;
680 const AffineTransform& transform = matrixTearOff->value(); 396 const AffineTransform& transform = matrixTearOff->value();
681 setTransform(transform.a(), transform.b(), transform.c(), transform.d(), tra nsform.e(), transform.f()); 397 setTransform(transform.a(), transform.b(), transform.c(), transform.d(), tra nsform.e(), transform.f());
682 } 398 }
683 399
684 void CanvasRenderingContext2D::scale(double sx, double sy) 400 void BaseRenderingContext2D::scale(double sx, double sy)
685 { 401 {
686 SkCanvas* c = drawingCanvas(); 402 SkCanvas* c = drawingCanvas();
687 if (!c) 403 if (!c)
688 return; 404 return;
689 405
690 if (!std::isfinite(sx) || !std::isfinite(sy)) 406 if (!std::isfinite(sx) || !std::isfinite(sy))
691 return; 407 return;
692 408
693 AffineTransform newTransform = state().transform(); 409 AffineTransform newTransform = state().transform();
694 newTransform.scaleNonUniform(sx, sy); 410 newTransform.scaleNonUniform(sx, sy);
695 if (state().transform() == newTransform) 411 if (state().transform() == newTransform)
696 return; 412 return;
697 413
698 modifiableState().setTransform(newTransform); 414 modifiableState().setTransform(newTransform);
699 if (!state().isTransformInvertible()) 415 if (!state().isTransformInvertible())
700 return; 416 return;
701 417
702 c->scale(sx, sy); 418 c->scale(sx, sy);
703 m_path.transform(AffineTransform().scaleNonUniform(1.0 / sx, 1.0 / sy)); 419 m_path.transform(AffineTransform().scaleNonUniform(1.0 / sx, 1.0 / sy));
704 } 420 }
705 421
706 void CanvasRenderingContext2D::rotate(double angleInRadians) 422 void BaseRenderingContext2D::rotate(double angleInRadians)
707 { 423 {
708 SkCanvas* c = drawingCanvas(); 424 SkCanvas* c = drawingCanvas();
709 if (!c) 425 if (!c)
710 return; 426 return;
711 427
712 if (!std::isfinite(angleInRadians)) 428 if (!std::isfinite(angleInRadians))
713 return; 429 return;
714 430
715 AffineTransform newTransform = state().transform(); 431 AffineTransform newTransform = state().transform();
716 newTransform.rotateRadians(angleInRadians); 432 newTransform.rotateRadians(angleInRadians);
717 if (state().transform() == newTransform) 433 if (state().transform() == newTransform)
718 return; 434 return;
719 435
720 modifiableState().setTransform(newTransform); 436 modifiableState().setTransform(newTransform);
721 if (!state().isTransformInvertible()) 437 if (!state().isTransformInvertible())
722 return; 438 return;
723 c->rotate(angleInRadians * (180.0 / piFloat)); 439 c->rotate(angleInRadians * (180.0 / piFloat));
724 m_path.transform(AffineTransform().rotateRadians(-angleInRadians)); 440 m_path.transform(AffineTransform().rotateRadians(-angleInRadians));
725 } 441 }
726 442
727 void CanvasRenderingContext2D::translate(double tx, double ty) 443 void BaseRenderingContext2D::translate(double tx, double ty)
728 { 444 {
729 SkCanvas* c = drawingCanvas(); 445 SkCanvas* c = drawingCanvas();
730 if (!c) 446 if (!c)
731 return; 447 return;
732 if (!state().isTransformInvertible()) 448 if (!state().isTransformInvertible())
733 return; 449 return;
734 450
735 if (!std::isfinite(tx) || !std::isfinite(ty)) 451 if (!std::isfinite(tx) || !std::isfinite(ty))
736 return; 452 return;
737 453
738 AffineTransform newTransform = state().transform(); 454 AffineTransform newTransform = state().transform();
739 newTransform.translate(tx, ty); 455 newTransform.translate(tx, ty);
740 if (state().transform() == newTransform) 456 if (state().transform() == newTransform)
741 return; 457 return;
742 458
743 modifiableState().setTransform(newTransform); 459 modifiableState().setTransform(newTransform);
744 if (!state().isTransformInvertible()) 460 if (!state().isTransformInvertible())
745 return; 461 return;
746 c->translate(tx, ty); 462 c->translate(tx, ty);
747 m_path.transform(AffineTransform().translate(-tx, -ty)); 463 m_path.transform(AffineTransform().translate(-tx, -ty));
748 } 464 }
749 465
750 void CanvasRenderingContext2D::transform(double m11, double m12, double m21, dou ble m22, double dx, double dy) 466 void BaseRenderingContext2D::transform(double m11, double m12, double m21, doubl e m22, double dx, double dy)
751 { 467 {
752 SkCanvas* c = drawingCanvas(); 468 SkCanvas* c = drawingCanvas();
753 if (!c) 469 if (!c)
754 return; 470 return;
755 471
756 if (!std::isfinite(m11) || !std::isfinite(m21) || !std::isfinite(dx) || !std ::isfinite(m12) || !std::isfinite(m22) || !std::isfinite(dy)) 472 if (!std::isfinite(m11) || !std::isfinite(m21) || !std::isfinite(dx) || !std ::isfinite(m12) || !std::isfinite(m22) || !std::isfinite(dy))
757 return; 473 return;
758 474
759 AffineTransform transform(m11, m12, m21, m22, dx, dy); 475 AffineTransform transform(m11, m12, m21, m22, dx, dy);
760 AffineTransform newTransform = state().transform() * transform; 476 AffineTransform newTransform = state().transform() * transform;
761 if (state().transform() == newTransform) 477 if (state().transform() == newTransform)
762 return; 478 return;
763 479
764 modifiableState().setTransform(newTransform); 480 modifiableState().setTransform(newTransform);
765 if (!state().isTransformInvertible()) 481 if (!state().isTransformInvertible())
766 return; 482 return;
767 483
768 c->concat(affineTransformToSkMatrix(transform)); 484 c->concat(affineTransformToSkMatrix(transform));
769 m_path.transform(transform.inverse()); 485 m_path.transform(transform.inverse());
770 } 486 }
771 487
772 void CanvasRenderingContext2D::resetTransform() 488 void BaseRenderingContext2D::resetTransform()
773 { 489 {
774 SkCanvas* c = drawingCanvas(); 490 SkCanvas* c = drawingCanvas();
775 if (!c) 491 if (!c)
776 return; 492 return;
777 493
778 AffineTransform ctm = state().transform(); 494 AffineTransform ctm = state().transform();
779 bool invertibleCTM = state().isTransformInvertible(); 495 bool invertibleCTM = state().isTransformInvertible();
780 // It is possible that CTM is identity while CTM is not invertible. 496 // It is possible that CTM is identity while CTM is not invertible.
781 // When CTM becomes non-invertible, realizeSaves() can make CTM identity. 497 // When CTM becomes non-invertible, realizeSaves() can make CTM identity.
782 if (ctm.isIdentity() && invertibleCTM) 498 if (ctm.isIdentity() && invertibleCTM)
783 return; 499 return;
784 500
785 // resetTransform() resolves the non-invertible CTM state. 501 // resetTransform() resolves the non-invertible CTM state.
786 modifiableState().resetTransform(); 502 modifiableState().resetTransform();
787 c->setMatrix(affineTransformToSkMatrix(canvas()->baseTransform())); 503 c->setMatrix(affineTransformToSkMatrix(baseTransform()));
788 504
789 if (invertibleCTM) 505 if (invertibleCTM)
790 m_path.transform(ctm); 506 m_path.transform(ctm);
791 // When else, do nothing because all transform methods didn't update m_path when CTM became non-invertible. 507 // When else, do nothing because all transform methods didn't update m_path when CTM became non-invertible.
792 // It means that resetTransform() restores m_path just before CTM became non -invertible. 508 // It means that resetTransform() restores m_path just before CTM became non -invertible.
793 } 509 }
794 510
795 void CanvasRenderingContext2D::setTransform(double m11, double m12, double m21, double m22, double dx, double dy) 511 void BaseRenderingContext2D::setTransform(double m11, double m12, double m21, do uble m22, double dx, double dy)
796 { 512 {
797 SkCanvas* c = drawingCanvas(); 513 SkCanvas* c = drawingCanvas();
798 if (!c) 514 if (!c)
799 return; 515 return;
800 516
801 if (!std::isfinite(m11) || !std::isfinite(m21) || !std::isfinite(dx) || !std ::isfinite(m12) || !std::isfinite(m22) || !std::isfinite(dy)) 517 if (!std::isfinite(m11) || !std::isfinite(m21) || !std::isfinite(dx) || !std ::isfinite(m12) || !std::isfinite(m22) || !std::isfinite(dy))
802 return; 518 return;
803 519
804 resetTransform(); 520 resetTransform();
805 transform(m11, m12, m21, m22, dx, dy); 521 transform(m11, m12, m21, m22, dx, dy);
806 } 522 }
807 523
808 void CanvasRenderingContext2D::beginPath() 524 void BaseRenderingContext2D::beginPath()
809 { 525 {
810 m_path.clear(); 526 m_path.clear();
811 } 527 }
812 528
813 static bool validateRectForCanvas(double& x, double& y, double& width, double& h eight) 529 static bool validateRectForCanvas(double& x, double& y, double& width, double& h eight)
814 { 530 {
815 if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(width) || !std: :isfinite(height)) 531 if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(width) || !std: :isfinite(height))
816 return false; 532 return false;
817 533
818 if (!width && !height) 534 if (!width && !height)
819 return false; 535 return false;
820 536
821 if (width < 0) { 537 if (width < 0) {
822 width = -width; 538 width = -width;
823 x -= width; 539 x -= width;
824 } 540 }
825 541
826 if (height < 0) { 542 if (height < 0) {
827 height = -height; 543 height = -height;
828 y -= height; 544 y -= height;
829 } 545 }
830 546
831 return true; 547 return true;
832 } 548 }
833 549
834 static bool isFullCanvasCompositeMode(SkXfermode::Mode op) 550 bool BaseRenderingContext2D::isFullCanvasCompositeMode(SkXfermode::Mode op)
835 { 551 {
836 // See 4.8.11.1.3 Compositing 552 // See 4.8.11.1.3 Compositing
837 // CompositeSourceAtop and CompositeDestinationOut are not listed here as th e platforms already 553 // CompositeSourceAtop and CompositeDestinationOut are not listed here as th e platforms already
838 // implement the specification's behavior. 554 // implement the specification's behavior.
839 return op == SkXfermode::kSrcIn_Mode || op == SkXfermode::kSrcOut_Mode || op == SkXfermode::kDstIn_Mode || op == SkXfermode::kDstATop_Mode; 555 return op == SkXfermode::kSrcIn_Mode || op == SkXfermode::kSrcOut_Mode || op == SkXfermode::kDstIn_Mode || op == SkXfermode::kDstATop_Mode;
840 } 556 }
841 557
842 template<typename DrawFunc>
843 void CanvasRenderingContext2D::compositedDraw(const DrawFunc& drawFunc, SkCanvas * c, CanvasRenderingContext2DState::PaintType paintType, CanvasRenderingContext2 DState::ImageType imageType)
844 {
845 SkImageFilter* filter = state().getFilter(canvas(), accessFont(), canvas()-> size(), this);
846 ASSERT(isFullCanvasCompositeMode(state().globalComposite()) || filter);
847 SkMatrix ctm = c->getTotalMatrix();
848 c->resetMatrix();
849 SkPaint compositePaint;
850 compositePaint.setXfermodeMode(state().globalComposite());
851 if (state().shouldDrawShadows()) {
852 // unroll into two independently composited passes if drawing shadows
853 SkPaint shadowPaint = *state().getPaint(paintType, DrawShadowOnly, image Type);
854 int saveCount = c->getSaveCount();
855 if (filter) {
856 SkPaint filterPaint;
857 filterPaint.setImageFilter(filter);
858 // TODO(junov): crbug.com/502921 We could use primitive bounds if we knew that the filter
859 // does not affect transparent black regions.
860 c->saveLayer(nullptr, &shadowPaint);
861 c->saveLayer(nullptr, &filterPaint);
862 SkPaint foregroundPaint = *state().getPaint(paintType, DrawForegroun dOnly, imageType);
863 c->setMatrix(ctm);
864 drawFunc(c, &foregroundPaint);
865 } else {
866 ASSERT(isFullCanvasCompositeMode(state().globalComposite()));
867 c->saveLayer(nullptr, &compositePaint);
868 shadowPaint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
869 c->setMatrix(ctm);
870 drawFunc(c, &shadowPaint);
871 }
872 c->restoreToCount(saveCount);
873 }
874
875 compositePaint.setImageFilter(filter);
876 // TODO(junov): crbug.com/502921 We could use primitive bounds if we knew th at the filter
877 // does not affect transparent black regions *and* !isFullCanvasCompositeMod e
878 c->saveLayer(nullptr, &compositePaint);
879 SkPaint foregroundPaint = *state().getPaint(paintType, DrawForegroundOnly, i mageType);
880 foregroundPaint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
881 c->setMatrix(ctm);
882 drawFunc(c, &foregroundPaint);
883 c->restore();
884 c->setMatrix(ctm);
885 }
886
887 template<typename DrawFunc, typename ContainsFunc>
888 bool CanvasRenderingContext2D::draw(const DrawFunc& drawFunc, const ContainsFunc & drawCoversClipBounds, const SkRect& bounds, CanvasRenderingContext2DState::Pai ntType paintType, CanvasRenderingContext2DState::ImageType imageType)
889 {
890 if (!state().isTransformInvertible())
891 return false;
892
893 SkIRect clipBounds;
894 if (!drawingCanvas() || !drawingCanvas()->getClipDeviceBounds(&clipBounds))
895 return false;
896
897 // If gradient size is zero, then paint nothing.
898 CanvasStyle* style = state().style(paintType);
899 if (style) {
900 CanvasGradient* gradient = style->canvasGradient();
901 if (gradient && gradient->gradient()->isZeroSize())
902 return false;
903 }
904
905 if (isFullCanvasCompositeMode(state().globalComposite()) || state().hasFilte r(canvas(), accessFont(), canvas()->size(), this)) {
906 compositedDraw(drawFunc, drawingCanvas(), paintType, imageType);
907 didDraw(clipBounds);
908 } else if (state().globalComposite() == SkXfermode::kSrc_Mode) {
909 clearCanvas(); // takes care of checkOverdraw()
910 const SkPaint* paint = state().getPaint(paintType, DrawForegroundOnly, i mageType);
911 drawFunc(drawingCanvas(), paint);
912 didDraw(clipBounds);
913 } else {
914 SkIRect dirtyRect;
915 if (computeDirtyRect(bounds, clipBounds, &dirtyRect)) {
916 const SkPaint* paint = state().getPaint(paintType, DrawShadowAndFore ground, imageType);
917 if (paintType != CanvasRenderingContext2DState::StrokePaintType && d rawCoversClipBounds(clipBounds))
918 checkOverdraw(bounds, paint, imageType, ClipFill);
919 drawFunc(drawingCanvas(), paint);
920 didDraw(dirtyRect);
921 }
922 }
923 return true;
924 }
925
926 static bool isPathExpensive(const Path& path) 558 static bool isPathExpensive(const Path& path)
927 { 559 {
928 const SkPath& skPath = path.skPath(); 560 const SkPath& skPath = path.skPath();
929 if (ExpensiveCanvasHeuristicParameters::ConcavePathsAreExpensive && !skPath. isConvex()) 561 if (ExpensiveCanvasHeuristicParameters::ConcavePathsAreExpensive && !skPath. isConvex())
930 return true; 562 return true;
931 563
932 if (skPath.countPoints() > ExpensiveCanvasHeuristicParameters::ExpensivePath PointCount) 564 if (skPath.countPoints() > ExpensiveCanvasHeuristicParameters::ExpensivePath PointCount)
933 return true; 565 return true;
934 566
935 return false; 567 return false;
936 } 568 }
937 569
938 void CanvasRenderingContext2D::drawPathInternal(const Path& path, CanvasRenderin gContext2DState::PaintType paintType, SkPath::FillType fillType) 570 void BaseRenderingContext2D::drawPathInternal(const Path& path, CanvasRenderingC ontext2DState::PaintType paintType, SkPath::FillType fillType)
939 { 571 {
940 if (path.isEmpty()) 572 if (path.isEmpty())
941 return; 573 return;
942 574
943 SkPath skPath = path.skPath(); 575 SkPath skPath = path.skPath();
944 FloatRect bounds = path.boundingRect(); 576 FloatRect bounds = path.boundingRect();
945 skPath.setFillType(fillType); 577 skPath.setFillType(fillType);
946 578
947 if (paintType == CanvasRenderingContext2DState::StrokePaintType) 579 if (paintType == CanvasRenderingContext2DState::StrokePaintType)
948 inflateStrokeRect(bounds); 580 inflateStrokeRect(bounds);
949 581
950 if (!drawingCanvas()) 582 if (!drawingCanvas())
951 return; 583 return;
952 584
953 if (draw( 585 if (draw(
954 [&skPath, this](SkCanvas* c, const SkPaint* paint) // draw lambda 586 [&skPath, this](SkCanvas* c, const SkPaint* paint) // draw lambda
955 { 587 {
956 c->drawPath(skPath, *paint); 588 c->drawPath(skPath, *paint);
957 }, 589 },
958 [](const SkIRect& rect) // overdraw test lambda 590 [](const SkIRect& rect) // overdraw test lambda
959 { 591 {
960 return false; 592 return false;
961 }, bounds, paintType)) { 593 }, bounds, paintType)) {
962 if (isPathExpensive(path)) { 594 if (isPathExpensive(path)) {
963 ImageBuffer* buffer = canvas()->buffer(); 595 ImageBuffer* buffer = imageBuffer();
964 if (buffer) 596 if (buffer)
965 buffer->setHasExpensiveOp(); 597 buffer->setHasExpensiveOp();
966 } 598 }
967 } 599 }
968 } 600 }
969 601
970 static SkPath::FillType parseWinding(const String& windingRuleString) 602 static SkPath::FillType parseWinding(const String& windingRuleString)
971 { 603 {
972 if (windingRuleString == "nonzero") 604 if (windingRuleString == "nonzero")
973 return SkPath::kWinding_FillType; 605 return SkPath::kWinding_FillType;
974 if (windingRuleString == "evenodd") 606 if (windingRuleString == "evenodd")
975 return SkPath::kEvenOdd_FillType; 607 return SkPath::kEvenOdd_FillType;
976 608
977 ASSERT_NOT_REACHED(); 609 ASSERT_NOT_REACHED();
978 return SkPath::kEvenOdd_FillType; 610 return SkPath::kEvenOdd_FillType;
979 } 611 }
980 612
981 void CanvasRenderingContext2D::fill(const String& windingRuleString) 613 void BaseRenderingContext2D::fill(const String& windingRuleString)
982 { 614 {
983 drawPathInternal(m_path, CanvasRenderingContext2DState::FillPaintType, parse Winding(windingRuleString)); 615 drawPathInternal(m_path, CanvasRenderingContext2DState::FillPaintType, parse Winding(windingRuleString));
984 } 616 }
985 617
986 void CanvasRenderingContext2D::fill(Path2D* domPath, const String& windingRuleSt ring) 618 void BaseRenderingContext2D::fill(Path2D* domPath, const String& windingRuleStri ng)
987 { 619 {
988 drawPathInternal(domPath->path(), CanvasRenderingContext2DState::FillPaintTy pe, parseWinding(windingRuleString)); 620 drawPathInternal(domPath->path(), CanvasRenderingContext2DState::FillPaintTy pe, parseWinding(windingRuleString));
989 } 621 }
990 622
991 void CanvasRenderingContext2D::stroke() 623 void BaseRenderingContext2D::stroke()
992 { 624 {
993 drawPathInternal(m_path, CanvasRenderingContext2DState::StrokePaintType); 625 drawPathInternal(m_path, CanvasRenderingContext2DState::StrokePaintType);
994 } 626 }
995 627
996 void CanvasRenderingContext2D::stroke(Path2D* domPath) 628 void BaseRenderingContext2D::stroke(Path2D* domPath)
997 { 629 {
998 drawPathInternal(domPath->path(), CanvasRenderingContext2DState::StrokePaint Type); 630 drawPathInternal(domPath->path(), CanvasRenderingContext2DState::StrokePaint Type);
999 } 631 }
1000 632
1001 void CanvasRenderingContext2D::fillRect(double x, double y, double width, double height) 633 void BaseRenderingContext2D::fillRect(double x, double y, double width, double h eight)
1002 { 634 {
1003 if (!validateRectForCanvas(x, y, width, height)) 635 if (!validateRectForCanvas(x, y, width, height))
1004 return; 636 return;
1005 637
1006 if (!drawingCanvas()) 638 if (!drawingCanvas())
1007 return; 639 return;
1008 640
1009 SkRect rect = SkRect::MakeXYWH(x, y, width, height); 641 SkRect rect = SkRect::MakeXYWH(x, y, width, height);
1010 draw( 642 draw(
1011 [&rect, this](SkCanvas* c, const SkPaint* paint) // draw lambda 643 [&rect, this](SkCanvas* c, const SkPaint* paint) // draw lambda
(...skipping 14 matching lines...) Expand all
1026 SkPath path; 658 SkPath path;
1027 path.moveTo(rect.x(), rect.y()); 659 path.moveTo(rect.x(), rect.y());
1028 path.lineTo(rect.maxX(), rect.maxY()); 660 path.lineTo(rect.maxX(), rect.maxY());
1029 path.close(); 661 path.close();
1030 canvas->drawPath(path, *paint); 662 canvas->drawPath(path, *paint);
1031 return; 663 return;
1032 } 664 }
1033 canvas->drawRect(rect, *paint); 665 canvas->drawRect(rect, *paint);
1034 } 666 }
1035 667
1036 void CanvasRenderingContext2D::strokeRect(double x, double y, double width, doub le height) 668 void BaseRenderingContext2D::strokeRect(double x, double y, double width, double height)
1037 { 669 {
1038 if (!validateRectForCanvas(x, y, width, height)) 670 if (!validateRectForCanvas(x, y, width, height))
1039 return; 671 return;
1040 672
1041 if (!drawingCanvas()) 673 if (!drawingCanvas())
1042 return; 674 return;
1043 675
1044 SkRect rect = SkRect::MakeXYWH(x, y, width, height); 676 SkRect rect = SkRect::MakeXYWH(x, y, width, height);
1045 FloatRect bounds = rect; 677 FloatRect bounds = rect;
1046 inflateStrokeRect(bounds); 678 inflateStrokeRect(bounds);
1047 draw( 679 draw(
1048 [&rect, this](SkCanvas* c, const SkPaint* paint) // draw lambda 680 [&rect, this](SkCanvas* c, const SkPaint* paint) // draw lambda
1049 { 681 {
1050 strokeRectOnCanvas(rect, c, paint); 682 strokeRectOnCanvas(rect, c, paint);
1051 }, 683 },
1052 [](const SkIRect& clipBounds) // overdraw test lambda 684 [](const SkIRect& clipBounds) // overdraw test lambda
1053 { 685 {
1054 return false; 686 return false;
1055 }, bounds, CanvasRenderingContext2DState::StrokePaintType); 687 }, bounds, CanvasRenderingContext2DState::StrokePaintType);
1056 } 688 }
1057 689
1058 void CanvasRenderingContext2D::clipInternal(const Path& path, const String& wind ingRuleString) 690 void BaseRenderingContext2D::clipInternal(const Path& path, const String& windin gRuleString)
1059 { 691 {
1060 SkCanvas* c = drawingCanvas(); 692 SkCanvas* c = drawingCanvas();
1061 if (!c) { 693 if (!c) {
1062 return; 694 return;
1063 } 695 }
1064 if (!state().isTransformInvertible()) { 696 if (!state().isTransformInvertible()) {
1065 return; 697 return;
1066 } 698 }
1067 699
1068 SkPath skPath = path.skPath(); 700 SkPath skPath = path.skPath();
1069 skPath.setFillType(parseWinding(windingRuleString)); 701 skPath.setFillType(parseWinding(windingRuleString));
1070 modifiableState().clipPath(skPath, m_clipAntialiasing); 702 modifiableState().clipPath(skPath, m_clipAntialiasing);
1071 c->clipPath(skPath, SkRegion::kIntersect_Op, m_clipAntialiasing == AntiAlias ed); 703 c->clipPath(skPath, SkRegion::kIntersect_Op, m_clipAntialiasing == AntiAlias ed);
1072 if (ExpensiveCanvasHeuristicParameters::ComplexClipsAreExpensive && !skPath. isRect(0) && canvas()->hasImageBuffer()) { 704 if (ExpensiveCanvasHeuristicParameters::ComplexClipsAreExpensive && !skPath. isRect(0) && hasImageBuffer()) {
1073 canvas()->buffer()->setHasExpensiveOp(); 705 imageBuffer()->setHasExpensiveOp();
1074 } 706 }
1075 } 707 }
1076 708
1077 void CanvasRenderingContext2D::clip(const String& windingRuleString) 709 void BaseRenderingContext2D::clip(const String& windingRuleString)
1078 { 710 {
1079 clipInternal(m_path, windingRuleString); 711 clipInternal(m_path, windingRuleString);
1080 } 712 }
1081 713
1082 void CanvasRenderingContext2D::clip(Path2D* domPath, const String& windingRuleSt ring) 714 void BaseRenderingContext2D::clip(Path2D* domPath, const String& windingRuleStri ng)
1083 { 715 {
1084 clipInternal(domPath->path(), windingRuleString); 716 clipInternal(domPath->path(), windingRuleString);
1085 } 717 }
1086 718
1087 bool CanvasRenderingContext2D::isPointInPath(const double x, const double y, con st String& windingRuleString) 719 bool BaseRenderingContext2D::isPointInPath(const double x, const double y, const String& windingRuleString)
1088 { 720 {
1089 return isPointInPathInternal(m_path, x, y, windingRuleString); 721 return isPointInPathInternal(m_path, x, y, windingRuleString);
1090 } 722 }
1091 723
1092 bool CanvasRenderingContext2D::isPointInPath(Path2D* domPath, const double x, co nst double y, const String& windingRuleString) 724 bool BaseRenderingContext2D::isPointInPath(Path2D* domPath, const double x, cons t double y, const String& windingRuleString)
1093 { 725 {
1094 return isPointInPathInternal(domPath->path(), x, y, windingRuleString); 726 return isPointInPathInternal(domPath->path(), x, y, windingRuleString);
1095 } 727 }
1096 728
1097 bool CanvasRenderingContext2D::isPointInPathInternal(const Path& path, const dou ble x, const double y, const String& windingRuleString) 729 bool BaseRenderingContext2D::isPointInPathInternal(const Path& path, const doubl e x, const double y, const String& windingRuleString)
1098 { 730 {
1099 SkCanvas* c = drawingCanvas(); 731 SkCanvas* c = drawingCanvas();
1100 if (!c) 732 if (!c)
1101 return false; 733 return false;
1102 if (!state().isTransformInvertible()) 734 if (!state().isTransformInvertible())
1103 return false; 735 return false;
1104 736
1105 FloatPoint point(x, y); 737 FloatPoint point(x, y);
1106 if (!std::isfinite(point.x()) || !std::isfinite(point.y())) 738 if (!std::isfinite(point.x()) || !std::isfinite(point.y()))
1107 return false; 739 return false;
1108 AffineTransform ctm = state().transform(); 740 AffineTransform ctm = state().transform();
1109 FloatPoint transformedPoint = ctm.inverse().mapPoint(point); 741 FloatPoint transformedPoint = ctm.inverse().mapPoint(point);
1110 742
1111 return path.contains(transformedPoint, SkFillTypeToWindRule(parseWinding(win dingRuleString))); 743 return path.contains(transformedPoint, SkFillTypeToWindRule(parseWinding(win dingRuleString)));
1112 } 744 }
1113 745
1114 bool CanvasRenderingContext2D::isPointInStroke(const double x, const double y) 746 bool BaseRenderingContext2D::isPointInStroke(const double x, const double y)
1115 { 747 {
1116 return isPointInStrokeInternal(m_path, x, y); 748 return isPointInStrokeInternal(m_path, x, y);
1117 } 749 }
1118 750
1119 bool CanvasRenderingContext2D::isPointInStroke(Path2D* domPath, const double x, const double y) 751 bool BaseRenderingContext2D::isPointInStroke(Path2D* domPath, const double x, co nst double y)
1120 { 752 {
1121 return isPointInStrokeInternal(domPath->path(), x, y); 753 return isPointInStrokeInternal(domPath->path(), x, y);
1122 } 754 }
1123 755
1124 bool CanvasRenderingContext2D::isPointInStrokeInternal(const Path& path, const d ouble x, const double y) 756 bool BaseRenderingContext2D::isPointInStrokeInternal(const Path& path, const dou ble x, const double y)
1125 { 757 {
1126 SkCanvas* c = drawingCanvas(); 758 SkCanvas* c = drawingCanvas();
1127 if (!c) 759 if (!c)
1128 return false; 760 return false;
1129 if (!state().isTransformInvertible()) 761 if (!state().isTransformInvertible())
1130 return false; 762 return false;
1131 763
1132 FloatPoint point(x, y); 764 FloatPoint point(x, y);
1133 if (!std::isfinite(point.x()) || !std::isfinite(point.y())) 765 if (!std::isfinite(point.x()) || !std::isfinite(point.y()))
1134 return false; 766 return false;
1135 AffineTransform ctm = state().transform(); 767 AffineTransform ctm = state().transform();
1136 FloatPoint transformedPoint = ctm.inverse().mapPoint(point); 768 FloatPoint transformedPoint = ctm.inverse().mapPoint(point);
1137 769
1138 StrokeData strokeData; 770 StrokeData strokeData;
1139 strokeData.setThickness(state().lineWidth()); 771 strokeData.setThickness(state().lineWidth());
1140 strokeData.setLineCap(state().lineCap()); 772 strokeData.setLineCap(state().lineCap());
1141 strokeData.setLineJoin(state().lineJoin()); 773 strokeData.setLineJoin(state().lineJoin());
1142 strokeData.setMiterLimit(state().miterLimit()); 774 strokeData.setMiterLimit(state().miterLimit());
1143 Vector<float> lineDash(state().lineDash().size()); 775 Vector<float> lineDash(state().lineDash().size());
1144 std::copy(state().lineDash().begin(), state().lineDash().end(), lineDash.beg in()); 776 std::copy(state().lineDash().begin(), state().lineDash().end(), lineDash.beg in());
1145 strokeData.setLineDash(lineDash, state().lineDashOffset()); 777 strokeData.setLineDash(lineDash, state().lineDashOffset());
1146 return path.strokeContains(transformedPoint, strokeData); 778 return path.strokeContains(transformedPoint, strokeData);
1147 } 779 }
1148 780
1149 void CanvasRenderingContext2D::scrollPathIntoView() 781 void BaseRenderingContext2D::clearRect(double x, double y, double width, double height)
1150 {
1151 scrollPathIntoViewInternal(m_path);
1152 }
1153
1154 void CanvasRenderingContext2D::scrollPathIntoView(Path2D* path2d)
1155 {
1156 scrollPathIntoViewInternal(path2d->path());
1157 }
1158
1159 void CanvasRenderingContext2D::scrollPathIntoViewInternal(const Path& path)
1160 {
1161 if (!state().isTransformInvertible() || path.isEmpty())
1162 return;
1163
1164 canvas()->document().updateLayoutIgnorePendingStylesheets();
1165
1166 LayoutObject* renderer = canvas()->layoutObject();
1167 LayoutBox* layoutBox = canvas()->layoutBox();
1168 if (!renderer || !layoutBox)
1169 return;
1170
1171 // Apply transformation and get the bounding rect
1172 Path transformedPath = path;
1173 transformedPath.transform(state().transform());
1174 FloatRect boundingRect = transformedPath.boundingRect();
1175
1176 // Offset by the canvas rect
1177 LayoutRect pathRect(boundingRect);
1178 IntRect canvasRect = layoutBox->absoluteContentBox();
1179 pathRect.moveBy(canvasRect.location());
1180
1181 renderer->scrollRectToVisible(
1182 pathRect, ScrollAlignment::alignCenterAlways, ScrollAlignment::alignTopA lways);
1183
1184 // TODO: should implement "inform the user" that the caret and/or
1185 // selection the specified rectangle of the canvas. See http://crbug.com/357 987
1186 }
1187
1188 void CanvasRenderingContext2D::clearRect(double x, double y, double width, doubl e height)
1189 { 782 {
1190 if (!validateRectForCanvas(x, y, width, height)) 783 if (!validateRectForCanvas(x, y, width, height))
1191 return; 784 return;
1192 785
1193 SkCanvas* c = drawingCanvas(); 786 SkCanvas* c = drawingCanvas();
1194 if (!c) 787 if (!c)
1195 return; 788 return;
1196 if (!state().isTransformInvertible()) 789 if (!state().isTransformInvertible())
1197 return; 790 return;
1198 791
(...skipping 11 matching lines...) Expand all
1210 if (drawingCanvas()) 803 if (drawingCanvas())
1211 drawingCanvas()->drawRect(rect, clearPaint); 804 drawingCanvas()->drawRect(rect, clearPaint);
1212 didDraw(clipBounds); 805 didDraw(clipBounds);
1213 } else { 806 } else {
1214 SkIRect dirtyRect; 807 SkIRect dirtyRect;
1215 if (computeDirtyRect(rect, clipBounds, &dirtyRect)) { 808 if (computeDirtyRect(rect, clipBounds, &dirtyRect)) {
1216 c->drawRect(rect, clearPaint); 809 c->drawRect(rect, clearPaint);
1217 didDraw(dirtyRect); 810 didDraw(dirtyRect);
1218 } 811 }
1219 } 812 }
1220
1221 if (m_hitRegionManager) {
1222 m_hitRegionManager->removeHitRegionsInRect(rect, state().transform());
1223 }
1224 } 813 }
1225 814
1226 static inline FloatRect normalizeRect(const FloatRect& rect) 815 static inline FloatRect normalizeRect(const FloatRect& rect)
1227 { 816 {
1228 return FloatRect(std::min(rect.x(), rect.maxX()), 817 return FloatRect(std::min(rect.x(), rect.maxX()),
1229 std::min(rect.y(), rect.maxY()), 818 std::min(rect.y(), rect.maxY()),
1230 std::max(rect.width(), -rect.width()), 819 std::max(rect.width(), -rect.width()),
1231 std::max(rect.height(), -rect.height())); 820 std::max(rect.height(), -rect.height()));
1232 } 821 }
1233 822
(...skipping 23 matching lines...) Expand all
1257 if (value.isHTMLVideoElement()) 846 if (value.isHTMLVideoElement())
1258 return value.getAsHTMLVideoElement().get(); 847 return value.getAsHTMLVideoElement().get();
1259 if (value.isHTMLCanvasElement()) 848 if (value.isHTMLCanvasElement())
1260 return value.getAsHTMLCanvasElement().get(); 849 return value.getAsHTMLCanvasElement().get();
1261 if (value.isImageBitmap()) 850 if (value.isImageBitmap())
1262 return value.getAsImageBitmap().get(); 851 return value.getAsImageBitmap().get();
1263 ASSERT_NOT_REACHED(); 852 ASSERT_NOT_REACHED();
1264 return nullptr; 853 return nullptr;
1265 } 854 }
1266 855
1267 void CanvasRenderingContext2D::drawImage(const CanvasImageSourceUnion& imageSour ce, double x, double y, ExceptionState& exceptionState) 856 void BaseRenderingContext2D::drawImage(const CanvasImageSourceUnion& imageSource , double x, double y, ExceptionState& exceptionState)
1268 { 857 {
1269 CanvasImageSource* imageSourceInternal = toImageSourceInternal(imageSource); 858 CanvasImageSource* imageSourceInternal = toImageSourceInternal(imageSource);
1270 FloatSize sourceRectSize = imageSourceInternal->elementSize(); 859 FloatSize sourceRectSize = imageSourceInternal->elementSize();
1271 FloatSize destRectSize = imageSourceInternal->defaultDestinationSize(); 860 FloatSize destRectSize = imageSourceInternal->defaultDestinationSize();
1272 drawImage(imageSourceInternal, 0, 0, sourceRectSize.width(), sourceRectSize. height(), x, y, destRectSize.width(), destRectSize.height(), exceptionState); 861 drawImage(imageSourceInternal, 0, 0, sourceRectSize.width(), sourceRectSize. height(), x, y, destRectSize.width(), destRectSize.height(), exceptionState);
1273 } 862 }
1274 863
1275 void CanvasRenderingContext2D::drawImage(const CanvasImageSourceUnion& imageSour ce, 864 void BaseRenderingContext2D::drawImage(const CanvasImageSourceUnion& imageSource ,
1276 double x, double y, double width, double height, ExceptionState& exceptionSt ate) 865 double x, double y, double width, double height, ExceptionState& exceptionSt ate)
1277 { 866 {
1278 CanvasImageSource* imageSourceInternal = toImageSourceInternal(imageSource); 867 CanvasImageSource* imageSourceInternal = toImageSourceInternal(imageSource);
1279 FloatSize sourceRectSize = imageSourceInternal->elementSize(); 868 FloatSize sourceRectSize = imageSourceInternal->elementSize();
1280 drawImage(imageSourceInternal, 0, 0, sourceRectSize.width(), sourceRectSize. height(), x, y, width, height, exceptionState); 869 drawImage(imageSourceInternal, 0, 0, sourceRectSize.width(), sourceRectSize. height(), x, y, width, height, exceptionState);
1281 } 870 }
1282 871
1283 void CanvasRenderingContext2D::drawImage(const CanvasImageSourceUnion& imageSour ce, 872 void BaseRenderingContext2D::drawImage(const CanvasImageSourceUnion& imageSource ,
1284 double sx, double sy, double sw, double sh, 873 double sx, double sy, double sw, double sh,
1285 double dx, double dy, double dw, double dh, ExceptionState& exceptionState) 874 double dx, double dy, double dw, double dh, ExceptionState& exceptionState)
1286 { 875 {
1287 CanvasImageSource* imageSourceInternal = toImageSourceInternal(imageSource); 876 CanvasImageSource* imageSourceInternal = toImageSourceInternal(imageSource);
1288 drawImage(imageSourceInternal, sx, sy, sw, sh, dx, dy, dw, dh, exceptionStat e); 877 drawImage(imageSourceInternal, sx, sy, sw, sh, dx, dy, dw, dh, exceptionStat e);
1289 } 878 }
1290 879
1291 bool CanvasRenderingContext2D::shouldDrawImageAntialiased(const FloatRect& destR ect) const 880 bool BaseRenderingContext2D::shouldDrawImageAntialiased(const FloatRect& destRec t) const
1292 { 881 {
1293 if (!shouldAntialias()) 882 if (!state().shouldAntialias())
1294 return false; 883 return false;
1295 SkCanvas* c = drawingCanvas(); 884 SkCanvas* c = drawingCanvas();
1296 ASSERT(c); 885 ASSERT(c);
1297 886
1298 const SkMatrix &ctm = c->getTotalMatrix(); 887 const SkMatrix &ctm = c->getTotalMatrix();
1299 // Don't disable anti-aliasing if we're rotated or skewed. 888 // Don't disable anti-aliasing if we're rotated or skewed.
1300 if (!ctm.rectStaysRect()) 889 if (!ctm.rectStaysRect())
1301 return true; 890 return true;
1302 // Check if the dimensions of the destination are "small" (less than one 891 // Check if the dimensions of the destination are "small" (less than one
1303 // device pixel). To prevent sudden drop-outs. Since we know that 892 // device pixel). To prevent sudden drop-outs. Since we know that
1304 // kRectStaysRect_Mask is set, the matrix either has scale and no skew or 893 // kRectStaysRect_Mask is set, the matrix either has scale and no skew or
1305 // vice versa. We can query the kAffine_Mask flag to determine which case 894 // vice versa. We can query the kAffine_Mask flag to determine which case
1306 // it is. 895 // it is.
1307 // FIXME: This queries the CTM while drawing, which is generally 896 // FIXME: This queries the CTM while drawing, which is generally
1308 // discouraged. Always drawing with AA can negatively impact performance 897 // discouraged. Always drawing with AA can negatively impact performance
1309 // though - that's why it's not always on. 898 // though - that's why it's not always on.
1310 SkScalar widthExpansion, heightExpansion; 899 SkScalar widthExpansion, heightExpansion;
1311 if (ctm.getType() & SkMatrix::kAffine_Mask) 900 if (ctm.getType() & SkMatrix::kAffine_Mask)
1312 widthExpansion = ctm[SkMatrix::kMSkewY], heightExpansion = ctm[SkMatrix: :kMSkewX]; 901 widthExpansion = ctm[SkMatrix::kMSkewY], heightExpansion = ctm[SkMatrix: :kMSkewX];
1313 else 902 else
1314 widthExpansion = ctm[SkMatrix::kMScaleX], heightExpansion = ctm[SkMatrix ::kMScaleY]; 903 widthExpansion = ctm[SkMatrix::kMScaleX], heightExpansion = ctm[SkMatrix ::kMScaleY];
1315 return destRect.width() * fabs(widthExpansion) < 1 || destRect.height() * fa bs(heightExpansion) < 1; 904 return destRect.width() * fabs(widthExpansion) < 1 || destRect.height() * fa bs(heightExpansion) < 1;
1316 } 905 }
1317 906
1318 void CanvasRenderingContext2D::drawImageInternal(SkCanvas* c, CanvasImageSource* imageSource, Image* image, const FloatRect& srcRect, const FloatRect& dstRect, const SkPaint* paint) 907 void BaseRenderingContext2D::drawImageInternal(SkCanvas* c, CanvasImageSource* i mageSource, Image* image, const FloatRect& srcRect, const FloatRect& dstRect, co nst SkPaint* paint)
1319 { 908 {
1320 int initialSaveCount = c->getSaveCount(); 909 int initialSaveCount = c->getSaveCount();
1321 SkPaint imagePaint = *paint; 910 SkPaint imagePaint = *paint;
1322 911
1323 if (paint->getImageFilter()) { 912 if (paint->getImageFilter()) {
1324 SkMatrix invCtm; 913 SkMatrix invCtm;
1325 if (!c->getTotalMatrix().invert(&invCtm)) { 914 if (!c->getTotalMatrix().invert(&invCtm)) {
1326 // There is an earlier check for invertibility, but the arithmetic 915 // There is an earlier check for invertibility, but the arithmetic
1327 // in AffineTransform is not exactly identical, so it is possible 916 // in AffineTransform is not exactly identical, so it is possible
1328 // for SkMatrix to find the transform to be non-invertible at this s tage. 917 // for SkMatrix to find the transform to be non-invertible at this s tage.
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
1367 if (imageSource->isCanvasElement()) { 956 if (imageSource->isCanvasElement()) {
1368 HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(imageSource) ; 957 HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(imageSource) ;
1369 if (canvas->isAnimated2D()) { 958 if (canvas->isAnimated2D()) {
1370 *reason = DisableDeferralReasonDrawImageOfAnimated2dCanvas; 959 *reason = DisableDeferralReasonDrawImageOfAnimated2dCanvas;
1371 return true; 960 return true;
1372 } 961 }
1373 } 962 }
1374 return false; 963 return false;
1375 } 964 }
1376 965
1377 void CanvasRenderingContext2D::drawImage(CanvasImageSource* imageSource, 966 void BaseRenderingContext2D::drawImage(CanvasImageSource* imageSource,
1378 double sx, double sy, double sw, double sh, 967 double sx, double sy, double sw, double sh,
1379 double dx, double dy, double dw, double dh, ExceptionState& exceptionState) 968 double dx, double dy, double dw, double dh, ExceptionState& exceptionState)
1380 { 969 {
1381 if (!drawingCanvas()) 970 if (!drawingCanvas())
1382 return; 971 return;
1383 972
1384 RefPtr<Image> image; 973 RefPtr<Image> image;
1385 SourceImageStatus sourceImageStatus = InvalidSourceImageStatus; 974 SourceImageStatus sourceImageStatus = InvalidSourceImageStatus;
1386 if (!imageSource->isVideoElement()) { 975 if (!imageSource->isVideoElement()) {
1387 AccelerationHint hint = canvas()->buffer()->isAccelerated() ? PreferAcce leration : PreferNoAcceleration; 976 AccelerationHint hint = imageBuffer()->isAccelerated() ? PreferAccelerat ion : PreferNoAcceleration;
1388 image = imageSource->getSourceImageForCanvas(&sourceImageStatus, hint, S napshotReasonDrawImage); 977 image = imageSource->getSourceImageForCanvas(&sourceImageStatus, hint, S napshotReasonDrawImage);
1389 if (sourceImageStatus == UndecodableSourceImageStatus) 978 if (sourceImageStatus == UndecodableSourceImageStatus)
1390 exceptionState.throwDOMException(InvalidStateError, "The HTMLImageEl ement provided is in the 'broken' state."); 979 exceptionState.throwDOMException(InvalidStateError, "The HTMLImageEl ement provided is in the 'broken' state.");
1391 if (!image || !image->width() || !image->height()) 980 if (!image || !image->width() || !image->height())
1392 return; 981 return;
1393 } else { 982 } else {
1394 if (!static_cast<HTMLVideoElement*>(imageSource)->hasAvailableVideoFrame ()) 983 if (!static_cast<HTMLVideoElement*>(imageSource)->hasAvailableVideoFrame ())
1395 return; 984 return;
1396 } 985 }
1397 986
1398 if (!std::isfinite(dx) || !std::isfinite(dy) || !std::isfinite(dw) || !std:: isfinite(dh) 987 if (!std::isfinite(dx) || !std::isfinite(dy) || !std::isfinite(dw) || !std:: isfinite(dh)
1399 || !std::isfinite(sx) || !std::isfinite(sy) || !std::isfinite(sw) || !st d::isfinite(sh) 988 || !std::isfinite(sx) || !std::isfinite(sy) || !std::isfinite(sw) || !st d::isfinite(sh)
1400 || !dw || !dh || !sw || !sh) 989 || !dw || !dh || !sw || !sh)
1401 return; 990 return;
1402 991
1403 FloatRect srcRect = normalizeRect(FloatRect(sx, sy, sw, sh)); 992 FloatRect srcRect = normalizeRect(FloatRect(sx, sy, sw, sh));
1404 FloatRect dstRect = normalizeRect(FloatRect(dx, dy, dw, dh)); 993 FloatRect dstRect = normalizeRect(FloatRect(dx, dy, dw, dh));
1405 994
1406 clipRectsToImageRect(FloatRect(FloatPoint(), imageSource->elementSize()), &s rcRect, &dstRect); 995 clipRectsToImageRect(FloatRect(FloatPoint(), imageSource->elementSize()), &s rcRect, &dstRect);
1407 996
1408 imageSource->adjustDrawRects(&srcRect, &dstRect); 997 imageSource->adjustDrawRects(&srcRect, &dstRect);
1409 998
1410 if (srcRect.isEmpty()) 999 if (srcRect.isEmpty())
1411 return; 1000 return;
1412 1001
1413 DisableDeferralReason reason = DisableDeferralReasonUnknown; 1002 DisableDeferralReason reason = DisableDeferralReasonUnknown;
1414 if (shouldDisableDeferral(imageSource, &reason) || image->isTextureBacked()) 1003 if (shouldDisableDeferral(imageSource, &reason) || image->isTextureBacked())
1415 canvas()->disableDeferral(reason); 1004 disableDeferral(reason);
1416 1005
1417 validateStateStack(); 1006 validateStateStack();
1418 1007
1419 draw( 1008 draw(
1420 [this, &imageSource, &image, &srcRect, dstRect](SkCanvas* c, const SkPai nt* paint) // draw lambda 1009 [this, &imageSource, &image, &srcRect, dstRect](SkCanvas* c, const SkPai nt* paint) // draw lambda
1421 { 1010 {
1422 drawImageInternal(c, imageSource, image.get(), srcRect, dstRect, pai nt); 1011 drawImageInternal(c, imageSource, image.get(), srcRect, dstRect, pai nt);
1423 }, 1012 },
1424 [this, &dstRect](const SkIRect& clipBounds) // overdraw test lambda 1013 [this, &dstRect](const SkIRect& clipBounds) // overdraw test lambda
1425 { 1014 {
1426 return rectContainsTransformedRect(dstRect, clipBounds); 1015 return rectContainsTransformedRect(dstRect, clipBounds);
1427 }, dstRect, CanvasRenderingContext2DState::ImagePaintType, 1016 }, dstRect, CanvasRenderingContext2DState::ImagePaintType,
1428 imageSource->isOpaque() ? CanvasRenderingContext2DState::OpaqueImage : C anvasRenderingContext2DState::NonOpaqueImage); 1017 imageSource->isOpaque() ? CanvasRenderingContext2DState::OpaqueImage : C anvasRenderingContext2DState::NonOpaqueImage);
1429 1018
1430 validateStateStack(); 1019 validateStateStack();
1431 1020
1432 bool isExpensive = false; 1021 bool isExpensive = false;
1433 1022
1434 if (ExpensiveCanvasHeuristicParameters::SVGImageSourcesAreExpensive && image Source->isSVGSource()) 1023 if (ExpensiveCanvasHeuristicParameters::SVGImageSourcesAreExpensive && image Source->isSVGSource())
1435 isExpensive = true; 1024 isExpensive = true;
1436 1025
1437 if (imageSource->elementSize().width() * imageSource->elementSize().height() > canvas()->width() * canvas()->height() * ExpensiveCanvasHeuristicParameters:: ExpensiveImageSizeRatio) 1026 if (imageSource->elementSize().width() * imageSource->elementSize().height() > width() * height() * ExpensiveCanvasHeuristicParameters::ExpensiveImageSizeRa tio)
1438 isExpensive = true; 1027 isExpensive = true;
1439 1028
1440 if (isExpensive) { 1029 if (isExpensive) {
1441 ImageBuffer* buffer = canvas()->buffer(); 1030 ImageBuffer* buffer = imageBuffer();
1442 if (buffer) 1031 if (buffer)
1443 buffer->setHasExpensiveOp(); 1032 buffer->setHasExpensiveOp();
1444 } 1033 }
1445 1034
1446 if (imageSource->isCanvasElement() && static_cast<HTMLCanvasElement*>(imageS ource)->is3D()) { 1035 if (imageSource->isCanvasElement() && static_cast<HTMLCanvasElement*>(imageS ource)->is3D()) {
1447 // WebGL to 2D canvas: must flush graphics context to prevent a race 1036 // WebGL to 2D canvas: must flush graphics context to prevent a race
1448 // FIXME: crbug.com/516331 Fix the underlying synchronization issue so t his flush can be eliminated. 1037 // FIXME: crbug.com/516331 Fix the underlying synchronization issue so t his flush can be eliminated.
1449 canvas()->buffer()->flushGpu(FlushReasonDrawImageOfWebGL); 1038 imageBuffer()->flushGpu(FlushReasonDrawImageOfWebGL);
1450 } 1039 }
1451 1040
1452 if (canvas()->originClean() && wouldTaintOrigin(imageSource)) 1041 if (originClean() && wouldTaintOrigin(imageSource))
1453 canvas()->setOriginTainted(); 1042 setOriginTainted();
1454 } 1043 }
1455 1044
1456 void CanvasRenderingContext2D::clearCanvas() 1045 void BaseRenderingContext2D::clearCanvas()
1457 { 1046 {
1458 FloatRect canvasRect(0, 0, canvas()->width(), canvas()->height()); 1047 FloatRect canvasRect(0, 0, width(), height());
1459 checkOverdraw(canvasRect, 0, CanvasRenderingContext2DState::NoImage, ClipFil l); 1048 checkOverdraw(canvasRect, 0, CanvasRenderingContext2DState::NoImage, ClipFil l);
1460 SkCanvas* c = drawingCanvas(); 1049 SkCanvas* c = drawingCanvas();
1461 if (c) 1050 if (c)
1462 c->clear(m_hasAlpha ? SK_ColorTRANSPARENT : SK_ColorBLACK); 1051 c->clear(hasAlpha() ? SK_ColorTRANSPARENT : SK_ColorBLACK);
1463 } 1052 }
1464 1053
1465 bool CanvasRenderingContext2D::rectContainsTransformedRect(const FloatRect& rect , const SkIRect& transformedRect) const 1054 bool BaseRenderingContext2D::rectContainsTransformedRect(const FloatRect& rect, const SkIRect& transformedRect) const
1466 { 1055 {
1467 FloatQuad quad(rect); 1056 FloatQuad quad(rect);
1468 FloatQuad transformedQuad(FloatRect(transformedRect.x(), transformedRect.y() , transformedRect.width(), transformedRect.height())); 1057 FloatQuad transformedQuad(FloatRect(transformedRect.x(), transformedRect.y() , transformedRect.width(), transformedRect.height()));
1469 return state().transform().mapQuad(quad).containsQuad(transformedQuad); 1058 return state().transform().mapQuad(quad).containsQuad(transformedQuad);
1470 } 1059 }
1471 1060
1472 CanvasGradient* CanvasRenderingContext2D::createLinearGradient(double x0, double y0, double x1, double y1) 1061 CanvasGradient* BaseRenderingContext2D::createLinearGradient(double x0, double y 0, double x1, double y1)
1473 { 1062 {
1474 CanvasGradient* gradient = CanvasGradient::create(FloatPoint(x0, y0), FloatP oint(x1, y1)); 1063 CanvasGradient* gradient = CanvasGradient::create(FloatPoint(x0, y0), FloatP oint(x1, y1));
1475 return gradient; 1064 return gradient;
1476 } 1065 }
1477 1066
1478 CanvasGradient* CanvasRenderingContext2D::createRadialGradient(double x0, double y0, double r0, double x1, double y1, double r1, ExceptionState& exceptionState) 1067 CanvasGradient* BaseRenderingContext2D::createRadialGradient(double x0, double y 0, double r0, double x1, double y1, double r1, ExceptionState& exceptionState)
1479 { 1068 {
1480 if (r0 < 0 || r1 < 0) { 1069 if (r0 < 0 || r1 < 0) {
1481 exceptionState.throwDOMException(IndexSizeError, String::format("The %s provided is less than 0.", r0 < 0 ? "r0" : "r1")); 1070 exceptionState.throwDOMException(IndexSizeError, String::format("The %s provided is less than 0.", r0 < 0 ? "r0" : "r1"));
1482 return nullptr; 1071 return nullptr;
1483 } 1072 }
1484 1073
1485 CanvasGradient* gradient = CanvasGradient::create(FloatPoint(x0, y0), r0, Fl oatPoint(x1, y1), r1); 1074 CanvasGradient* gradient = CanvasGradient::create(FloatPoint(x0, y0), r0, Fl oatPoint(x1, y1), r1);
1486 return gradient; 1075 return gradient;
1487 } 1076 }
1488 1077
1489 CanvasPattern* CanvasRenderingContext2D::createPattern(const CanvasImageSourceUn ion& imageSource, const String& repetitionType, ExceptionState& exceptionState) 1078 CanvasPattern* BaseRenderingContext2D::createPattern(const CanvasImageSourceUnio n& imageSource, const String& repetitionType, ExceptionState& exceptionState)
1490 { 1079 {
1491 Pattern::RepeatMode repeatMode = CanvasPattern::parseRepetitionType(repetiti onType, exceptionState); 1080 Pattern::RepeatMode repeatMode = CanvasPattern::parseRepetitionType(repetiti onType, exceptionState);
1492 if (exceptionState.hadException()) 1081 if (exceptionState.hadException())
1493 return nullptr; 1082 return nullptr;
1494 1083
1495 SourceImageStatus status; 1084 SourceImageStatus status;
1496 CanvasImageSource* imageSourceInternal = toImageSourceInternal(imageSource); 1085 CanvasImageSource* imageSourceInternal = toImageSourceInternal(imageSource);
1497 RefPtr<Image> imageForRendering = imageSourceInternal->getSourceImageForCanv as(&status, PreferNoAcceleration, SnapshotReasonCreatePattern); 1086 RefPtr<Image> imageForRendering = imageSourceInternal->getSourceImageForCanv as(&status, PreferNoAcceleration, SnapshotReasonCreatePattern);
1498 1087
1499 switch (status) { 1088 switch (status) {
(...skipping 14 matching lines...) Expand all
1514 ASSERT_NOT_REACHED(); 1103 ASSERT_NOT_REACHED();
1515 return nullptr; 1104 return nullptr;
1516 } 1105 }
1517 ASSERT(imageForRendering); 1106 ASSERT(imageForRendering);
1518 1107
1519 bool originClean = !wouldTaintOrigin(imageSourceInternal); 1108 bool originClean = !wouldTaintOrigin(imageSourceInternal);
1520 1109
1521 return CanvasPattern::create(imageForRendering.release(), repeatMode, origin Clean); 1110 return CanvasPattern::create(imageForRendering.release(), repeatMode, origin Clean);
1522 } 1111 }
1523 1112
1524 bool CanvasRenderingContext2D::computeDirtyRect(const FloatRect& localRect, SkIR ect* dirtyRect) 1113 bool BaseRenderingContext2D::computeDirtyRect(const FloatRect& localRect, SkIRec t* dirtyRect)
1525 { 1114 {
1526 SkIRect clipBounds; 1115 SkIRect clipBounds;
1527 if (!drawingCanvas()->getClipDeviceBounds(&clipBounds)) 1116 if (!drawingCanvas()->getClipDeviceBounds(&clipBounds))
1528 return false; 1117 return false;
1529 return computeDirtyRect(localRect, clipBounds, dirtyRect); 1118 return computeDirtyRect(localRect, clipBounds, dirtyRect);
1530 } 1119 }
1531 1120
1532 bool CanvasRenderingContext2D::computeDirtyRect(const FloatRect& localRect, cons t SkIRect& transformedClipBounds, SkIRect* dirtyRect) 1121 bool BaseRenderingContext2D::computeDirtyRect(const FloatRect& localRect, const SkIRect& transformedClipBounds, SkIRect* dirtyRect)
1533 { 1122 {
1534 FloatRect canvasRect = state().transform().mapRect(localRect); 1123 FloatRect canvasRect = state().transform().mapRect(localRect);
1535 1124
1536 if (alphaChannel(state().shadowColor())) { 1125 if (alphaChannel(state().shadowColor())) {
1537 FloatRect shadowRect(canvasRect); 1126 FloatRect shadowRect(canvasRect);
1538 shadowRect.move(state().shadowOffset()); 1127 shadowRect.move(state().shadowOffset());
1539 shadowRect.inflate(state().shadowBlur()); 1128 shadowRect.inflate(state().shadowBlur());
1540 canvasRect.unite(shadowRect); 1129 canvasRect.unite(shadowRect);
1541 } 1130 }
1542 1131
1543 SkIRect canvasIRect; 1132 SkIRect canvasIRect;
1544 static_cast<SkRect>(canvasRect).roundOut(&canvasIRect); 1133 static_cast<SkRect>(canvasRect).roundOut(&canvasIRect);
1545 if (!canvasIRect.intersect(transformedClipBounds)) 1134 if (!canvasIRect.intersect(transformedClipBounds))
1546 return false; 1135 return false;
1547 1136
1548 if (dirtyRect) 1137 if (dirtyRect)
1549 *dirtyRect = canvasIRect; 1138 *dirtyRect = canvasIRect;
1550 1139
1551 return true; 1140 return true;
1552 } 1141 }
1553 1142
1554 void CanvasRenderingContext2D::didDraw(const SkIRect& dirtyRect) 1143 ImageData* BaseRenderingContext2D::createImageData(ImageData* imageData) const
1555 {
1556 if (dirtyRect.isEmpty())
1557 return;
1558
1559 if (ExpensiveCanvasHeuristicParameters::BlurredShadowsAreExpensive && state( ).shouldDrawShadows() && state().shadowBlur() > 0) {
1560 ImageBuffer* buffer = canvas()->buffer();
1561 if (buffer)
1562 buffer->setHasExpensiveOp();
1563 }
1564
1565 canvas()->didDraw(SkRect::Make(dirtyRect));
1566 }
1567
1568 SkCanvas* CanvasRenderingContext2D::drawingCanvas() const
1569 {
1570 if (isContextLost())
1571 return nullptr;
1572 return canvas()->drawingCanvas();
1573 }
1574
1575 ImageData* CanvasRenderingContext2D::createImageData(ImageData* imageData) const
1576 { 1144 {
1577 return ImageData::create(imageData->size()); 1145 return ImageData::create(imageData->size());
1578 } 1146 }
1579 1147
1580 ImageData* CanvasRenderingContext2D::createImageData(double sw, double sh, Excep tionState& exceptionState) const 1148 ImageData* BaseRenderingContext2D::createImageData(double sw, double sh, Excepti onState& exceptionState) const
1581 { 1149 {
1582 if (!sw || !sh) { 1150 if (!sw || !sh) {
1583 exceptionState.throwDOMException(IndexSizeError, String::format("The sou rce %s is 0.", sw ? "height" : "width")); 1151 exceptionState.throwDOMException(IndexSizeError, String::format("The sou rce %s is 0.", sw ? "height" : "width"));
1584 return nullptr; 1152 return nullptr;
1585 } 1153 }
1586 1154
1587 FloatSize logicalSize(fabs(sw), fabs(sh)); 1155 FloatSize logicalSize(fabs(sw), fabs(sh));
1588 if (!logicalSize.isExpressibleAsIntSize()) 1156 if (!logicalSize.isExpressibleAsIntSize())
1589 return nullptr; 1157 return nullptr;
1590 1158
1591 IntSize size = expandedIntSize(logicalSize); 1159 IntSize size = expandedIntSize(logicalSize);
1592 if (size.width() < 1) 1160 if (size.width() < 1)
1593 size.setWidth(1); 1161 size.setWidth(1);
1594 if (size.height() < 1) 1162 if (size.height() < 1)
1595 size.setHeight(1); 1163 size.setHeight(1);
1596 1164
1597 return ImageData::create(size); 1165 return ImageData::create(size);
1598 } 1166 }
1599 1167
1600 ImageData* CanvasRenderingContext2D::getImageData(double sx, double sy, double s w, double sh, ExceptionState& exceptionState) const 1168 ImageData* BaseRenderingContext2D::getImageData(double sx, double sy, double sw, double sh, ExceptionState& exceptionState) const
1601 { 1169 {
1602 if (!canvas()->originClean()) 1170 if (!originClean())
1603 exceptionState.throwSecurityError("The canvas has been tainted by cross- origin data."); 1171 exceptionState.throwSecurityError("The canvas has been tainted by cross- origin data.");
1604 else if (!sw || !sh) 1172 else if (!sw || !sh)
1605 exceptionState.throwDOMException(IndexSizeError, String::format("The sou rce %s is 0.", sw ? "height" : "width")); 1173 exceptionState.throwDOMException(IndexSizeError, String::format("The sou rce %s is 0.", sw ? "height" : "width"));
1606 1174
1607 if (exceptionState.hadException()) 1175 if (exceptionState.hadException())
1608 return nullptr; 1176 return nullptr;
1609 1177
1610 if (sw < 0) { 1178 if (sw < 0) {
1611 sx += sw; 1179 sx += sw;
1612 sw = -sw; 1180 sw = -sw;
1613 } 1181 }
1614 if (sh < 0) { 1182 if (sh < 0) {
1615 sy += sh; 1183 sy += sh;
1616 sh = -sh; 1184 sh = -sh;
1617 } 1185 }
1618 1186
1619 FloatRect logicalRect(sx, sy, sw, sh); 1187 FloatRect logicalRect(sx, sy, sw, sh);
1620 if (logicalRect.width() < 1) 1188 if (logicalRect.width() < 1)
1621 logicalRect.setWidth(1); 1189 logicalRect.setWidth(1);
1622 if (logicalRect.height() < 1) 1190 if (logicalRect.height() < 1)
1623 logicalRect.setHeight(1); 1191 logicalRect.setHeight(1);
1624 if (!logicalRect.isExpressibleAsIntRect()) 1192 if (!logicalRect.isExpressibleAsIntRect())
1625 return nullptr; 1193 return nullptr;
1626 1194
1627 IntRect imageDataRect = enclosingIntRect(logicalRect); 1195 IntRect imageDataRect = enclosingIntRect(logicalRect);
1628 ImageBuffer* buffer = canvas()->buffer(); 1196 ImageBuffer* buffer = imageBuffer();
1629 if (!buffer || isContextLost()) 1197 if (!buffer || isContextLost())
1630 return ImageData::create(imageDataRect.size()); 1198 return ImageData::create(imageDataRect.size());
1631 1199
1632 WTF::ArrayBufferContents contents; 1200 WTF::ArrayBufferContents contents;
1633 if (!buffer->getImageData(Unmultiplied, imageDataRect, contents)) 1201 if (!buffer->getImageData(Unmultiplied, imageDataRect, contents))
1634 return nullptr; 1202 return nullptr;
1635 1203
1636 RefPtr<DOMArrayBuffer> arrayBuffer = DOMArrayBuffer::create(contents); 1204 RefPtr<DOMArrayBuffer> arrayBuffer = DOMArrayBuffer::create(contents);
1637 return ImageData::create( 1205 return ImageData::create(
1638 imageDataRect.size(), 1206 imageDataRect.size(),
1639 DOMUint8ClampedArray::create(arrayBuffer, 0, arrayBuffer->byteLength())) ; 1207 DOMUint8ClampedArray::create(arrayBuffer, 0, arrayBuffer->byteLength())) ;
1640 } 1208 }
1641 1209
1642 void CanvasRenderingContext2D::putImageData(ImageData* data, double dx, double d y, ExceptionState& exceptionState) 1210 void BaseRenderingContext2D::putImageData(ImageData* data, double dx, double dy, ExceptionState& exceptionState)
1643 { 1211 {
1644 putImageData(data, dx, dy, 0, 0, data->width(), data->height(), exceptionSta te); 1212 putImageData(data, dx, dy, 0, 0, data->width(), data->height(), exceptionSta te);
1645 } 1213 }
1646 1214
1647 void CanvasRenderingContext2D::putImageData(ImageData* data, double dx, double d y, double dirtyX, double dirtyY, double dirtyWidth, double dirtyHeight, Exceptio nState& exceptionState) 1215 void BaseRenderingContext2D::putImageData(ImageData* data, double dx, double dy, double dirtyX, double dirtyY, double dirtyWidth, double dirtyHeight, ExceptionS tate& exceptionState)
1648 { 1216 {
1649 if (data->data()->bufferBase()->isNeutered()) { 1217 if (data->data()->bufferBase()->isNeutered()) {
1650 exceptionState.throwDOMException(InvalidStateError, "The source data has been neutered."); 1218 exceptionState.throwDOMException(InvalidStateError, "The source data has been neutered.");
1651 return; 1219 return;
1652 } 1220 }
1653 ImageBuffer* buffer = canvas()->buffer(); 1221 ImageBuffer* buffer = imageBuffer();
1654 if (!buffer) 1222 if (!buffer)
1655 return; 1223 return;
1656 1224
1657 if (dirtyWidth < 0) { 1225 if (dirtyWidth < 0) {
1658 dirtyX += dirtyWidth; 1226 dirtyX += dirtyWidth;
1659 dirtyWidth = -dirtyWidth; 1227 dirtyWidth = -dirtyWidth;
1660 } 1228 }
1661 1229
1662 if (dirtyHeight < 0) { 1230 if (dirtyHeight < 0) {
1663 dirtyY += dirtyHeight; 1231 dirtyY += dirtyHeight;
(...skipping 11 matching lines...) Expand all
1675 IntRect sourceRect(destRect); 1243 IntRect sourceRect(destRect);
1676 sourceRect.move(-destOffset); 1244 sourceRect.move(-destOffset);
1677 1245
1678 checkOverdraw(destRect, 0, CanvasRenderingContext2DState::NoImage, Untransfo rmedUnclippedFill); 1246 checkOverdraw(destRect, 0, CanvasRenderingContext2DState::NoImage, Untransfo rmedUnclippedFill);
1679 1247
1680 buffer->putByteArray(Unmultiplied, data->data()->data(), IntSize(data->width (), data->height()), sourceRect, IntPoint(destOffset)); 1248 buffer->putByteArray(Unmultiplied, data->data()->data(), IntSize(data->width (), data->height()), sourceRect, IntPoint(destOffset));
1681 1249
1682 didDraw(destRect); 1250 didDraw(destRect);
1683 } 1251 }
1684 1252
1685 String CanvasRenderingContext2D::font() const 1253 void BaseRenderingContext2D::inflateStrokeRect(FloatRect& rect) const
1686 {
1687 if (!state().hasRealizedFont())
1688 return defaultFont;
1689
1690 canvas()->document().canvasFontCache()->willUseCurrentFont();
1691 StringBuilder serializedFont;
1692 const FontDescription& fontDescription = state().font().fontDescription();
1693
1694 if (fontDescription.style() == FontStyleItalic)
1695 serializedFont.appendLiteral("italic ");
1696 if (fontDescription.weight() == FontWeightBold)
1697 serializedFont.appendLiteral("bold ");
1698 if (fontDescription.variant() == FontVariantSmallCaps)
1699 serializedFont.appendLiteral("small-caps ");
1700
1701 serializedFont.appendNumber(fontDescription.computedPixelSize());
1702 serializedFont.appendLiteral("px");
1703
1704 const FontFamily& firstFontFamily = fontDescription.family();
1705 for (const FontFamily* fontFamily = &firstFontFamily; fontFamily; fontFamily = fontFamily->next()) {
1706 if (fontFamily != &firstFontFamily)
1707 serializedFont.append(',');
1708
1709 // FIXME: We should append family directly to serializedFont rather than building a temporary string.
1710 String family = fontFamily->family();
1711 if (family.startsWith("-webkit-"))
1712 family = family.substring(8);
1713 if (family.contains(' '))
1714 family = "\"" + family + "\"";
1715
1716 serializedFont.append(' ');
1717 serializedFont.append(family);
1718 }
1719
1720 return serializedFont.toString();
1721 }
1722
1723 void CanvasRenderingContext2D::setFont(const String& newFont)
1724 {
1725 // The style resolution required for rendering text is not available in fram e-less documents.
1726 if (!canvas()->document().frame())
1727 return;
1728
1729 canvas()->document().updateLayoutTreeForNodeIfNeeded(canvas());
1730
1731 // The following early exit is dependent on the cache not being empty
1732 // because an empty cache may indicate that a style change has occured
1733 // which would require that the font be re-resolved. This check has to
1734 // come after the layout tree update to flush pending style changes.
1735 if (newFont == state().unparsedFont() && state().hasRealizedFont() && m_font sResolvedUsingCurrentStyle.size() > 0)
1736 return;
1737
1738 CanvasFontCache* canvasFontCache = canvas()->document().canvasFontCache();
1739
1740 // Map the <canvas> font into the text style. If the font uses keywords like larger/smaller, these will work
1741 // relative to the canvas.
1742 RefPtr<ComputedStyle> fontStyle;
1743 const ComputedStyle* computedStyle = canvas()->ensureComputedStyle();
1744 if (computedStyle) {
1745 HashMap<String, Font>::iterator i = m_fontsResolvedUsingCurrentStyle.fin d(newFont);
1746 if (i != m_fontsResolvedUsingCurrentStyle.end()) {
1747 ASSERT(m_fontLRUList.contains(newFont));
1748 m_fontLRUList.remove(newFont);
1749 m_fontLRUList.add(newFont);
1750 modifiableState().setFont(i->value, canvas()->document().styleEngine ().fontSelector());
1751 } else {
1752 MutableStylePropertySet* parsedStyle = canvasFontCache->parseFont(ne wFont);
1753 if (!parsedStyle)
1754 return;
1755 fontStyle = ComputedStyle::create();
1756 FontDescription elementFontDescription(computedStyle->fontDescriptio n());
1757 // Reset the computed size to avoid inheriting the zoom factor from the <canvas> element.
1758 elementFontDescription.setComputedSize(elementFontDescription.specif iedSize());
1759 fontStyle->setFontDescription(elementFontDescription);
1760 fontStyle->font().update(fontStyle->font().fontSelector());
1761 canvas()->document().ensureStyleResolver().computeFont(fontStyle.get (), *parsedStyle);
1762 m_fontsResolvedUsingCurrentStyle.add(newFont, fontStyle->font());
1763 ASSERT(!m_fontLRUList.contains(newFont));
1764 m_fontLRUList.add(newFont);
1765 pruneLocalFontCache(canvasFontCache->hardMaxFonts()); // hard limit
1766 schedulePruneLocalFontCacheIfNeeded(); // soft limit
1767 modifiableState().setFont(fontStyle->font(), canvas()->document().st yleEngine().fontSelector());
1768 }
1769 } else {
1770 Font resolvedFont;
1771 if (!canvasFontCache->getFontUsingDefaultStyle(newFont, resolvedFont))
1772 return;
1773 modifiableState().setFont(resolvedFont, canvas()->document().styleEngine ().fontSelector());
1774 }
1775
1776 // The parse succeeded.
1777 String newFontSafeCopy(newFont); // Create a string copy since newFont can b e deleted inside realizeSaves.
1778 modifiableState().setUnparsedFont(newFontSafeCopy);
1779 }
1780
1781 void CanvasRenderingContext2D::schedulePruneLocalFontCacheIfNeeded()
1782 {
1783 if (m_pruneLocalFontCacheScheduled)
1784 return;
1785 m_pruneLocalFontCacheScheduled = true;
1786 Platform::current()->currentThread()->addTaskObserver(this);
1787 }
1788
1789 void CanvasRenderingContext2D::didProcessTask()
1790 {
1791 // The rendering surface needs to be prepared now because it will be too lat e
1792 // to create a layer once we are in the paint invalidation phase.
1793 canvas()->prepareSurfaceForPaintingIfNeeded();
1794
1795 pruneLocalFontCache(canvas()->document().canvasFontCache()->maxFonts());
1796 m_pruneLocalFontCacheScheduled = false;
1797 Platform::current()->currentThread()->removeTaskObserver(this);
1798 }
1799
1800 void CanvasRenderingContext2D::pruneLocalFontCache(size_t targetSize)
1801 {
1802 if (targetSize == 0) {
1803 // Short cut: LRU does not matter when evicting everything
1804 m_fontLRUList.clear();
1805 m_fontsResolvedUsingCurrentStyle.clear();
1806 return;
1807 }
1808 while (m_fontLRUList.size() > targetSize) {
1809 m_fontsResolvedUsingCurrentStyle.remove(m_fontLRUList.first());
1810 m_fontLRUList.removeFirst();
1811 }
1812 }
1813
1814 void CanvasRenderingContext2D::styleDidChange(const ComputedStyle* oldStyle, con st ComputedStyle& newStyle)
1815 {
1816 if (oldStyle && oldStyle->font() == newStyle.font())
1817 return;
1818 pruneLocalFontCache(0);
1819 }
1820
1821 void CanvasRenderingContext2D::filterNeedsInvalidation()
1822 {
1823 state().clearResolvedFilter();
1824 }
1825
1826 String CanvasRenderingContext2D::textAlign() const
1827 {
1828 return textAlignName(state().textAlign());
1829 }
1830
1831 void CanvasRenderingContext2D::setTextAlign(const String& s)
1832 {
1833 TextAlign align;
1834 if (!parseTextAlign(s, align))
1835 return;
1836 if (state().textAlign() == align)
1837 return;
1838 modifiableState().setTextAlign(align);
1839 }
1840
1841 String CanvasRenderingContext2D::textBaseline() const
1842 {
1843 return textBaselineName(state().textBaseline());
1844 }
1845
1846 void CanvasRenderingContext2D::setTextBaseline(const String& s)
1847 {
1848 TextBaseline baseline;
1849 if (!parseTextBaseline(s, baseline))
1850 return;
1851 if (state().textBaseline() == baseline)
1852 return;
1853 modifiableState().setTextBaseline(baseline);
1854 }
1855
1856 static inline TextDirection toTextDirection(CanvasRenderingContext2DState::Direc tion direction, HTMLCanvasElement* canvas, const ComputedStyle** computedStyle = 0)
1857 {
1858 const ComputedStyle* style = (computedStyle || direction == CanvasRenderingC ontext2DState::DirectionInherit) ? canvas->ensureComputedStyle() : nullptr;
1859 if (computedStyle)
1860 *computedStyle = style;
1861 switch (direction) {
1862 case CanvasRenderingContext2DState::DirectionInherit:
1863 return style ? style->direction() : LTR;
1864 case CanvasRenderingContext2DState::DirectionRTL:
1865 return RTL;
1866 case CanvasRenderingContext2DState::DirectionLTR:
1867 return LTR;
1868 }
1869 ASSERT_NOT_REACHED();
1870 return LTR;
1871 }
1872
1873 String CanvasRenderingContext2D::direction() const
1874 {
1875 if (state().direction() == CanvasRenderingContext2DState::DirectionInherit)
1876 canvas()->document().updateLayoutTreeForNodeIfNeeded(canvas());
1877 return toTextDirection(state().direction(), canvas()) == RTL ? rtl : ltr;
1878 }
1879
1880 void CanvasRenderingContext2D::setDirection(const String& directionString)
1881 {
1882 CanvasRenderingContext2DState::Direction direction;
1883 if (directionString == inherit)
1884 direction = CanvasRenderingContext2DState::DirectionInherit;
1885 else if (directionString == rtl)
1886 direction = CanvasRenderingContext2DState::DirectionRTL;
1887 else if (directionString == ltr)
1888 direction = CanvasRenderingContext2DState::DirectionLTR;
1889 else
1890 return;
1891
1892 if (state().direction() == direction)
1893 return;
1894
1895 modifiableState().setDirection(direction);
1896 }
1897
1898 void CanvasRenderingContext2D::fillText(const String& text, double x, double y)
1899 {
1900 drawTextInternal(text, x, y, CanvasRenderingContext2DState::FillPaintType);
1901 }
1902
1903 void CanvasRenderingContext2D::fillText(const String& text, double x, double y, double maxWidth)
1904 {
1905 drawTextInternal(text, x, y, CanvasRenderingContext2DState::FillPaintType, & maxWidth);
1906 }
1907
1908 void CanvasRenderingContext2D::strokeText(const String& text, double x, double y )
1909 {
1910 drawTextInternal(text, x, y, CanvasRenderingContext2DState::StrokePaintType) ;
1911 }
1912
1913 void CanvasRenderingContext2D::strokeText(const String& text, double x, double y , double maxWidth)
1914 {
1915 drawTextInternal(text, x, y, CanvasRenderingContext2DState::StrokePaintType, &maxWidth);
1916 }
1917
1918 TextMetrics* CanvasRenderingContext2D::measureText(const String& text)
1919 {
1920 TextMetrics* metrics = TextMetrics::create();
1921
1922 // The style resolution required for rendering text is not available in fram e-less documents.
1923 if (!canvas()->document().frame())
1924 return metrics;
1925
1926 canvas()->document().updateLayoutTreeForNodeIfNeeded(canvas());
1927 const Font& font = accessFont();
1928
1929 TextDirection direction;
1930 if (state().direction() == CanvasRenderingContext2DState::DirectionInherit)
1931 direction = determineDirectionality(text);
1932 else
1933 direction = toTextDirection(state().direction(), canvas());
1934 TextRun textRun(text, 0, 0, TextRun::AllowTrailingExpansion | TextRun::Forbi dLeadingExpansion, direction, false);
1935 textRun.setNormalizeSpace(true);
1936 FloatRect textBounds = font.selectionRectForText(textRun, FloatPoint(), font .fontDescription().computedSize(), 0, -1, true);
1937
1938 // x direction
1939 metrics->setWidth(font.width(textRun));
1940 metrics->setActualBoundingBoxLeft(-textBounds.x());
1941 metrics->setActualBoundingBoxRight(textBounds.maxX());
1942
1943 // y direction
1944 const FontMetrics& fontMetrics = font.fontMetrics();
1945 const float ascent = fontMetrics.floatAscent();
1946 const float descent = fontMetrics.floatDescent();
1947 const float baselineY = getFontBaseline(fontMetrics);
1948
1949 metrics->setFontBoundingBoxAscent(ascent - baselineY);
1950 metrics->setFontBoundingBoxDescent(descent + baselineY);
1951 metrics->setActualBoundingBoxAscent(-textBounds.y() - baselineY);
1952 metrics->setActualBoundingBoxDescent(textBounds.maxY() + baselineY);
1953
1954 // Note : top/bottom and ascend/descend are currently the same, so there's n o difference
1955 // between the EM box's top and bottom and the font's ascend and desc end
1956 metrics->setEmHeightAscent(0);
1957 metrics->setEmHeightDescent(0);
1958
1959 metrics->setHangingBaseline(-0.8f * ascent + baselineY);
1960 metrics->setAlphabeticBaseline(baselineY);
1961 metrics->setIdeographicBaseline(descent + baselineY);
1962 return metrics;
1963 }
1964
1965 void CanvasRenderingContext2D::drawTextInternal(const String& text, double x, do uble y, CanvasRenderingContext2DState::PaintType paintType, double* maxWidth)
1966 {
1967 // The style resolution required for rendering text is not available in fram e-less documents.
1968 if (!canvas()->document().frame())
1969 return;
1970
1971 // accessFont needs the style to be up to date, but updating style can cause script to run,
1972 // (e.g. due to autofocus) which can free the canvas (set size to 0, for exa mple), so update
1973 // style before grabbing the drawingCanvas.
1974 canvas()->document().updateLayoutTreeForNodeIfNeeded(canvas());
1975
1976 SkCanvas* c = drawingCanvas();
1977 if (!c)
1978 return;
1979
1980 if (!std::isfinite(x) || !std::isfinite(y))
1981 return;
1982 if (maxWidth && (!std::isfinite(*maxWidth) || *maxWidth <= 0))
1983 return;
1984
1985 // Currently, SkPictureImageFilter does not support subpixel text anti-alias ing, which
1986 // is expected when !m_hasAlpha, so we need to fall out of display list mode when
1987 // drawing text to an opaque canvas
1988 // crbug.com/583809
1989 if (!m_hasAlpha && !isAccelerated())
1990 canvas()->disableDeferral(DisableDeferralReasonSubPixelTextAntiAliasingS upport);
1991
1992 const Font& font = accessFont();
1993 if (!font.primaryFont())
1994 return;
1995
1996 const FontMetrics& fontMetrics = font.fontMetrics();
1997
1998 // FIXME: Need to turn off font smoothing.
1999
2000 const ComputedStyle* computedStyle = 0;
2001 TextDirection direction = toTextDirection(state().direction(), canvas(), &co mputedStyle);
2002 bool isRTL = direction == RTL;
2003 bool override = computedStyle ? isOverride(computedStyle->unicodeBidi()) : f alse;
2004
2005 TextRun textRun(text, 0, 0, TextRun::AllowTrailingExpansion, direction, over ride);
2006 textRun.setNormalizeSpace(true);
2007 // Draw the item text at the correct point.
2008 FloatPoint location(x, y + getFontBaseline(fontMetrics));
2009 double fontWidth = font.width(textRun);
2010
2011 bool useMaxWidth = (maxWidth && *maxWidth < fontWidth);
2012 double width = useMaxWidth ? *maxWidth : fontWidth;
2013
2014 TextAlign align = state().textAlign();
2015 if (align == StartTextAlign)
2016 align = isRTL ? RightTextAlign : LeftTextAlign;
2017 else if (align == EndTextAlign)
2018 align = isRTL ? LeftTextAlign : RightTextAlign;
2019
2020 switch (align) {
2021 case CenterTextAlign:
2022 location.setX(location.x() - width / 2);
2023 break;
2024 case RightTextAlign:
2025 location.setX(location.x() - width);
2026 break;
2027 default:
2028 break;
2029 }
2030
2031 // The slop built in to this mask rect matches the heuristic used in FontCGW in.cpp for GDI text.
2032 TextRunPaintInfo textRunPaintInfo(textRun);
2033 textRunPaintInfo.bounds = FloatRect(location.x() - fontMetrics.height() / 2,
2034 location.y() - fontMetrics.ascent() - fontMetrics.lineGap(),
2035 width + fontMetrics.height(),
2036 fontMetrics.lineSpacing());
2037 if (paintType == CanvasRenderingContext2DState::StrokePaintType)
2038 inflateStrokeRect(textRunPaintInfo.bounds);
2039
2040 CanvasRenderingContext2DAutoRestoreSkCanvas stateRestorer(this);
2041 if (useMaxWidth) {
2042 drawingCanvas()->save();
2043 drawingCanvas()->translate(location.x(), location.y());
2044 // We draw when fontWidth is 0 so compositing operations (eg, a "copy" o p) still work.
2045 drawingCanvas()->scale((fontWidth > 0 ? (width / fontWidth) : 0), 1);
2046 location = FloatPoint();
2047 }
2048
2049 draw(
2050 [&font, this, &textRunPaintInfo, &location](SkCanvas* c, const SkPaint* paint) // draw lambda
2051 {
2052 font.drawBidiText(c, textRunPaintInfo, location, Font::UseFallbackIf FontNotReady, cDeviceScaleFactor, *paint);
2053 },
2054 [](const SkIRect& rect) // overdraw test lambda
2055 {
2056 return false;
2057 },
2058 textRunPaintInfo.bounds, paintType);
2059 }
2060
2061 void CanvasRenderingContext2D::inflateStrokeRect(FloatRect& rect) const
2062 { 1254 {
2063 // Fast approximation of the stroke's bounding rect. 1255 // Fast approximation of the stroke's bounding rect.
2064 // This yields a slightly oversized rect but is very fast 1256 // This yields a slightly oversized rect but is very fast
2065 // compared to Path::strokeBoundingRect(). 1257 // compared to Path::strokeBoundingRect().
2066 static const double root2 = sqrtf(2); 1258 static const double root2 = sqrtf(2);
2067 double delta = state().lineWidth() / 2; 1259 double delta = state().lineWidth() / 2;
2068 if (state().lineJoin() == MiterJoin) 1260 if (state().lineJoin() == MiterJoin)
2069 delta *= state().miterLimit(); 1261 delta *= state().miterLimit();
2070 else if (state().lineCap() == SquareCap) 1262 else if (state().lineCap() == SquareCap)
2071 delta *= root2; 1263 delta *= root2;
2072 1264
2073 rect.inflate(delta); 1265 rect.inflate(delta);
2074 } 1266 }
2075 1267
2076 const Font& CanvasRenderingContext2D::accessFont() 1268 bool BaseRenderingContext2D::imageSmoothingEnabled() const
2077 {
2078 if (!state().hasRealizedFont())
2079 setFont(state().unparsedFont());
2080 canvas()->document().canvasFontCache()->willUseCurrentFont();
2081 return state().font();
2082 }
2083
2084 int CanvasRenderingContext2D::getFontBaseline(const FontMetrics& fontMetrics) co nst
2085 {
2086 switch (state().textBaseline()) {
2087 case TopTextBaseline:
2088 return fontMetrics.ascent();
2089 case HangingTextBaseline:
2090 // According to http://wiki.apache.org/xmlgraphics-fop/LineLayout/Alignm entHandling
2091 // "FOP (Formatting Objects Processor) puts the hanging baseline at 80% of the ascender height"
2092 return (fontMetrics.ascent() * 4) / 5;
2093 case BottomTextBaseline:
2094 case IdeographicTextBaseline:
2095 return -fontMetrics.descent();
2096 case MiddleTextBaseline:
2097 return -fontMetrics.descent() + fontMetrics.height() / 2;
2098 case AlphabeticTextBaseline:
2099 default:
2100 // Do nothing.
2101 break;
2102 }
2103 return 0;
2104 }
2105
2106 void CanvasRenderingContext2D::setIsHidden(bool hidden)
2107 {
2108 if (canvas()->hasImageBuffer())
2109 canvas()->buffer()->setIsHidden(hidden);
2110 if (hidden) {
2111 pruneLocalFontCache(0);
2112 }
2113 }
2114
2115 bool CanvasRenderingContext2D::isTransformInvertible() const
2116 {
2117 return state().isTransformInvertible();
2118 }
2119
2120 WebLayer* CanvasRenderingContext2D::platformLayer() const
2121 {
2122 return canvas()->buffer() ? canvas()->buffer()->platformLayer() : 0;
2123 }
2124
2125 bool CanvasRenderingContext2D::imageSmoothingEnabled() const
2126 { 1269 {
2127 return state().imageSmoothingEnabled(); 1270 return state().imageSmoothingEnabled();
2128 } 1271 }
2129 1272
2130 void CanvasRenderingContext2D::setImageSmoothingEnabled(bool enabled) 1273 void BaseRenderingContext2D::setImageSmoothingEnabled(bool enabled)
2131 { 1274 {
2132 if (enabled == state().imageSmoothingEnabled()) 1275 if (enabled == state().imageSmoothingEnabled())
2133 return; 1276 return;
2134 1277
2135 modifiableState().setImageSmoothingEnabled(enabled); 1278 modifiableState().setImageSmoothingEnabled(enabled);
2136 } 1279 }
2137 1280
2138 String CanvasRenderingContext2D::imageSmoothingQuality() const 1281 String BaseRenderingContext2D::imageSmoothingQuality() const
2139 { 1282 {
2140 return state().imageSmoothingQuality(); 1283 return state().imageSmoothingQuality();
2141 } 1284 }
2142 1285
2143 void CanvasRenderingContext2D::setImageSmoothingQuality(const String& quality) 1286 void BaseRenderingContext2D::setImageSmoothingQuality(const String& quality)
2144 { 1287 {
2145 if (quality == state().imageSmoothingQuality()) 1288 if (quality == state().imageSmoothingQuality())
2146 return; 1289 return;
2147 1290
2148 modifiableState().setImageSmoothingQuality(quality); 1291 modifiableState().setImageSmoothingQuality(quality);
2149 } 1292 }
2150 1293
2151 void CanvasRenderingContext2D::getContextAttributes(Canvas2DContextAttributes& a ttrs) const 1294 void BaseRenderingContext2D::checkOverdraw(const SkRect& rect, const SkPaint* pa int, CanvasRenderingContext2DState::ImageType imageType, DrawType drawType)
2152 {
2153 attrs.setAlpha(m_hasAlpha);
2154 }
2155
2156 void CanvasRenderingContext2D::drawFocusIfNeeded(Element* element)
2157 {
2158 drawFocusIfNeededInternal(m_path, element);
2159 }
2160
2161 void CanvasRenderingContext2D::drawFocusIfNeeded(Path2D* path2d, Element* elemen t)
2162 {
2163 drawFocusIfNeededInternal(path2d->path(), element);
2164 }
2165
2166 void CanvasRenderingContext2D::drawFocusIfNeededInternal(const Path& path, Eleme nt* element)
2167 {
2168 if (!focusRingCallIsValid(path, element))
2169 return;
2170
2171 // Note: we need to check document->focusedElement() rather than just callin g
2172 // element->focused(), because element->focused() isn't updated until after
2173 // focus events fire.
2174 if (element->document().focusedElement() == element) {
2175 scrollPathIntoViewInternal(path);
2176 drawFocusRing(path);
2177 }
2178
2179 // Update its accessible bounds whether it's focused or not.
2180 updateElementAccessibility(path, element);
2181 }
2182
2183 bool CanvasRenderingContext2D::focusRingCallIsValid(const Path& path, Element* e lement)
2184 {
2185 ASSERT(element);
2186 if (!state().isTransformInvertible())
2187 return false;
2188 if (path.isEmpty())
2189 return false;
2190 if (!element->isDescendantOf(canvas()))
2191 return false;
2192
2193 return true;
2194 }
2195
2196 void CanvasRenderingContext2D::drawFocusRing(const Path& path)
2197 {
2198 if (!drawingCanvas())
2199 return;
2200
2201 SkColor color = LayoutTheme::theme().focusRingColor().rgb();
2202 const int focusRingWidth = 5;
2203
2204 drawPlatformFocusRing(path.skPath(), drawingCanvas(), color, focusRingWidth) ;
2205
2206 // We need to add focusRingWidth to dirtyRect.
2207 StrokeData strokeData;
2208 strokeData.setThickness(focusRingWidth);
2209
2210 SkIRect dirtyRect;
2211 if (!computeDirtyRect(path.strokeBoundingRect(strokeData), &dirtyRect))
2212 return;
2213
2214 didDraw(dirtyRect);
2215 }
2216
2217 void CanvasRenderingContext2D::updateElementAccessibility(const Path& path, Elem ent* element)
2218 {
2219 element->document().updateLayoutIgnorePendingStylesheets();
2220 AXObjectCache* axObjectCache = element->document().existingAXObjectCache();
2221 LayoutBoxModelObject* lbmo = canvas()->layoutBoxModelObject();
2222 LayoutObject* renderer = canvas()->layoutObject();
2223 if (!axObjectCache || !lbmo || !renderer)
2224 return;
2225
2226 // Get the transformed path.
2227 Path transformedPath = path;
2228 transformedPath.transform(state().transform());
2229
2230 // Offset by the canvas rect, taking border and padding into account.
2231 IntRect canvasRect = renderer->absoluteBoundingBoxRect();
2232 canvasRect.move(lbmo->borderLeft() + lbmo->paddingLeft(), lbmo->borderTop() + lbmo->paddingTop());
2233 LayoutRect elementRect = enclosingLayoutRect(transformedPath.boundingRect()) ;
2234 elementRect.moveBy(canvasRect.location());
2235 axObjectCache->setCanvasObjectBounds(element, elementRect);
2236 }
2237
2238 void CanvasRenderingContext2D::addHitRegion(const HitRegionOptions& options, Exc eptionState& exceptionState)
2239 {
2240 if (options.id().isEmpty() && !options.control()) {
2241 exceptionState.throwDOMException(NotSupportedError, "Both id and control are null.");
2242 return;
2243 }
2244
2245 if (options.control() && !canvas()->isSupportedInteractiveCanvasFallback(*op tions.control())) {
2246 exceptionState.throwDOMException(NotSupportedError, "The control is neit her null nor a supported interactive canvas fallback element.");
2247 return;
2248 }
2249
2250 Path hitRegionPath = options.hasPath() ? options.path()->path() : m_path;
2251
2252 SkCanvas* c = drawingCanvas();
2253
2254 if (hitRegionPath.isEmpty() || !c || !state().isTransformInvertible()
2255 || !c->getClipDeviceBounds(0)) {
2256 exceptionState.throwDOMException(NotSupportedError, "The specified path has no pixels.");
2257 return;
2258 }
2259
2260 hitRegionPath.transform(state().transform());
2261
2262 if (state().hasClip()) {
2263 hitRegionPath.intersectPath(state().getCurrentClipPath());
2264 if (hitRegionPath.isEmpty())
2265 exceptionState.throwDOMException(NotSupportedError, "The specified p ath has no pixels.");
2266 }
2267
2268 if (!m_hitRegionManager)
2269 m_hitRegionManager = HitRegionManager::create();
2270
2271 // Remove previous region (with id or control)
2272 m_hitRegionManager->removeHitRegionById(options.id());
2273 m_hitRegionManager->removeHitRegionByControl(options.control().get());
2274
2275 RefPtrWillBeRawPtr<HitRegion> hitRegion = HitRegion::create(hitRegionPath, o ptions);
2276 Element* element = hitRegion->control();
2277 if (element && element->isDescendantOf(canvas()))
2278 updateElementAccessibility(hitRegion->path(), hitRegion->control());
2279 m_hitRegionManager->addHitRegion(hitRegion.release());
2280 }
2281
2282 void CanvasRenderingContext2D::removeHitRegion(const String& id)
2283 {
2284 if (m_hitRegionManager)
2285 m_hitRegionManager->removeHitRegionById(id);
2286 }
2287
2288 void CanvasRenderingContext2D::clearHitRegions()
2289 {
2290 if (m_hitRegionManager)
2291 m_hitRegionManager->removeAllHitRegions();
2292 }
2293
2294 HitRegion* CanvasRenderingContext2D::hitRegionAtPoint(const FloatPoint& point)
2295 {
2296 if (m_hitRegionManager)
2297 return m_hitRegionManager->getHitRegionAtPoint(point);
2298
2299 return nullptr;
2300 }
2301
2302 unsigned CanvasRenderingContext2D::hitRegionsCount() const
2303 {
2304 if (m_hitRegionManager)
2305 return m_hitRegionManager->getHitRegionsCount();
2306
2307 return 0;
2308 }
2309
2310 void CanvasRenderingContext2D::checkOverdraw(const SkRect& rect, const SkPaint* paint, CanvasRenderingContext2DState::ImageType imageType, DrawType drawType)
2311 { 1295 {
2312 SkCanvas* c = drawingCanvas(); 1296 SkCanvas* c = drawingCanvas();
2313 if (!c || !canvas()->buffer()->isRecording()) 1297 if (!c || !imageBuffer()->isRecording())
2314 return; 1298 return;
2315 1299
2316 SkRect deviceRect; 1300 SkRect deviceRect;
2317 if (drawType == UntransformedUnclippedFill) { 1301 if (drawType == UntransformedUnclippedFill) {
2318 deviceRect = rect; 1302 deviceRect = rect;
2319 } else { 1303 } else {
2320 ASSERT(drawType == ClipFill); 1304 ASSERT(drawType == ClipFill);
2321 if (state().hasComplexClip()) 1305 if (state().hasComplexClip())
2322 return; 1306 return;
2323 1307
(...skipping 26 matching lines...) Expand all
2350 return; 1334 return;
2351 } 1335 }
2352 } 1336 }
2353 1337
2354 alpha = paint->getAlpha(); 1338 alpha = paint->getAlpha();
2355 1339
2356 if (isSourceOver && imageType == CanvasRenderingContext2DState::NoImage) { 1340 if (isSourceOver && imageType == CanvasRenderingContext2DState::NoImage) {
2357 SkShader* shader = paint->getShader(); 1341 SkShader* shader = paint->getShader();
2358 if (shader) { 1342 if (shader) {
2359 if (shader->isOpaque() && alpha == 0xFF) 1343 if (shader->isOpaque() && alpha == 0xFF)
2360 canvas()->buffer()->willOverwriteCanvas(); 1344 imageBuffer()->willOverwriteCanvas();
2361 return; 1345 return;
2362 } 1346 }
2363 } 1347 }
2364 } 1348 }
2365 1349
2366 if (isSourceOver) { 1350 if (isSourceOver) {
2367 // With source over, we need to certify that alpha == 0xFF for all pixel s 1351 // With source over, we need to certify that alpha == 0xFF for all pixel s
2368 if (imageType == CanvasRenderingContext2DState::NonOpaqueImage) 1352 if (imageType == CanvasRenderingContext2DState::NonOpaqueImage)
2369 return; 1353 return;
2370 if (alpha < 0xFF) 1354 if (alpha < 0xFF)
2371 return; 1355 return;
2372 } 1356 }
2373 1357
2374 canvas()->buffer()->willOverwriteCanvas(); 1358 imageBuffer()->willOverwriteCanvas();
1359 }
1360
1361 DEFINE_TRACE(BaseRenderingContext2D)
1362 {
1363 visitor->trace(m_stateStack);
2375 } 1364 }
2376 1365
2377 } // namespace blink 1366 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698