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