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