RecordedEvent.h (19064B)
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 15 #include "RecordingTypes.h" 16 #include "mozilla/PodOperations.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 explicit ReferencePtr(uintptr_t aLongPtr) : mLongPtr(uint64_t(aLongPtr)) {} 47 48 ReferencePtr& operator=(const void* aLongPtr) { 49 mLongPtr = uint64_t(aLongPtr); 50 return *this; 51 } 52 53 template <typename T> 54 ReferencePtr& operator=(const RefPtr<T>& aPtr) { 55 mLongPtr = uint64_t(aPtr.get()); 56 return *this; 57 } 58 59 operator void*() const { return (void*)mLongPtr; } 60 61 explicit operator uintptr_t() const { return uintptr_t(mLongPtr); } 62 63 // Implement some operators so this class can be used as a key in 64 // stdlib classes. 65 bool operator<(const ReferencePtr& aOther) const { 66 return mLongPtr < aOther.mLongPtr; 67 } 68 69 bool operator>(const ReferencePtr& aOther) const { 70 return mLongPtr > aOther.mLongPtr; 71 } 72 73 bool operator==(const ReferencePtr& aOther) const { 74 return mLongPtr == aOther.mLongPtr; 75 } 76 77 bool operator!=(const ReferencePtr& aOther) const { 78 return !(*this == aOther); 79 } 80 81 bool operator>=(const ReferencePtr& aOther) const { 82 return mLongPtr >= aOther.mLongPtr; 83 } 84 85 uint64_t mLongPtr; 86 }; 87 88 struct RecordedFontDetails { 89 uint64_t fontDataKey = 0; 90 uint32_t index = 0; 91 }; 92 93 struct RecordedDependentSurface { 94 NS_INLINE_DECL_REFCOUNTING(RecordedDependentSurface); 95 96 RecordedDependentSurface(const IntSize& aSize, 97 mozilla::ipc::ByteBuf&& aRecording) 98 : mSize(aSize), mRecording(std::move(aRecording)) {} 99 100 IntSize mSize; 101 mozilla::ipc::ByteBuf mRecording; 102 103 private: 104 ~RecordedDependentSurface() = default; 105 }; 106 107 // Used by the Azure drawing debugger (player2d) 108 inline std::string StringFromPtr(ReferencePtr aPtr) { 109 std::stringstream stream; 110 stream << aPtr; 111 return stream.str(); 112 } 113 114 class Translator { 115 public: 116 virtual ~Translator() = default; 117 118 virtual DrawTarget* LookupDrawTarget(ReferencePtr aRefPtr) = 0; 119 virtual Path* LookupPath(ReferencePtr aRefPtr) = 0; 120 virtual SourceSurface* LookupSourceSurface(ReferencePtr aRefPtr) = 0; 121 virtual FilterNode* LookupFilterNode(ReferencePtr aRefPtr) = 0; 122 virtual already_AddRefed<GradientStops> LookupGradientStops( 123 ReferencePtr aRefPtr) = 0; 124 virtual ScaledFont* LookupScaledFont(ReferencePtr aRefPtr) = 0; 125 virtual UnscaledFont* LookupUnscaledFont(ReferencePtr aRefPtr) = 0; 126 virtual NativeFontResource* LookupNativeFontResource(uint64_t aKey) = 0; 127 virtual already_AddRefed<SourceSurface> LookupExternalSurface(uint64_t aKey) { 128 return nullptr; 129 } 130 virtual already_AddRefed<SourceSurface> 131 LookupSourceSurfaceFromSurfaceDescriptor( 132 const layers::SurfaceDescriptor& aDesc) { 133 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 134 return nullptr; 135 } 136 void DrawDependentSurface(uint64_t aKey, const Rect& aRect); 137 virtual void AddDrawTarget(ReferencePtr aRefPtr, DrawTarget* aDT) = 0; 138 virtual void RemoveDrawTarget(ReferencePtr aRefPtr) = 0; 139 virtual bool SetCurrentDrawTarget(ReferencePtr aRefPtr) = 0; 140 virtual void AddPath(ReferencePtr aRefPtr, Path* aPath) = 0; 141 virtual void RemovePath(ReferencePtr aRefPtr) = 0; 142 virtual void AddSourceSurface(ReferencePtr aRefPtr, SourceSurface* aPath) = 0; 143 virtual void RemoveSourceSurface(ReferencePtr aRefPtr) = 0; 144 virtual void AddFilterNode(mozilla::gfx::ReferencePtr aRefPtr, 145 FilterNode* aSurface) = 0; 146 virtual void RemoveFilterNode(mozilla::gfx::ReferencePtr aRefPtr) = 0; 147 148 /** 149 * Get GradientStops compatible with the translation DrawTarget type. 150 * @param aRawStops array of raw gradient stops required 151 * @param aNumStops length of aRawStops 152 * @param aExtendMode extend mode required 153 * @return an already addrefed GradientStops for our DrawTarget type 154 */ 155 virtual already_AddRefed<GradientStops> GetOrCreateGradientStops( 156 DrawTarget* aDrawTarget, GradientStop* aRawStops, uint32_t aNumStops, 157 ExtendMode aExtendMode) { 158 return aDrawTarget->CreateGradientStops(aRawStops, aNumStops, aExtendMode); 159 } 160 virtual void AddGradientStops(ReferencePtr aRefPtr, GradientStops* aPath) = 0; 161 virtual void RemoveGradientStops(ReferencePtr aRefPtr) = 0; 162 virtual void AddScaledFont(ReferencePtr aRefPtr, ScaledFont* aScaledFont) = 0; 163 virtual void RemoveScaledFont(ReferencePtr aRefPtr) = 0; 164 virtual void AddUnscaledFont(ReferencePtr aRefPtr, 165 UnscaledFont* aUnscaledFont) = 0; 166 virtual void RemoveUnscaledFont(ReferencePtr aRefPtr) = 0; 167 virtual void AddNativeFontResource( 168 uint64_t aKey, NativeFontResource* aNativeFontResource) = 0; 169 170 virtual already_AddRefed<DrawTarget> CreateDrawTarget(ReferencePtr aRefPtr, 171 const IntSize& aSize, 172 SurfaceFormat aFormat); 173 virtual DrawTarget* GetReferenceDrawTarget() = 0; 174 virtual Matrix GetReferenceDrawTargetTransform() { return Matrix(); } 175 virtual void* GetFontContext() { return nullptr; } 176 177 void SetDependentSurfaces( 178 nsRefPtrHashtable<nsUint64HashKey, RecordedDependentSurface>* 179 aDependentSurfaces) { 180 mDependentSurfaces = aDependentSurfaces; 181 } 182 183 // NOTE that the returned DrawTarget may be in an error state! 184 DrawTarget* GetCurrentDrawTarget() const { return mCurrentDT; } 185 186 nsRefPtrHashtable<nsUint64HashKey, RecordedDependentSurface>* 187 mDependentSurfaces = nullptr; 188 DrawTarget* mCurrentDT = nullptr; 189 }; 190 191 struct ColorPatternStorage { 192 DeviceColor mColor; 193 }; 194 195 struct LinearGradientPatternStorage { 196 Point mBegin; 197 Point mEnd; 198 ReferencePtr mStops; 199 Matrix mMatrix; 200 }; 201 202 struct RadialGradientPatternStorage { 203 Point mCenter1; 204 Point mCenter2; 205 Float mRadius1; 206 Float mRadius2; 207 ReferencePtr mStops; 208 Matrix mMatrix; 209 }; 210 211 struct ConicGradientPatternStorage { 212 Point mCenter; 213 Float mAngle; 214 Float mStartOffset; 215 Float mEndOffset; 216 ReferencePtr mStops; 217 Matrix mMatrix; 218 }; 219 220 struct SurfacePatternStorage { 221 ExtendMode mExtend; 222 SamplingFilter mSamplingFilter; 223 ReferencePtr mSurface; 224 Matrix mMatrix; 225 IntRect mSamplingRect; 226 }; 227 228 struct PatternStorage { 229 PatternType mType; 230 union { 231 char* mStorage; 232 char mColor[sizeof(ColorPatternStorage)]; 233 char mLinear[sizeof(LinearGradientPatternStorage)]; 234 char mRadial[sizeof(RadialGradientPatternStorage)]; 235 char mConic[sizeof(ConicGradientPatternStorage)]; 236 char mSurface[sizeof(SurfacePatternStorage)]; 237 }; 238 }; 239 240 /* SizeCollector and MemWriter are used 241 * in a pair to first collect the size of the 242 * event that we're going to write and then 243 * to write it without checking each individual 244 * size. */ 245 struct SizeCollector { 246 SizeCollector() : mTotalSize(0) {} 247 void write(const char*, size_t s) { mTotalSize += s; } 248 size_t mTotalSize; 249 }; 250 251 struct MemWriter { 252 constexpr explicit MemWriter(char* aPtr) : mPtr(aPtr) {} 253 void write(const char* aData, size_t aSize) { 254 memcpy(mPtr, aData, aSize); 255 mPtr += aSize; 256 } 257 char* mPtr; 258 }; 259 260 // An istream like class for reading from memory 261 struct MemReader { 262 constexpr MemReader(const char* aData, size_t aLen) 263 : mData(aData), mEnd(aData + aLen) {} 264 void read(char* s, std::streamsize n) { 265 if (n <= (mEnd - mData)) { 266 memcpy(s, mData, n); 267 mData += n; 268 } else { 269 // We've requested more data than is available 270 // set the Reader into an eof state 271 SetIsBad(); 272 } 273 } 274 bool eof() { return mData > mEnd; } 275 bool good() { return !eof(); } 276 void SetIsBad() { mData = mEnd + 1; } 277 278 const char* mData; 279 const char* mEnd; 280 }; 281 282 class ContiguousBuffer { 283 public: 284 ContiguousBuffer(char* aStart, size_t aSize) 285 : mWriter(aStart), mEnd(aStart + aSize) {} 286 287 constexpr MOZ_IMPLICIT ContiguousBuffer(std::nullptr_t) : mWriter(nullptr) {} 288 289 MemWriter& Writer() { return mWriter; } 290 291 size_t SizeRemaining() { return mWriter.mPtr ? mEnd - mWriter.mPtr : 0; } 292 293 bool IsValid() { return !!mWriter.mPtr; } 294 295 private: 296 MemWriter mWriter; 297 char* mEnd = nullptr; 298 }; 299 300 // Allows a derived class to provide guaranteed contiguous buffer. 301 class ContiguousBufferStream { 302 public: 303 /** 304 * Templated RecordEvent function so that we can record into the buffer 305 * quickly using MemWriter. 306 * 307 * @param aRecordedEvent the event to record 308 */ 309 template <class RE> 310 void RecordEvent(const RE* aRecordedEvent) { 311 SizeCollector size; 312 WriteElement(size, aRecordedEvent->GetType()); 313 aRecordedEvent->Record(size); 314 auto& buffer = GetContiguousBuffer(size.mTotalSize); 315 if (!buffer.IsValid()) { 316 return; 317 } 318 319 MOZ_ASSERT(size.mTotalSize <= buffer.SizeRemaining()); 320 321 WriteElement(buffer.Writer(), aRecordedEvent->GetType()); 322 aRecordedEvent->Record(buffer.Writer()); 323 IncrementEventCount(); 324 } 325 326 protected: 327 /** 328 * Provide a contiguous buffer with at least aSize remaining. 329 */ 330 virtual ContiguousBuffer& GetContiguousBuffer(size_t aSize) = 0; 331 332 virtual void IncrementEventCount() = 0; 333 }; 334 335 struct MemStream { 336 char* mData; 337 size_t mLength; 338 size_t mCapacity; 339 bool mValid = true; 340 bool Resize(size_t aSize) { 341 if (!mValid) { 342 return false; 343 } 344 mLength = aSize; 345 if (mLength > mCapacity) { 346 mCapacity = mCapacity * 2; 347 // check if the doubled capacity is enough 348 // otherwise use double mLength 349 if (mLength > mCapacity) { 350 mCapacity = mLength * 2; 351 } 352 char* data = (char*)realloc(mData, mCapacity); 353 if (!data) { 354 free(mData); 355 } 356 mData = data; 357 } 358 if (mData) { 359 return true; 360 } 361 NS_ERROR("Failed to allocate MemStream!"); 362 mValid = false; 363 mLength = 0; 364 mCapacity = 0; 365 return false; 366 } 367 368 void reset() { 369 free(mData); 370 mData = nullptr; 371 mValid = true; 372 mLength = 0; 373 mCapacity = 0; 374 } 375 376 MemStream(const MemStream&) = delete; 377 MemStream(MemStream&&) = delete; 378 MemStream& operator=(const MemStream&) = delete; 379 MemStream& operator=(MemStream&&) = delete; 380 381 void write(const char* aData, size_t aSize) { 382 if (Resize(mLength + aSize)) { 383 memcpy(mData + mLength - aSize, aData, aSize); 384 } 385 } 386 387 MemStream() : mData(nullptr), mLength(0), mCapacity(0) {} 388 ~MemStream() { free(mData); } 389 }; 390 391 class EventStream { 392 public: 393 virtual void write(const char* aData, size_t aSize) = 0; 394 virtual void read(char* aOut, size_t aSize) = 0; 395 virtual bool good() = 0; 396 virtual void SetIsBad() = 0; 397 }; 398 399 class RecordedEvent { 400 public: 401 enum EventType : uint8_t { 402 INVALID = 0, 403 DRAWTARGETCREATION, 404 DRAWTARGETDESTRUCTION, 405 SETCURRENTDRAWTARGET, 406 FILLRECT, 407 STROKERECT, 408 STROKELINE, 409 STROKECIRCLE, 410 CLEARRECT, 411 COPYSURFACE, 412 SETPERMITSUBPIXELAA, 413 SETTRANSFORM, 414 PUSHCLIP, 415 PUSHCLIPRECT, 416 POPCLIP, 417 REMOVEALLCLIPS, 418 FILL, 419 FILLCIRCLE, 420 FILLGLYPHS, 421 STROKEGLYPHS, 422 MASK, 423 STROKE, 424 DRAWSURFACE, 425 DRAWSURFACEDESCRIPTOR, 426 DRAWDEPENDENTSURFACE, 427 DRAWSURFACEWITHSHADOW, 428 DRAWSHADOW, 429 PATHCREATION, 430 PATHDESTRUCTION, 431 SOURCESURFACECREATION, 432 SOURCESURFACEDESTRUCTION, 433 GRADIENTSTOPSCREATION, 434 GRADIENTSTOPSDESTRUCTION, 435 SNAPSHOT, 436 SCALEDFONTCREATION, 437 SCALEDFONTDESTRUCTION, 438 MASKSURFACE, 439 FILTERNODECREATION, 440 DEFERFILTERINPUT, 441 FILTERNODEDESTRUCTION, 442 DRAWFILTER, 443 FILTERNODESETATTRIBUTE, 444 FILTERNODESETINPUT, 445 CREATESIMILARDRAWTARGET, 446 CREATECLIPPEDDRAWTARGET, 447 CREATEDRAWTARGETFORFILTER, 448 FONTDATA, 449 FONTDESC, 450 PUSHLAYER, 451 PUSHLAYERWITHBLEND, 452 POPLAYER, 453 UNSCALEDFONTCREATION, 454 UNSCALEDFONTDESTRUCTION, 455 INTOLUMINANCE, 456 EXTRACTSUBRECT, 457 EXTERNALSURFACECREATION, 458 FLUSH, 459 DETACHALLSNAPSHOTS, 460 OPTIMIZESOURCESURFACE, 461 LINK, 462 DESTINATION, 463 LAST, 464 }; 465 466 virtual ~RecordedEvent() = default; 467 468 static std::string GetEventName(EventType aType); 469 470 /** 471 * Play back this event using the translator. Note that derived classes 472 * should 473 * only return false when there is a fatal error, as it will probably mean 474 * the 475 * translation will abort. 476 * @param aTranslator Translator to be used for retrieving other referenced 477 * objects and making playback decisions. 478 * @return true unless a fatal problem has occurred and playback should 479 * abort. 480 */ 481 virtual bool PlayEvent(Translator* aTranslator) const { return true; } 482 483 virtual void RecordToStream(std::ostream& aStream) const = 0; 484 virtual void RecordToStream(EventStream& aStream) const = 0; 485 virtual void RecordToStream(ContiguousBufferStream& aStream) const = 0; 486 virtual void RecordToStream(MemStream& aStream) const = 0; 487 488 virtual void OutputSimpleEventInfo(std::stringstream& aStringStream) const {} 489 490 template <class S> 491 void RecordPatternData(S& aStream, 492 const PatternStorage& aPatternStorage) const; 493 template <class S> 494 void ReadPatternData(S& aStream, PatternStorage& aPatternStorage) const; 495 void StorePattern(PatternStorage& aDestination, const Pattern& aSource) const; 496 497 virtual std::string GetName() const = 0; 498 499 virtual ReferencePtr GetDestinedDT() { return nullptr; } 500 501 void OutputSimplePatternInfo(const PatternStorage& aStorage, 502 std::stringstream& aOutput) const; 503 504 template <class S> 505 static bool DoWithEvent(S& aStream, EventType aType, 506 const std::function<bool(RecordedEvent*)>& aAction); 507 static bool DoWithEventFromStream( 508 EventStream& aStream, EventType aType, 509 const std::function<bool(RecordedEvent*)>& aAction); 510 static bool DoWithEventFromReader( 511 MemReader& aReader, EventType aType, 512 const std::function<bool(RecordedEvent*)>& aAction); 513 514 EventType GetType() const { return (EventType)mType; } 515 516 protected: 517 friend class DrawEventRecorderPrivate; 518 friend class DrawEventRecorderMemory; 519 static void RecordUnscaledFont(UnscaledFont* aUnscaledFont, 520 std::ostream* aOutput); 521 static void RecordUnscaledFont(UnscaledFont* aUnscaledFont, 522 MemStream& aOutput); 523 template <class S> 524 static void RecordUnscaledFontImpl(UnscaledFont* aUnscaledFont, S& aOutput); 525 526 MOZ_IMPLICIT RecordedEvent(EventType aType) : mType(aType) {} 527 528 EventType mType; 529 }; 530 531 class RecordedStrokeOptionsMixin { 532 public: 533 template <class S> 534 void RecordStrokeOptions(S& aStream, 535 const StrokeOptions& aStrokeOptions) const; 536 template <class S> 537 void ReadStrokeOptions(S& aStream, StrokeOptions& aStrokeOptions); 538 539 protected: 540 UniquePtr<Float[]> mDashPatternStorage; 541 }; 542 543 template <typename T, typename Z = size_t> 544 class RecordedEventArray { 545 public: 546 T* data() { return mData.get(); } 547 const T* data() const { return mData.get(); } 548 Z size() const { return mSize; } 549 bool empty() const { return !mSize; } 550 551 void Assign(const T* aData, Z aSize) { 552 mSize = aSize; 553 mData = MakeUnique<T[]>(aSize); 554 PodCopy(mData.get(), aData, aSize); 555 } 556 557 bool TryAlloc(Z aSize) { 558 if (mSize > 0) { 559 MOZ_ASSERT_UNREACHABLE(); 560 return false; 561 } 562 mData = MakeUniqueFallible<T[]>(aSize); 563 if (!mData) { 564 return false; 565 } 566 mSize = aSize; 567 return true; 568 } 569 570 bool TryAssign(const T* aData, Z aSize) { 571 if (!TryAlloc(aSize)) { 572 return false; 573 } 574 PodCopy(mData.get(), aData, aSize); 575 return true; 576 } 577 578 template <typename S> 579 void Write(S& aStream) const { 580 if (mSize) { 581 aStream.write(reinterpret_cast<const char*>(mData.get()), 582 sizeof(T) * mSize); 583 } 584 } 585 586 template <typename S> 587 bool Read(S& aStream, Z aSize) { 588 if (!aStream.good() || !TryAlloc(aSize)) { 589 return false; 590 } 591 aStream.read(reinterpret_cast<char*>(mData.get()), sizeof(T) * mSize); 592 if (!aStream.good()) { 593 Clear(); 594 return false; 595 } 596 return true; 597 } 598 599 void Clear() { 600 mSize = 0; 601 mData.reset(); 602 } 603 604 protected: 605 Z mSize = 0; 606 UniquePtr<T[]> mData; 607 }; 608 609 class RecordedEventCString : public RecordedEventArray<char> { 610 public: 611 explicit RecordedEventCString(const char* aStr = nullptr) { 612 if (aStr) { 613 if (size_t len = strlen(aStr)) { 614 Assign(aStr, len + 1); 615 } 616 } 617 } 618 619 template <typename S> 620 bool Read(S& aStream, size_t aSize) { 621 if (!RecordedEventArray<char>::Read(aStream, aSize) || 622 (size() > 0 && !memchr(data(), '\0', size()))) { 623 Clear(); 624 return false; 625 } 626 return true; 627 } 628 }; 629 630 template <class Derived> 631 class RecordedEventDerived : public RecordedEvent { 632 using RecordedEvent::RecordedEvent; 633 634 public: 635 void RecordToStream(std::ostream& aStream) const override { 636 WriteElement(aStream, this->mType); 637 static_cast<const Derived*>(this)->Record(aStream); 638 } 639 void RecordToStream(EventStream& aStream) const override { 640 WriteElement(aStream, this->mType); 641 static_cast<const Derived*>(this)->Record(aStream); 642 } 643 void RecordToStream(ContiguousBufferStream& aStream) const final { 644 aStream.RecordEvent(static_cast<const Derived*>(this)); 645 } 646 void RecordToStream(MemStream& aStream) const override { 647 SizeCollector size; 648 WriteElement(size, this->mType); 649 static_cast<const Derived*>(this)->Record(size); 650 651 if (!aStream.Resize(aStream.mLength + size.mTotalSize)) { 652 return; 653 } 654 655 MemWriter writer(aStream.mData + aStream.mLength - size.mTotalSize); 656 WriteElement(writer, this->mType); 657 static_cast<const Derived*>(this)->Record(writer); 658 } 659 }; 660 661 } // namespace gfx 662 } // namespace mozilla 663 664 // Helper struct that allows ReferencePtr to be used as a key in 665 // std::unordered_map 666 template <> 667 struct std::hash<mozilla::gfx::ReferencePtr> { 668 std::size_t operator()(const mozilla::gfx::ReferencePtr& aRef) const { 669 return std::hash<uint64_t>{}(aRef.mLongPtr); 670 } 671 }; 672 673 #endif