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