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_GFX_DRAWCOMMAND_H_
7 #define MOZILLA_GFX_DRAWCOMMAND_H_
8
9 #include <math.h>
10
11 #include "2D.h"
12 #include "Filters.h"
13 #include <vector>
14
15 namespace mozilla {
16 namespace gfx {
17
18 enum class CommandType : int8_t {
19 DRAWSURFACE = 0,
20 DRAWFILTER,
21 DRAWSURFACEWITHSHADOW,
22 CLEARRECT,
23 COPYSURFACE,
24 COPYRECT,
25 FILLRECT,
26 STROKERECT,
27 STROKELINE,
28 STROKE,
29 FILL,
30 FILLGLYPHS,
31 MASK,
32 MASKSURFACE,
33 PUSHCLIP,
34 PUSHCLIPRECT,
35 POPCLIP,
36 SETTRANSFORM,
37 FLUSH
38 };
39
40 class DrawingCommand
41 {
42 public:
~DrawingCommand()43 virtual ~DrawingCommand() {}
44
45 virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix* aTransform = nullptr) const = 0;
46
GetAffectedRect(Rect & aDeviceRect,const Matrix & aTransform)47 virtual bool GetAffectedRect(Rect& aDeviceRect, const Matrix& aTransform) const { return false; }
48
49 protected:
DrawingCommand(CommandType aType)50 explicit DrawingCommand(CommandType aType)
51 : mType(aType)
52 {
53 }
54
GetType()55 CommandType GetType() { return mType; }
56
57 private:
58 CommandType mType;
59 };
60
61 class StoredPattern
62 {
63 public:
StoredPattern(const Pattern & aPattern)64 explicit StoredPattern(const Pattern& aPattern)
65 {
66 Assign(aPattern);
67 }
68
Assign(const Pattern & aPattern)69 void Assign(const Pattern& aPattern)
70 {
71 switch (aPattern.GetType()) {
72 case PatternType::COLOR:
73 new (mColor)ColorPattern(*static_cast<const ColorPattern*>(&aPattern));
74 return;
75 case PatternType::SURFACE:
76 {
77 SurfacePattern* surfPat = new (mSurface)SurfacePattern(*static_cast<const SurfacePattern*>(&aPattern));
78 surfPat->mSurface->GuaranteePersistance();
79 return;
80 }
81 case PatternType::LINEAR_GRADIENT:
82 new (mLinear)LinearGradientPattern(*static_cast<const LinearGradientPattern*>(&aPattern));
83 return;
84 case PatternType::RADIAL_GRADIENT:
85 new (mRadial)RadialGradientPattern(*static_cast<const RadialGradientPattern*>(&aPattern));
86 return;
87 }
88 }
89
~StoredPattern()90 ~StoredPattern()
91 {
92 reinterpret_cast<Pattern*>(mPattern)->~Pattern();
93 }
94
95 operator Pattern&()
96 {
97 return *reinterpret_cast<Pattern*>(mPattern);
98 }
99
100 operator const Pattern&() const
101 {
102 return *reinterpret_cast<const Pattern*>(mPattern);
103 }
104
StoredPattern(const StoredPattern & aPattern)105 StoredPattern(const StoredPattern& aPattern)
106 {
107 Assign(aPattern);
108 }
109
110 private:
111 StoredPattern operator=(const StoredPattern& aOther)
112 {
113 // Block this so that we notice if someone's doing excessive assigning.
114 return *this;
115 }
116
117 union {
118 char mPattern[sizeof(Pattern)];
119 char mColor[sizeof(ColorPattern)];
120 char mLinear[sizeof(LinearGradientPattern)];
121 char mRadial[sizeof(RadialGradientPattern)];
122 char mSurface[sizeof(SurfacePattern)];
123 };
124 };
125
126 class DrawSurfaceCommand : public DrawingCommand
127 {
128 public:
DrawSurfaceCommand(SourceSurface * aSurface,const Rect & aDest,const Rect & aSource,const DrawSurfaceOptions & aSurfOptions,const DrawOptions & aOptions)129 DrawSurfaceCommand(SourceSurface *aSurface, const Rect& aDest,
130 const Rect& aSource, const DrawSurfaceOptions& aSurfOptions,
131 const DrawOptions& aOptions)
132 : DrawingCommand(CommandType::DRAWSURFACE)
133 , mSurface(aSurface), mDest(aDest)
134 , mSource(aSource), mSurfOptions(aSurfOptions)
135 , mOptions(aOptions)
136 {
137 }
138
ExecuteOnDT(DrawTarget * aDT,const Matrix *)139 virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const
140 {
141 aDT->DrawSurface(mSurface, mDest, mSource, mSurfOptions, mOptions);
142 }
143
144 private:
145 RefPtr<SourceSurface> mSurface;
146 Rect mDest;
147 Rect mSource;
148 DrawSurfaceOptions mSurfOptions;
149 DrawOptions mOptions;
150 };
151
152 class DrawFilterCommand : public DrawingCommand
153 {
154 public:
DrawFilterCommand(FilterNode * aFilter,const Rect & aSourceRect,const Point & aDestPoint,const DrawOptions & aOptions)155 DrawFilterCommand(FilterNode* aFilter, const Rect& aSourceRect,
156 const Point& aDestPoint, const DrawOptions& aOptions)
157 : DrawingCommand(CommandType::DRAWSURFACE)
158 , mFilter(aFilter), mSourceRect(aSourceRect)
159 , mDestPoint(aDestPoint), mOptions(aOptions)
160 {
161 }
162
ExecuteOnDT(DrawTarget * aDT,const Matrix *)163 virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const
164 {
165 aDT->DrawFilter(mFilter, mSourceRect, mDestPoint, mOptions);
166 }
167
168 private:
169 RefPtr<FilterNode> mFilter;
170 Rect mSourceRect;
171 Point mDestPoint;
172 DrawOptions mOptions;
173 };
174
175 class ClearRectCommand : public DrawingCommand
176 {
177 public:
ClearRectCommand(const Rect & aRect)178 explicit ClearRectCommand(const Rect& aRect)
179 : DrawingCommand(CommandType::CLEARRECT)
180 , mRect(aRect)
181 {
182 }
183
ExecuteOnDT(DrawTarget * aDT,const Matrix *)184 virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const
185 {
186 aDT->ClearRect(mRect);
187 }
188
189 private:
190 Rect mRect;
191 };
192
193 class CopySurfaceCommand : public DrawingCommand
194 {
195 public:
CopySurfaceCommand(SourceSurface * aSurface,const IntRect & aSourceRect,const IntPoint & aDestination)196 CopySurfaceCommand(SourceSurface* aSurface,
197 const IntRect& aSourceRect,
198 const IntPoint& aDestination)
199 : DrawingCommand(CommandType::COPYSURFACE)
200 , mSurface(aSurface)
201 , mSourceRect(aSourceRect)
202 , mDestination(aDestination)
203 {
204 }
205
ExecuteOnDT(DrawTarget * aDT,const Matrix * aTransform)206 virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix* aTransform) const
207 {
208 MOZ_ASSERT(!aTransform || !aTransform->HasNonIntegerTranslation());
209 Point dest(Float(mDestination.x), Float(mDestination.y));
210 if (aTransform) {
211 dest = aTransform->TransformPoint(dest);
212 }
213 aDT->CopySurface(mSurface, mSourceRect, IntPoint(uint32_t(dest.x), uint32_t(dest.y)));
214 }
215
216 private:
217 RefPtr<SourceSurface> mSurface;
218 IntRect mSourceRect;
219 IntPoint mDestination;
220 };
221
222 class FillRectCommand : public DrawingCommand
223 {
224 public:
FillRectCommand(const Rect & aRect,const Pattern & aPattern,const DrawOptions & aOptions)225 FillRectCommand(const Rect& aRect,
226 const Pattern& aPattern,
227 const DrawOptions& aOptions)
228 : DrawingCommand(CommandType::FILLRECT)
229 , mRect(aRect)
230 , mPattern(aPattern)
231 , mOptions(aOptions)
232 {
233 }
234
ExecuteOnDT(DrawTarget * aDT,const Matrix *)235 virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const
236 {
237 aDT->FillRect(mRect, mPattern, mOptions);
238 }
239
GetAffectedRect(Rect & aDeviceRect,const Matrix & aTransform)240 bool GetAffectedRect(Rect& aDeviceRect, const Matrix& aTransform) const
241 {
242 aDeviceRect = aTransform.TransformBounds(mRect);
243 return true;
244 }
245
246 private:
247 Rect mRect;
248 StoredPattern mPattern;
249 DrawOptions mOptions;
250 };
251
252 class StrokeRectCommand : public DrawingCommand
253 {
254 public:
StrokeRectCommand(const Rect & aRect,const Pattern & aPattern,const StrokeOptions & aStrokeOptions,const DrawOptions & aOptions)255 StrokeRectCommand(const Rect& aRect,
256 const Pattern& aPattern,
257 const StrokeOptions& aStrokeOptions,
258 const DrawOptions& aOptions)
259 : DrawingCommand(CommandType::STROKERECT)
260 , mRect(aRect)
261 , mPattern(aPattern)
262 , mStrokeOptions(aStrokeOptions)
263 , mOptions(aOptions)
264 {
265 if (aStrokeOptions.mDashLength) {
266 mDashes.resize(aStrokeOptions.mDashLength);
267 mStrokeOptions.mDashPattern = &mDashes.front();
268 memcpy(&mDashes.front(), aStrokeOptions.mDashPattern, mStrokeOptions.mDashLength * sizeof(Float));
269 }
270 }
271
ExecuteOnDT(DrawTarget * aDT,const Matrix *)272 virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const
273 {
274 aDT->StrokeRect(mRect, mPattern, mStrokeOptions, mOptions);
275 }
276
277 private:
278 Rect mRect;
279 StoredPattern mPattern;
280 StrokeOptions mStrokeOptions;
281 DrawOptions mOptions;
282 std::vector<Float> mDashes;
283 };
284
285 class StrokeLineCommand : public DrawingCommand
286 {
287 public:
StrokeLineCommand(const Point & aStart,const Point & aEnd,const Pattern & aPattern,const StrokeOptions & aStrokeOptions,const DrawOptions & aOptions)288 StrokeLineCommand(const Point& aStart,
289 const Point& aEnd,
290 const Pattern& aPattern,
291 const StrokeOptions& aStrokeOptions,
292 const DrawOptions& aOptions)
293 : DrawingCommand(CommandType::STROKELINE)
294 , mStart(aStart)
295 , mEnd(aEnd)
296 , mPattern(aPattern)
297 , mStrokeOptions(aStrokeOptions)
298 , mOptions(aOptions)
299 {
300 }
301
ExecuteOnDT(DrawTarget * aDT,const Matrix *)302 virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const
303 {
304 aDT->StrokeLine(mStart, mEnd, mPattern, mStrokeOptions, mOptions);
305 }
306
307 private:
308 Point mStart;
309 Point mEnd;
310 StoredPattern mPattern;
311 StrokeOptions mStrokeOptions;
312 DrawOptions mOptions;
313 };
314
315 class FillCommand : public DrawingCommand
316 {
317 public:
FillCommand(const Path * aPath,const Pattern & aPattern,const DrawOptions & aOptions)318 FillCommand(const Path* aPath,
319 const Pattern& aPattern,
320 const DrawOptions& aOptions)
321 : DrawingCommand(CommandType::FILL)
322 , mPath(const_cast<Path*>(aPath))
323 , mPattern(aPattern)
324 , mOptions(aOptions)
325 {
326 }
327
ExecuteOnDT(DrawTarget * aDT,const Matrix *)328 virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const
329 {
330 aDT->Fill(mPath, mPattern, mOptions);
331 }
332
GetAffectedRect(Rect & aDeviceRect,const Matrix & aTransform)333 bool GetAffectedRect(Rect& aDeviceRect, const Matrix& aTransform) const
334 {
335 aDeviceRect = mPath->GetBounds(aTransform);
336 return true;
337 }
338
339 private:
340 RefPtr<Path> mPath;
341 StoredPattern mPattern;
342 DrawOptions mOptions;
343 };
344
345 #ifndef M_SQRT2
346 #define M_SQRT2 1.41421356237309504880
347 #endif
348
349 #ifndef M_SQRT1_2
350 #define M_SQRT1_2 0.707106781186547524400844362104849039
351 #endif
352
353 // The logic for this comes from _cairo_stroke_style_max_distance_from_path
354 static Rect
PathExtentsToMaxStrokeExtents(const StrokeOptions & aStrokeOptions,const Rect & aRect,const Matrix & aTransform)355 PathExtentsToMaxStrokeExtents(const StrokeOptions &aStrokeOptions,
356 const Rect &aRect,
357 const Matrix &aTransform)
358 {
359 double styleExpansionFactor = 0.5f;
360
361 if (aStrokeOptions.mLineCap == CapStyle::SQUARE) {
362 styleExpansionFactor = M_SQRT1_2;
363 }
364
365 if (aStrokeOptions.mLineJoin == JoinStyle::MITER &&
366 styleExpansionFactor < M_SQRT2 * aStrokeOptions.mMiterLimit) {
367 styleExpansionFactor = M_SQRT2 * aStrokeOptions.mMiterLimit;
368 }
369
370 styleExpansionFactor *= aStrokeOptions.mLineWidth;
371
372 double dx = styleExpansionFactor * hypot(aTransform._11, aTransform._21);
373 double dy = styleExpansionFactor * hypot(aTransform._22, aTransform._12);
374
375 Rect result = aRect;
376 result.Inflate(dx, dy);
377 return result;
378 }
379
380 class StrokeCommand : public DrawingCommand
381 {
382 public:
StrokeCommand(const Path * aPath,const Pattern & aPattern,const StrokeOptions & aStrokeOptions,const DrawOptions & aOptions)383 StrokeCommand(const Path* aPath,
384 const Pattern& aPattern,
385 const StrokeOptions& aStrokeOptions,
386 const DrawOptions& aOptions)
387 : DrawingCommand(CommandType::STROKE)
388 , mPath(const_cast<Path*>(aPath))
389 , mPattern(aPattern)
390 , mStrokeOptions(aStrokeOptions)
391 , mOptions(aOptions)
392 {
393 if (aStrokeOptions.mDashLength) {
394 mDashes.resize(aStrokeOptions.mDashLength);
395 mStrokeOptions.mDashPattern = &mDashes.front();
396 memcpy(&mDashes.front(), aStrokeOptions.mDashPattern, mStrokeOptions.mDashLength * sizeof(Float));
397 }
398 }
399
ExecuteOnDT(DrawTarget * aDT,const Matrix *)400 virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const
401 {
402 aDT->Stroke(mPath, mPattern, mStrokeOptions, mOptions);
403 }
404
GetAffectedRect(Rect & aDeviceRect,const Matrix & aTransform)405 bool GetAffectedRect(Rect& aDeviceRect, const Matrix& aTransform) const
406 {
407 aDeviceRect = PathExtentsToMaxStrokeExtents(mStrokeOptions, mPath->GetBounds(aTransform), aTransform);
408 return true;
409 }
410
411 private:
412 RefPtr<Path> mPath;
413 StoredPattern mPattern;
414 StrokeOptions mStrokeOptions;
415 DrawOptions mOptions;
416 std::vector<Float> mDashes;
417 };
418
419 class FillGlyphsCommand : public DrawingCommand
420 {
421 public:
FillGlyphsCommand(ScaledFont * aFont,const GlyphBuffer & aBuffer,const Pattern & aPattern,const DrawOptions & aOptions,const GlyphRenderingOptions * aRenderingOptions)422 FillGlyphsCommand(ScaledFont* aFont,
423 const GlyphBuffer& aBuffer,
424 const Pattern& aPattern,
425 const DrawOptions& aOptions,
426 const GlyphRenderingOptions* aRenderingOptions)
427 : DrawingCommand(CommandType::FILLGLYPHS)
428 , mFont(aFont)
429 , mPattern(aPattern)
430 , mOptions(aOptions)
431 , mRenderingOptions(const_cast<GlyphRenderingOptions*>(aRenderingOptions))
432 {
433 mGlyphs.resize(aBuffer.mNumGlyphs);
434 memcpy(&mGlyphs.front(), aBuffer.mGlyphs, sizeof(Glyph) * aBuffer.mNumGlyphs);
435 }
436
ExecuteOnDT(DrawTarget * aDT,const Matrix *)437 virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const
438 {
439 GlyphBuffer buf;
440 buf.mNumGlyphs = mGlyphs.size();
441 buf.mGlyphs = &mGlyphs.front();
442 aDT->FillGlyphs(mFont, buf, mPattern, mOptions, mRenderingOptions);
443 }
444
445 private:
446 RefPtr<ScaledFont> mFont;
447 std::vector<Glyph> mGlyphs;
448 StoredPattern mPattern;
449 DrawOptions mOptions;
450 RefPtr<GlyphRenderingOptions> mRenderingOptions;
451 };
452
453 class MaskCommand : public DrawingCommand
454 {
455 public:
MaskCommand(const Pattern & aSource,const Pattern & aMask,const DrawOptions & aOptions)456 MaskCommand(const Pattern& aSource,
457 const Pattern& aMask,
458 const DrawOptions& aOptions)
459 : DrawingCommand(CommandType::MASK)
460 , mSource(aSource)
461 , mMask(aMask)
462 , mOptions(aOptions)
463 {
464 }
465
ExecuteOnDT(DrawTarget * aDT,const Matrix *)466 virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const
467 {
468 aDT->Mask(mSource, mMask, mOptions);
469 }
470
471 private:
472 StoredPattern mSource;
473 StoredPattern mMask;
474 DrawOptions mOptions;
475 };
476
477 class MaskSurfaceCommand : public DrawingCommand
478 {
479 public:
MaskSurfaceCommand(const Pattern & aSource,const SourceSurface * aMask,const Point & aOffset,const DrawOptions & aOptions)480 MaskSurfaceCommand(const Pattern& aSource,
481 const SourceSurface* aMask,
482 const Point& aOffset,
483 const DrawOptions& aOptions)
484 : DrawingCommand(CommandType::MASKSURFACE)
485 , mSource(aSource)
486 , mMask(const_cast<SourceSurface*>(aMask))
487 , mOffset(aOffset)
488 , mOptions(aOptions)
489 {
490 }
491
ExecuteOnDT(DrawTarget * aDT,const Matrix *)492 virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const
493 {
494 aDT->MaskSurface(mSource, mMask, mOffset, mOptions);
495 }
496
497 private:
498 StoredPattern mSource;
499 RefPtr<SourceSurface> mMask;
500 Point mOffset;
501 DrawOptions mOptions;
502 };
503
504 class PushClipCommand : public DrawingCommand
505 {
506 public:
PushClipCommand(const Path * aPath)507 explicit PushClipCommand(const Path* aPath)
508 : DrawingCommand(CommandType::PUSHCLIP)
509 , mPath(const_cast<Path*>(aPath))
510 {
511 }
512
ExecuteOnDT(DrawTarget * aDT,const Matrix *)513 virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const
514 {
515 aDT->PushClip(mPath);
516 }
517
518 private:
519 RefPtr<Path> mPath;
520 };
521
522 class PushClipRectCommand : public DrawingCommand
523 {
524 public:
PushClipRectCommand(const Rect & aRect)525 explicit PushClipRectCommand(const Rect& aRect)
526 : DrawingCommand(CommandType::PUSHCLIPRECT)
527 , mRect(aRect)
528 {
529 }
530
ExecuteOnDT(DrawTarget * aDT,const Matrix *)531 virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const
532 {
533 aDT->PushClipRect(mRect);
534 }
535
536 private:
537 Rect mRect;
538 };
539
540 class PopClipCommand : public DrawingCommand
541 {
542 public:
PopClipCommand()543 PopClipCommand()
544 : DrawingCommand(CommandType::POPCLIP)
545 {
546 }
547
ExecuteOnDT(DrawTarget * aDT,const Matrix *)548 virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const
549 {
550 aDT->PopClip();
551 }
552 };
553
554 class SetTransformCommand : public DrawingCommand
555 {
556 public:
SetTransformCommand(const Matrix & aTransform)557 explicit SetTransformCommand(const Matrix& aTransform)
558 : DrawingCommand(CommandType::SETTRANSFORM)
559 , mTransform(aTransform)
560 {
561 }
562
ExecuteOnDT(DrawTarget * aDT,const Matrix * aMatrix)563 virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix* aMatrix) const
564 {
565 if (aMatrix) {
566 aDT->SetTransform(mTransform * (*aMatrix));
567 } else {
568 aDT->SetTransform(mTransform);
569 }
570 }
571
572 private:
573 Matrix mTransform;
574 };
575
576 class FlushCommand : public DrawingCommand
577 {
578 public:
FlushCommand()579 explicit FlushCommand()
580 : DrawingCommand(CommandType::FLUSH)
581 {
582 }
583
ExecuteOnDT(DrawTarget * aDT,const Matrix *)584 virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const
585 {
586 aDT->Flush();
587 }
588 };
589
590 } // namespace gfx
591
592 } // namespace mozilla
593
594 #endif /* MOZILLA_GFX_DRAWCOMMAND_H_ */
595