| 1 | /* |
| 2 | * Copyright (C) 2006, 2007, 2009, 2010, 2011, 2012, 2017 Apple Inc. All rights reserved. |
| 3 | * |
| 4 | * Redistribution and use in source and binary forms, with or without |
| 5 | * modification, are permitted provided that the following conditions |
| 6 | * are met: |
| 7 | * 1. Redistributions of source code must retain the above copyright |
| 8 | * notice, this list of conditions and the following disclaimer. |
| 9 | * 2. Redistributions in binary form must reproduce the above copyright |
| 10 | * notice, this list of conditions and the following disclaimer in the |
| 11 | * documentation and/or other materials provided with the distribution. |
| 12 | * |
| 13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
| 14 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| 16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
| 17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| 18 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| 19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| 20 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| 21 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 24 | */ |
| 25 | |
| 26 | #pragma once |
| 27 | |
| 28 | #include "AffineTransform.h" |
| 29 | #include "CanvasDirection.h" |
| 30 | #include "CanvasFillRule.h" |
| 31 | #include "CanvasLineCap.h" |
| 32 | #include "CanvasLineJoin.h" |
| 33 | #include "CanvasPath.h" |
| 34 | #include "CanvasRenderingContext.h" |
| 35 | #include "CanvasStyle.h" |
| 36 | #include "CanvasTextAlign.h" |
| 37 | #include "CanvasTextBaseline.h" |
| 38 | #include "Color.h" |
| 39 | #include "FloatSize.h" |
| 40 | #include "FontCascade.h" |
| 41 | #include "FontSelectorClient.h" |
| 42 | #include "GraphicsContext.h" |
| 43 | #include "GraphicsTypes.h" |
| 44 | #include "ImageBuffer.h" |
| 45 | #include "ImageSmoothingQuality.h" |
| 46 | #include "Path.h" |
| 47 | #include "PlatformLayer.h" |
| 48 | #include <wtf/Vector.h> |
| 49 | #include <wtf/text/WTFString.h> |
| 50 | |
| 51 | namespace WebCore { |
| 52 | |
| 53 | class TypedOMCSSImageValue; |
| 54 | class CachedImage; |
| 55 | class CanvasBase; |
| 56 | class CanvasGradient; |
| 57 | class CanvasPattern; |
| 58 | class DOMMatrix; |
| 59 | class FloatRect; |
| 60 | class GraphicsContext; |
| 61 | class HTMLImageElement; |
| 62 | class HTMLVideoElement; |
| 63 | class ImageBitmap; |
| 64 | class ImageData; |
| 65 | class Path2D; |
| 66 | class RenderStyle; |
| 67 | class RenderObject; |
| 68 | class TextMetrics; |
| 69 | |
| 70 | struct DOMMatrix2DInit; |
| 71 | |
| 72 | #if ENABLE(VIDEO) && ENABLE(CSS_TYPED_OM) |
| 73 | using CanvasImageSource = Variant<RefPtr<HTMLImageElement>, RefPtr<HTMLVideoElement>, RefPtr<HTMLCanvasElement>, RefPtr<ImageBitmap>, RefPtr<TypedOMCSSImageValue>>; |
| 74 | #elif ENABLE(VIDEO) |
| 75 | using CanvasImageSource = Variant<RefPtr<HTMLImageElement>, RefPtr<HTMLVideoElement>, RefPtr<HTMLCanvasElement>, RefPtr<ImageBitmap>>; |
| 76 | #else |
| 77 | using CanvasImageSource = Variant<RefPtr<HTMLImageElement>, RefPtr<HTMLCanvasElement>, RefPtr<ImageBitmap>>; |
| 78 | #endif |
| 79 | |
| 80 | class CanvasRenderingContext2DBase : public CanvasRenderingContext, public CanvasPath { |
| 81 | WTF_MAKE_ISO_ALLOCATED(CanvasRenderingContext2DBase); |
| 82 | public: |
| 83 | CanvasRenderingContext2DBase(CanvasBase&, bool usesCSSCompatibilityParseMode, bool usesDashboardCompatibilityMode); |
| 84 | virtual ~CanvasRenderingContext2DBase(); |
| 85 | |
| 86 | float lineWidth() const; |
| 87 | void setLineWidth(float); |
| 88 | |
| 89 | CanvasLineCap lineCap() const; |
| 90 | void setLineCap(CanvasLineCap); |
| 91 | void setLineCap(const String&); |
| 92 | |
| 93 | CanvasLineJoin lineJoin() const; |
| 94 | void setLineJoin(CanvasLineJoin); |
| 95 | void setLineJoin(const String&); |
| 96 | |
| 97 | float miterLimit() const; |
| 98 | void setMiterLimit(float); |
| 99 | |
| 100 | const Vector<float>& getLineDash() const; |
| 101 | void setLineDash(const Vector<float>&); |
| 102 | const Vector<float>& webkitLineDash() const { return getLineDash(); } |
| 103 | void setWebkitLineDash(const Vector<float>&); |
| 104 | |
| 105 | float lineDashOffset() const; |
| 106 | void setLineDashOffset(float); |
| 107 | |
| 108 | float shadowOffsetX() const; |
| 109 | void setShadowOffsetX(float); |
| 110 | |
| 111 | float shadowOffsetY() const; |
| 112 | void setShadowOffsetY(float); |
| 113 | |
| 114 | float shadowBlur() const; |
| 115 | void setShadowBlur(float); |
| 116 | |
| 117 | String shadowColor() const; |
| 118 | void setShadowColor(const String&); |
| 119 | |
| 120 | float globalAlpha() const; |
| 121 | void setGlobalAlpha(float); |
| 122 | |
| 123 | String globalCompositeOperation() const; |
| 124 | void setGlobalCompositeOperation(const String&); |
| 125 | |
| 126 | void save() { ++m_unrealizedSaveCount; } |
| 127 | void restore(); |
| 128 | |
| 129 | void scale(float sx, float sy); |
| 130 | void rotate(float angleInRadians); |
| 131 | void translate(float tx, float ty); |
| 132 | void transform(float m11, float m12, float m21, float m22, float dx, float dy); |
| 133 | |
| 134 | Ref<DOMMatrix> getTransform() const; |
| 135 | void setTransform(float m11, float m12, float m21, float m22, float dx, float dy); |
| 136 | ExceptionOr<void> setTransform(DOMMatrix2DInit&&); |
| 137 | void resetTransform(); |
| 138 | |
| 139 | void setStrokeColor(const String& color, Optional<float> alpha = WTF::nullopt); |
| 140 | void setStrokeColor(float grayLevel, float alpha = 1.0); |
| 141 | void setStrokeColor(float r, float g, float b, float a); |
| 142 | void setStrokeColor(float c, float m, float y, float k, float a); |
| 143 | |
| 144 | void setFillColor(const String& color, Optional<float> alpha = WTF::nullopt); |
| 145 | void setFillColor(float grayLevel, float alpha = 1.0f); |
| 146 | void setFillColor(float r, float g, float b, float a); |
| 147 | void setFillColor(float c, float m, float y, float k, float a); |
| 148 | |
| 149 | void beginPath(); |
| 150 | |
| 151 | void fill(CanvasFillRule = CanvasFillRule::Nonzero); |
| 152 | void stroke(); |
| 153 | void clip(CanvasFillRule = CanvasFillRule::Nonzero); |
| 154 | |
| 155 | void fill(Path2D&, CanvasFillRule = CanvasFillRule::Nonzero); |
| 156 | void stroke(Path2D&); |
| 157 | void clip(Path2D&, CanvasFillRule = CanvasFillRule::Nonzero); |
| 158 | |
| 159 | bool isPointInPath(float x, float y, CanvasFillRule = CanvasFillRule::Nonzero); |
| 160 | bool isPointInStroke(float x, float y); |
| 161 | |
| 162 | bool isPointInPath(Path2D&, float x, float y, CanvasFillRule = CanvasFillRule::Nonzero); |
| 163 | bool isPointInStroke(Path2D&, float x, float y); |
| 164 | |
| 165 | void clearRect(float x, float y, float width, float height); |
| 166 | void fillRect(float x, float y, float width, float height); |
| 167 | void strokeRect(float x, float y, float width, float height); |
| 168 | |
| 169 | void setShadow(float width, float height, float blur, const String& color = String(), Optional<float> alpha = WTF::nullopt); |
| 170 | void setShadow(float width, float height, float blur, float grayLevel, float alpha = 1.0); |
| 171 | void setShadow(float width, float height, float blur, float r, float g, float b, float a); |
| 172 | void setShadow(float width, float height, float blur, float c, float m, float y, float k, float a); |
| 173 | |
| 174 | void clearShadow(); |
| 175 | |
| 176 | ExceptionOr<void> drawImage(CanvasImageSource&&, float dx, float dy); |
| 177 | ExceptionOr<void> drawImage(CanvasImageSource&&, float dx, float dy, float dw, float dh); |
| 178 | ExceptionOr<void> drawImage(CanvasImageSource&&, float sx, float sy, float sw, float sh, float dx, float dy, float dw, float dh); |
| 179 | |
| 180 | void drawImageFromRect(HTMLImageElement&, float sx = 0, float sy = 0, float sw = 0, float sh = 0, float dx = 0, float dy = 0, float dw = 0, float dh = 0, const String& compositeOperation = emptyString()); |
| 181 | |
| 182 | using Style = Variant<String, RefPtr<CanvasGradient>, RefPtr<CanvasPattern>>; |
| 183 | Style strokeStyle() const; |
| 184 | void setStrokeStyle(Style&&); |
| 185 | Style fillStyle() const; |
| 186 | void setFillStyle(Style&&); |
| 187 | |
| 188 | ExceptionOr<Ref<CanvasGradient>> createLinearGradient(float x0, float y0, float x1, float y1); |
| 189 | ExceptionOr<Ref<CanvasGradient>> createRadialGradient(float x0, float y0, float r0, float x1, float y1, float r1); |
| 190 | ExceptionOr<RefPtr<CanvasPattern>> createPattern(CanvasImageSource&&, const String& repetition); |
| 191 | |
| 192 | RefPtr<ImageData> createImageData(ImageData&) const; |
| 193 | ExceptionOr<RefPtr<ImageData>> createImageData(float width, float height) const; |
| 194 | ExceptionOr<RefPtr<ImageData>> getImageData(float sx, float sy, float sw, float sh) const; |
| 195 | void putImageData(ImageData&, float dx, float dy); |
| 196 | void putImageData(ImageData&, float dx, float dy, float dirtyX, float dirtyY, float dirtyWidth, float dirtyHeight); |
| 197 | |
| 198 | float webkitBackingStorePixelRatio() const { return 1; } |
| 199 | |
| 200 | void reset(); |
| 201 | |
| 202 | LineCap getLineCap() const { return state().lineCap; } |
| 203 | LineJoin getLineJoin() const { return state().lineJoin; } |
| 204 | |
| 205 | bool imageSmoothingEnabled() const; |
| 206 | void setImageSmoothingEnabled(bool); |
| 207 | |
| 208 | ImageSmoothingQuality imageSmoothingQuality() const; |
| 209 | void setImageSmoothingQuality(ImageSmoothingQuality); |
| 210 | |
| 211 | void setPath(Path2D&); |
| 212 | Ref<Path2D> getPath() const; |
| 213 | |
| 214 | bool usesDisplayListDrawing() const { return m_usesDisplayListDrawing; }; |
| 215 | void setUsesDisplayListDrawing(bool flag) { m_usesDisplayListDrawing = flag; }; |
| 216 | |
| 217 | bool tracksDisplayListReplay() const { return m_tracksDisplayListReplay; } |
| 218 | void setTracksDisplayListReplay(bool); |
| 219 | |
| 220 | String displayListAsText(DisplayList::AsTextFlags) const; |
| 221 | String replayDisplayListAsText(DisplayList::AsTextFlags) const; |
| 222 | |
| 223 | using Direction = CanvasDirection; |
| 224 | |
| 225 | class FontProxy : public FontSelectorClient { |
| 226 | public: |
| 227 | FontProxy() = default; |
| 228 | virtual ~FontProxy(); |
| 229 | FontProxy(const FontProxy&); |
| 230 | FontProxy& operator=(const FontProxy&); |
| 231 | |
| 232 | bool realized() const { return m_font.fontSelector(); } |
| 233 | void initialize(FontSelector&, const RenderStyle&); |
| 234 | const FontMetrics& fontMetrics() const; |
| 235 | const FontCascadeDescription& fontDescription() const; |
| 236 | float width(const TextRun&, GlyphOverflow* = 0) const; |
| 237 | void drawBidiText(GraphicsContext&, const TextRun&, const FloatPoint&, FontCascade::CustomFontNotReadyAction) const; |
| 238 | |
| 239 | private: |
| 240 | void update(FontSelector&); |
| 241 | void fontsNeedUpdate(FontSelector&) override; |
| 242 | |
| 243 | FontCascade m_font; |
| 244 | }; |
| 245 | |
| 246 | struct State final { |
| 247 | State(); |
| 248 | |
| 249 | State(const State&); |
| 250 | State& operator=(const State&); |
| 251 | |
| 252 | String unparsedStrokeColor; |
| 253 | String unparsedFillColor; |
| 254 | CanvasStyle strokeStyle; |
| 255 | CanvasStyle fillStyle; |
| 256 | float lineWidth; |
| 257 | LineCap lineCap; |
| 258 | LineJoin lineJoin; |
| 259 | float miterLimit; |
| 260 | FloatSize shadowOffset; |
| 261 | float shadowBlur; |
| 262 | Color shadowColor; |
| 263 | float globalAlpha; |
| 264 | CompositeOperator globalComposite; |
| 265 | BlendMode globalBlend; |
| 266 | AffineTransform transform; |
| 267 | bool hasInvertibleTransform; |
| 268 | Vector<float> lineDash; |
| 269 | float lineDashOffset; |
| 270 | bool imageSmoothingEnabled; |
| 271 | ImageSmoothingQuality imageSmoothingQuality; |
| 272 | |
| 273 | // Text state. |
| 274 | TextAlign textAlign; |
| 275 | TextBaseline textBaseline; |
| 276 | Direction direction; |
| 277 | |
| 278 | String unparsedFont; |
| 279 | FontProxy font; |
| 280 | }; |
| 281 | |
| 282 | const State& state() const { return m_stateStack.last(); } |
| 283 | const Vector<State, 1>& stateStack(); |
| 284 | |
| 285 | protected: |
| 286 | static const int DefaultFontSize; |
| 287 | static const char* const DefaultFontFamily; |
| 288 | static const char* const DefaultFont; |
| 289 | |
| 290 | enum CanvasDidDrawOption { |
| 291 | CanvasDidDrawApplyNone = 0, |
| 292 | CanvasDidDrawApplyTransform = 1, |
| 293 | CanvasDidDrawApplyShadow = 1 << 1, |
| 294 | CanvasDidDrawApplyClip = 1 << 2, |
| 295 | CanvasDidDrawApplyAll = 0xffffffff |
| 296 | }; |
| 297 | |
| 298 | bool isFullCanvasCompositeMode(CompositeOperator); |
| 299 | |
| 300 | State& modifiableState() { ASSERT(!m_unrealizedSaveCount || m_stateStack.size() >= MaxSaveCount); return m_stateStack.last(); } |
| 301 | |
| 302 | void applyLineDash() const; |
| 303 | void setShadow(const FloatSize& offset, float blur, const Color&); |
| 304 | void applyShadow(); |
| 305 | bool shouldDrawShadows() const; |
| 306 | |
| 307 | void didDraw(const FloatRect&, unsigned options = CanvasDidDrawApplyAll); |
| 308 | void didDrawEntireCanvas(); |
| 309 | |
| 310 | void paintRenderingResultsToCanvas() override; |
| 311 | |
| 312 | GraphicsContext* drawingContext() const; |
| 313 | |
| 314 | void unwindStateStack(); |
| 315 | void realizeSaves(); |
| 316 | void realizeSavesLoop(); |
| 317 | |
| 318 | void applyStrokePattern(); |
| 319 | void applyFillPattern(); |
| 320 | |
| 321 | void setStrokeStyle(CanvasStyle); |
| 322 | void setFillStyle(CanvasStyle); |
| 323 | |
| 324 | ExceptionOr<RefPtr<CanvasPattern>> createPattern(HTMLImageElement&, bool repeatX, bool repeatY); |
| 325 | ExceptionOr<RefPtr<CanvasPattern>> createPattern(CanvasBase&, bool repeatX, bool repeatY); |
| 326 | #if ENABLE(VIDEO) |
| 327 | ExceptionOr<RefPtr<CanvasPattern>> createPattern(HTMLVideoElement&, bool repeatX, bool repeatY); |
| 328 | #endif |
| 329 | ExceptionOr<RefPtr<CanvasPattern>> createPattern(ImageBitmap&, bool repeatX, bool repeatY); |
| 330 | #if ENABLE(CSS_TYPED_OM) |
| 331 | ExceptionOr<RefPtr<CanvasPattern>> createPattern(TypedOMCSSImageValue&, bool repeatX, bool repeatY); |
| 332 | #endif |
| 333 | |
| 334 | ExceptionOr<void> drawImage(HTMLImageElement&, const FloatRect& srcRect, const FloatRect& dstRect); |
| 335 | ExceptionOr<void> drawImage(HTMLImageElement&, const FloatRect& srcRect, const FloatRect& dstRect, const CompositeOperator&, const BlendMode&); |
| 336 | ExceptionOr<void> drawImage(HTMLCanvasElement&, const FloatRect& srcRect, const FloatRect& dstRect); |
| 337 | ExceptionOr<void> drawImage(Document&, CachedImage*, const RenderObject*, const FloatRect& imageRect, const FloatRect& srcRect, const FloatRect& dstRect, const CompositeOperator&, const BlendMode&); |
| 338 | #if ENABLE(VIDEO) |
| 339 | ExceptionOr<void> drawImage(HTMLVideoElement&, const FloatRect& srcRect, const FloatRect& dstRect); |
| 340 | #endif |
| 341 | #if ENABLE(CSS_TYPED_OM) |
| 342 | ExceptionOr<void> drawImage(TypedOMCSSImageValue&, const FloatRect& srcRect, const FloatRect& dstRect); |
| 343 | #endif |
| 344 | ExceptionOr<void> drawImage(ImageBitmap&, const FloatRect& srcRect, const FloatRect& dstRect); |
| 345 | |
| 346 | void beginCompositeLayer(); |
| 347 | void endCompositeLayer(); |
| 348 | |
| 349 | void fillInternal(const Path&, CanvasFillRule); |
| 350 | void strokeInternal(const Path&); |
| 351 | void clipInternal(const Path&, CanvasFillRule); |
| 352 | |
| 353 | bool isPointInPathInternal(const Path&, float x, float y, CanvasFillRule); |
| 354 | bool isPointInStrokeInternal(const Path&, float x, float y); |
| 355 | |
| 356 | void clearCanvas(); |
| 357 | Path transformAreaToDevice(const Path&) const; |
| 358 | Path transformAreaToDevice(const FloatRect&) const; |
| 359 | bool rectContainsCanvas(const FloatRect&) const; |
| 360 | |
| 361 | template<class T> IntRect calculateCompositingBufferRect(const T&, IntSize*); |
| 362 | std::unique_ptr<ImageBuffer> createCompositingBuffer(const IntRect&); |
| 363 | void compositeBuffer(ImageBuffer&, const IntRect&, CompositeOperator); |
| 364 | |
| 365 | void inflateStrokeRect(FloatRect&) const; |
| 366 | |
| 367 | template<class T> void fullCanvasCompositedDrawImage(T&, const FloatRect&, const FloatRect&, CompositeOperator); |
| 368 | |
| 369 | void prepareGradientForDashboard(CanvasGradient&) const; |
| 370 | |
| 371 | ExceptionOr<RefPtr<ImageData>> getImageData(ImageBuffer::CoordinateSystem, float sx, float sy, float sw, float sh) const; |
| 372 | void putImageData(ImageData&, ImageBuffer::CoordinateSystem, float dx, float dy, float dirtyX, float dirtyY, float dirtyWidth, float dirtyHeight); |
| 373 | |
| 374 | bool isAccelerated() const override; |
| 375 | |
| 376 | bool hasInvertibleTransform() const override { return state().hasInvertibleTransform; } |
| 377 | |
| 378 | #if ENABLE(ACCELERATED_2D_CANVAS) |
| 379 | PlatformLayer* platformLayer() const override; |
| 380 | #endif |
| 381 | |
| 382 | void clearPathForDashboardBackwardCompatibilityMode(); |
| 383 | |
| 384 | static const unsigned MaxSaveCount = 1024 * 16; |
| 385 | Vector<State, 1> m_stateStack; |
| 386 | unsigned m_unrealizedSaveCount { 0 }; |
| 387 | bool m_usesCSSCompatibilityParseMode; |
| 388 | #if ENABLE(DASHBOARD_SUPPORT) |
| 389 | bool m_usesDashboardCompatibilityMode; |
| 390 | #endif |
| 391 | bool m_usesDisplayListDrawing { false }; |
| 392 | bool m_tracksDisplayListReplay { false }; |
| 393 | mutable std::unique_ptr<struct DisplayListDrawingContext> m_recordingContext; |
| 394 | }; |
| 395 | |
| 396 | } // namespace WebCore |
| 397 | |
| 398 | |