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