Haiku BGradient: Experimental Color Stops and Compatibility Boundaries
Use Haiku BGradient cautiously: understand color-stop mutation and drawing integration, and isolate its explicitly experimental API from stable data.
BGradient is Haiku’s public family of gradient value classes, but its own header begins with an unusually important warning: the API is experimental and may change, its color-stop offsets currently use the interval [0..255] but could move to [0..1], it has no forward binary compatibility padding, and its object size may change. That is not a minor implementation note. It means application code should isolate this family behind a small adapter, rebuild against the target Haiku release, and never persist the in-memory object layout as a file or network format.
The class exposes a gradient type, a list of color stops, and concrete geometry in subclasses such as linear, radial, diamond, and conic gradients. BGradient derives from BArchivable, which is useful for Haiku object archiving but should not be confused with a permanent interchange format. Because the documentation is largely marked undocumented and the stability warning is explicit in the headers, this guide describes the current source interface as a version-specific integration boundary rather than a finalized cross-release guarantee.
Keep gradient data separate from durable design state
Store the design intent in your own model: color values, a normalized application-level position, gradient kind, and geometry. Convert that model into a Haiku BGradient only when a view or drawing helper needs it. The wrapper lets one module translate your stable representation into the current Haiku offset interval. If Haiku later changes the scale, only that adapter and its tests need to change.
Do not serialize sizeof(BGradient), copy its private bytes, or place a raw object in a custom file. Even though the class supports archiving, do not treat undocumented archive field names as your product’s long-term file contract. Define your own versioned schema and reconstruct a gradient from your own stops and geometry on load. This also makes it possible to validate malformed or out-of-range values before invoking drawing code.
struct AppGradientStop {
rgb_color color;
float position; // Application convention: normalized 0.0 through 1.0.
};
bool BuildHaikuGradient(const AppGradientStop* stops, int32 count,
BGradientLinear* output)
{
if (stops == NULL || output == NULL || count < 2)
return false;
output->MakeEmpty();
for (int32 i = 0; i < count; ++i) {
if (!std::isfinite(stops[i].position)
|| stops[i].position < 0.0f || stops[i].position > 1.0f)
return false;
const float haikuOffset = stops[i].position * 255.0f;
if (output->AddColor(stops[i].color, haikuOffset) < 0)
return false;
}
output->SortColorStopsByOffset();
return output->CountColorStops() == count;
}
This is an adapter sketch, not a claim that every Haiku build uses this conversion forever. Verify the current AddColor() return convention, offset interpretation, and concrete class constructor against the installed SDK before compiling. The multiplication by 255 is intentionally localized so a future range change does not leak into every application feature. The function should also preserve the previous valid output on failure in production; build into a temporary object and replace the caller’s value only after all stops succeed.
Treat color stops as mutable collection state
The current public header exposes AddColor, AddColorStop, RemoveColor, SetColorStop, SetColor, SetOffset, CountColorStops, accessors, and SortColorStopsByOffset. These methods make stop editing possible, but direct accessors return pointers into the gradient’s stop storage. Do not retain a pointer from ColorStopAt() or ColorStops() across a mutation that can insert, remove, or reorder stops. Copy the stop values you need, make the mutation, then reacquire any pointers.
For editor controls, keep a separate selected-stop identifier or index and update it after sorting. A numeric index is not a permanent identity: sorting by offset changes its meaning, and removing an earlier stop shifts later positions. If the user drags a stop, decide whether equal positions are allowed and how stable ordering is handled. Do not rely on undocumented tie-breaking when two stops share the same offset.
Validate count and offsets at your own API boundary. The public setter signatures do not substitute for a policy on NaN, infinity, duplicate offsets, or empty gradients. Decide whether positions are clamped, rejected, or normalized. Reject NaN explicitly because it does not sort as an ordinary number. If you allow duplicate offsets for hard transitions, test the visible result on the target release rather than inferring renderer behavior from the data structure.
Keep gradient geometry distinct from stop interpolation
BGradientLinear, BGradientRadial, BGradientRadialFocus, BGradientDiamond, and BGradientConic are separate subclasses that add geometry to the color-stop list. The type enum also includes TYPE_NONE. Select a concrete class that expresses the intended geometry and keep the geometry inputs with your application model. A list of colors alone does not say where a linear gradient begins or ends, how a radial center is chosen, or what a conic angle means.
The current headers and implementations, not generic assumptions about CSS or SVG, are the authority for Haiku’s exact gradient geometry. Avoid claiming identical interpolation, color-space behavior, spread modes, or transform semantics unless the target API explicitly documents those rules. If your application imports gradients from another format, translate that format’s geometry and stop values deliberately, and document unsupported features such as repeated or reflected spread if Haiku’s API does not expose them.
Use the view’s drawing interface to apply a gradient only after verifying the target method and the gradient subtype expected by the current SDK. Keep drawing inside the normal view drawing lifecycle, honor the update rectangle, and do not retain a pointer to a temporary gradient after the draw call. Recompute geometry when the view frame or transform changes; a gradient can be correct as data and still be visually misaligned if it remains in stale local coordinates.
Isolate experimental classes from stable application interfaces
Experimental status changes engineering decisions. Do not expose BGradient as a plugin ABI boundary, a public C++ interface promised across releases, or a library’s externally supported type unless you control the exact Haiku target. Keep it out of public headers where possible. Prefer a wrapper that accepts plain color-stop records and converts internally, and rebuild all dependent code against the target’s actual headers.
The lack of forward binary compatibility padding means adding virtual methods can break binary compatibility; the object size may also change. This is a concrete warning against distributing a binary that expects the class layout to stay fixed across Haiku revisions. Source code may still be useful, but compile it on the supported release and test the produced binary there. Do not overstate the warning as proof that the current source API is unusable; it is a signal to avoid promising ABI stability that the project does not promise.
For an application that must support multiple Haiku revisions, compile a tiny compatibility probe in CI. Check that required headers and methods exist, instantiate each subtype used, add and enumerate stops, archive only if required, and render a deterministic sample to a bitmap. A compile-only test catches signature changes; a pixel comparison or manual screenshot catches geometry and drawing changes. Keep golden images version-scoped if rasterization legitimately changes.
Failure cases worth testing
Exercise empty, one-stop, many-stop, duplicate-stop, and out-of-range input; NaN and infinity; stop removal at both ends; repeated sorting; and gradient objects restored from application-owned versioned data. Confirm the UI does not crash if a gradient cannot be constructed. Test every subtype the application uses and verify its geometry after resize and coordinate transformation.
Also test a Haiku update before declaring compatibility. Rebuild, inspect changed headers, and run the visual test suite on the actual target. A successful build on another operating system cannot validate Haiku’s API, and a successful build against one Haiku checkout does not establish binary compatibility with a future release.
BGradient can be useful for current Haiku drawing code, but the project explicitly warns that it is experimental. The production-quality choice is to isolate it, retain a versioned application model, validate all stop data, avoid ABI promises, and test the exact Haiku versions you ship.
Related:
- Haiku BShape: Constructing Reusable Vector Paths
- Haiku BPolygon: Vertex Geometry, Mapping, and Safe Drawing
Sources: