Florin Malita | b341810 | 2020-10-15 18:10:29 -0400 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2016 Google Inc. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license that can be |
| 5 | * found in the LICENSE file. |
| 6 | */ |
| 7 | |
| 8 | #ifndef SkSVGRenderContext_DEFINED |
| 9 | #define SkSVGRenderContext_DEFINED |
| 10 | |
Florin Malita | 7006e15 | 2020-11-10 15:24:59 -0500 | [diff] [blame] | 11 | #include "include/core/SkFontMgr.h" |
Florin Malita | 3010f3d | 2021-04-30 10:48:42 -0400 | [diff] [blame] | 12 | #include "include/core/SkM44.h" |
Florin Malita | b341810 | 2020-10-15 18:10:29 -0400 | [diff] [blame] | 13 | #include "include/core/SkPaint.h" |
| 14 | #include "include/core/SkPath.h" |
| 15 | #include "include/core/SkRect.h" |
| 16 | #include "include/core/SkSize.h" |
| 17 | #include "include/core/SkTypes.h" |
Florin Malita | 24df67d | 2021-01-26 18:45:34 -0500 | [diff] [blame] | 18 | #include "modules/skresources/include/SkResources.h" |
Florin Malita | b341810 | 2020-10-15 18:10:29 -0400 | [diff] [blame] | 19 | #include "modules/svg/include/SkSVGAttribute.h" |
| 20 | #include "modules/svg/include/SkSVGIDMapper.h" |
| 21 | #include "src/core/SkTLazy.h" |
| 22 | |
| 23 | class SkCanvas; |
| 24 | class SkSVGLength; |
| 25 | |
| 26 | class SkSVGLengthContext { |
| 27 | public: |
| 28 | SkSVGLengthContext(const SkSize& viewport, SkScalar dpi = 90) |
| 29 | : fViewport(viewport), fDPI(dpi) {} |
| 30 | |
| 31 | enum class LengthType { |
| 32 | kHorizontal, |
| 33 | kVertical, |
| 34 | kOther, |
| 35 | }; |
| 36 | |
| 37 | const SkSize& viewPort() const { return fViewport; } |
| 38 | void setViewPort(const SkSize& viewport) { fViewport = viewport; } |
| 39 | |
| 40 | SkScalar resolve(const SkSVGLength&, LengthType) const; |
| 41 | SkRect resolveRect(const SkSVGLength& x, const SkSVGLength& y, |
| 42 | const SkSVGLength& w, const SkSVGLength& h) const; |
| 43 | |
| 44 | private: |
| 45 | SkSize fViewport; |
| 46 | SkScalar fDPI; |
| 47 | }; |
| 48 | |
| 49 | struct SkSVGPresentationContext { |
| 50 | SkSVGPresentationContext(); |
| 51 | SkSVGPresentationContext(const SkSVGPresentationContext&) = default; |
| 52 | SkSVGPresentationContext& operator=(const SkSVGPresentationContext&) = default; |
| 53 | |
| 54 | // Inherited presentation attributes, computed for the current node. |
| 55 | SkSVGPresentationAttributes fInherited; |
Florin Malita | b341810 | 2020-10-15 18:10:29 -0400 | [diff] [blame] | 56 | }; |
| 57 | |
| 58 | class SkSVGRenderContext { |
| 59 | public: |
Florin Malita | 48fb05b | 2021-04-30 14:22:33 -0400 | [diff] [blame] | 60 | // Captures data required for object bounding box resolution. |
| 61 | struct OBBScope { |
| 62 | const SkSVGNode* fNode; |
| 63 | const SkSVGRenderContext* fCtx; |
| 64 | }; |
| 65 | |
Florin Malita | 24df67d | 2021-01-26 18:45:34 -0500 | [diff] [blame] | 66 | SkSVGRenderContext(SkCanvas*, const sk_sp<SkFontMgr>&, |
| 67 | const sk_sp<skresources::ResourceProvider>&, const SkSVGIDMapper&, |
Florin Malita | 7006e15 | 2020-11-10 15:24:59 -0500 | [diff] [blame] | 68 | const SkSVGLengthContext&, const SkSVGPresentationContext&, |
Florin Malita | 48fb05b | 2021-04-30 14:22:33 -0400 | [diff] [blame] | 69 | const OBBScope&); |
Florin Malita | b341810 | 2020-10-15 18:10:29 -0400 | [diff] [blame] | 70 | SkSVGRenderContext(const SkSVGRenderContext&); |
| 71 | SkSVGRenderContext(const SkSVGRenderContext&, SkCanvas*); |
Florin Malita | 48fb05b | 2021-04-30 14:22:33 -0400 | [diff] [blame] | 72 | // Establish a new OBB scope. Normally used when entering a node's render scope. |
Tyler Denniston | 53281c7 | 2020-10-22 15:54:24 -0400 | [diff] [blame] | 73 | SkSVGRenderContext(const SkSVGRenderContext&, const SkSVGNode*); |
Florin Malita | b341810 | 2020-10-15 18:10:29 -0400 | [diff] [blame] | 74 | ~SkSVGRenderContext(); |
| 75 | |
| 76 | const SkSVGLengthContext& lengthContext() const { return *fLengthContext; } |
| 77 | SkSVGLengthContext* writableLengthContext() { return fLengthContext.writable(); } |
| 78 | |
| 79 | const SkSVGPresentationContext& presentationContext() const { return *fPresentationContext; } |
| 80 | |
| 81 | SkCanvas* canvas() const { return fCanvas; } |
| 82 | void saveOnce(); |
| 83 | |
| 84 | enum ApplyFlags { |
| 85 | kLeaf = 1 << 0, // the target node doesn't have descendants |
| 86 | }; |
| 87 | void applyPresentationAttributes(const SkSVGPresentationAttributes&, uint32_t flags); |
| 88 | |
| 89 | // Scoped wrapper that temporarily clears the original node reference. |
| 90 | class BorrowedNode { |
| 91 | public: |
| 92 | explicit BorrowedNode(sk_sp<SkSVGNode>* node) |
| 93 | : fOwner(node) { |
| 94 | if (fOwner) { |
| 95 | fBorrowed = std::move(*fOwner); |
| 96 | *fOwner = nullptr; |
| 97 | } |
| 98 | } |
| 99 | |
| 100 | ~BorrowedNode() { |
| 101 | if (fOwner) { |
| 102 | *fOwner = std::move(fBorrowed); |
| 103 | } |
| 104 | } |
| 105 | |
| 106 | const SkSVGNode* get() const { return fBorrowed.get(); } |
| 107 | const SkSVGNode* operator->() const { return fBorrowed.get(); } |
| 108 | const SkSVGNode& operator*() const { return *fBorrowed; } |
| 109 | |
| 110 | operator bool() const { return !!fBorrowed; } |
| 111 | |
| 112 | private: |
| 113 | // noncopyable |
| 114 | BorrowedNode(const BorrowedNode&) = delete; |
| 115 | BorrowedNode& operator=(BorrowedNode&) = delete; |
| 116 | |
| 117 | sk_sp<SkSVGNode>* fOwner; |
| 118 | sk_sp<SkSVGNode> fBorrowed; |
| 119 | }; |
| 120 | |
| 121 | // Note: the id->node association is cleared for the lifetime of the returned value |
| 122 | // (effectively breaks reference cycles, assuming appropriate return value scoping). |
Tyler Denniston | e71f547 | 2021-01-27 13:30:59 -0500 | [diff] [blame] | 123 | BorrowedNode findNodeById(const SkSVGIRI&) const; |
Florin Malita | b341810 | 2020-10-15 18:10:29 -0400 | [diff] [blame] | 124 | |
Florin Malita | bde06cc | 2021-01-19 10:12:37 -0500 | [diff] [blame] | 125 | SkTLazy<SkPaint> fillPaint() const; |
| 126 | SkTLazy<SkPaint> strokePaint() const; |
Florin Malita | b341810 | 2020-10-15 18:10:29 -0400 | [diff] [blame] | 127 | |
Tyler Denniston | b2d1a3b | 2020-12-11 10:31:07 -0500 | [diff] [blame] | 128 | SkSVGColorType resolveSvgColor(const SkSVGColor&) const; |
| 129 | |
Florin Malita | b341810 | 2020-10-15 18:10:29 -0400 | [diff] [blame] | 130 | // The local computed clip path (not inherited). |
| 131 | const SkPath* clipPath() const { return fClipPath.getMaybeNull(); } |
| 132 | |
Tyler Denniston | 8ca4626 | 2021-02-02 16:16:21 -0500 | [diff] [blame] | 133 | const sk_sp<skresources::ResourceProvider>& resourceProvider() const { |
| 134 | return fResourceProvider; |
| 135 | } |
| 136 | |
Florin Malita | 7006e15 | 2020-11-10 15:24:59 -0500 | [diff] [blame] | 137 | sk_sp<SkFontMgr> fontMgr() const { |
| 138 | return fFontMgr ? fFontMgr : SkFontMgr::RefDefault(); |
| 139 | } |
| 140 | |
Florin Malita | 3010f3d | 2021-04-30 10:48:42 -0400 | [diff] [blame] | 141 | // Returns the translate/scale transformation required to map into the current OBB scope, |
| 142 | // with the specified units. |
| 143 | struct OBBTransform { |
| 144 | SkV2 offset, scale; |
| 145 | }; |
| 146 | OBBTransform transformForCurrentOBB(SkSVGObjectBoundingBoxUnits) const; |
| 147 | |
Florin Malita | 4919110 | 2021-01-14 11:58:09 -0500 | [diff] [blame] | 148 | SkRect resolveOBBRect(const SkSVGLength& x, const SkSVGLength& y, |
| 149 | const SkSVGLength& w, const SkSVGLength& h, |
| 150 | SkSVGObjectBoundingBoxUnits) const; |
| 151 | |
Florin Malita | b341810 | 2020-10-15 18:10:29 -0400 | [diff] [blame] | 152 | private: |
| 153 | // Stack-only |
| 154 | void* operator new(size_t) = delete; |
| 155 | void* operator new(size_t, void*) = delete; |
| 156 | SkSVGRenderContext& operator=(const SkSVGRenderContext&) = delete; |
| 157 | |
Tyler Denniston | a22d21e | 2021-01-15 12:12:35 -0500 | [diff] [blame] | 158 | void applyOpacity(SkScalar opacity, uint32_t flags, bool hasFilter); |
Florin Malita | 836c2ca | 2021-01-13 11:48:02 -0500 | [diff] [blame] | 159 | void applyFilter(const SkSVGFuncIRI&); |
| 160 | void applyClip(const SkSVGFuncIRI&); |
Florin Malita | 4919110 | 2021-01-14 11:58:09 -0500 | [diff] [blame] | 161 | void applyMask(const SkSVGFuncIRI&); |
Florin Malita | bde06cc | 2021-01-19 10:12:37 -0500 | [diff] [blame] | 162 | |
| 163 | SkTLazy<SkPaint> commonPaint(const SkSVGPaint&, float opacity) const; |
Florin Malita | b341810 | 2020-10-15 18:10:29 -0400 | [diff] [blame] | 164 | |
Florin Malita | 7006e15 | 2020-11-10 15:24:59 -0500 | [diff] [blame] | 165 | const sk_sp<SkFontMgr>& fFontMgr; |
Florin Malita | 24df67d | 2021-01-26 18:45:34 -0500 | [diff] [blame] | 166 | const sk_sp<skresources::ResourceProvider>& fResourceProvider; |
Florin Malita | b341810 | 2020-10-15 18:10:29 -0400 | [diff] [blame] | 167 | const SkSVGIDMapper& fIDMapper; |
| 168 | SkTCopyOnFirstWrite<SkSVGLengthContext> fLengthContext; |
| 169 | SkTCopyOnFirstWrite<SkSVGPresentationContext> fPresentationContext; |
| 170 | SkCanvas* fCanvas; |
| 171 | // The save count on 'fCanvas' at construction time. |
| 172 | // A restoreToCount() will be issued on destruction. |
| 173 | int fCanvasSaveCount; |
| 174 | |
| 175 | // clipPath, if present for the current context (not inherited). |
| 176 | SkTLazy<SkPath> fClipPath; |
Tyler Denniston | 53281c7 | 2020-10-22 15:54:24 -0400 | [diff] [blame] | 177 | |
Florin Malita | bde06cc | 2021-01-19 10:12:37 -0500 | [diff] [blame] | 178 | // Deferred opacity optimization for leaf nodes. |
| 179 | float fDeferredPaintOpacity = 1; |
| 180 | |
Florin Malita | 48fb05b | 2021-04-30 14:22:33 -0400 | [diff] [blame] | 181 | // Current object bounding box scope. |
| 182 | const OBBScope fOBBScope; |
Florin Malita | b341810 | 2020-10-15 18:10:29 -0400 | [diff] [blame] | 183 | }; |
| 184 | |
| 185 | #endif // SkSVGRenderContext_DEFINED |