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

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

Powered by Google App Engine
This is Rietveld 408576698