/************************************************************************************************** * This file is a part of Ultralight. * * * * See for licensing and more. * * * * (C) 2024 Ultralight, Inc. * **************************************************************************************************/ #pragma once #include #include #include #include namespace ultralight { /// /// User-defined pixel buffer surface. /// /// The library uses this to store pixel data when rendering Views on the CPU (see /// ViewConfig::is_accelerated). /// /// You can provide the library with your own Surface implementation to reduce the latency of /// displaying pixels in your application (Views will be drawn directly to a block of memory /// controlled by you). /// /// When a View is rendered on the CPU, you can retrieve the backing Surface via View::surface(). /// /// @pre This is automatically managed for you when using App::Create(), if you want to override /// Surface or SurfaceFactory, you'll need to use Renderer::Create() instead. /// /// ## Default Implementation /// /// A default Surface implementation, BitmapSurface, is automatically provided by the library when /// you call Renderer::Create() without defining a custom SurfaceFactory. /// /// You should cast the Surface to a BitmapSurface to access the underlying Bitmap. /// /// ## Setting the Surface Implementation /// /// To define your own implementation, you should inherit from this class, handle the virtual /// member functions, and then define a custom SurfaceFactory that creates/destroys an /// instance of your class. /// /// After that, you should pass an instance of your custom SurfaceFactory class to /// Platform::set_surface_factory() before calling Renderer::Create(). /// class UExport Surface { public: virtual ~Surface(); /// /// Width (in pixels). /// virtual uint32_t width() const = 0; /// /// Height (in pixels). /// virtual uint32_t height() const = 0; /// /// Number of bytes between rows (usually width * 4) /// virtual uint32_t row_bytes() const = 0; /// /// Size in bytes. /// virtual size_t size() const = 0; /// /// Lock the pixel buffer and get a pointer to the beginning of the data for reading/writing. /// /// @note Native pixel format is premultiplied BGRA 32-bit (8 bits per channel). /// virtual void* LockPixels() = 0; /// /// Unlock the pixel buffer. /// virtual void UnlockPixels() = 0; /// /// Resize the pixel buffer to a certain width and height (both in pixels). /// /// This should never be called while pixels are locked. /// virtual void Resize(uint32_t width, uint32_t height) = 0; /// /// Set the dirty bounds to a certain value. /// /// This is called after the Renderer paints to an area of the pixel buffer. (The new value will /// be joined with the existing dirty_bounds()) /// virtual void set_dirty_bounds(const IntRect& bounds); /// /// Get the dirty bounds. /// /// This value can be used to determine which portion of the pixel buffer has been updated since /// the last call to ClearDirtyBounds(). /// /// The general algorithm to determine if a Surface needs display is: ///
  ///   if (!surface.dirty_bounds().IsEmpty()) {
  ///       // Surface pixels are dirty and needs display.
  ///       // Cast Surface to native Surface and use it here (pseudo code)
  ///       DisplaySurface(surface);
  ///
  ///       // Once you're done, clear the dirty bounds:
  ///       surface.ClearDirtyBounds();
  ///  }
  ///  
/// virtual IntRect dirty_bounds() const; /// /// Clear the dirty bounds. /// /// You should call this after you're done displaying the Surface. /// virtual void ClearDirtyBounds(); protected: Surface(); IntRect dirty_bounds_; }; /// /// User-defined factory to provide your own surface implementation. /// /// The library uses this to create/destroy Surface instances when rendering Views on the CPU. /// /// @pre This is automatically managed for you when using App::Create(), if you want to override /// Surface or SurfaceFactory, you'll need to use Renderer::Create() instead. /// /// ## Setting the Surface Factory /// /// The default factory creates/destroys a BitmapSurface but you can override this by providing your /// own factory to Platform::set_surface_factory(). /// class UExport SurfaceFactory { public: virtual ~SurfaceFactory(); /// /// Create a native Surface with a certain width and height (in pixels). /// virtual Surface* CreateSurface(uint32_t width, uint32_t height) = 0; /// /// Destroy a native Surface previously created by CreateSurface(). /// virtual void DestroySurface(Surface* surface) = 0; }; /// /// The default surface implementation, backed by a bitmap. /// /// This is automatically provided by the library when you call Renderer::Create() without defining /// a custom SurfaceFactory. /// /// This implementation uses a Bitmap to store pixel data (retrieve it via BitmapSurface::bitmap()). /// class UExport BitmapSurface : public Surface { public: virtual uint32_t width() const override; virtual uint32_t height() const override; virtual uint32_t row_bytes() const override; virtual size_t size() const override; virtual void* LockPixels() override; virtual void UnlockPixels() override; virtual void Resize(uint32_t width, uint32_t height) override; /// /// Get the underlying Bitmap. /// RefPtr bitmap(); protected: BitmapSurface(uint32_t width, uint32_t height); virtual ~BitmapSurface(); BitmapSurface(const BitmapSurface&) = delete; void operator=(const BitmapSurface&) = delete; friend class BitmapSurfaceFactory; void* impl_; }; /// /// Get the default Bitmap Surface Factory singleton. (Do not destroy this, this singleton is owned /// by the library). /// UExport SurfaceFactory* GetBitmapSurfaceFactory(); } // namespace ultralight