1 /* -*- Mode: C++; tab-width: 20; 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/. */
6 #include "DrawTargetRecording.h"
7 #include "PathRecording.h"
17 class SourceSurfaceRecording
: public SourceSurface
20 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceRecording
)
21 SourceSurfaceRecording(SourceSurface
*aFinalSurface
, DrawEventRecorderPrivate
*aRecorder
)
22 : mFinalSurface(aFinalSurface
), mRecorder(aRecorder
)
26 ~SourceSurfaceRecording()
28 mRecorder
->RecordEvent(RecordedSourceSurfaceDestruction(this));
31 virtual SurfaceType
GetType() const { return SurfaceType::RECORDING
; }
32 virtual IntSize
GetSize() const { return mFinalSurface
->GetSize(); }
33 virtual SurfaceFormat
GetFormat() const { return mFinalSurface
->GetFormat(); }
34 virtual TemporaryRef
<DataSourceSurface
> GetDataSurface() { return mFinalSurface
->GetDataSurface(); }
36 RefPtr
<SourceSurface
> mFinalSurface
;
37 RefPtr
<DrawEventRecorderPrivate
> mRecorder
;
40 class GradientStopsRecording
: public GradientStops
43 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GradientStopsRecording
)
44 GradientStopsRecording(GradientStops
*aFinalGradientStops
, DrawEventRecorderPrivate
*aRecorder
)
45 : mFinalGradientStops(aFinalGradientStops
), mRecorder(aRecorder
)
49 ~GradientStopsRecording()
51 mRecorder
->RecordEvent(RecordedGradientStopsDestruction(this));
54 virtual BackendType
GetBackendType() const { return BackendType::RECORDING
; }
56 RefPtr
<GradientStops
> mFinalGradientStops
;
57 RefPtr
<DrawEventRecorderPrivate
> mRecorder
;
60 static SourceSurface
*
61 GetSourceSurface(SourceSurface
*aSurface
)
63 if (aSurface
->GetType() != SurfaceType::RECORDING
) {
67 return static_cast<SourceSurfaceRecording
*>(aSurface
)->mFinalSurface
;
70 static GradientStops
*
71 GetGradientStops(GradientStops
*aStops
)
73 if (aStops
->GetBackendType() != BackendType::RECORDING
) {
77 return static_cast<GradientStopsRecording
*>(aStops
)->mFinalGradientStops
;
80 class FilterNodeRecording
: public FilterNode
83 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeRecording
)
84 using FilterNode::SetAttribute
;
86 FilterNodeRecording(FilterNode
*aFinalFilterNode
, DrawEventRecorderPrivate
*aRecorder
)
87 : mFinalFilterNode(aFinalFilterNode
), mRecorder(aRecorder
)
91 ~FilterNodeRecording()
93 mRecorder
->RecordEvent(RecordedFilterNodeDestruction(this));
96 virtual void SetInput(uint32_t aIndex
, SourceSurface
*aSurface
)
98 mRecorder
->RecordEvent(RecordedFilterNodeSetInput(this, aIndex
, aSurface
));
99 mFinalFilterNode
->SetInput(aIndex
, GetSourceSurface(aSurface
));
101 virtual void SetInput(uint32_t aIndex
, FilterNode
*aFilter
)
103 FilterNode
*finalNode
= aFilter
;
104 if (aFilter
->GetBackendType() != FILTER_BACKEND_RECORDING
) {
105 gfxWarning() << "Non recording filter node used with recording DrawTarget!";
107 finalNode
= static_cast<FilterNodeRecording
*>(aFilter
)->mFinalFilterNode
;
110 mRecorder
->RecordEvent(RecordedFilterNodeSetInput(this, aIndex
, aFilter
));
111 mFinalFilterNode
->SetInput(aIndex
, finalNode
);
115 #define FORWARD_SET_ATTRIBUTE(type, argtype) \
116 virtual void SetAttribute(uint32_t aIndex, type aValue) { \
117 mRecorder->RecordEvent(RecordedFilterNodeSetAttribute(this, aIndex, aValue, RecordedFilterNodeSetAttribute::ARGTYPE_##argtype)); \
118 mFinalFilterNode->SetAttribute(aIndex, aValue); \
121 FORWARD_SET_ATTRIBUTE(bool, BOOL
);
122 FORWARD_SET_ATTRIBUTE(uint32_t, UINT32
);
123 FORWARD_SET_ATTRIBUTE(Float
, FLOAT
);
124 FORWARD_SET_ATTRIBUTE(const Size
&, SIZE
);
125 FORWARD_SET_ATTRIBUTE(const IntSize
&, INTSIZE
);
126 FORWARD_SET_ATTRIBUTE(const IntPoint
&, INTPOINT
);
127 FORWARD_SET_ATTRIBUTE(const Rect
&, RECT
);
128 FORWARD_SET_ATTRIBUTE(const IntRect
&, INTRECT
);
129 FORWARD_SET_ATTRIBUTE(const Point
&, POINT
);
130 FORWARD_SET_ATTRIBUTE(const Matrix5x4
&, MATRIX5X4
);
131 FORWARD_SET_ATTRIBUTE(const Point3D
&, POINT3D
);
132 FORWARD_SET_ATTRIBUTE(const Color
&, COLOR
);
134 #undef FORWARD_SET_ATTRIBUTE
136 virtual void SetAttribute(uint32_t aIndex
, const Float
* aFloat
, uint32_t aSize
) {
137 mRecorder
->RecordEvent(RecordedFilterNodeSetAttribute(this, aIndex
, aFloat
, aSize
));
138 mFinalFilterNode
->SetAttribute(aIndex
, aFloat
, aSize
);
141 virtual FilterBackend
GetBackendType() MOZ_OVERRIDE
{ return FILTER_BACKEND_RECORDING
; }
143 RefPtr
<FilterNode
> mFinalFilterNode
;
144 RefPtr
<DrawEventRecorderPrivate
> mRecorder
;
148 GetFilterNode(FilterNode
* aNode
)
150 if (aNode
->GetBackendType() != FILTER_BACKEND_RECORDING
) {
151 gfxWarning() << "Non recording filter node used with recording DrawTarget!";
155 return static_cast<FilterNodeRecording
*>(aNode
)->mFinalFilterNode
;
158 struct AdjustedPattern
160 explicit AdjustedPattern(const Pattern
&aPattern
)
163 mOrigPattern
= const_cast<Pattern
*>(&aPattern
);
168 mPattern
->~Pattern();
174 switch(mOrigPattern
->GetType()) {
175 case PatternType::COLOR
:
177 case PatternType::SURFACE
:
179 SurfacePattern
*surfPat
= static_cast<SurfacePattern
*>(mOrigPattern
);
181 new (mSurfPat
) SurfacePattern(GetSourceSurface(surfPat
->mSurface
),
182 surfPat
->mExtendMode
, surfPat
->mMatrix
,
186 case PatternType::LINEAR_GRADIENT
:
188 LinearGradientPattern
*linGradPat
= static_cast<LinearGradientPattern
*>(mOrigPattern
);
190 new (mLinGradPat
) LinearGradientPattern(linGradPat
->mBegin
, linGradPat
->mEnd
,
191 GetGradientStops(linGradPat
->mStops
),
192 linGradPat
->mMatrix
);
195 case PatternType::RADIAL_GRADIENT
:
197 RadialGradientPattern
*radGradPat
= static_cast<RadialGradientPattern
*>(mOrigPattern
);
199 new (mRadGradPat
) RadialGradientPattern(radGradPat
->mCenter1
, radGradPat
->mCenter2
,
200 radGradPat
->mRadius1
, radGradPat
->mRadius2
,
201 GetGradientStops(radGradPat
->mStops
),
202 radGradPat
->mMatrix
);
206 return new (mColPat
) ColorPattern(Color());
213 char mColPat
[sizeof(ColorPattern
)];
214 char mLinGradPat
[sizeof(LinearGradientPattern
)];
215 char mRadGradPat
[sizeof(RadialGradientPattern
)];
216 char mSurfPat
[sizeof(SurfacePattern
)];
219 Pattern
*mOrigPattern
;
223 DrawTargetRecording::DrawTargetRecording(DrawEventRecorder
*aRecorder
, DrawTarget
*aDT
, bool aHasData
)
224 : mRecorder(static_cast<DrawEventRecorderPrivate
*>(aRecorder
))
227 RefPtr
<SourceSurface
> snapshot
= aHasData
? mFinalDT
->Snapshot() : nullptr;
228 mRecorder
->RecordEvent(RecordedDrawTargetCreation(this,
229 mFinalDT
->GetBackendType(),
231 mFinalDT
->GetFormat(),
232 aHasData
, snapshot
));
233 mFormat
= mFinalDT
->GetFormat();
236 DrawTargetRecording::~DrawTargetRecording()
238 mRecorder
->RecordEvent(RecordedDrawTargetDestruction(this));
242 DrawTargetRecording::FillRect(const Rect
&aRect
,
243 const Pattern
&aPattern
,
244 const DrawOptions
&aOptions
)
246 mRecorder
->RecordEvent(RecordedFillRect(this, aRect
, aPattern
, aOptions
));
247 mFinalDT
->FillRect(aRect
, *AdjustedPattern(aPattern
), aOptions
);
251 DrawTargetRecording::StrokeRect(const Rect
&aRect
,
252 const Pattern
&aPattern
,
253 const StrokeOptions
&aStrokeOptions
,
254 const DrawOptions
&aOptions
)
256 mRecorder
->RecordEvent(RecordedStrokeRect(this, aRect
, aPattern
, aStrokeOptions
, aOptions
));
257 mFinalDT
->StrokeRect(aRect
, *AdjustedPattern(aPattern
), aStrokeOptions
, aOptions
);
261 DrawTargetRecording::StrokeLine(const Point
&aBegin
,
263 const Pattern
&aPattern
,
264 const StrokeOptions
&aStrokeOptions
,
265 const DrawOptions
&aOptions
)
267 mRecorder
->RecordEvent(RecordedStrokeLine(this, aBegin
, aEnd
, aPattern
, aStrokeOptions
, aOptions
));
268 mFinalDT
->StrokeLine(aBegin
, aEnd
, *AdjustedPattern(aPattern
), aStrokeOptions
, aOptions
);
272 DrawTargetRecording::GetPathForPathRecording(const Path
*aPath
) const
274 if (aPath
->GetBackendType() != BackendType::RECORDING
) {
278 return static_cast<const PathRecording
*>(aPath
)->mPath
;
282 DrawTargetRecording::Fill(const Path
*aPath
,
283 const Pattern
&aPattern
,
284 const DrawOptions
&aOptions
)
288 mRecorder
->RecordEvent(RecordedFill(this, const_cast<Path
*>(aPath
), aPattern
, aOptions
));
289 mFinalDT
->Fill(GetPathForPathRecording(aPath
), *AdjustedPattern(aPattern
), aOptions
);
292 struct RecordingFontUserData
295 RefPtr
<DrawEventRecorderPrivate
> recorder
;
298 void RecordingFontUserDataDestroyFunc(void *aUserData
)
300 RecordingFontUserData
*userData
=
301 static_cast<RecordingFontUserData
*>(aUserData
);
303 // TODO support font in b2g recordings
304 #ifndef MOZ_WIDGET_GONK
305 userData
->recorder
->RecordEvent(RecordedScaledFontDestruction(userData
->refPtr
));
312 DrawTargetRecording::FillGlyphs(ScaledFont
*aFont
,
313 const GlyphBuffer
&aBuffer
,
314 const Pattern
&aPattern
,
315 const DrawOptions
&aOptions
,
316 const GlyphRenderingOptions
*aRenderingOptions
)
318 if (!aFont
->GetUserData(reinterpret_cast<UserDataKey
*>(mRecorder
.get()))) {
319 // TODO support font in b2g recordings
320 #ifndef MOZ_WIDGET_GONK
321 mRecorder
->RecordEvent(RecordedScaledFontCreation(aFont
, aFont
));
323 RecordingFontUserData
*userData
= new RecordingFontUserData
;
324 userData
->refPtr
= aFont
;
325 userData
->recorder
= mRecorder
;
326 aFont
->AddUserData(reinterpret_cast<UserDataKey
*>(mRecorder
.get()), userData
,
327 &RecordingFontUserDataDestroyFunc
);
330 // TODO support font in b2g recordings
331 #ifndef MOZ_WIDGET_GONK
332 mRecorder
->RecordEvent(RecordedFillGlyphs(this, aFont
, aPattern
, aOptions
, aBuffer
.mGlyphs
, aBuffer
.mNumGlyphs
));
334 mFinalDT
->FillGlyphs(aFont
, aBuffer
, aPattern
, aOptions
, aRenderingOptions
);
338 DrawTargetRecording::Mask(const Pattern
&aSource
,
339 const Pattern
&aMask
,
340 const DrawOptions
&aOptions
)
342 mRecorder
->RecordEvent(RecordedMask(this, aSource
, aMask
, aOptions
));
343 mFinalDT
->Mask(*AdjustedPattern(aSource
), *AdjustedPattern(aMask
), aOptions
);
347 DrawTargetRecording::MaskSurface(const Pattern
&aSource
,
348 SourceSurface
*aMask
,
350 const DrawOptions
&aOptions
)
352 mRecorder
->RecordEvent(RecordedMaskSurface(this, aSource
, aMask
, aOffset
, aOptions
));
353 mFinalDT
->MaskSurface(*AdjustedPattern(aSource
), GetSourceSurface(aMask
), aOffset
, aOptions
);
357 DrawTargetRecording::Stroke(const Path
*aPath
,
358 const Pattern
&aPattern
,
359 const StrokeOptions
&aStrokeOptions
,
360 const DrawOptions
&aOptions
)
364 mRecorder
->RecordEvent(RecordedStroke(this, const_cast<Path
*>(aPath
), aPattern
, aStrokeOptions
, aOptions
));
365 mFinalDT
->Stroke(GetPathForPathRecording(aPath
), *AdjustedPattern(aPattern
), aStrokeOptions
, aOptions
);
368 TemporaryRef
<SourceSurface
>
369 DrawTargetRecording::Snapshot()
371 RefPtr
<SourceSurface
> surf
= mFinalDT
->Snapshot();
373 RefPtr
<SourceSurface
> retSurf
= new SourceSurfaceRecording(surf
, mRecorder
);
375 mRecorder
->RecordEvent(RecordedSnapshot(retSurf
, this));
377 return retSurf
.forget();
381 DrawTargetRecording::DrawSurface(SourceSurface
*aSurface
,
384 const DrawSurfaceOptions
&aSurfOptions
,
385 const DrawOptions
&aOptions
)
387 mRecorder
->RecordEvent(RecordedDrawSurface(this, aSurface
, aDest
, aSource
, aSurfOptions
, aOptions
));
388 mFinalDT
->DrawSurface(GetSourceSurface(aSurface
), aDest
, aSource
, aSurfOptions
, aOptions
);
392 DrawTargetRecording::DrawSurfaceWithShadow(SourceSurface
*aSurface
,
395 const Point
&aOffset
,
399 mRecorder
->RecordEvent(RecordedDrawSurfaceWithShadow(this, aSurface
, aDest
, aColor
, aOffset
, aSigma
, aOp
));
400 mFinalDT
->DrawSurfaceWithShadow(GetSourceSurface(aSurface
), aDest
, aColor
, aOffset
, aSigma
, aOp
);
404 DrawTargetRecording::DrawFilter(FilterNode
*aNode
,
405 const Rect
&aSourceRect
,
406 const Point
&aDestPoint
,
407 const DrawOptions
&aOptions
)
409 mRecorder
->RecordEvent(RecordedDrawFilter(this, aNode
, aSourceRect
, aDestPoint
, aOptions
));
410 mFinalDT
->DrawFilter(GetFilterNode(aNode
), aSourceRect
, aDestPoint
, aOptions
);
413 TemporaryRef
<FilterNode
>
414 DrawTargetRecording::CreateFilter(FilterType aType
)
416 RefPtr
<FilterNode
> node
= mFinalDT
->CreateFilter(aType
);
418 RefPtr
<FilterNode
> retNode
= new FilterNodeRecording(node
, mRecorder
);
420 mRecorder
->RecordEvent(RecordedFilterNodeCreation(retNode
, aType
));
422 return retNode
.forget();
426 DrawTargetRecording::ClearRect(const Rect
&aRect
)
428 mRecorder
->RecordEvent(RecordedClearRect(this, aRect
));
429 mFinalDT
->ClearRect(aRect
);
433 DrawTargetRecording::CopySurface(SourceSurface
*aSurface
,
434 const IntRect
&aSourceRect
,
435 const IntPoint
&aDestination
)
437 mRecorder
->RecordEvent(RecordedCopySurface(this, aSurface
, aSourceRect
, aDestination
));
438 mFinalDT
->CopySurface(GetSourceSurface(aSurface
), aSourceRect
, aDestination
);
442 DrawTargetRecording::PushClip(const Path
*aPath
)
446 mRecorder
->RecordEvent(RecordedPushClip(this, const_cast<Path
*>(aPath
)));
447 mFinalDT
->PushClip(GetPathForPathRecording(aPath
));
451 DrawTargetRecording::PushClipRect(const Rect
&aRect
)
453 mRecorder
->RecordEvent(RecordedPushClipRect(this, aRect
));
454 mFinalDT
->PushClipRect(aRect
);
458 DrawTargetRecording::PopClip()
460 mRecorder
->RecordEvent(RecordedPopClip(this));
464 TemporaryRef
<SourceSurface
>
465 DrawTargetRecording::CreateSourceSurfaceFromData(unsigned char *aData
,
466 const IntSize
&aSize
,
468 SurfaceFormat aFormat
) const
470 RefPtr
<SourceSurface
> surf
= mFinalDT
->CreateSourceSurfaceFromData(aData
, aSize
, aStride
, aFormat
);
472 RefPtr
<SourceSurface
> retSurf
= new SourceSurfaceRecording(surf
, mRecorder
);
474 mRecorder
->RecordEvent(RecordedSourceSurfaceCreation(retSurf
, aData
, aStride
, aSize
, aFormat
));
476 return retSurf
.forget();
479 TemporaryRef
<SourceSurface
>
480 DrawTargetRecording::OptimizeSourceSurface(SourceSurface
*aSurface
) const
482 RefPtr
<SourceSurface
> surf
= mFinalDT
->OptimizeSourceSurface(aSurface
);
484 RefPtr
<SourceSurface
> retSurf
= new SourceSurfaceRecording(surf
, mRecorder
);
486 RefPtr
<DataSourceSurface
> dataSurf
= surf
->GetDataSurface();
489 // Let's try get it off the original surface.
490 dataSurf
= aSurface
->GetDataSurface();
494 gfxWarning() << "Recording failed to record SourceSurface created from OptimizeSourceSurface";
495 // Insert a bogus source surface.
496 uint8_t *sourceData
= new uint8_t[surf
->GetSize().width
* surf
->GetSize().height
* BytesPerPixel(surf
->GetFormat())];
497 memset(sourceData
, 0, surf
->GetSize().width
* surf
->GetSize().height
* BytesPerPixel(surf
->GetFormat()));
498 mRecorder
->RecordEvent(
499 RecordedSourceSurfaceCreation(retSurf
, sourceData
,
500 surf
->GetSize().width
* BytesPerPixel(surf
->GetFormat()),
501 surf
->GetSize(), surf
->GetFormat()));
502 delete [] sourceData
;
504 mRecorder
->RecordEvent(
505 RecordedSourceSurfaceCreation(retSurf
, dataSurf
->GetData(), dataSurf
->Stride(),
506 dataSurf
->GetSize(), dataSurf
->GetFormat()));
509 return retSurf
.forget();
512 TemporaryRef
<SourceSurface
>
513 DrawTargetRecording::CreateSourceSurfaceFromNativeSurface(const NativeSurface
&aSurface
) const
515 RefPtr
<SourceSurface
> surf
= mFinalDT
->CreateSourceSurfaceFromNativeSurface(aSurface
);
517 RefPtr
<SourceSurface
> retSurf
= new SourceSurfaceRecording(surf
, mRecorder
);
519 RefPtr
<DataSourceSurface
> dataSurf
= surf
->GetDataSurface();
522 gfxWarning() << "Recording failed to record SourceSurface created from OptimizeSourceSurface";
523 // Insert a bogus source surface.
524 uint8_t *sourceData
= new uint8_t[surf
->GetSize().width
* surf
->GetSize().height
* BytesPerPixel(surf
->GetFormat())];
525 memset(sourceData
, 0, surf
->GetSize().width
* surf
->GetSize().height
* BytesPerPixel(surf
->GetFormat()));
526 mRecorder
->RecordEvent(
527 RecordedSourceSurfaceCreation(retSurf
, sourceData
,
528 surf
->GetSize().width
* BytesPerPixel(surf
->GetFormat()),
529 surf
->GetSize(), surf
->GetFormat()));
530 delete [] sourceData
;
532 mRecorder
->RecordEvent(
533 RecordedSourceSurfaceCreation(retSurf
, dataSurf
->GetData(), dataSurf
->Stride(),
534 dataSurf
->GetSize(), dataSurf
->GetFormat()));
537 return retSurf
.forget();
540 TemporaryRef
<DrawTarget
>
541 DrawTargetRecording::CreateSimilarDrawTarget(const IntSize
&aSize
, SurfaceFormat aFormat
) const
543 RefPtr
<DrawTarget
> dt
= mFinalDT
->CreateSimilarDrawTarget(aSize
, aFormat
);
544 return new DrawTargetRecording(mRecorder
.get(), dt
);
547 TemporaryRef
<PathBuilder
>
548 DrawTargetRecording::CreatePathBuilder(FillRule aFillRule
) const
550 RefPtr
<PathBuilder
> builder
= mFinalDT
->CreatePathBuilder(aFillRule
);
551 return new PathBuilderRecording(builder
, aFillRule
);
554 TemporaryRef
<GradientStops
>
555 DrawTargetRecording::CreateGradientStops(GradientStop
*aStops
,
557 ExtendMode aExtendMode
) const
559 RefPtr
<GradientStops
> stops
= mFinalDT
->CreateGradientStops(aStops
, aNumStops
, aExtendMode
);
561 RefPtr
<GradientStops
> retStops
= new GradientStopsRecording(stops
, mRecorder
);
563 mRecorder
->RecordEvent(RecordedGradientStopsCreation(retStops
, aStops
, aNumStops
, aExtendMode
));
565 return retStops
.forget();
569 DrawTargetRecording::SetTransform(const Matrix
&aTransform
)
571 mRecorder
->RecordEvent(RecordedSetTransform(this, aTransform
));
572 DrawTarget::SetTransform(aTransform
);
573 mFinalDT
->SetTransform(aTransform
);
577 DrawTargetRecording::EnsureStored(const Path
*aPath
)
579 if (!mRecorder
->HasStoredPath(aPath
)) {
580 if (aPath
->GetBackendType() != BackendType::RECORDING
) {
581 gfxWarning() << "Cannot record this fill path properly!";
583 PathRecording
*recPath
= const_cast<PathRecording
*>(static_cast<const PathRecording
*>(aPath
));
584 mRecorder
->RecordEvent(RecordedPathCreation(recPath
));
585 mRecorder
->AddStoredPath(aPath
);
586 recPath
->mStoredRecorders
.push_back(mRecorder
);