docs
Loading...
Searching...
No Matches
Surfaceabstract

#include <Ultralight/platform/Surface.h>

Overview

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().

Precondition
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().

Inheritance diagram for Surface:
BitmapSurface

Static Public Member Functions

static void ShiftPixels (void *pixels, uint32_t row_bytes, const IntRect &rect, int dx, int dy)
 Shift a rectangle of 32-bit pixels in place.

Public Member Functions

virtual ~Surface ()
virtual uint32_t width () const =0
 Width (in pixels).
virtual uint32_t height () const =0
 Height (in pixels).
virtual uint32_t row_bytes () const =0
 Number of bytes between rows (usually width * 4).
virtual size_t size () const =0
 Size in bytes.
virtual void * LockPixels ()=0
 Lock the pixel buffer and get a pointer to the beginning of the data for reading/writing.
virtual void UnlockPixels ()=0
 Unlock the pixel buffer.
LockedPixels< Surface * > LockPixelsSafe ()
 Lock the pixel buffer for reading/writing (safe version, automatically unlocks).
virtual void Resize (uint32_t width, uint32_t height)=0
 Resize the pixel buffer to a certain width and height (both in pixels).
virtual bool Scroll (const IntRect &rect, int dx, int dy)=0
 Shift a rectangle of pixels by an offset.
virtual void set_dirty_bounds (const IntRect &bounds)
 Add a rectangle to the dirty area.
virtual IntRect dirty_bounds () const
 Get the dirty bounds.
virtual void ClearDirtyBounds ()
 Clear the dirty bounds.
uint32_t dirty_rect_count () const
 Get the number of dirty rectangles (0 when nothing has been painted since the last clear).
IntRect dirty_rect (uint32_t index) const
 Get a dirty rectangle by index.

Static Public Attributes

static constexpr uint32_t kMaxDirtyRects = 8
 The most dirty rectangles the library keeps apart before merging them.

Protected Member Functions

 Surface ()

Protected Attributes

IntRect dirty_bounds_
IntRect dirty_rects_ [kMaxDirtyRects]
uint32_t dirty_rect_count_ = 0

Constructor & Destructor Documentation

◆ ~Surface()

virtual ~Surface ( )
virtual

◆ Surface()

Surface ( )
protected

Member Function Documentation

◆ ClearDirtyBounds()

virtual void ClearDirtyBounds ( )
virtual

Clear the dirty bounds.

You should call this after you're done displaying the Surface.

◆ dirty_bounds()

virtual IntRect dirty_bounds ( ) const
virtual

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(). It always lies inside the surface, and it is empty when nothing has been painted since the last clear. It is the union of the rectangles dirty_rect() lists.

Note
The library clears the bounds itself when it resizes the surface, then paints the whole buffer, so a resize never leaves you a stale rectangle from the old size.

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();
}

◆ dirty_rect()

IntRect dirty_rect ( uint32_t index) const

Get a dirty rectangle by index.

Each rectangle lies inside dirty_bounds() and the surface. dirty_bounds() is the union of these; copy each one instead of the union to move fewer pixels when the page changed in several places (eg, a scrolled page with a fixed header). If you only ever copy dirty_bounds(), you can ignore this list.

Parameters
indexA value below dirty_rect_count().
Returns
Returns the rectangle, or an empty rectangle for an index out of range.

◆ dirty_rect_count()

uint32_t dirty_rect_count ( ) const

Get the number of dirty rectangles (0 when nothing has been painted since the last clear).

◆ height()

virtual uint32_t height ( ) const
pure virtual

Height (in pixels).

Implemented in BitmapSurface.

◆ LockPixels()

virtual void * LockPixels ( )
pure virtual

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).
Returns
Returns a pointer to the beginning of the locked pixel buffer. The buffer remains valid until UnlockPixels() is called.

Implemented in BitmapSurface.

◆ LockPixelsSafe()

LockedPixels< Surface * > LockPixelsSafe ( )
inline

Lock the pixel buffer for reading/writing (safe version, automatically unlocks).

Returns
Returns a managed container that can be used to access the pixel buffer (LockedPixels::data()). This container automatically unlocks the pixels when it goes out of scope.

◆ Resize()

virtual void Resize ( uint32_t width,
uint32_t height )
pure virtual

Resize the pixel buffer to a certain width and height (both in pixels).

This should never be called while pixels are locked.

Implemented in BitmapSurface.

◆ row_bytes()

virtual uint32_t row_bytes ( ) const
pure virtual

Number of bytes between rows (usually width * 4).

Implemented in BitmapSurface.

◆ Scroll()

virtual bool Scroll ( const IntRect & rect,
int dx,
int dy )
pure virtual

Shift a rectangle of pixels by an offset.

The library calls this during Renderer::Render() when a page scrolls, moving already painted pixels instead of repainting them. Afterward, the library repaints only the exposed strip.

The Surface pixel buffer is the source the library paints into. The destination is wherever you copy those pixels to display them (eg, a GPU texture or a window). Scroll() always shifts the source.

Most implementations do this with one call to ShiftPixels().

Parameters
rectThe rectangle to shift (in pixels). This always lies inside the surface, and the shift is smaller than the rectangle on each axis.
dxThe horizontal shift, in pixels (positive moves pixels to the right).
dyThe vertical shift, in pixels (positive moves pixels down).
Returns
Return false in most cases. This means the destination was not shifted. The library then adds rect to dirty_bounds() so you copy the moved pixels from the source to the destination again. Return true only in the rare case where you shifted the destination by the same offset yourself (eg, you scrolled your window or copied within your GPU texture)– the library then reports only the newly exposed strip as dirty.
Note
This is called while pixels are locked (between LockPixels() and UnlockPixels()). Shift through the pointer you returned from LockPixels()– do not lock the buffer again.
Note
Rows may be padded. Step rows by row_bytes(), never by width * 4.

Implemented in BitmapSurface.

◆ set_dirty_bounds()

virtual void set_dirty_bounds ( const IntRect & bounds)
virtual

Add a rectangle to the dirty area.

The library calls this after it paints an area of the pixel buffer. The rectangle is clipped to the surface and kept as one of up to kMaxDirtyRects dirty rectangles (nearby ones are merged), and dirty_bounds() grows to their union, until you call ClearDirtyBounds(). An empty or out-of-bounds rectangle changes nothing.

◆ ShiftPixels()

void ShiftPixels ( void * pixels,
uint32_t row_bytes,
const IntRect & rect,
int dx,
int dy )
static

Shift a rectangle of 32-bit pixels in place.

Use this from Scroll() (and anywhere else you hold a locked pixel buffer) to move the pixels of rect by dx and dy; overlapping rows and columns are handled for you. The strip the shift exposes keeps its old contents.

Parameters
pixelsPointer to the first row of the buffer (as returned by LockPixels()).
row_bytesNumber of bytes between rows.
rectThe rectangle to shift (in pixels, inside the buffer).
dxThe horizontal shift, in pixels (positive moves pixels to the right).
dyThe vertical shift, in pixels (positive moves pixels down).

◆ size()

virtual size_t size ( ) const
pure virtual

Size in bytes.

Implemented in BitmapSurface.

◆ UnlockPixels()

virtual void UnlockPixels ( )
pure virtual

Unlock the pixel buffer.

Implemented in BitmapSurface.

◆ width()

virtual uint32_t width ( ) const
pure virtual

Width (in pixels).

Implemented in BitmapSurface.

Member Data Documentation

◆ dirty_bounds_

IntRect dirty_bounds_
protected

◆ dirty_rect_count_

uint32_t dirty_rect_count_ = 0
protected

◆ dirty_rects_

IntRect dirty_rects_[kMaxDirtyRects]
protected

◆ kMaxDirtyRects

uint32_t kMaxDirtyRects = 8
staticconstexpr

The most dirty rectangles the library keeps apart before merging them.


The documentation for this class was generated from the following file: