diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
commit | 43a97878ce14b72f0981164f87f2e35e14151312 (patch) | |
tree | 620249daf56c0258faa40cbdcf9cfba06de2a846 /gfx/2d/RecordedEvent.h | |
parent | Initial commit. (diff) | |
download | firefox-upstream.tar.xz firefox-upstream.zip |
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/2d/RecordedEvent.h')
-rw-r--r-- | gfx/2d/RecordedEvent.h | 517 |
1 files changed, 517 insertions, 0 deletions
diff --git a/gfx/2d/RecordedEvent.h b/gfx/2d/RecordedEvent.h new file mode 100644 index 0000000000..17516436e2 --- /dev/null +++ b/gfx/2d/RecordedEvent.h @@ -0,0 +1,517 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MOZILLA_GFX_RECORDEDEVENT_H_ +#define MOZILLA_GFX_RECORDEDEVENT_H_ + +#include <ostream> +#include <sstream> +#include <cstring> +#include <functional> +#include <vector> + +#include "RecordingTypes.h" +#include "mozilla/gfx/Point.h" +#include "mozilla/gfx/Types.h" +#include "mozilla/ipc/ByteBuf.h" +#include "nsRefPtrHashtable.h" + +namespace mozilla { +namespace gfx { + +const uint32_t kMagicInt = 0xc001feed; + +// A change in major revision means a change in event binary format, causing +// loss of backwards compatibility. Old streams will not work in a player +// using a newer major revision. And new streams will not work in a player +// using an older major revision. +const uint16_t kMajorRevision = 10; +// A change in minor revision means additions of new events. New streams will +// not play in older players. +const uint16_t kMinorRevision = 3; + +struct ReferencePtr { + ReferencePtr() : mLongPtr(0) {} + + MOZ_IMPLICIT ReferencePtr(const void* aLongPtr) + : mLongPtr(uint64_t(aLongPtr)) {} + + template <typename T> + MOZ_IMPLICIT ReferencePtr(const RefPtr<T>& aPtr) + : mLongPtr(uint64_t(aPtr.get())) {} + + ReferencePtr& operator=(const void* aLongPtr) { + mLongPtr = uint64_t(aLongPtr); + return *this; + } + + template <typename T> + ReferencePtr& operator=(const RefPtr<T>& aPtr) { + mLongPtr = uint64_t(aPtr.get()); + return *this; + } + + operator void*() const { return (void*)mLongPtr; } + + uint64_t mLongPtr; +}; + +struct RecordedFontDetails { + uint64_t fontDataKey = 0; + uint32_t size = 0; + uint32_t index = 0; +}; + +struct RecordedDependentSurface { + NS_INLINE_DECL_REFCOUNTING(RecordedDependentSurface); + + RecordedDependentSurface(const IntSize& aSize, + mozilla::ipc::ByteBuf&& aRecording) + : mSize(aSize), mRecording(std::move(aRecording)) {} + + IntSize mSize; + mozilla::ipc::ByteBuf mRecording; + + private: + ~RecordedDependentSurface() = default; +}; + +// Used by the Azure drawing debugger (player2d) +inline std::string StringFromPtr(ReferencePtr aPtr) { + std::stringstream stream; + stream << aPtr; + return stream.str(); +} + +class Translator { + public: + virtual ~Translator() = default; + + virtual DrawTarget* LookupDrawTarget(ReferencePtr aRefPtr) = 0; + virtual Path* LookupPath(ReferencePtr aRefPtr) = 0; + virtual SourceSurface* LookupSourceSurface(ReferencePtr aRefPtr) = 0; + virtual FilterNode* LookupFilterNode(ReferencePtr aRefPtr) = 0; + virtual already_AddRefed<GradientStops> LookupGradientStops( + ReferencePtr aRefPtr) = 0; + virtual ScaledFont* LookupScaledFont(ReferencePtr aRefPtr) = 0; + virtual UnscaledFont* LookupUnscaledFont(ReferencePtr aRefPtr) = 0; + virtual NativeFontResource* LookupNativeFontResource(uint64_t aKey) = 0; + virtual already_AddRefed<SourceSurface> LookupExternalSurface(uint64_t aKey) { + return nullptr; + } + void DrawDependentSurface(ReferencePtr aDrawTarget, uint64_t aKey, + const Rect& aRect); + virtual void AddDrawTarget(ReferencePtr aRefPtr, DrawTarget* aDT) = 0; + virtual void RemoveDrawTarget(ReferencePtr aRefPtr) = 0; + virtual void AddPath(ReferencePtr aRefPtr, Path* aPath) = 0; + virtual void RemovePath(ReferencePtr aRefPtr) = 0; + virtual void AddSourceSurface(ReferencePtr aRefPtr, SourceSurface* aPath) = 0; + virtual void RemoveSourceSurface(ReferencePtr aRefPtr) = 0; + virtual void AddFilterNode(mozilla::gfx::ReferencePtr aRefPtr, + FilterNode* aSurface) = 0; + virtual void RemoveFilterNode(mozilla::gfx::ReferencePtr aRefPtr) = 0; + + /** + * Get GradientStops compatible with the translation DrawTarget type. + * @param aRawStops array of raw gradient stops required + * @param aNumStops length of aRawStops + * @param aExtendMode extend mode required + * @return an already addrefed GradientStops for our DrawTarget type + */ + virtual already_AddRefed<GradientStops> GetOrCreateGradientStops( + GradientStop* aRawStops, uint32_t aNumStops, ExtendMode aExtendMode) { + return GetReferenceDrawTarget()->CreateGradientStops(aRawStops, aNumStops, + aExtendMode); + } + virtual void AddGradientStops(ReferencePtr aRefPtr, GradientStops* aPath) = 0; + virtual void RemoveGradientStops(ReferencePtr aRefPtr) = 0; + virtual void AddScaledFont(ReferencePtr aRefPtr, ScaledFont* aScaledFont) = 0; + virtual void RemoveScaledFont(ReferencePtr aRefPtr) = 0; + virtual void AddUnscaledFont(ReferencePtr aRefPtr, + UnscaledFont* aUnscaledFont) = 0; + virtual void RemoveUnscaledFont(ReferencePtr aRefPtr) = 0; + virtual void AddNativeFontResource( + uint64_t aKey, NativeFontResource* aNativeFontResource) = 0; + + virtual already_AddRefed<DrawTarget> CreateDrawTarget(ReferencePtr aRefPtr, + const IntSize& aSize, + SurfaceFormat aFormat); + virtual DrawTarget* GetReferenceDrawTarget() = 0; + virtual Matrix GetReferenceDrawTargetTransform() { return Matrix(); } + virtual void* GetFontContext() { return nullptr; } + + void SetDependentSurfaces( + nsRefPtrHashtable<nsUint64HashKey, RecordedDependentSurface>* + aDependentSurfaces) { + mDependentSurfaces = aDependentSurfaces; + } + + nsRefPtrHashtable<nsUint64HashKey, RecordedDependentSurface>* + mDependentSurfaces = nullptr; +}; + +struct ColorPatternStorage { + DeviceColor mColor; +}; + +struct LinearGradientPatternStorage { + Point mBegin; + Point mEnd; + ReferencePtr mStops; + Matrix mMatrix; +}; + +struct RadialGradientPatternStorage { + Point mCenter1; + Point mCenter2; + Float mRadius1; + Float mRadius2; + ReferencePtr mStops; + Matrix mMatrix; +}; + +struct ConicGradientPatternStorage { + Point mCenter; + Float mAngle; + Float mStartOffset; + Float mEndOffset; + ReferencePtr mStops; + Matrix mMatrix; +}; + +struct SurfacePatternStorage { + ExtendMode mExtend; + SamplingFilter mSamplingFilter; + ReferencePtr mSurface; + Matrix mMatrix; + IntRect mSamplingRect; +}; + +struct PatternStorage { + PatternType mType; + union { + char* mStorage; + char mColor[sizeof(ColorPatternStorage)]; + char mLinear[sizeof(LinearGradientPatternStorage)]; + char mRadial[sizeof(RadialGradientPatternStorage)]; + char mConic[sizeof(ConicGradientPatternStorage)]; + char mSurface[sizeof(SurfacePatternStorage)]; + }; +}; + +/* SizeCollector and MemWriter are used + * in a pair to first collect the size of the + * event that we're going to write and then + * to write it without checking each individual + * size. */ +struct SizeCollector { + SizeCollector() : mTotalSize(0) {} + void write(const char*, size_t s) { mTotalSize += s; } + size_t mTotalSize; +}; + +struct MemWriter { + explicit MemWriter(char* aPtr) : mPtr(aPtr) {} + void write(const char* aData, size_t aSize) { + memcpy(mPtr, aData, aSize); + mPtr += aSize; + } + char* mPtr; +}; + +// This is a simple interface for an EventRingBuffer, so we can use it in the +// RecordedEvent reading and writing machinery. +class EventRingBuffer { + public: + /** + * Templated RecordEvent function so that when we have enough contiguous + * space we can record into the buffer quickly using MemWriter. + * + * @param aRecordedEvent the event to record + */ + template <class RE> + void RecordEvent(const RE* aRecordedEvent) { + SizeCollector size; + WriteElement(size, aRecordedEvent->GetType()); + aRecordedEvent->Record(size); + if (size.mTotalSize > mAvailable) { + WaitForAndRecalculateAvailableSpace(); + } + if (size.mTotalSize <= mAvailable) { + MemWriter writer(mBufPos); + WriteElement(writer, aRecordedEvent->GetType()); + aRecordedEvent->Record(writer); + UpdateWriteTotalsBy(size.mTotalSize); + } else { + WriteElement(*this, aRecordedEvent->GetType()); + aRecordedEvent->Record(*this); + } + } + + /** + * Simple write function required by WriteElement. + * + * @param aData the data to be written to the buffer + * @param aSize the number of chars to write + */ + virtual void write(const char* const aData, const size_t aSize) = 0; + + /** + * Simple read function required by ReadElement. + * + * @param aOut the pointer to read into + * @param aSize the number of chars to read + */ + virtual void read(char* const aOut, const size_t aSize) = 0; + + virtual bool good() const = 0; + + virtual void SetIsBad() = 0; + + protected: + /** + * Wait until space is available for writing and then set mBufPos and + * mAvailable. + */ + virtual bool WaitForAndRecalculateAvailableSpace() = 0; + + /** + * Update write count, mBufPos and mAvailable. + * + * @param aCount number of bytes written + */ + virtual void UpdateWriteTotalsBy(uint32_t aCount) = 0; + + char* mBufPos = nullptr; + uint32_t mAvailable = 0; +}; + +struct MemStream { + char* mData; + size_t mLength; + size_t mCapacity; + bool mValid = true; + bool Resize(size_t aSize) { + if (!mValid) { + return false; + } + mLength = aSize; + if (mLength > mCapacity) { + mCapacity = mCapacity * 2; + // check if the doubled capacity is enough + // otherwise use double mLength + if (mLength > mCapacity) { + mCapacity = mLength * 2; + } + char* data = (char*)realloc(mData, mCapacity); + if (!data) { + free(mData); + } + mData = data; + } + if (mData) { + return true; + } + NS_ERROR("Failed to allocate MemStream!"); + mValid = false; + mLength = 0; + mCapacity = 0; + return false; + } + + void reset() { + free(mData); + mData = nullptr; + mValid = true; + mLength = 0; + mCapacity = 0; + } + + MemStream(const MemStream&) = delete; + MemStream(MemStream&&) = delete; + MemStream& operator=(const MemStream&) = delete; + MemStream& operator=(MemStream&&) = delete; + + void write(const char* aData, size_t aSize) { + if (Resize(mLength + aSize)) { + memcpy(mData + mLength - aSize, aData, aSize); + } + } + + MemStream() : mData(nullptr), mLength(0), mCapacity(0) {} + ~MemStream() { free(mData); } +}; + +class EventStream { + public: + virtual void write(const char* aData, size_t aSize) = 0; + virtual void read(char* aOut, size_t aSize) = 0; + virtual bool good() = 0; + virtual void SetIsBad() = 0; +}; + +class RecordedEvent { + public: + enum EventType { + DRAWTARGETCREATION = 0, + DRAWTARGETDESTRUCTION, + FILLRECT, + STROKERECT, + STROKELINE, + CLEARRECT, + COPYSURFACE, + SETTRANSFORM, + PUSHCLIP, + PUSHCLIPRECT, + POPCLIP, + FILL, + FILLGLYPHS, + MASK, + STROKE, + DRAWSURFACE, + DRAWDEPENDENTSURFACE, + DRAWSURFACEWITHSHADOW, + PATHCREATION, + PATHDESTRUCTION, + SOURCESURFACECREATION, + SOURCESURFACEDESTRUCTION, + GRADIENTSTOPSCREATION, + GRADIENTSTOPSDESTRUCTION, + SNAPSHOT, + SCALEDFONTCREATION, + SCALEDFONTDESTRUCTION, + MASKSURFACE, + FILTERNODECREATION, + FILTERNODEDESTRUCTION, + DRAWFILTER, + FILTERNODESETATTRIBUTE, + FILTERNODESETINPUT, + CREATESIMILARDRAWTARGET, + CREATECLIPPEDDRAWTARGET, + CREATEDRAWTARGETFORFILTER, + FONTDATA, + FONTDESC, + PUSHLAYER, + PUSHLAYERWITHBLEND, + POPLAYER, + UNSCALEDFONTCREATION, + UNSCALEDFONTDESTRUCTION, + INTOLUMINANCE, + EXTERNALSURFACECREATION, + FLUSH, + DETACHALLSNAPSHOTS, + OPTIMIZESOURCESURFACE, + LINK, + DESTINATION, + LAST, + }; + + virtual ~RecordedEvent() = default; + + static std::string GetEventName(EventType aType); + + /** + * Play back this event using the translator. Note that derived classes + * should + * only return false when there is a fatal error, as it will probably mean + * the + * translation will abort. + * @param aTranslator Translator to be used for retrieving other referenced + * objects and making playback decisions. + * @return true unless a fatal problem has occurred and playback should + * abort. + */ + virtual bool PlayEvent(Translator* aTranslator) const { return true; } + + virtual void RecordToStream(std::ostream& aStream) const = 0; + virtual void RecordToStream(EventStream& aStream) const = 0; + virtual void RecordToStream(EventRingBuffer& aStream) const = 0; + virtual void RecordToStream(MemStream& aStream) const = 0; + + virtual void OutputSimpleEventInfo(std::stringstream& aStringStream) const {} + + template <class S> + void RecordPatternData(S& aStream, + const PatternStorage& aPatternStorage) const; + template <class S> + void ReadPatternData(S& aStream, PatternStorage& aPatternStorage) const; + void StorePattern(PatternStorage& aDestination, const Pattern& aSource) const; + template <class S> + void RecordStrokeOptions(S& aStream, + const StrokeOptions& aStrokeOptions) const; + template <class S> + void ReadStrokeOptions(S& aStream, StrokeOptions& aStrokeOptions); + + virtual std::string GetName() const = 0; + + virtual ReferencePtr GetDestinedDT() { return nullptr; } + + void OutputSimplePatternInfo(const PatternStorage& aStorage, + std::stringstream& aOutput) const; + + template <class S> + static bool DoWithEvent(S& aStream, EventType aType, + const std::function<bool(RecordedEvent*)>& aAction); + static bool DoWithEventFromStream( + EventStream& aStream, EventType aType, + const std::function<bool(RecordedEvent*)>& aAction); + static bool DoWithEventFromStream( + EventRingBuffer& aStream, EventType aType, + const std::function<bool(RecordedEvent*)>& aAction); + + EventType GetType() const { return (EventType)mType; } + + protected: + friend class DrawEventRecorderPrivate; + friend class DrawEventRecorderMemory; + static void RecordUnscaledFont(UnscaledFont* aUnscaledFont, + std::ostream* aOutput); + static void RecordUnscaledFont(UnscaledFont* aUnscaledFont, + MemStream& aOutput); + template <class S> + static void RecordUnscaledFontImpl(UnscaledFont* aUnscaledFont, S& aOutput); + + MOZ_IMPLICIT RecordedEvent(int32_t aType) : mType(aType) {} + + int32_t mType; + std::vector<Float> mDashPatternStorage; +}; + +template <class Derived> +class RecordedEventDerived : public RecordedEvent { + using RecordedEvent::RecordedEvent; + + public: + void RecordToStream(std::ostream& aStream) const override { + WriteElement(aStream, this->mType); + static_cast<const Derived*>(this)->Record(aStream); + } + void RecordToStream(EventStream& aStream) const override { + WriteElement(aStream, this->mType); + static_cast<const Derived*>(this)->Record(aStream); + } + void RecordToStream(EventRingBuffer& aStream) const final { + aStream.RecordEvent(static_cast<const Derived*>(this)); + } + void RecordToStream(MemStream& aStream) const override { + SizeCollector size; + WriteElement(size, this->mType); + static_cast<const Derived*>(this)->Record(size); + + if (!aStream.Resize(aStream.mLength + size.mTotalSize)) { + return; + } + + MemWriter writer(aStream.mData + aStream.mLength - size.mTotalSize); + WriteElement(writer, this->mType); + static_cast<const Derived*>(this)->Record(writer); + } +}; + +} // namespace gfx +} // namespace mozilla + +#endif |