| File: | var/lib/jenkins/workspace/firefox-scan-build/gfx/2d/InlineTranslator.cpp |
| Warning: | line 40, column 21 The left operand of '>' is a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | |||
| 2 | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ | |||
| 3 | /* This Source Code Form is subject to the terms of the Mozilla Public | |||
| 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this | |||
| 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |||
| 6 | ||||
| 7 | #include "InlineTranslator.h" | |||
| 8 | #include "RecordedEventImpl.h" | |||
| 9 | ||||
| 10 | #include "mozilla/gfx/RecordingTypes.h" | |||
| 11 | ||||
| 12 | using namespace mozilla::gfx; | |||
| 13 | ||||
| 14 | namespace mozilla::gfx { | |||
| 15 | ||||
| 16 | InlineTranslator::InlineTranslator() : mFontContext(nullptr) {} | |||
| 17 | ||||
| 18 | InlineTranslator::InlineTranslator(DrawTarget* aDT, void* aFontContext) | |||
| 19 | : mBaseDT(aDT), mFontContext(aFontContext) {} | |||
| 20 | ||||
| 21 | bool InlineTranslator::TranslateRecording(char* aData, size_t aLen) { | |||
| 22 | MemReader reader(aData, aLen); | |||
| 23 | ||||
| 24 | uint32_t magicInt; | |||
| 25 | ReadElement(reader, magicInt); | |||
| 26 | if (magicInt != mozilla::gfx::kMagicInt) { | |||
| ||||
| 27 | mError = "Magic"; | |||
| 28 | return false; | |||
| 29 | } | |||
| 30 | ||||
| 31 | uint16_t majorRevision; | |||
| 32 | ReadElement(reader, majorRevision); | |||
| 33 | if (majorRevision != kMajorRevision) { | |||
| 34 | mError = "Major"; | |||
| 35 | return false; | |||
| 36 | } | |||
| 37 | ||||
| 38 | uint16_t minorRevision; | |||
| 39 | ReadElement(reader, minorRevision); | |||
| 40 | if (minorRevision > kMinorRevision) { | |||
| ||||
| 41 | mError = "Minor"; | |||
| 42 | return false; | |||
| 43 | } | |||
| 44 | ||||
| 45 | uint8_t eventType = RecordedEvent::EventType::INVALID; | |||
| 46 | ReadElement(reader, eventType); | |||
| 47 | while (reader.good()) { | |||
| 48 | bool success = RecordedEvent::DoWithEvent( | |||
| 49 | reader, static_cast<RecordedEvent::EventType>(eventType), | |||
| 50 | [&](RecordedEvent* recordedEvent) -> bool { | |||
| 51 | // Make sure that the whole event was read from the stream | |||
| 52 | // successfully. | |||
| 53 | if (!reader.good()) { | |||
| 54 | mError = " READ"; | |||
| 55 | return false; | |||
| 56 | } | |||
| 57 | ||||
| 58 | if (!recordedEvent->PlayEvent(this)) { | |||
| 59 | mError = " PLAY"; | |||
| 60 | return false; | |||
| 61 | } | |||
| 62 | ||||
| 63 | return true; | |||
| 64 | }); | |||
| 65 | if (!success) { | |||
| 66 | mError = RecordedEvent::GetEventName( | |||
| 67 | static_cast<RecordedEvent::EventType>(eventType)) + | |||
| 68 | mError; | |||
| 69 | return false; | |||
| 70 | } | |||
| 71 | ||||
| 72 | ReadElement(reader, eventType); | |||
| 73 | } | |||
| 74 | ||||
| 75 | return true; | |||
| 76 | } | |||
| 77 | ||||
| 78 | already_AddRefed<DrawTarget> InlineTranslator::CreateDrawTarget( | |||
| 79 | ReferencePtr aRefPtr, const gfx::IntSize& aSize, | |||
| 80 | gfx::SurfaceFormat aFormat) { | |||
| 81 | MOZ_ASSERT(mBaseDT, "mBaseDT has not been initialized.")do { static_assert( mozilla::detail::AssertionConditionType< decltype(mBaseDT)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(mBaseDT))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mBaseDT" " (" "mBaseDT has not been initialized." ")", "/var/lib/jenkins/workspace/firefox-scan-build/gfx/2d/InlineTranslator.cpp" , 81); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mBaseDT" ") (" "mBaseDT has not been initialized." ")"); do { *((volatile int *)__null) = 81; __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); | |||
| 82 | ||||
| 83 | RefPtr<DrawTarget> drawTarget = mBaseDT; | |||
| 84 | AddDrawTarget(aRefPtr, drawTarget); | |||
| 85 | return drawTarget.forget(); | |||
| 86 | } | |||
| 87 | ||||
| 88 | already_AddRefed<SourceSurface> InlineTranslator::LookupExternalSurface( | |||
| 89 | uint64_t aKey) { | |||
| 90 | if (!mExternalSurfaces) { | |||
| 91 | return nullptr; | |||
| 92 | } | |||
| 93 | RefPtr<SourceSurface> surface = mExternalSurfaces->Get(aKey); | |||
| 94 | return surface.forget(); | |||
| 95 | } | |||
| 96 | ||||
| 97 | } // namespace mozilla::gfx |
| 1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
| 2 | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
| 3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
| 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
| 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| 6 | |
| 7 | #ifndef MOZILLA_GFX_RECORDINGTYPES_H_ |
| 8 | #define MOZILLA_GFX_RECORDINGTYPES_H_ |
| 9 | |
| 10 | #include <ostream> |
| 11 | #include <vector> |
| 12 | |
| 13 | #include "Logging.h" |
| 14 | |
| 15 | namespace mozilla { |
| 16 | namespace gfx { |
| 17 | |
| 18 | template <class S, class T> |
| 19 | struct ElementStreamFormat { |
| 20 | static void Write(S& aStream, const T& aElement) { |
| 21 | aStream.write(reinterpret_cast<const char*>(&aElement), sizeof(T)); |
| 22 | } |
| 23 | static void Read(S& aStream, T& aElement) { |
| 24 | aStream.read(reinterpret_cast<char*>(&aElement), sizeof(T)); |
| 25 | } |
| 26 | }; |
| 27 | template <class S> |
| 28 | struct ElementStreamFormat<S, bool> { |
| 29 | static void Write(S& aStream, const bool& aElement) { |
| 30 | char boolChar = aElement ? '\x01' : '\x00'; |
| 31 | aStream.write(&boolChar, sizeof(boolChar)); |
| 32 | } |
| 33 | static void Read(S& aStream, bool& aElement) { |
| 34 | char boolChar; |
| 35 | aStream.read(&boolChar, sizeof(boolChar)); |
| 36 | switch (boolChar) { |
| 37 | case '\x00': |
| 38 | aElement = false; |
| 39 | break; |
| 40 | case '\x01': |
| 41 | aElement = true; |
| 42 | break; |
| 43 | default: |
| 44 | aStream.SetIsBad(); |
| 45 | aElement = false; |
| 46 | break; |
| 47 | } |
| 48 | } |
| 49 | }; |
| 50 | |
| 51 | template <class S, class T> |
| 52 | void WriteElement(S& aStream, const T& aElement) { |
| 53 | ElementStreamFormat<S, T>::Write(aStream, aElement); |
| 54 | } |
| 55 | template <class S, class T> |
| 56 | void WriteVector(S& aStream, const std::vector<T>& aVector) { |
| 57 | size_t size = aVector.size(); |
| 58 | WriteElement(aStream, size); |
| 59 | if (size) { |
| 60 | aStream.write(reinterpret_cast<const char*>(aVector.data()), |
| 61 | sizeof(T) * size); |
| 62 | } |
| 63 | } |
| 64 | |
| 65 | // ReadElement is disabled for enum types. Use ReadElementConstrained instead. |
| 66 | template <class S, class T, |
| 67 | typename = typename std::enable_if<!std::is_enum<T>::value>::type> |
| 68 | void ReadElement(S& aStream, T& aElement) { |
| 69 | ElementStreamFormat<S, T>::Read(aStream, aElement); |
| 70 | } |
| 71 | template <class S, class T> |
| 72 | void ReadElementConstrained(S& aStream, T& aElement, const T& aMinValue, |
| 73 | const T& aMaxValue) { |
| 74 | ElementStreamFormat<S, T>::Read(aStream, aElement); |
| 75 | if (aElement < aMinValue || aElement > aMaxValue) { |
| 76 | aStream.SetIsBad(); |
| 77 | } |
| 78 | } |
| 79 | template <class S, class T> |
| 80 | void ReadVector(S& aStream, std::vector<T>& aVector) { |
| 81 | size_t size; |
| 82 | ReadElement(aStream, size); |
| 83 | if (size && aStream.good()) { |
| 84 | aVector.resize(size); |
| 85 | aStream.read(reinterpret_cast<char*>(aVector.data()), sizeof(T) * size); |
| 86 | } else { |
| 87 | aVector.clear(); |
| 88 | } |
| 89 | } |
| 90 | |
| 91 | } // namespace gfx |
| 92 | } // namespace mozilla |
| 93 | |
| 94 | #endif /* MOZILLA_GFX_RECORDINGTYPES_H_ */ |
| 1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
| 2 | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
| 3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
| 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
| 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| 6 | |
| 7 | #ifndef MOZILLA_GFX_RECORDEDEVENT_H_ |
| 8 | #define MOZILLA_GFX_RECORDEDEVENT_H_ |
| 9 | |
| 10 | #include <ostream> |
| 11 | #include <sstream> |
| 12 | #include <cstring> |
| 13 | #include <functional> |
| 14 | #include <vector> |
| 15 | |
| 16 | #include "RecordingTypes.h" |
| 17 | #include "mozilla/gfx/Point.h" |
| 18 | #include "mozilla/gfx/Types.h" |
| 19 | #include "mozilla/ipc/ByteBuf.h" |
| 20 | #include "nsRefPtrHashtable.h" |
| 21 | |
| 22 | namespace mozilla { |
| 23 | namespace gfx { |
| 24 | |
| 25 | const uint32_t kMagicInt = 0xc001feed; |
| 26 | |
| 27 | // A change in major revision means a change in event binary format, causing |
| 28 | // loss of backwards compatibility. Old streams will not work in a player |
| 29 | // using a newer major revision. And new streams will not work in a player |
| 30 | // using an older major revision. |
| 31 | const uint16_t kMajorRevision = 10; |
| 32 | // A change in minor revision means additions of new events. New streams will |
| 33 | // not play in older players. |
| 34 | const uint16_t kMinorRevision = 3; |
| 35 | |
| 36 | struct ReferencePtr { |
| 37 | ReferencePtr() : mLongPtr(0) {} |
| 38 | |
| 39 | MOZ_IMPLICIT ReferencePtr(const void* aLongPtr) |
| 40 | : mLongPtr(uint64_t(aLongPtr)) {} |
| 41 | |
| 42 | template <typename T> |
| 43 | MOZ_IMPLICIT ReferencePtr(const RefPtr<T>& aPtr) |
| 44 | : mLongPtr(uint64_t(aPtr.get())) {} |
| 45 | |
| 46 | ReferencePtr& operator=(const void* aLongPtr) { |
| 47 | mLongPtr = uint64_t(aLongPtr); |
| 48 | return *this; |
| 49 | } |
| 50 | |
| 51 | template <typename T> |
| 52 | ReferencePtr& operator=(const RefPtr<T>& aPtr) { |
| 53 | mLongPtr = uint64_t(aPtr.get()); |
| 54 | return *this; |
| 55 | } |
| 56 | |
| 57 | operator void*() const { return (void*)mLongPtr; } |
| 58 | |
| 59 | uint64_t mLongPtr; |
| 60 | }; |
| 61 | |
| 62 | struct RecordedFontDetails { |
| 63 | uint64_t fontDataKey = 0; |
| 64 | uint32_t size = 0; |
| 65 | uint32_t index = 0; |
| 66 | }; |
| 67 | |
| 68 | struct RecordedDependentSurface { |
| 69 | NS_INLINE_DECL_REFCOUNTING(RecordedDependentSurface)public: MozExternalRefCountType AddRef(void) { static_assert( !std::is_destructible_v<RecordedDependentSurface>, "Reference-counted class " "RecordedDependentSurface" " should not have a public destructor. " "Make this class's destructor non-public"); do { static_assert ( mozilla::detail::AssertionConditionType<decltype(int32_t (mRefCnt) >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0" " (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/gfx/RecordedEvent.h" , 69); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { *((volatile int*)__null) = 69; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); _mOwningThread.AssertOwnership("RecordedDependentSurface" " not thread-safe"); ++mRefCnt; NS_LogAddRef((this), (mRefCnt ), ("RecordedDependentSurface"), (uint32_t)(sizeof(*this))); return mRefCnt; } MozExternalRefCountType Release(void) { do { static_assert ( mozilla::detail::AssertionConditionType<decltype(int32_t (mRefCnt) > 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/gfx/RecordedEvent.h" , 69); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { *((volatile int*)__null) = 69 ; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); _mOwningThread.AssertOwnership("RecordedDependentSurface" " not thread-safe"); --mRefCnt; NS_LogRelease((this), (mRefCnt ), ("RecordedDependentSurface")); if (mRefCnt == 0) { mRefCnt = 1; delete (this); return 0; } return mRefCnt; } using HasThreadSafeRefCnt = std::false_type; protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread; public:; |
| 70 | |
| 71 | RecordedDependentSurface(const IntSize& aSize, |
| 72 | mozilla::ipc::ByteBuf&& aRecording) |
| 73 | : mSize(aSize), mRecording(std::move(aRecording)) {} |
| 74 | |
| 75 | IntSize mSize; |
| 76 | mozilla::ipc::ByteBuf mRecording; |
| 77 | |
| 78 | private: |
| 79 | ~RecordedDependentSurface() = default; |
| 80 | }; |
| 81 | |
| 82 | // Used by the Azure drawing debugger (player2d) |
| 83 | inline std::string StringFromPtr(ReferencePtr aPtr) { |
| 84 | std::stringstream stream; |
| 85 | stream << aPtr; |
| 86 | return stream.str(); |
| 87 | } |
| 88 | |
| 89 | class Translator { |
| 90 | public: |
| 91 | virtual ~Translator() = default; |
| 92 | |
| 93 | virtual DrawTarget* LookupDrawTarget(ReferencePtr aRefPtr) = 0; |
| 94 | virtual Path* LookupPath(ReferencePtr aRefPtr) = 0; |
| 95 | virtual SourceSurface* LookupSourceSurface(ReferencePtr aRefPtr) = 0; |
| 96 | virtual FilterNode* LookupFilterNode(ReferencePtr aRefPtr) = 0; |
| 97 | virtual already_AddRefed<GradientStops> LookupGradientStops( |
| 98 | ReferencePtr aRefPtr) = 0; |
| 99 | virtual ScaledFont* LookupScaledFont(ReferencePtr aRefPtr) = 0; |
| 100 | virtual UnscaledFont* LookupUnscaledFont(ReferencePtr aRefPtr) = 0; |
| 101 | virtual NativeFontResource* LookupNativeFontResource(uint64_t aKey) = 0; |
| 102 | virtual already_AddRefed<SourceSurface> LookupExternalSurface(uint64_t aKey) { |
| 103 | return nullptr; |
| 104 | } |
| 105 | virtual already_AddRefed<SourceSurface> |
| 106 | LookupSourceSurfaceFromSurfaceDescriptor( |
| 107 | const layers::SurfaceDescriptor& aDesc) { |
| 108 | MOZ_ASSERT_UNREACHABLE("unexpected to be called")do { static_assert( mozilla::detail::AssertionConditionType< decltype(false)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: " "unexpected to be called" ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/gfx/RecordedEvent.h" , 108); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") (" "MOZ_ASSERT_UNREACHABLE: " "unexpected to be called" ")"); do { *((volatile int*)__null) = 108; __attribute__((nomerge)) :: abort(); } while (false); } } while (false); |
| 109 | return nullptr; |
| 110 | } |
| 111 | void DrawDependentSurface(uint64_t aKey, const Rect& aRect); |
| 112 | virtual void AddDrawTarget(ReferencePtr aRefPtr, DrawTarget* aDT) = 0; |
| 113 | virtual void RemoveDrawTarget(ReferencePtr aRefPtr) = 0; |
| 114 | virtual bool SetCurrentDrawTarget(ReferencePtr aRefPtr) = 0; |
| 115 | virtual void AddPath(ReferencePtr aRefPtr, Path* aPath) = 0; |
| 116 | virtual void RemovePath(ReferencePtr aRefPtr) = 0; |
| 117 | virtual void AddSourceSurface(ReferencePtr aRefPtr, SourceSurface* aPath) = 0; |
| 118 | virtual void RemoveSourceSurface(ReferencePtr aRefPtr) = 0; |
| 119 | virtual void AddFilterNode(mozilla::gfx::ReferencePtr aRefPtr, |
| 120 | FilterNode* aSurface) = 0; |
| 121 | virtual void RemoveFilterNode(mozilla::gfx::ReferencePtr aRefPtr) = 0; |
| 122 | |
| 123 | /** |
| 124 | * Get GradientStops compatible with the translation DrawTarget type. |
| 125 | * @param aRawStops array of raw gradient stops required |
| 126 | * @param aNumStops length of aRawStops |
| 127 | * @param aExtendMode extend mode required |
| 128 | * @return an already addrefed GradientStops for our DrawTarget type |
| 129 | */ |
| 130 | virtual already_AddRefed<GradientStops> GetOrCreateGradientStops( |
| 131 | DrawTarget* aDrawTarget, GradientStop* aRawStops, uint32_t aNumStops, |
| 132 | ExtendMode aExtendMode) { |
| 133 | return aDrawTarget->CreateGradientStops(aRawStops, aNumStops, aExtendMode); |
| 134 | } |
| 135 | virtual void AddGradientStops(ReferencePtr aRefPtr, GradientStops* aPath) = 0; |
| 136 | virtual void RemoveGradientStops(ReferencePtr aRefPtr) = 0; |
| 137 | virtual void AddScaledFont(ReferencePtr aRefPtr, ScaledFont* aScaledFont) = 0; |
| 138 | virtual void RemoveScaledFont(ReferencePtr aRefPtr) = 0; |
| 139 | virtual void AddUnscaledFont(ReferencePtr aRefPtr, |
| 140 | UnscaledFont* aUnscaledFont) = 0; |
| 141 | virtual void RemoveUnscaledFont(ReferencePtr aRefPtr) = 0; |
| 142 | virtual void AddNativeFontResource( |
| 143 | uint64_t aKey, NativeFontResource* aNativeFontResource) = 0; |
| 144 | |
| 145 | virtual already_AddRefed<DrawTarget> CreateDrawTarget(ReferencePtr aRefPtr, |
| 146 | const IntSize& aSize, |
| 147 | SurfaceFormat aFormat); |
| 148 | virtual DrawTarget* GetReferenceDrawTarget() = 0; |
| 149 | virtual Matrix GetReferenceDrawTargetTransform() { return Matrix(); } |
| 150 | virtual void* GetFontContext() { return nullptr; } |
| 151 | |
| 152 | void SetDependentSurfaces( |
| 153 | nsRefPtrHashtable<nsUint64HashKey, RecordedDependentSurface>* |
| 154 | aDependentSurfaces) { |
| 155 | mDependentSurfaces = aDependentSurfaces; |
| 156 | } |
| 157 | |
| 158 | DrawTarget* GetCurrentDrawTarget() const { |
| 159 | return mCurrentDT && mCurrentDT->IsValid() ? mCurrentDT : nullptr; |
| 160 | } |
| 161 | |
| 162 | nsRefPtrHashtable<nsUint64HashKey, RecordedDependentSurface>* |
| 163 | mDependentSurfaces = nullptr; |
| 164 | DrawTarget* mCurrentDT = nullptr; |
| 165 | }; |
| 166 | |
| 167 | struct ColorPatternStorage { |
| 168 | DeviceColor mColor; |
| 169 | }; |
| 170 | |
| 171 | struct LinearGradientPatternStorage { |
| 172 | Point mBegin; |
| 173 | Point mEnd; |
| 174 | ReferencePtr mStops; |
| 175 | Matrix mMatrix; |
| 176 | }; |
| 177 | |
| 178 | struct RadialGradientPatternStorage { |
| 179 | Point mCenter1; |
| 180 | Point mCenter2; |
| 181 | Float mRadius1; |
| 182 | Float mRadius2; |
| 183 | ReferencePtr mStops; |
| 184 | Matrix mMatrix; |
| 185 | }; |
| 186 | |
| 187 | struct ConicGradientPatternStorage { |
| 188 | Point mCenter; |
| 189 | Float mAngle; |
| 190 | Float mStartOffset; |
| 191 | Float mEndOffset; |
| 192 | ReferencePtr mStops; |
| 193 | Matrix mMatrix; |
| 194 | }; |
| 195 | |
| 196 | struct SurfacePatternStorage { |
| 197 | ExtendMode mExtend; |
| 198 | SamplingFilter mSamplingFilter; |
| 199 | ReferencePtr mSurface; |
| 200 | Matrix mMatrix; |
| 201 | IntRect mSamplingRect; |
| 202 | }; |
| 203 | |
| 204 | struct PatternStorage { |
| 205 | PatternType mType; |
| 206 | union { |
| 207 | char* mStorage; |
| 208 | char mColor[sizeof(ColorPatternStorage)]; |
| 209 | char mLinear[sizeof(LinearGradientPatternStorage)]; |
| 210 | char mRadial[sizeof(RadialGradientPatternStorage)]; |
| 211 | char mConic[sizeof(ConicGradientPatternStorage)]; |
| 212 | char mSurface[sizeof(SurfacePatternStorage)]; |
| 213 | }; |
| 214 | }; |
| 215 | |
| 216 | /* SizeCollector and MemWriter are used |
| 217 | * in a pair to first collect the size of the |
| 218 | * event that we're going to write and then |
| 219 | * to write it without checking each individual |
| 220 | * size. */ |
| 221 | struct SizeCollector { |
| 222 | SizeCollector() : mTotalSize(0) {} |
| 223 | void write(const char*, size_t s) { mTotalSize += s; } |
| 224 | size_t mTotalSize; |
| 225 | }; |
| 226 | |
| 227 | struct MemWriter { |
| 228 | constexpr explicit MemWriter(char* aPtr) : mPtr(aPtr) {} |
| 229 | void write(const char* aData, size_t aSize) { |
| 230 | memcpy(mPtr, aData, aSize); |
| 231 | mPtr += aSize; |
| 232 | } |
| 233 | char* mPtr; |
| 234 | }; |
| 235 | |
| 236 | // An istream like class for reading from memory |
| 237 | struct MemReader { |
| 238 | constexpr MemReader(char* aData, size_t aLen) |
| 239 | : mData(aData), mEnd(aData + aLen) {} |
| 240 | void read(char* s, std::streamsize n) { |
| 241 | if (n <= (mEnd - mData)) { |
| 242 | memcpy(s, mData, n); |
| 243 | mData += n; |
| 244 | } else { |
| 245 | // We've requested more data than is available |
| 246 | // set the Reader into an eof state |
| 247 | SetIsBad(); |
| 248 | } |
| 249 | } |
| 250 | bool eof() { return mData > mEnd; } |
| 251 | bool good() { return !eof(); } |
| 252 | void SetIsBad() { mData = mEnd + 1; } |
| 253 | |
| 254 | char* mData; |
| 255 | char* mEnd; |
| 256 | }; |
| 257 | |
| 258 | class ContiguousBuffer { |
| 259 | public: |
| 260 | ContiguousBuffer(char* aStart, size_t aSize) |
| 261 | : mWriter(aStart), mEnd(aStart + aSize) {} |
| 262 | |
| 263 | constexpr MOZ_IMPLICIT ContiguousBuffer(std::nullptr_t) : mWriter(nullptr) {} |
| 264 | |
| 265 | MemWriter& Writer() { return mWriter; } |
| 266 | |
| 267 | size_t SizeRemaining() { return mWriter.mPtr ? mEnd - mWriter.mPtr : 0; } |
| 268 | |
| 269 | bool IsValid() { return !!mWriter.mPtr; } |
| 270 | |
| 271 | private: |
| 272 | MemWriter mWriter; |
| 273 | char* mEnd = nullptr; |
| 274 | }; |
| 275 | |
| 276 | // Allows a derived class to provide guaranteed contiguous buffer. |
| 277 | class ContiguousBufferStream { |
| 278 | public: |
| 279 | /** |
| 280 | * Templated RecordEvent function so that we can record into the buffer |
| 281 | * quickly using MemWriter. |
| 282 | * |
| 283 | * @param aRecordedEvent the event to record |
| 284 | */ |
| 285 | template <class RE> |
| 286 | void RecordEvent(const RE* aRecordedEvent) { |
| 287 | SizeCollector size; |
| 288 | WriteElement(size, aRecordedEvent->GetType()); |
| 289 | aRecordedEvent->Record(size); |
| 290 | auto& buffer = GetContiguousBuffer(size.mTotalSize); |
| 291 | if (!buffer.IsValid()) { |
| 292 | return; |
| 293 | } |
| 294 | |
| 295 | MOZ_ASSERT(size.mTotalSize <= buffer.SizeRemaining())do { static_assert( mozilla::detail::AssertionConditionType< decltype(size.mTotalSize <= buffer.SizeRemaining())>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(size.mTotalSize <= buffer.SizeRemaining()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("size.mTotalSize <= buffer.SizeRemaining()" , "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/gfx/RecordedEvent.h" , 295); AnnotateMozCrashReason("MOZ_ASSERT" "(" "size.mTotalSize <= buffer.SizeRemaining()" ")"); do { *((volatile int*)__null) = 295; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 296 | |
| 297 | WriteElement(buffer.Writer(), aRecordedEvent->GetType()); |
| 298 | aRecordedEvent->Record(buffer.Writer()); |
| 299 | IncrementEventCount(); |
| 300 | } |
| 301 | |
| 302 | protected: |
| 303 | /** |
| 304 | * Provide a contiguous buffer with at least aSize remaining. |
| 305 | */ |
| 306 | virtual ContiguousBuffer& GetContiguousBuffer(size_t aSize) = 0; |
| 307 | |
| 308 | virtual void IncrementEventCount() = 0; |
| 309 | }; |
| 310 | |
| 311 | struct MemStream { |
| 312 | char* mData; |
| 313 | size_t mLength; |
| 314 | size_t mCapacity; |
| 315 | bool mValid = true; |
| 316 | bool Resize(size_t aSize) { |
| 317 | if (!mValid) { |
| 318 | return false; |
| 319 | } |
| 320 | mLength = aSize; |
| 321 | if (mLength > mCapacity) { |
| 322 | mCapacity = mCapacity * 2; |
| 323 | // check if the doubled capacity is enough |
| 324 | // otherwise use double mLength |
| 325 | if (mLength > mCapacity) { |
| 326 | mCapacity = mLength * 2; |
| 327 | } |
| 328 | char* data = (char*)realloc(mData, mCapacity); |
| 329 | if (!data) { |
| 330 | free(mData); |
| 331 | } |
| 332 | mData = data; |
| 333 | } |
| 334 | if (mData) { |
| 335 | return true; |
| 336 | } |
| 337 | NS_ERROR("Failed to allocate MemStream!")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "Failed to allocate MemStream!" , "Error", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/gfx/RecordedEvent.h" , 337); MOZ_PretendNoReturn(); } while (0); |
| 338 | mValid = false; |
| 339 | mLength = 0; |
| 340 | mCapacity = 0; |
| 341 | return false; |
| 342 | } |
| 343 | |
| 344 | void reset() { |
| 345 | free(mData); |
| 346 | mData = nullptr; |
| 347 | mValid = true; |
| 348 | mLength = 0; |
| 349 | mCapacity = 0; |
| 350 | } |
| 351 | |
| 352 | MemStream(const MemStream&) = delete; |
| 353 | MemStream(MemStream&&) = delete; |
| 354 | MemStream& operator=(const MemStream&) = delete; |
| 355 | MemStream& operator=(MemStream&&) = delete; |
| 356 | |
| 357 | void write(const char* aData, size_t aSize) { |
| 358 | if (Resize(mLength + aSize)) { |
| 359 | memcpy(mData + mLength - aSize, aData, aSize); |
| 360 | } |
| 361 | } |
| 362 | |
| 363 | MemStream() : mData(nullptr), mLength(0), mCapacity(0) {} |
| 364 | ~MemStream() { free(mData); } |
| 365 | }; |
| 366 | |
| 367 | class EventStream { |
| 368 | public: |
| 369 | virtual void write(const char* aData, size_t aSize) = 0; |
| 370 | virtual void read(char* aOut, size_t aSize) = 0; |
| 371 | virtual bool good() = 0; |
| 372 | virtual void SetIsBad() = 0; |
| 373 | }; |
| 374 | |
| 375 | class RecordedEvent { |
| 376 | public: |
| 377 | enum EventType : uint8_t { |
| 378 | INVALID = 0, |
| 379 | DRAWTARGETCREATION, |
| 380 | DRAWTARGETDESTRUCTION, |
| 381 | SETCURRENTDRAWTARGET, |
| 382 | FILLRECT, |
| 383 | STROKERECT, |
| 384 | STROKELINE, |
| 385 | STROKECIRCLE, |
| 386 | CLEARRECT, |
| 387 | COPYSURFACE, |
| 388 | SETPERMITSUBPIXELAA, |
| 389 | SETTRANSFORM, |
| 390 | PUSHCLIP, |
| 391 | PUSHCLIPRECT, |
| 392 | POPCLIP, |
| 393 | REMOVEALLCLIPS, |
| 394 | FILL, |
| 395 | FILLCIRCLE, |
| 396 | FILLGLYPHS, |
| 397 | STROKEGLYPHS, |
| 398 | MASK, |
| 399 | STROKE, |
| 400 | DRAWSURFACE, |
| 401 | DRAWSURFACEDESCRIPTOR, |
| 402 | DRAWDEPENDENTSURFACE, |
| 403 | DRAWSURFACEWITHSHADOW, |
| 404 | DRAWSHADOW, |
| 405 | PATHCREATION, |
| 406 | PATHDESTRUCTION, |
| 407 | SOURCESURFACECREATION, |
| 408 | SOURCESURFACEDESTRUCTION, |
| 409 | GRADIENTSTOPSCREATION, |
| 410 | GRADIENTSTOPSDESTRUCTION, |
| 411 | SNAPSHOT, |
| 412 | SCALEDFONTCREATION, |
| 413 | SCALEDFONTDESTRUCTION, |
| 414 | MASKSURFACE, |
| 415 | FILTERNODECREATION, |
| 416 | FILTERNODEDESTRUCTION, |
| 417 | DRAWFILTER, |
| 418 | FILTERNODESETATTRIBUTE, |
| 419 | FILTERNODESETINPUT, |
| 420 | CREATESIMILARDRAWTARGET, |
| 421 | CREATECLIPPEDDRAWTARGET, |
| 422 | CREATEDRAWTARGETFORFILTER, |
| 423 | FONTDATA, |
| 424 | FONTDESC, |
| 425 | PUSHLAYER, |
| 426 | PUSHLAYERWITHBLEND, |
| 427 | POPLAYER, |
| 428 | UNSCALEDFONTCREATION, |
| 429 | UNSCALEDFONTDESTRUCTION, |
| 430 | INTOLUMINANCE, |
| 431 | EXTRACTSUBRECT, |
| 432 | EXTERNALSURFACECREATION, |
| 433 | FLUSH, |
| 434 | DETACHALLSNAPSHOTS, |
| 435 | OPTIMIZESOURCESURFACE, |
| 436 | LINK, |
| 437 | DESTINATION, |
| 438 | LAST, |
| 439 | }; |
| 440 | |
| 441 | virtual ~RecordedEvent() = default; |
| 442 | |
| 443 | static std::string GetEventName(EventType aType); |
| 444 | |
| 445 | /** |
| 446 | * Play back this event using the translator. Note that derived classes |
| 447 | * should |
| 448 | * only return false when there is a fatal error, as it will probably mean |
| 449 | * the |
| 450 | * translation will abort. |
| 451 | * @param aTranslator Translator to be used for retrieving other referenced |
| 452 | * objects and making playback decisions. |
| 453 | * @return true unless a fatal problem has occurred and playback should |
| 454 | * abort. |
| 455 | */ |
| 456 | virtual bool PlayEvent(Translator* aTranslator) const { return true; } |
| 457 | |
| 458 | virtual void RecordToStream(std::ostream& aStream) const = 0; |
| 459 | virtual void RecordToStream(EventStream& aStream) const = 0; |
| 460 | virtual void RecordToStream(ContiguousBufferStream& aStream) const = 0; |
| 461 | virtual void RecordToStream(MemStream& aStream) const = 0; |
| 462 | |
| 463 | virtual void OutputSimpleEventInfo(std::stringstream& aStringStream) const {} |
| 464 | |
| 465 | template <class S> |
| 466 | void RecordPatternData(S& aStream, |
| 467 | const PatternStorage& aPatternStorage) const; |
| 468 | template <class S> |
| 469 | void ReadPatternData(S& aStream, PatternStorage& aPatternStorage) const; |
| 470 | void StorePattern(PatternStorage& aDestination, const Pattern& aSource) const; |
| 471 | template <class S> |
| 472 | void RecordStrokeOptions(S& aStream, |
| 473 | const StrokeOptions& aStrokeOptions) const; |
| 474 | template <class S> |
| 475 | void ReadStrokeOptions(S& aStream, StrokeOptions& aStrokeOptions); |
| 476 | |
| 477 | virtual std::string GetName() const = 0; |
| 478 | |
| 479 | virtual ReferencePtr GetDestinedDT() { return nullptr; } |
| 480 | |
| 481 | void OutputSimplePatternInfo(const PatternStorage& aStorage, |
| 482 | std::stringstream& aOutput) const; |
| 483 | |
| 484 | template <class S> |
| 485 | static bool DoWithEvent(S& aStream, EventType aType, |
| 486 | const std::function<bool(RecordedEvent*)>& aAction); |
| 487 | static bool DoWithEventFromStream( |
| 488 | EventStream& aStream, EventType aType, |
| 489 | const std::function<bool(RecordedEvent*)>& aAction); |
| 490 | static bool DoWithEventFromReader( |
| 491 | MemReader& aReader, EventType aType, |
| 492 | const std::function<bool(RecordedEvent*)>& aAction); |
| 493 | |
| 494 | EventType GetType() const { return (EventType)mType; } |
| 495 | |
| 496 | protected: |
| 497 | friend class DrawEventRecorderPrivate; |
| 498 | friend class DrawEventRecorderMemory; |
| 499 | static void RecordUnscaledFont(UnscaledFont* aUnscaledFont, |
| 500 | std::ostream* aOutput); |
| 501 | static void RecordUnscaledFont(UnscaledFont* aUnscaledFont, |
| 502 | MemStream& aOutput); |
| 503 | template <class S> |
| 504 | static void RecordUnscaledFontImpl(UnscaledFont* aUnscaledFont, S& aOutput); |
| 505 | |
| 506 | MOZ_IMPLICIT RecordedEvent(EventType aType) : mType(aType) {} |
| 507 | |
| 508 | EventType mType; |
| 509 | std::vector<Float> mDashPatternStorage; |
| 510 | }; |
| 511 | |
| 512 | template <class Derived> |
| 513 | class RecordedEventDerived : public RecordedEvent { |
| 514 | using RecordedEvent::RecordedEvent; |
| 515 | |
| 516 | public: |
| 517 | void RecordToStream(std::ostream& aStream) const override { |
| 518 | WriteElement(aStream, this->mType); |
| 519 | static_cast<const Derived*>(this)->Record(aStream); |
| 520 | } |
| 521 | void RecordToStream(EventStream& aStream) const override { |
| 522 | WriteElement(aStream, this->mType); |
| 523 | static_cast<const Derived*>(this)->Record(aStream); |
| 524 | } |
| 525 | void RecordToStream(ContiguousBufferStream& aStream) const final { |
| 526 | aStream.RecordEvent(static_cast<const Derived*>(this)); |
| 527 | } |
| 528 | void RecordToStream(MemStream& aStream) const override { |
| 529 | SizeCollector size; |
| 530 | WriteElement(size, this->mType); |
| 531 | static_cast<const Derived*>(this)->Record(size); |
| 532 | |
| 533 | if (!aStream.Resize(aStream.mLength + size.mTotalSize)) { |
| 534 | return; |
| 535 | } |
| 536 | |
| 537 | MemWriter writer(aStream.mData + aStream.mLength - size.mTotalSize); |
| 538 | WriteElement(writer, this->mType); |
| 539 | static_cast<const Derived*>(this)->Record(writer); |
| 540 | } |
| 541 | }; |
| 542 | |
| 543 | } // namespace gfx |
| 544 | } // namespace mozilla |
| 545 | |
| 546 | #endif |