SVGContextPaint.h (10232B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef LAYOUT_SVG_SVGCONTEXTPAINT_H_ 8 #define LAYOUT_SVG_SVGCONTEXTPAINT_H_ 9 10 #include "DrawMode.h" 11 #include "ImgDrawResult.h" 12 #include "gfxMatrix.h" 13 #include "gfxPattern.h" 14 #include "gfxTypes.h" 15 #include "gfxUtils.h" 16 #include "mozilla/AlreadyAddRefed.h" 17 #include "mozilla/Assertions.h" 18 #include "mozilla/gfx/2D.h" 19 #include "nsColor.h" 20 #include "nsRefPtrHashtable.h" 21 #include "nsStyleStruct.h" 22 #include "nsTArray.h" 23 24 class gfxContext; 25 26 namespace mozilla { 27 class SVGPaintServerFrame; 28 29 namespace dom { 30 class Document; 31 } 32 33 /** 34 * This class is used to pass information about a context element through to 35 * SVG painting code in order to resolve the 'context-fill' and related 36 * keywords. See: 37 * 38 * https://www.w3.org/TR/SVG2/painting.html#context-paint 39 * 40 * This feature allows the color in an SVG-in-OpenType glyph to come from the 41 * computed style for the text that is being drawn, for example, or for color 42 * in an SVG embedded by an <img> element to come from the embedding <img> 43 * element. 44 * 45 * This class is reference counted so that it can be shared among many similar 46 * SVGImageContext objects. (SVGImageContext objects are frequently 47 * copy-constructed with small modifications, and we'd like for those copies to 48 * be able to share their context-paint data cheaply.) However, in most cases, 49 * SVGContextPaint instances are stored in a local RefPtr and only last for the 50 * duration of a function call. 51 * XXX Note: SVGImageContext doesn't actually have a SVGContextPaint member yet, 52 * but it will in a later patch in the patch series that added this comment. 53 */ 54 class SVGContextPaint : public RefCounted<SVGContextPaint> { 55 protected: 56 using DrawTarget = mozilla::gfx::DrawTarget; 57 using Float = mozilla::gfx::Float; 58 using imgDrawingParams = mozilla::image::imgDrawingParams; 59 60 SVGContextPaint() : mDashOffset(0.0f), mStrokeWidth(0.0f) {} 61 62 public: 63 MOZ_DECLARE_REFCOUNTED_TYPENAME(SVGContextPaint) 64 65 virtual ~SVGContextPaint() = default; 66 67 virtual already_AddRefed<gfxPattern> GetFillPattern( 68 const DrawTarget* aDrawTarget, float aOpacity, const gfxMatrix& aCTM, 69 imgDrawingParams& aImgParams) = 0; 70 virtual already_AddRefed<gfxPattern> GetStrokePattern( 71 const DrawTarget* aDrawTarget, float aOpacity, const gfxMatrix& aCTM, 72 imgDrawingParams& aImgParams) = 0; 73 virtual float GetFillOpacity() const = 0; 74 virtual float GetStrokeOpacity() const = 0; 75 76 already_AddRefed<gfxPattern> GetFillPattern(const DrawTarget* aDrawTarget, 77 const gfxMatrix& aCTM, 78 imgDrawingParams& aImgParams) { 79 return GetFillPattern(aDrawTarget, GetFillOpacity(), aCTM, aImgParams); 80 } 81 82 already_AddRefed<gfxPattern> GetStrokePattern(const DrawTarget* aDrawTarget, 83 const gfxMatrix& aCTM, 84 imgDrawingParams& aImgParams) { 85 return GetStrokePattern(aDrawTarget, GetStrokeOpacity(), aCTM, aImgParams); 86 } 87 88 static SVGContextPaint* GetContextPaint(nsIContent* aContent); 89 90 // XXX This gets the geometry params from the gfxContext. We should get that 91 // information from the actual paint context! 92 void InitStrokeGeometry(gfxContext* aContext, float devUnitsPerSVGUnit); 93 94 const FallibleTArray<Float>& GetStrokeDashArray() const { return mDashes; } 95 96 Float GetStrokeDashOffset() const { return mDashOffset; } 97 98 Float GetStrokeWidth() const { return mStrokeWidth; } 99 100 virtual uint32_t Hash() const { 101 MOZ_ASSERT_UNREACHABLE( 102 "Only VectorImage needs to hash, and that should " 103 "only be operating on our SVGEmbeddingContextPaint " 104 "subclass"); 105 return 0; 106 } 107 108 /** 109 * Returns true if image context paint is allowed to be used in an image that 110 * has the given URI, else returns false. 111 */ 112 static bool IsAllowedForImageFromURI(nsIURI* aURI); 113 114 private: 115 // Member-vars are initialized in InitStrokeGeometry. 116 FallibleTArray<Float> mDashes; 117 MOZ_INIT_OUTSIDE_CTOR Float mDashOffset; 118 MOZ_INIT_OUTSIDE_CTOR Float mStrokeWidth; 119 }; 120 121 /** 122 * RAII class used to temporarily set and remove an SVGContextPaint while a 123 * piece of SVG is being painted. The context paint is set on the SVG's owner 124 * document, as expected by SVGContextPaint::GetContextPaint. Any pre-existing 125 * context paint is restored after this class removes the context paint that it 126 * set. 127 */ 128 class MOZ_RAII AutoSetRestoreSVGContextPaint { 129 public: 130 AutoSetRestoreSVGContextPaint(const SVGContextPaint* aContextPaint, 131 dom::Document* aDocument); 132 ~AutoSetRestoreSVGContextPaint(); 133 134 private: 135 dom::Document* mDocument; 136 // The context paint that needs to be restored by our dtor after it removes 137 // aContextPaint: 138 const SVGContextPaint* mOuterContextPaint; 139 }; 140 141 /** 142 * This class should be flattened into SVGContextPaint once we get rid of the 143 * other sub-class (SimpleTextContextPaint). 144 */ 145 struct SVGContextPaintImpl : public SVGContextPaint { 146 protected: 147 using DrawTarget = mozilla::gfx::DrawTarget; 148 149 public: 150 DrawMode Init(const DrawTarget* aDrawTarget, const gfxMatrix& aContextMatrix, 151 nsIFrame* aFrame, SVGContextPaint* aOuterContextPaint, 152 imgDrawingParams& aImgParams); 153 154 already_AddRefed<gfxPattern> GetFillPattern( 155 const DrawTarget* aDrawTarget, float aOpacity, const gfxMatrix& aCTM, 156 imgDrawingParams& aImgParams) override; 157 already_AddRefed<gfxPattern> GetStrokePattern( 158 const DrawTarget* aDrawTarget, float aOpacity, const gfxMatrix& aCTM, 159 imgDrawingParams& aImgParams) override; 160 161 void SetFillOpacity(float aOpacity) { mFillOpacity = aOpacity; } 162 float GetFillOpacity() const override { return mFillOpacity; } 163 164 void SetStrokeOpacity(float aOpacity) { mStrokeOpacity = aOpacity; } 165 float GetStrokeOpacity() const override { return mStrokeOpacity; } 166 167 struct Paint { 168 enum class Tag : uint8_t { 169 None, 170 Color, 171 PaintServer, 172 ContextFill, 173 ContextStroke, 174 }; 175 176 Paint() : mPaintDefinition{}, mPaintType(Tag::None) {} 177 178 void SetPaintServer(nsIFrame* aFrame, const gfxMatrix& aContextMatrix, 179 SVGPaintServerFrame* aPaintServerFrame) { 180 mPaintType = Tag::PaintServer; 181 mPaintDefinition.mPaintServerFrame = aPaintServerFrame; 182 mFrame = aFrame; 183 mContextMatrix = aContextMatrix; 184 } 185 186 void SetColor(const nscolor& aColor) { 187 mPaintType = Tag::Color; 188 mPaintDefinition.mColor = aColor; 189 } 190 191 void SetContextPaint(SVGContextPaint* aContextPaint, Tag aTag) { 192 MOZ_ASSERT(aTag == Tag::ContextFill || aTag == Tag::ContextStroke); 193 mPaintType = aTag; 194 mPaintDefinition.mContextPaint = aContextPaint; 195 } 196 197 union { 198 SVGPaintServerFrame* mPaintServerFrame; 199 SVGContextPaint* mContextPaint; 200 nscolor mColor; 201 } mPaintDefinition; 202 203 // Initialized (if needed) in SetPaintServer(): 204 MOZ_INIT_OUTSIDE_CTOR nsIFrame* mFrame; 205 // CTM defining the user space for the pattern we will use. 206 gfxMatrix mContextMatrix; 207 Tag mPaintType; 208 209 // Device-space-to-pattern-space 210 gfxMatrix mPatternMatrix; 211 nsRefPtrHashtable<nsFloatHashKey, gfxPattern> mPatternCache; 212 213 already_AddRefed<gfxPattern> GetPattern( 214 const DrawTarget* aDrawTarget, float aOpacity, 215 StyleSVGPaint nsStyleSVG::* aFillOrStroke, const gfxMatrix& aCTM, 216 imgDrawingParams& aImgParams); 217 }; 218 219 Paint mFillPaint; 220 Paint mStrokePaint; 221 222 float mFillOpacity; 223 float mStrokeOpacity; 224 }; 225 226 /** 227 * This class is used to pass context paint to an SVG image when an element 228 * references that image (e.g. via HTML <img> or SVG <image>, or by referencing 229 * it from a CSS property such as 'background-image'). In this case we only 230 * support context colors and not paint servers. 231 */ 232 class SVGEmbeddingContextPaint : public SVGContextPaint { 233 using DeviceColor = gfx::DeviceColor; 234 235 public: 236 SVGEmbeddingContextPaint() : mFillOpacity(1.0f), mStrokeOpacity(1.0f) {} 237 238 bool operator==(const SVGEmbeddingContextPaint& aOther) const { 239 MOZ_ASSERT(GetStrokeWidth() == aOther.GetStrokeWidth() && 240 GetStrokeDashOffset() == aOther.GetStrokeDashOffset() && 241 GetStrokeDashArray() == aOther.GetStrokeDashArray(), 242 "We don't currently include these in the context information " 243 "from an embedding element"); 244 return mFill == aOther.mFill && mStroke == aOther.mStroke && 245 mFillOpacity == aOther.mFillOpacity && 246 mStrokeOpacity == aOther.mStrokeOpacity; 247 } 248 249 void SetFill(nscolor aFill) { mFill.emplace(gfx::ToDeviceColor(aFill)); } 250 const Maybe<DeviceColor>& GetFill() const { return mFill; } 251 void SetStroke(nscolor aStroke) { 252 mStroke.emplace(gfx::ToDeviceColor(aStroke)); 253 } 254 const Maybe<DeviceColor>& GetStroke() const { return mStroke; } 255 256 /** 257 * Returns a pattern of type PatternType::COLOR, or else nullptr. 258 */ 259 already_AddRefed<gfxPattern> GetFillPattern( 260 const DrawTarget* aDrawTarget, float aFillOpacity, const gfxMatrix& aCTM, 261 imgDrawingParams& aImgParams) override; 262 263 /** 264 * Returns a pattern of type PatternType::COLOR, or else nullptr. 265 */ 266 already_AddRefed<gfxPattern> GetStrokePattern( 267 const DrawTarget* aDrawTarget, float aStrokeOpacity, 268 const gfxMatrix& aCTM, imgDrawingParams& aImgParams) override; 269 270 void SetFillOpacity(float aOpacity) { mFillOpacity = aOpacity; } 271 float GetFillOpacity() const override { return mFillOpacity; }; 272 273 void SetStrokeOpacity(float aOpacity) { mStrokeOpacity = aOpacity; } 274 float GetStrokeOpacity() const override { return mStrokeOpacity; }; 275 276 uint32_t Hash() const override; 277 278 private: 279 Maybe<DeviceColor> mFill; 280 Maybe<DeviceColor> mStroke; 281 float mFillOpacity; 282 float mStrokeOpacity; 283 }; 284 285 } // namespace mozilla 286 287 #endif // LAYOUT_SVG_SVGCONTEXTPAINT_H_